|
@@ -1,57 +1,86 @@
|
|
<template>
|
|
<template>
|
|
- <div class="app-container">
|
|
|
|
- <div class="mx-toolbar">
|
|
|
|
- <button><span class="icon">+</span> 放大</button>
|
|
|
|
- <button><span class="icon">-</span> 缩小</button>
|
|
|
|
- <button><span class="icon">↻</span> 实际大小</button>
|
|
|
|
- <button><span class="icon">×</span> 删除</button>
|
|
|
|
- <button><span class="icon">💾</span> 保存</button>
|
|
|
|
- <button><span class="icon">📂</span> 加载</button>
|
|
|
|
- <button><span class="icon">📤</span> 导出XML</button>
|
|
|
|
- <button><span class="icon">📥</span> 导入XML</button>
|
|
|
|
- <input ref="fileInput" type="file" accept=".xml" style="display: none" />
|
|
|
|
- </div>
|
|
|
|
|
|
+ <div class="mxgraph-box">
|
|
|
|
+ <!-- 左侧 -->
|
|
<div class="editor-layout">
|
|
<div class="editor-layout">
|
|
- <div class="mx-palette">
|
|
|
|
- <div class="palette-title">基本图形</div>
|
|
|
|
- <div class="palette-shape">
|
|
|
|
- <span v-for="(shape, index) in shapes" :key="index" :style="shape.style" :class="shape.class"
|
|
|
|
|
|
+ <!-- 图形节点 -->
|
|
|
|
+ <t-collapse v-model="activeNames">
|
|
|
|
+ <t-collapse-panel value="1" header="基本图形">
|
|
|
|
+ <span
|
|
|
|
+ v-for="(shape, index) in shapes"
|
|
|
|
+ :key="index"
|
|
|
|
+ :style="shape.style"
|
|
|
|
+ :class="shape.class"
|
|
ref="baseShapeRef">
|
|
ref="baseShapeRef">
|
|
- <!-- <span class="shape-label">{{ shape.label }}</span> -->
|
|
|
|
|
|
+ <!-- <span class="shape-label">{{ shape.title }}</span> -->
|
|
</span>
|
|
</span>
|
|
|
|
+ </t-collapse-panel>
|
|
|
|
+ </t-collapse>
|
|
|
|
+ </div>
|
|
|
|
+ <!-- 顶部工具 -->
|
|
|
|
+ <div class="mx-toolbar">
|
|
|
|
+ <t-col :span="4">
|
|
|
|
+ <div
|
|
|
|
+ class="grid-content bg-purple"
|
|
|
|
+ style="color: rgb(64, 158, 255); font-weight: 800; font-size: 22px; margin-left: 44px">
|
|
|
|
+ 测试用例
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
- <div ref="graphContainerRef" id="mxgraph-container" class="mxgraph-container"></div>
|
|
|
|
- <div class="mx-properties">
|
|
|
|
- <div class="properties-title">属性</div>
|
|
|
|
- <div v-if="selectedCell" class="properties-content">
|
|
|
|
- <div class="property-item">
|
|
|
|
- <label>文本:</label>
|
|
|
|
- <input v-model="cellText" @change="updateCellText" type="text" />
|
|
|
|
- </div>
|
|
|
|
- <div class="property-item">
|
|
|
|
- <label>宽度:</label>
|
|
|
|
- <input v-model.number="cellGeometry.width" @change="updateCellGeometry" type="number" min="10" />
|
|
|
|
- </div>
|
|
|
|
- <div class="property-item">
|
|
|
|
- <label>高度:</label>
|
|
|
|
- <input v-model.number="cellGeometry.height" @change="updateCellGeometry" type="number" min="10" />
|
|
|
|
- </div>
|
|
|
|
- <div class="property-item">
|
|
|
|
- <label>填充色:</label>
|
|
|
|
- <input v-model="cellStyle.fillColor" @change="updateCellStyle" type="color" />
|
|
|
|
- </div>
|
|
|
|
- <div class="property-item">
|
|
|
|
- <label>边框色:</label>
|
|
|
|
- <input v-model="cellStyle.strokeColor" @change="updateCellStyle" type="color" />
|
|
|
|
- </div>
|
|
|
|
|
|
+ </t-col>
|
|
|
|
+ <t-col :span="4" class="tools-group">
|
|
|
|
+ <t-tooltip class="item" effect="dark" content="放大" placement="bottom">
|
|
|
|
+ <t-button variant="text">
|
|
|
|
+ <template #icon><add-icon /></template>
|
|
|
|
+ </t-button>
|
|
|
|
+ </t-tooltip>
|
|
|
|
+ <t-tooltip class="item" effect="dark" content="缩小" placement="bottom">
|
|
|
|
+ <t-button variant="text">
|
|
|
|
+ <template #icon><MinusIcon /></template>
|
|
|
|
+ </t-button>
|
|
|
|
+ </t-tooltip>
|
|
|
|
+ </t-col>
|
|
|
|
+ <input ref="fileInput" type="file" accept=".xml" style="display: none" />
|
|
|
|
+ </div>
|
|
|
|
+ <!-- 中心画布 -->
|
|
|
|
+ <div ref="graphContainerRef" id="mxgraph-container" class="mxgraph-container"></div>
|
|
|
|
+ <!-- 右侧属性 -->
|
|
|
|
+ <div class="mx-properties">
|
|
|
|
+ <div class="properties-title">属性</div>
|
|
|
|
+ <div v-if="selectedCell" class="properties-content">
|
|
|
|
+ <div class="property-item">
|
|
|
|
+ <label>文本:</label>
|
|
|
|
+ <input v-model="cellText" @change="updateCellText" type="text" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="property-item">
|
|
|
|
+ <label>宽度:</label>
|
|
|
|
+ <input
|
|
|
|
+ v-model.number="cellGeometry.width"
|
|
|
|
+ @change="updateCellGeometry"
|
|
|
|
+ type="number"
|
|
|
|
+ min="10" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="property-item">
|
|
|
|
+ <label>高度:</label>
|
|
|
|
+ <input
|
|
|
|
+ v-model.number="cellGeometry.height"
|
|
|
|
+ @change="updateCellGeometry"
|
|
|
|
+ type="number"
|
|
|
|
+ min="10" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="property-item">
|
|
|
|
+ <label>填充色:</label>
|
|
|
|
+ <input v-model="cellStyle.fillColor" @change="updateCellStyle" type="color" />
|
|
|
|
+ </div>
|
|
|
|
+ <div class="property-item">
|
|
|
|
+ <label>边框色:</label>
|
|
|
|
+ <input v-model="cellStyle.strokeColor" @change="updateCellStyle" type="color" />
|
|
</div>
|
|
</div>
|
|
- <div v-else class="properties-empty">未选中任何元素</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
+ <div v-else class="properties-empty">未选中任何元素</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
|
+import { AddIcon, MinusIcon } from 'tdesign-icons-vue-next'
|
|
|
|
+
|
|
import {
|
|
import {
|
|
myMxConstants,
|
|
myMxConstants,
|
|
myMxGraph,
|
|
myMxGraph,
|
|
@@ -96,6 +125,7 @@ const textValue = ref('')
|
|
const isNode = ref(false)
|
|
const isNode = ref(false)
|
|
const cellStyle = ref<Record<string, any>>({})
|
|
const cellStyle = ref<Record<string, any>>({})
|
|
const edgeStyle = ref('orthogonalEdgeStyle')
|
|
const edgeStyle = ref('orthogonalEdgeStyle')
|
|
|
|
+const activeNames = ref(['1'])
|
|
|
|
|
|
const graphX = ref(100)
|
|
const graphX = ref(100)
|
|
const graphY = ref(10)
|
|
const graphY = ref(10)
|
|
@@ -692,55 +722,99 @@ onMounted(async () => {
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
@import '@/assets/graph/style/general-shap.css';
|
|
@import '@/assets/graph/style/general-shap.css';
|
|
|
|
|
|
-.app-container {
|
|
|
|
- width: 100vw;
|
|
|
|
- height: 100vh;
|
|
|
|
- display: flex;
|
|
|
|
- flex-direction: column;
|
|
|
|
- font-family: Arial, sans-serif;
|
|
|
|
- overflow: hidden;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-h1 {
|
|
|
|
- padding: 12px 20px;
|
|
|
|
- font-size: 18px;
|
|
|
|
- color: #333;
|
|
|
|
- border-bottom: 1px solid #e0e0e0;
|
|
|
|
- background: #f5f5f5;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.editor-layout {
|
|
|
|
- flex: 1;
|
|
|
|
|
|
+.mxgraph-box {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: calc(100vh - 90px);
|
|
display: flex;
|
|
display: flex;
|
|
|
|
+ position: relative;
|
|
overflow: hidden;
|
|
overflow: hidden;
|
|
-}
|
|
|
|
-
|
|
|
|
-.mx-palette {
|
|
|
|
- width: 160px;
|
|
|
|
- height: 100%;
|
|
|
|
- border-right: 1px solid #e0e0e0;
|
|
|
|
- background-color: #f5f5f5;
|
|
|
|
- overflow-y: auto;
|
|
|
|
- user-select: none;
|
|
|
|
-}
|
|
|
|
|
|
+ .editor-layout {
|
|
|
|
+ padding-top: 50px;
|
|
|
|
+ font-size: 20px;
|
|
|
|
+ background: #efefef;
|
|
|
|
+ text-align: center;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ border-right: 1px solid #ededed;
|
|
|
|
+ width: 10%;
|
|
|
|
+ position: relative;
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
+ overflow-y: scroll;
|
|
|
|
+ }
|
|
|
|
+ .editor-layout::-webkit-scrollbar {
|
|
|
|
+ display: none;
|
|
|
|
+ }
|
|
|
|
+ .mxgraph-container {
|
|
|
|
+ margin-top: 50px;
|
|
|
|
+ height: 100% !important;
|
|
|
|
+ line-height: 100%;
|
|
|
|
+ position: relative;
|
|
|
|
+ overflow: hidden;
|
|
|
|
+ background-color: #fff !important;
|
|
|
|
+ flex: 1;
|
|
|
|
+ height: calc(100vh - 90px);
|
|
|
|
+ background: url('@/assets/graph/images/grid.gif');
|
|
|
|
+ }
|
|
|
|
|
|
-.palette-title {
|
|
|
|
- padding: 10px;
|
|
|
|
- font-weight: bold;
|
|
|
|
- border-bottom: 1px solid #ddd;
|
|
|
|
- background-color: #eee;
|
|
|
|
- position: sticky;
|
|
|
|
- top: 0;
|
|
|
|
- z-index: 1;
|
|
|
|
|
|
+ .mx-toolbar {
|
|
|
|
+ position: absolute;
|
|
|
|
+ display: flex;
|
|
|
|
+ align-items: center;
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
+ top: 0;
|
|
|
|
+ left: 0;
|
|
|
|
+ padding: 0 20px 0 20px;
|
|
|
|
+ width: 100%;
|
|
|
|
+ z-index: 1000;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ height: 50px;
|
|
|
|
+ // border-bottom: 1px solid #ededed;
|
|
|
|
+ box-shadow: 0px 2px 8px -4px #c4c7c1;
|
|
|
|
+ .select-edgetype {
|
|
|
|
+ width: 100px;
|
|
|
|
+ margin-right: 10px;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .mxRubberband {
|
|
|
|
+ background-color: rgb(58, 58, 207);
|
|
|
|
+ position: absolute;
|
|
|
|
+ }
|
|
|
|
+ .mx-properties {
|
|
|
|
+ width: 260px;
|
|
|
|
+ background-color: #fff;
|
|
|
|
+ height: 100%;
|
|
|
|
+ position: absolute;
|
|
|
|
+ right: 0;
|
|
|
|
+ top: 0;
|
|
|
|
+ border-left: 1px solid #ededed;
|
|
|
|
+ padding-top: 50px;
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
+ .json-viewer {
|
|
|
|
+ overflow: auto;
|
|
|
|
+ position: absolute;
|
|
|
|
+ top: 35%;
|
|
|
|
+ width: 260px;
|
|
|
|
+ height: 70%;
|
|
|
|
+ bottom: 0;
|
|
|
|
+ right: 0;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ .tools-group {
|
|
|
|
+ display: flex;
|
|
|
|
+ justify-content: center;
|
|
|
|
+ button {
|
|
|
|
+ margin-left: 22px;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
-.palette-shape {
|
|
|
|
|
|
+</style>
|
|
|
|
+<style>
|
|
|
|
+.t-collapse-panel__wrapper .t-collapse-panel__content {
|
|
width: 100%;
|
|
width: 100%;
|
|
display: flex;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
flex-wrap: wrap;
|
|
justify-content: space-around;
|
|
justify-content: space-around;
|
|
align-content: space-around;
|
|
align-content: space-around;
|
|
-
|
|
|
|
|
|
+ padding: 0;
|
|
.common {
|
|
.common {
|
|
width: 30%;
|
|
width: 30%;
|
|
cursor: pointer;
|
|
cursor: pointer;
|
|
@@ -757,94 +831,4 @@ h1 {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
-.mxgraph-container {
|
|
|
|
- flex: 1;
|
|
|
|
- height: calc(100vh - 90px);
|
|
|
|
- background: url('@/assets/graph/images/grid.gif');
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.mx-properties {
|
|
|
|
- width: 240px;
|
|
|
|
- height: 100%;
|
|
|
|
- border-left: 1px solid #e0e0e0;
|
|
|
|
- background-color: #f5f5f5;
|
|
|
|
- overflow-y: auto;
|
|
|
|
- user-select: none;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.properties-title {
|
|
|
|
- padding: 10px;
|
|
|
|
- font-weight: bold;
|
|
|
|
- border-bottom: 1px solid #ddd;
|
|
|
|
- background-color: #eee;
|
|
|
|
- position: sticky;
|
|
|
|
- top: 0;
|
|
|
|
- z-index: 1;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.properties-content {
|
|
|
|
- padding: 10px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.properties-empty {
|
|
|
|
- padding: 20px;
|
|
|
|
- text-align: center;
|
|
|
|
- color: #999;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.property-item {
|
|
|
|
- margin-bottom: 15px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.property-item label {
|
|
|
|
- display: block;
|
|
|
|
- margin-bottom: 5px;
|
|
|
|
- font-size: 13px;
|
|
|
|
- color: #666;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.property-item input[type='text'],
|
|
|
|
-.property-item input[type='number'] {
|
|
|
|
- width: 100%;
|
|
|
|
- padding: 6px;
|
|
|
|
- border: 1px solid #ddd;
|
|
|
|
- border-radius: 3px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.property-item input[type='color'] {
|
|
|
|
- width: 100%;
|
|
|
|
- height: 30px;
|
|
|
|
- padding: 2px;
|
|
|
|
- border: 1px solid #ddd;
|
|
|
|
- border-radius: 3px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.mx-toolbar {
|
|
|
|
- padding: 8px 12px;
|
|
|
|
- background: #f5f5f5;
|
|
|
|
- border-bottom: 1px solid #e0e0e0;
|
|
|
|
- display: flex;
|
|
|
|
- gap: 8px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.mx-toolbar button {
|
|
|
|
- padding: 6px 12px;
|
|
|
|
- background: white;
|
|
|
|
- border: 1px solid #ddd;
|
|
|
|
- border-radius: 4px;
|
|
|
|
- cursor: pointer;
|
|
|
|
- display: flex;
|
|
|
|
- align-items: center;
|
|
|
|
- gap: 4px;
|
|
|
|
- font-size: 13px;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.mx-toolbar button:hover {
|
|
|
|
- background: #f0f0f0;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-.mx-toolbar .icon {
|
|
|
|
- font-size: 14px;
|
|
|
|
-}
|
|
|
|
</style>
|
|
</style>
|