@mx-sose-front/mx-sose-graph 1.1.2 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +721 -454
- package/dist/index.esm.js.map +1 -1
- package/dist/index.umd.js +7 -6
- package/dist/index.umd.js.map +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/components/ContextMenu/ContextMenu.vue +18 -4
- package/src/components/InteractionLayer.vue +408 -414
- package/src/components/NameEditor.vue +212 -0
- package/src/components/SelectionBox.vue +189 -0
- package/src/constants/index.ts +2 -0
- package/src/utils/contextMenuUtils.ts +63 -6
- package/src/utils/diagram.ts +19 -15
- package/src/utils/keyboardUtils.ts +28 -0
- package/src/utils/nameEditUtils.ts +6 -1
- package/src/utils/packgeMap.ts +0 -1
|
@@ -5,28 +5,9 @@
|
|
|
5
5
|
@mousedown="onLayerMouseDown" @mouseup="onLayerMouseUp" @click="onLayerClick"
|
|
6
6
|
@contextmenu.prevent="handleContextMenu">
|
|
7
7
|
<!-- 只在"选中对象是画布(diagram)"时显示四个角手柄 -->
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
<div v-for="h in resizeHandles" :key="h.position" class="resize-handle"
|
|
12
|
-
:class="[`resize-${h.position}`, { 'is-disabled': isMultiSelected }]" :style="getHandleStyle(h, s)"
|
|
13
|
-
@mousedown.stop.prevent="startResize($event, h.position, s)" />
|
|
14
|
-
</div>
|
|
15
|
-
<div class="action-buttons"
|
|
16
|
-
v-show="!isMultiSelected && s.scenarioMenus && s.scenarioMenus.length > 0 && s.shapeType != ShapeConfig.SHAPE_TYPE"
|
|
17
|
-
:style="actionButtonsStyle(s)">
|
|
18
|
-
<div v-if="s.modelTypePropertyId" class="border-btn">
|
|
19
|
-
<button class="action-btn edit-btn"
|
|
20
|
-
@mousedown.stop.prevent="clickModelTypePropertyIdButton(s.modelTypePropertyId, s)" title="设置类型">
|
|
21
|
-
<img src="../statics/icons/childIcons/设置类型.png" alt="设置类型">
|
|
22
|
-
</button>
|
|
23
|
-
</div>
|
|
24
|
-
<button v-for="value in s.scenarioMenus" class="action-btn edit-btn"
|
|
25
|
-
@mousedown.stop.prevent="clickActionButton($event, value.code, s)" @click.stop.prevent :title="value.name">
|
|
26
|
-
<img :src="getIcon('childIcons', value.icon || '')" />
|
|
27
|
-
</button>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
8
|
+
<SelectionBox v-for="s in graphStore.marqueeShapes" :key="s.id" :shape="s" :is-busy="isBusy"
|
|
9
|
+
:is-multi-selected="isMultiSelected" @resize-start="startResize" @action-button-click="clickActionButton"
|
|
10
|
+
@model-type-property-id-click="clickModelTypePropertyIdButton" />
|
|
30
11
|
<!-- 命中容器的高亮矩形(虚线框) -->
|
|
31
12
|
<div v-if="hoverRect" :class="[
|
|
32
13
|
'hover-container-outline',
|
|
@@ -35,39 +16,26 @@
|
|
|
35
16
|
'is-valid': graphStore.hoverNestable === true,
|
|
36
17
|
},
|
|
37
18
|
]" :style="{
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
19
|
+
left: hoverRect.x - 5 + 'px',
|
|
20
|
+
top: hoverRect.y - 5 + 'px',
|
|
21
|
+
width: hoverRect.width + 10 + 'px',
|
|
22
|
+
height: hoverRect.height + 10 + 'px',
|
|
23
|
+
}" />
|
|
43
24
|
<!-- 框选预览矩形 -->
|
|
44
25
|
<div v-if="marqueeRect" class="marquee-rect" :style="getMarqueeStyle(marqueeRect)" />
|
|
45
26
|
<!-- 拖动和缩放的预览框 -->
|
|
46
27
|
<component v-for="g in allGhosts" :key="g.id" class="ghost-shape" :is="getShapeComponent(g)" :shape="g"
|
|
47
28
|
:style="getGhostShapeStyle(g)" />
|
|
48
|
-
<!--
|
|
49
|
-
<
|
|
50
|
-
graphStore.selectedShape
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
&& !graphStore.pendingNestedIds.includes(graphStore.selectedShape.id)
|
|
54
|
-
" class="name-text-box-container" :style="nameTextBoxContainerStyle(graphStore.selectedShape.id)">
|
|
55
|
-
<div class="name-text-box" :style="nameTextBoxStyle(graphStore.selectedShape)" title="点击编辑名称"></div>
|
|
56
|
-
</div>
|
|
57
|
-
|
|
58
|
-
<!-- 名称编辑输入框 -->
|
|
59
|
-
<div v-if="isEditingName && graphStore.selectedShape && graphStore.selectedShape.shapeKey !== 'ConceptRole'"
|
|
60
|
-
class="name-editor-container" :style="nameEditorContainerStyle(graphStore.selectedShape)">
|
|
61
|
-
<input ref="nameInput" v-model="editingName" class="name-input" :style="nameInputStyle(graphStore.selectedShape)"
|
|
62
|
-
@blur="nameEditManager.handleBlur(graphStore.selectedShape)"
|
|
63
|
-
@keyup.enter="nameEditManager.handleKeyUp($event, graphStore.selectedShape)"
|
|
64
|
-
@keyup.escape="nameEditManager.cancelEdit()" />
|
|
65
|
-
</div>
|
|
29
|
+
<!-- 名称编辑组件 -->
|
|
30
|
+
<NameEditor :selected-shape="graphStore.selectedShape" :can-edit="!graphStore.pendingNestedIds.includes(
|
|
31
|
+
graphStore.selectedShape?.id || ''
|
|
32
|
+
)
|
|
33
|
+
" :is-editing-name="isEditingName" :editing-name="editingName" :name-edit-manager="nameEditManager" />
|
|
66
34
|
|
|
67
35
|
<!-- 使用右键菜单组件 -->
|
|
68
36
|
<ContextMenu v-if="selectedShape && !isMultiSelected" :visible="showContextMenu" :selected-shape="selectedShape"
|
|
69
37
|
:position="contextMenuPosition" @update:visible="showContextMenu = $event"
|
|
70
|
-
@
|
|
38
|
+
@show-property-panel="onLayerDblClick(true)" />
|
|
71
39
|
|
|
72
40
|
<!-- 连接层逻辑 - 当 connectShapeData 存在时显示 -->
|
|
73
41
|
<div v-if="connectShapeData && diagramBounds" class="connect-layer" :style="layerStyle">
|
|
@@ -90,12 +58,17 @@ import {
|
|
|
90
58
|
onMounted,
|
|
91
59
|
type CSSProperties,
|
|
92
60
|
watch,
|
|
61
|
+
watchEffect,
|
|
93
62
|
} from "vue";
|
|
94
63
|
import type { Shape } from "../types";
|
|
95
64
|
import { InteractionLayerEmits } from "../types/interactionLayer";
|
|
96
|
-
import type {
|
|
65
|
+
import type {
|
|
66
|
+
InteractionLayerProps,
|
|
67
|
+
ExternalCreateDragState,
|
|
68
|
+
} from "../types/interactionLayer";
|
|
97
69
|
import { useGraphStore } from "../store/graphStore";
|
|
98
|
-
import
|
|
70
|
+
import SelectionBox from "./SelectionBox.vue";
|
|
71
|
+
import NameEditor from "./NameEditor.vue";
|
|
99
72
|
|
|
100
73
|
// 工具:几何/命中/样式/拖拽
|
|
101
74
|
import {
|
|
@@ -111,17 +84,10 @@ import {
|
|
|
111
84
|
} from "../utils/geom";
|
|
112
85
|
import { pickTarget } from "../utils/hittest";
|
|
113
86
|
import {
|
|
114
|
-
ShapeConfig,
|
|
115
|
-
selectionBoxStyle,
|
|
116
|
-
handleStyle,
|
|
117
87
|
adjustCanvasToFitAllShapes,
|
|
118
88
|
actionButtonsStyle,
|
|
119
|
-
nameTextBoxContainerStyle,
|
|
120
|
-
nameTextBoxStyle,
|
|
121
|
-
nameEditorContainerStyle,
|
|
122
|
-
nameInputStyle,
|
|
123
89
|
getMarqueeStyle,
|
|
124
|
-
getLayerStyle
|
|
90
|
+
getLayerStyle,
|
|
125
91
|
} from "../utils/diagram";
|
|
126
92
|
import { withDrag } from "../utils/dom";
|
|
127
93
|
import { checkNestViaFront } from "../utils/policy";
|
|
@@ -136,13 +102,12 @@ import { isCompartment } from "../utils/compartment";
|
|
|
136
102
|
import { HighlightUtils } from "../utils/highlightUtils";
|
|
137
103
|
import { ContextMenuUtils } from "../utils/contextMenuUtils";
|
|
138
104
|
// 静态导入图片资源
|
|
139
|
-
import { getIcon } from "../utils/iconLoader";
|
|
140
105
|
import { getUuid } from "../utils/index";
|
|
141
106
|
import { ElMessage } from "element-plus";
|
|
142
|
-
import { snapPinToParentEdge, snapPinPointerOnMove } from
|
|
143
|
-
import { createKeyboardHandler } from
|
|
107
|
+
import { snapPinToParentEdge, snapPinPointerOnMove } from "../utils/pinUtils";
|
|
108
|
+
import { createKeyboardHandler } from "../utils/keyboardUtils";
|
|
144
109
|
import { NameEditManager } from "../utils/nameEditUtils";
|
|
145
|
-
import { guardOperate } from "../utils/license-guard"
|
|
110
|
+
import { guardOperate } from "../utils/license-guard";
|
|
146
111
|
import { createResizeUtils } from "../utils/resizeUtils";
|
|
147
112
|
|
|
148
113
|
const props = defineProps<InteractionLayerProps>();
|
|
@@ -155,7 +120,7 @@ const graphStore = useGraphStore();
|
|
|
155
120
|
const { selectedShape, connectMode } = storeToRefs(graphStore);
|
|
156
121
|
|
|
157
122
|
// 是否正在“外部创建拖拽”(
|
|
158
|
-
const isExternalCreateDragging = ref(false)
|
|
123
|
+
const isExternalCreateDragging = ref(false);
|
|
159
124
|
// 光标样式(仅在按下时切换)
|
|
160
125
|
const cursorStyle = ref<"default" | "pointer">("default");
|
|
161
126
|
// 缩放时使用的预览框
|
|
@@ -186,7 +151,7 @@ const allGhosts = computed<Shape[]>(() => {
|
|
|
186
151
|
const byId = new Map<string, Shape>();
|
|
187
152
|
// 收集所有Ghost形状
|
|
188
153
|
if (!isExternalCreateDragging.value) {
|
|
189
|
-
graphStore.ghostShadow.forEach(g => byId.set(g.id, g))
|
|
154
|
+
graphStore.ghostShadow.forEach((g) => byId.set(g.id, g));
|
|
190
155
|
}
|
|
191
156
|
// 缩放时的预览
|
|
192
157
|
resizeGhostShadow.value.forEach((g) => byId.set(g.id, g));
|
|
@@ -218,32 +183,42 @@ const nameEditManager = new NameEditManager({
|
|
|
218
183
|
if (graphStore.selectedShape) {
|
|
219
184
|
emit("editName", graphStore.selectedShape, newName, oldName);
|
|
220
185
|
}
|
|
221
|
-
}
|
|
186
|
+
},
|
|
222
187
|
});
|
|
223
188
|
|
|
224
189
|
// 缩放工具实例
|
|
225
|
-
const resizeUtils = createResizeUtils(
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
eventBus.emit('resize-start', { target });
|
|
232
|
-
},
|
|
233
|
-
onResizeEnd: (target) => {
|
|
234
|
-
eventBus.emit('resize-end', { target });
|
|
190
|
+
const resizeUtils = createResizeUtils(
|
|
191
|
+
layerRef,
|
|
192
|
+
{
|
|
193
|
+
packages: props.packages,
|
|
194
|
+
diagram: props.diagram,
|
|
195
|
+
taggedValueLabels: props.taggedValueLabels,
|
|
235
196
|
},
|
|
236
|
-
|
|
237
|
-
|
|
197
|
+
{
|
|
198
|
+
onResizeStart: (target) => {
|
|
199
|
+
eventBus.emit("resize-start", { target });
|
|
200
|
+
},
|
|
201
|
+
onResizeEnd: (target) => {
|
|
202
|
+
eventBus.emit("resize-end", { target });
|
|
203
|
+
},
|
|
204
|
+
onShapeUpdate: (id, updates) => {
|
|
205
|
+
graphStore.updateShape(id, updates);
|
|
206
|
+
},
|
|
238
207
|
}
|
|
239
|
-
|
|
208
|
+
);
|
|
240
209
|
|
|
241
210
|
// 解构缩放相关的变量
|
|
242
|
-
const {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
211
|
+
const { isResizing, groupGhost, startResize } = resizeUtils;
|
|
212
|
+
|
|
213
|
+
// 名称输入框引用
|
|
214
|
+
const nameInput = ref<HTMLInputElement | null>(null);
|
|
215
|
+
|
|
216
|
+
// 监听nameInput ref变化,将其传递给NameEditManager
|
|
217
|
+
watchEffect(() => {
|
|
218
|
+
if (nameInput.value) {
|
|
219
|
+
nameEditManager.setNameInput(nameInput.value);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
247
222
|
|
|
248
223
|
// 从名称编辑管理器获取响应式状态
|
|
249
224
|
const { isEditingName, editingName } = nameEditManager.editingState;
|
|
@@ -319,15 +294,17 @@ const highlightUtils = new HighlightUtils(graphStore);
|
|
|
319
294
|
|
|
320
295
|
// 高亮相关状态 - 使用计算属性从工具类获取
|
|
321
296
|
const highlightedShape = computed(() => highlightUtils.getHighlightedShape());
|
|
322
|
-
const sourceShape = ref<Shape | null>(null)
|
|
323
|
-
const recordClickPoint = ref({ x: 0, y: 0 })
|
|
297
|
+
const sourceShape = ref<Shape | null>(null);
|
|
298
|
+
const recordClickPoint = ref({ x: 0, y: 0 });
|
|
324
299
|
// 高亮相关状态
|
|
325
300
|
const highlightTimeout = ref<ReturnType<typeof setTimeout> | null>(null); // 高亮定时器
|
|
326
301
|
|
|
327
302
|
// 正在交互:缩放中 或 元素拖动中
|
|
328
|
-
const isBusy = computed(
|
|
329
|
-
|
|
330
|
-
|
|
303
|
+
const isBusy = computed(
|
|
304
|
+
() =>
|
|
305
|
+
isResizing.value ||
|
|
306
|
+
(graphStore.isDragging && graphStore.ghostShadow.length > 0)
|
|
307
|
+
);
|
|
331
308
|
|
|
332
309
|
// 监听所有可能影响菜单显示的操作状态
|
|
333
310
|
const shouldCloseMenu = computed(() => {
|
|
@@ -337,12 +314,7 @@ const shouldCloseMenu = computed(() => {
|
|
|
337
314
|
// 预览框(ghost)的 bounds,仅在缩放时存在
|
|
338
315
|
type Rect = { x: number; y: number; width: number; height: number };
|
|
339
316
|
|
|
340
|
-
|
|
341
|
-
const clickActionButton = (event: MouseEvent, value: string, shape: Shape) => {
|
|
342
|
-
// 阻止事件冒泡,避免触发 onLayerClick
|
|
343
|
-
event.stopPropagation();
|
|
344
|
-
event.preventDefault();
|
|
345
|
-
|
|
317
|
+
const clickActionButton = (value: string, shape: Shape) => {
|
|
346
318
|
// 如果正在编辑名称,先触发失焦以保存当前编辑的内容
|
|
347
319
|
if (isEditingName.value) {
|
|
348
320
|
nameEditManager.handleBlur(graphStore.selectedShape);
|
|
@@ -351,9 +323,9 @@ const clickActionButton = (event: MouseEvent, value: string, shape: Shape) => {
|
|
|
351
323
|
// 清除选中状态,避免第一次点击时取消选中导致需要点击两次
|
|
352
324
|
graphStore.clearSelection();
|
|
353
325
|
|
|
354
|
-
graphStore.setConnectMode(
|
|
355
|
-
emit(
|
|
356
|
-
}
|
|
326
|
+
graphStore.setConnectMode("action");
|
|
327
|
+
emit("actionButtonClick", value, shape);
|
|
328
|
+
};
|
|
357
329
|
|
|
358
330
|
const clickModelTypePropertyIdButton = (value: string, shape: Shape) => {
|
|
359
331
|
// 如果正在编辑名称,先触发失焦以保存当前编辑的内容
|
|
@@ -361,16 +333,12 @@ const clickModelTypePropertyIdButton = (value: string, shape: Shape) => {
|
|
|
361
333
|
nameEditManager.handleBlur(graphStore.selectedShape);
|
|
362
334
|
}
|
|
363
335
|
|
|
364
|
-
emit(
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// 计算样式:调用 utils(保持单一职责)
|
|
368
|
-
const getSelectionBoxStyle = (shape: Shape) => selectionBoxStyle(shape);
|
|
369
|
-
const getHandleStyle = (h: any, shape: Shape) => handleStyle(h.position, shape);
|
|
336
|
+
emit("modelTypePropertyIdButtonClick", value, shape);
|
|
337
|
+
};
|
|
370
338
|
|
|
371
|
-
//
|
|
372
|
-
const
|
|
373
|
-
|
|
339
|
+
// 名称编辑处理
|
|
340
|
+
const handleEditName = (shape: Shape, newName: string, oldName: string) => {
|
|
341
|
+
emit("editName", shape, newName, oldName);
|
|
374
342
|
};
|
|
375
343
|
|
|
376
344
|
// 属性面板
|
|
@@ -394,11 +362,8 @@ const onLayerClick = (evt: MouseEvent) => {
|
|
|
394
362
|
showContextMenu.value = false;
|
|
395
363
|
}
|
|
396
364
|
|
|
397
|
-
// 检查是否点击了name-text-box
|
|
365
|
+
// 检查是否点击了name-text-box(由NameEditor组件内部处理)
|
|
398
366
|
if (target.classList.contains("name-text-box")) {
|
|
399
|
-
if (nameEditManager.canEdit(graphStore.selectedShape)) {
|
|
400
|
-
startEditName();
|
|
401
|
-
}
|
|
402
367
|
return;
|
|
403
368
|
}
|
|
404
369
|
|
|
@@ -428,18 +393,21 @@ const onLayerClick = (evt: MouseEvent) => {
|
|
|
428
393
|
const clickY = localPoint.y;
|
|
429
394
|
|
|
430
395
|
// 判断点击位置是否有图形
|
|
431
|
-
const hasShapeAtPoint = EdgeUtils.isEndPointInShape(graphStore.shapes, {
|
|
396
|
+
const hasShapeAtPoint = EdgeUtils.isEndPointInShape(graphStore.shapes, {
|
|
397
|
+
x: clickX,
|
|
398
|
+
y: clickY,
|
|
399
|
+
});
|
|
432
400
|
|
|
433
401
|
// 修改:无论是否在action模式下,只要在连接状态且点击空白处,都创建新图元
|
|
434
402
|
if (!hasShapeAtPoint) {
|
|
435
403
|
// 使用 cloneDeep 克隆 sourceShape
|
|
436
404
|
if (!!sourceShape.value?.parenShapeId) {
|
|
437
405
|
isConnecting.value = false;
|
|
438
|
-
graphStore.setConnectMode(
|
|
406
|
+
graphStore.setConnectMode("connect");
|
|
439
407
|
highlightShape(null, false); // 取消图元高亮
|
|
440
408
|
highlightUtils.clearHighlightTimeout();
|
|
441
409
|
return;
|
|
442
|
-
}
|
|
410
|
+
}
|
|
443
411
|
const newShape = _.cloneDeep(foundSourceShape);
|
|
444
412
|
|
|
445
413
|
// 修改 id(使用 getUuid)
|
|
@@ -451,8 +419,9 @@ const onLayerClick = (evt: MouseEvent) => {
|
|
|
451
419
|
(menu) => menu.code === props.connectShapeData?.shapeKey
|
|
452
420
|
);
|
|
453
421
|
// 获取 targetModels,优先使用 currentMenu 中的值
|
|
454
|
-
const targetModels =
|
|
455
|
-
|
|
422
|
+
const targetModels =
|
|
423
|
+
currentMenu?.targetCreateModel?.split(",") ||
|
|
424
|
+
props.connectShapeData?.targetCreateModel?.split(",");
|
|
456
425
|
|
|
457
426
|
// 如果只有一个 targetModel,使用它作为 shapeKey
|
|
458
427
|
if (targetModels?.length === 1) {
|
|
@@ -474,11 +443,16 @@ const onLayerClick = (evt: MouseEvent) => {
|
|
|
474
443
|
y: newShapeY,
|
|
475
444
|
width: defaultWidth,
|
|
476
445
|
height: defaultHeight,
|
|
477
|
-
modelId:
|
|
446
|
+
modelId: "",
|
|
478
447
|
};
|
|
479
448
|
|
|
480
449
|
// 添加新 shape 到画布,只传递 shapeKey 和 x, y 坐标
|
|
481
|
-
emit(
|
|
450
|
+
emit("actionButtonAdd", {
|
|
451
|
+
shapeKey: newShape.shapeKey,
|
|
452
|
+
x: newShapeX,
|
|
453
|
+
y: newShapeY,
|
|
454
|
+
diagramId: diagramId,
|
|
455
|
+
});
|
|
482
456
|
return;
|
|
483
457
|
} else {
|
|
484
458
|
handleConnectLayerClick(evt);
|
|
@@ -489,7 +463,7 @@ const onLayerClick = (evt: MouseEvent) => {
|
|
|
489
463
|
|
|
490
464
|
// 处理线条点击事件
|
|
491
465
|
const handleEdgeClick = (shape: Shape, event: MouseEvent) => {
|
|
492
|
-
console.log(
|
|
466
|
+
console.log("通过edge-click事件选中的线条数据:", shape);
|
|
493
467
|
graphStore.selectShape(shape);
|
|
494
468
|
event.stopPropagation();
|
|
495
469
|
};
|
|
@@ -499,12 +473,16 @@ const DRAG_THRESHOLD = 4;
|
|
|
499
473
|
const onLayerMouseDown = (evt: MouseEvent) => {
|
|
500
474
|
return guardOperate(async () => {
|
|
501
475
|
// 若点击的是名称虚线框/容器,避免触发清选或框选(Pin 的名称可能在外部)
|
|
502
|
-
const t = evt.target as HTMLElement | null
|
|
503
|
-
if (
|
|
476
|
+
const t = evt.target as HTMLElement | null;
|
|
477
|
+
if (
|
|
478
|
+
t &&
|
|
479
|
+
(t.classList?.contains("name-text-box") ||
|
|
480
|
+
t.closest(".name-text-box-container"))
|
|
481
|
+
) {
|
|
504
482
|
// 不改变当前选中;让后续 click 事件去触发 startEditName
|
|
505
|
-
evt.stopPropagation()
|
|
506
|
-
evt.preventDefault()
|
|
507
|
-
return
|
|
483
|
+
evt.stopPropagation();
|
|
484
|
+
evt.preventDefault();
|
|
485
|
+
return;
|
|
508
486
|
}
|
|
509
487
|
if (isResizing.value || isEditingName.value) return;
|
|
510
488
|
if (graphStore.isDragging) graphStore.endDragShape();
|
|
@@ -528,11 +506,21 @@ const onLayerMouseDown = (evt: MouseEvent) => {
|
|
|
528
506
|
showContextMenu.value = false;
|
|
529
507
|
}
|
|
530
508
|
|
|
531
|
-
cursorStyle.value =
|
|
509
|
+
cursorStyle.value =
|
|
510
|
+
hit.kind === "shape" || hit.kind === "edge" || hit.kind === "pin"
|
|
511
|
+
? "pointer"
|
|
512
|
+
: "default";
|
|
532
513
|
// 进入“框选”的条件:
|
|
533
|
-
const wantMarquee =
|
|
514
|
+
const wantMarquee =
|
|
515
|
+
evt.shiftKey ||
|
|
516
|
+
(hit.kind !== "shape" && hit.kind !== "edge" && hit.kind !== "pin");
|
|
534
517
|
if (wantMarquee) {
|
|
535
|
-
if (
|
|
518
|
+
if (
|
|
519
|
+
hit.kind !== "shape" &&
|
|
520
|
+
hit.kind !== "edge" &&
|
|
521
|
+
hit.kind !== "pin" &&
|
|
522
|
+
!evt.shiftKey
|
|
523
|
+
) {
|
|
536
524
|
graphStore.clearSelection();
|
|
537
525
|
}
|
|
538
526
|
startMarquee(pt);
|
|
@@ -542,13 +530,17 @@ const onLayerMouseDown = (evt: MouseEvent) => {
|
|
|
542
530
|
// 双击触发不同逻辑
|
|
543
531
|
if (evt.detail === 2 && graphStore.marqueeShapes.length == 1) {
|
|
544
532
|
const selectedShape = graphStore.selectedShape;
|
|
545
|
-
console.log(
|
|
533
|
+
console.log("双击选中的图元:", selectedShape);
|
|
546
534
|
|
|
547
535
|
// 判断是否为Diagram组件
|
|
548
|
-
if (
|
|
536
|
+
if (
|
|
537
|
+
selectedShape &&
|
|
538
|
+
selectedShape.shapeType !== "edge" &&
|
|
539
|
+
props.diagram?.includes(selectedShape.shapeKey)
|
|
540
|
+
) {
|
|
549
541
|
// Diagram组件的特殊双击逻辑
|
|
550
542
|
// 这里可以添加你想要的其他逻辑,例如发射自定义事件
|
|
551
|
-
emit(
|
|
543
|
+
emit("diagramDoubleClick", selectedShape);
|
|
552
544
|
// console.log(selectedShape,'Diagram组件双击事件');
|
|
553
545
|
// 不打开属性面板
|
|
554
546
|
} else {
|
|
@@ -563,7 +555,12 @@ const onLayerMouseDown = (evt: MouseEvent) => {
|
|
|
563
555
|
const { shape } = hit;
|
|
564
556
|
|
|
565
557
|
// 打印选中元素的数据信息 - 确保每次点击都能看到
|
|
566
|
-
console.log(
|
|
558
|
+
console.log(
|
|
559
|
+
"点击选中的" +
|
|
560
|
+
(hit.kind === "edge" ? "线条" : hit.kind === "pin" ? "Pin" : "图元") +
|
|
561
|
+
"数据信息:",
|
|
562
|
+
shape
|
|
563
|
+
);
|
|
567
564
|
|
|
568
565
|
const isMulti = graphStore.selectedIds.length > 1;
|
|
569
566
|
const clickedInSelection = graphStore.selectedIds.includes(shape.id);
|
|
@@ -598,12 +595,25 @@ const onLayerMouseDown = (evt: MouseEvent) => {
|
|
|
598
595
|
// 如果是 pin 类型,需要在移动过程中将“指针位置”校正为吸附后的指针坐标
|
|
599
596
|
let targetPt = curr;
|
|
600
597
|
if (ids.length === 1) {
|
|
601
|
-
const draggedShape = graphStore.shapes.find(
|
|
602
|
-
|
|
603
|
-
|
|
598
|
+
const draggedShape = graphStore.shapes.find(
|
|
599
|
+
(x) => x.id === ids[0]
|
|
600
|
+
);
|
|
601
|
+
if (
|
|
602
|
+
draggedShape &&
|
|
603
|
+
draggedShape.shapeType === "pin" &&
|
|
604
|
+
draggedShape.parenShapeId
|
|
605
|
+
) {
|
|
606
|
+
const parentShape = graphStore.shapes.find(
|
|
607
|
+
(x) => x.id === draggedShape.parenShapeId
|
|
608
|
+
);
|
|
604
609
|
if (parentShape) {
|
|
605
610
|
// 使用移动专用的吸附方法:根据 dragOffset 计算应传入 moveDraggedShape 的指针坐标
|
|
606
|
-
targetPt = snapPinPointerOnMove(
|
|
611
|
+
targetPt = snapPinPointerOnMove(
|
|
612
|
+
curr,
|
|
613
|
+
parentShape,
|
|
614
|
+
draggedShape,
|
|
615
|
+
graphStore.dragOffset || undefined
|
|
616
|
+
);
|
|
607
617
|
}
|
|
608
618
|
}
|
|
609
619
|
}
|
|
@@ -623,7 +633,7 @@ const onLayerMouseDown = (evt: MouseEvent) => {
|
|
|
623
633
|
}
|
|
624
634
|
);
|
|
625
635
|
}
|
|
626
|
-
})
|
|
636
|
+
});
|
|
627
637
|
};
|
|
628
638
|
// 框选部分
|
|
629
639
|
const startMarquee = (anchor: { x: number; y: number }) => {
|
|
@@ -695,7 +705,11 @@ const contextMenuTarget = ref<Shape | null>(null);
|
|
|
695
705
|
const isConnectAllowed = ref(false);
|
|
696
706
|
|
|
697
707
|
// 高亮图元的边框样式 - 使用工具类实现
|
|
698
|
-
const highlightShape = (
|
|
708
|
+
const highlightShape = (
|
|
709
|
+
shape: Shape | null,
|
|
710
|
+
isHighlight: boolean,
|
|
711
|
+
isValidSource: boolean = true
|
|
712
|
+
) => {
|
|
699
713
|
highlightUtils.highlightShape(shape, isHighlight, isValidSource);
|
|
700
714
|
};
|
|
701
715
|
|
|
@@ -724,7 +738,7 @@ const handleContextMenu = (event: MouseEvent) => {
|
|
|
724
738
|
} else {
|
|
725
739
|
showContextMenu.value = false;
|
|
726
740
|
}
|
|
727
|
-
})
|
|
741
|
+
});
|
|
728
742
|
};
|
|
729
743
|
|
|
730
744
|
// 关闭右键菜单
|
|
@@ -747,35 +761,38 @@ watch(shouldCloseMenu, (shouldClose) => {
|
|
|
747
761
|
closeMenu();
|
|
748
762
|
}
|
|
749
763
|
});
|
|
750
|
-
watch(
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
if (
|
|
754
|
-
|
|
755
|
-
if (
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
highlightTimeout.value
|
|
764
|
+
watch(
|
|
765
|
+
() => props.actionButtonShapeDataId,
|
|
766
|
+
(newVal) => {
|
|
767
|
+
if (newVal) {
|
|
768
|
+
const foundShape = graphStore.shapes.find((x) => x.id === newVal);
|
|
769
|
+
if (foundShape) {
|
|
770
|
+
// 连接 sourceShape 和新 shape
|
|
771
|
+
if (sourceShape.value) {
|
|
772
|
+
const connectionData = EdgeUtils.completeConnection(
|
|
773
|
+
sourceShape.value,
|
|
774
|
+
foundShape,
|
|
775
|
+
{ x: recordClickPoint.value.x, y: recordClickPoint.value.y },
|
|
776
|
+
currentConnectPoint.value,
|
|
777
|
+
graphStore.shapes
|
|
778
|
+
);
|
|
779
|
+
|
|
780
|
+
if (connectionData) {
|
|
781
|
+
emit("connectEnd", connectionData);
|
|
782
|
+
graphStore.setConnectMode("connect");
|
|
783
|
+
isConnecting.value = false;
|
|
784
|
+
highlightUtils.clearHighlightTimeout();
|
|
785
|
+
if (highlightTimeout.value) {
|
|
786
|
+
clearTimeout(highlightTimeout.value);
|
|
787
|
+
highlightTimeout.value = null;
|
|
788
|
+
}
|
|
772
789
|
}
|
|
773
790
|
}
|
|
774
791
|
}
|
|
792
|
+
// 处理 actionButtonShapeData 的逻辑
|
|
775
793
|
}
|
|
776
|
-
// 处理 actionButtonShapeData 的逻辑
|
|
777
794
|
}
|
|
778
|
-
|
|
795
|
+
);
|
|
779
796
|
|
|
780
797
|
// 鼠标移动事件处理
|
|
781
798
|
const handleMouseMove = (event: MouseEvent) => {
|
|
@@ -818,21 +835,32 @@ const checkHoverTarget = (x: number, y: number) => {
|
|
|
818
835
|
if (hoverShape) {
|
|
819
836
|
// 检查连接有效性
|
|
820
837
|
let targetModels = props.connectShapeData?.targetModels;
|
|
821
|
-
if (connectMode.value ===
|
|
838
|
+
if (connectMode.value === "action") {
|
|
822
839
|
targetModels = props.connectShapeData?.scenarioMenus?.find(
|
|
823
840
|
(menu) => menu.code === props.connectShapeData?.shapeKey
|
|
824
841
|
)?.targetModels;
|
|
825
842
|
}
|
|
826
843
|
let isAllowed = true;
|
|
827
|
-
if (
|
|
828
|
-
|
|
844
|
+
if (
|
|
845
|
+
targetModels &&
|
|
846
|
+
Array.isArray(targetModels) &&
|
|
847
|
+
targetModels.length > 0
|
|
848
|
+
) {
|
|
849
|
+
const hoverShapeType = hoverShape.shapeKey || "";
|
|
829
850
|
isAllowed = targetModels.includes(hoverShapeType);
|
|
830
851
|
}
|
|
831
852
|
// 检查parenShapeId是否匹配(无论hoverShape是否改变都要检查)
|
|
832
853
|
if (props.connectShapeData?.sourceId) {
|
|
833
|
-
const sourceShape = graphStore.shapes.find(
|
|
834
|
-
|
|
835
|
-
|
|
854
|
+
const sourceShape = graphStore.shapes.find(
|
|
855
|
+
(it) => it.id === props.connectShapeData?.sourceId
|
|
856
|
+
);
|
|
857
|
+
if (
|
|
858
|
+
sourceShape &&
|
|
859
|
+
sourceShape.parenShapeId !== hoverShape.parenShapeId &&
|
|
860
|
+
hoverShape.shapeType !== "pin" &&
|
|
861
|
+
sourceShape.shapeType !== "pin"
|
|
862
|
+
) {
|
|
863
|
+
isAllowed = false;
|
|
836
864
|
}
|
|
837
865
|
}
|
|
838
866
|
// 只有当hoverShape改变且connectShapeData存在时才发射事件
|
|
@@ -841,19 +869,25 @@ const checkHoverTarget = (x: number, y: number) => {
|
|
|
841
869
|
// 使用更严格的优先级判断逻辑,确保只要有一个属性有实际值就使用它
|
|
842
870
|
let sourceModelId;
|
|
843
871
|
// 如果modelId是有效字符串或数字,使用modelId
|
|
844
|
-
if (
|
|
872
|
+
if (
|
|
873
|
+
props.connectShapeData.modelId &&
|
|
874
|
+
props.connectShapeData.modelId.toString().trim() !== ""
|
|
875
|
+
) {
|
|
845
876
|
sourceModelId = props.connectShapeData.modelId;
|
|
846
877
|
}
|
|
847
878
|
// 否则,如果sourceModelId是有效字符串或数字,使用sourceModelId
|
|
848
|
-
else if (
|
|
879
|
+
else if (
|
|
880
|
+
props.connectShapeData.sourceModelId &&
|
|
881
|
+
props.connectShapeData.sourceModelId.toString().trim() !== ""
|
|
882
|
+
) {
|
|
849
883
|
sourceModelId = props.connectShapeData.sourceModelId;
|
|
850
884
|
}
|
|
851
885
|
// 只有当sourceModelId有值时就发射事件,并将isAllowed的值一并传递
|
|
852
886
|
if (sourceModelId) {
|
|
853
|
-
eventBus.emit(
|
|
887
|
+
eventBus.emit("edge-check", {
|
|
854
888
|
sourceModelId: sourceModelId, // 显式指定键值对,避免属性简写可能带来的混淆
|
|
855
889
|
targetModelId: hoverShape.modelId,
|
|
856
|
-
isAllowed: isAllowed // 将验证结果一并发射
|
|
890
|
+
isAllowed: isAllowed, // 将验证结果一并发射
|
|
857
891
|
});
|
|
858
892
|
}
|
|
859
893
|
}
|
|
@@ -919,7 +953,11 @@ watch(
|
|
|
919
953
|
() => props.edgeCheck,
|
|
920
954
|
(newEdgeCheck) => {
|
|
921
955
|
// 只有在连接状态下且有高亮图元时才更新
|
|
922
|
-
if (
|
|
956
|
+
if (
|
|
957
|
+
isConnecting.value &&
|
|
958
|
+
highlightedShape.value &&
|
|
959
|
+
newEdgeCheck !== undefined
|
|
960
|
+
) {
|
|
923
961
|
// 使用后端验证结果更新高亮颜色
|
|
924
962
|
highlightShape(highlightedShape.value, true, newEdgeCheck);
|
|
925
963
|
}
|
|
@@ -933,7 +971,7 @@ const handleConnectLayerClick = (event: MouseEvent) => {
|
|
|
933
971
|
const hit = pickTarget(graphStore.shapes, localPoint);
|
|
934
972
|
|
|
935
973
|
if (
|
|
936
|
-
[
|
|
974
|
+
["shape", "pin"].includes(hit.kind) &&
|
|
937
975
|
hit.shape?.id &&
|
|
938
976
|
props.connectShapeData?.sourceId &&
|
|
939
977
|
hit.shape?.id !== props.connectShapeData.sourceId
|
|
@@ -956,14 +994,20 @@ const completeConnection = (
|
|
|
956
994
|
if (!isConnectAllowed.value) {
|
|
957
995
|
isConnecting.value = false;
|
|
958
996
|
highlightShape(null, false); // 取消图元高亮
|
|
959
|
-
graphStore.setConnectMode(
|
|
997
|
+
graphStore.setConnectMode("connect");
|
|
960
998
|
highlightUtils.clearHighlightTimeout();
|
|
961
|
-
ElMessage.error(
|
|
999
|
+
ElMessage.error("当前目标图元类型不符合连接要求");
|
|
962
1000
|
return;
|
|
963
1001
|
}
|
|
964
1002
|
|
|
965
1003
|
// 嵌套情况下只能连接同一个父图元
|
|
966
|
-
if (
|
|
1004
|
+
if (
|
|
1005
|
+
sourceShape &&
|
|
1006
|
+
clickedShape &&
|
|
1007
|
+
sourceShape.parenShapeId !== clickedShape.parenShapeId &&
|
|
1008
|
+
clickedShape.shapeType !== "pin" &&
|
|
1009
|
+
sourceShape.shapeType !== "pin"
|
|
1010
|
+
) {
|
|
967
1011
|
isConnecting.value = false;
|
|
968
1012
|
highlightShape(null, false); // 取消图元高亮
|
|
969
1013
|
highlightUtils.clearHighlightTimeout();
|
|
@@ -972,33 +1016,32 @@ const completeConnection = (
|
|
|
972
1016
|
// 检查目标图元类型是否符合targetModels要求
|
|
973
1017
|
const targetModels = props.connectShapeData?.targetModels;
|
|
974
1018
|
if (targetModels && Array.isArray(targetModels) && targetModels.length > 0) {
|
|
975
|
-
|
|
976
|
-
const clickedShapeType = clickedShape.shapeKey || '';
|
|
1019
|
+
const clickedShapeType = clickedShape.shapeKey || "";
|
|
977
1020
|
if (!targetModels.includes(clickedShapeType)) {
|
|
978
1021
|
isConnecting.value = false;
|
|
979
1022
|
highlightShape(null, false); // 取消图元高亮
|
|
980
1023
|
highlightUtils.clearHighlightTimeout();
|
|
981
1024
|
// alert('当前目标图元类型不符合连接要求');
|
|
982
|
-
ElMessage.error(
|
|
1025
|
+
ElMessage.error("当前目标图元类型不符合连接要求");
|
|
983
1026
|
return;
|
|
984
1027
|
}
|
|
985
1028
|
}
|
|
986
1029
|
|
|
987
1030
|
// 检查是否已存在相同类型的边
|
|
988
|
-
const existingEdge = graphStore.shapes.find(
|
|
989
|
-
shape
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1031
|
+
const existingEdge = graphStore.shapes.find(
|
|
1032
|
+
(shape: Shape) =>
|
|
1033
|
+
shape.shapeType === "edge" &&
|
|
1034
|
+
shape.sourceId === props.connectShapeData?.sourceId &&
|
|
1035
|
+
shape.targetId === clickedShape.id &&
|
|
1036
|
+
shape.shapeKey === props.connectShapeData?.shapeKey
|
|
993
1037
|
);
|
|
994
1038
|
|
|
995
|
-
|
|
996
1039
|
// 如果边已存在,错误提示并返回
|
|
997
1040
|
if (existingEdge) {
|
|
998
1041
|
// alert('同类型的边已经存在,不能重复添加');
|
|
999
|
-
ElMessage.error(
|
|
1042
|
+
ElMessage.error("同类型的边已经存在,不能重复添加");
|
|
1000
1043
|
isConnecting.value = false;
|
|
1001
|
-
graphStore.setConnectMode(
|
|
1044
|
+
graphStore.setConnectMode("connect");
|
|
1002
1045
|
highlightShape(null, false); // 取消图元高亮
|
|
1003
1046
|
highlightUtils.clearHighlightTimeout();
|
|
1004
1047
|
return;
|
|
@@ -1013,22 +1056,27 @@ const completeConnection = (
|
|
|
1013
1056
|
);
|
|
1014
1057
|
if (connectionData) {
|
|
1015
1058
|
// ServiceObjectFlow 特殊处理:需要在 sourcePoint 和 targetPoint 创建 pin
|
|
1016
|
-
if (
|
|
1059
|
+
if (
|
|
1060
|
+
props.connectShapeData?.shapeKey?.toLowerCase().includes("objectflow") &&
|
|
1061
|
+
sourceShape &&
|
|
1062
|
+
connectionData.sourcePoint &&
|
|
1063
|
+
connectionData.targetPoint
|
|
1064
|
+
) {
|
|
1017
1065
|
const result = EdgeUtils.handleServiceObjectFlowConnection(
|
|
1018
1066
|
sourceShape,
|
|
1019
1067
|
clickedShape,
|
|
1020
1068
|
connectionData
|
|
1021
1069
|
);
|
|
1022
|
-
emit(
|
|
1070
|
+
emit("objectFlowConnectEnd", {
|
|
1023
1071
|
connectionData: result.connectionData,
|
|
1024
1072
|
outputPinBounds: result.outputPinBounds,
|
|
1025
|
-
inputPinBounds: result.inputPinBounds
|
|
1073
|
+
inputPinBounds: result.inputPinBounds,
|
|
1026
1074
|
});
|
|
1027
1075
|
} else {
|
|
1028
|
-
(connectionData as any).sourceShape = sourceShape
|
|
1029
|
-
emit(
|
|
1076
|
+
(connectionData as any).sourceShape = sourceShape;
|
|
1077
|
+
emit("connectEnd", connectionData);
|
|
1030
1078
|
}
|
|
1031
|
-
graphStore.setConnectMode(
|
|
1079
|
+
graphStore.setConnectMode("connect");
|
|
1032
1080
|
isConnecting.value = false;
|
|
1033
1081
|
highlightShape(null, false); // 取消图元高亮
|
|
1034
1082
|
highlightUtils.clearHighlightTimeout();
|
|
@@ -1058,7 +1106,8 @@ const initializeConnectPoint = () => {
|
|
|
1058
1106
|
props.diagramBounds // 传递图表边界
|
|
1059
1107
|
);
|
|
1060
1108
|
|
|
1061
|
-
if (initialPoint && sourceShape) {
|
|
1109
|
+
if (initialPoint && sourceShape) {
|
|
1110
|
+
// 确保sourceShape存在,防止从工具栏拖拽时错误初始化
|
|
1062
1111
|
currentConnectPoint.value = initialPoint;
|
|
1063
1112
|
|
|
1064
1113
|
if (!isConnecting.value) {
|
|
@@ -1164,7 +1213,7 @@ const cancelConnection = () => {
|
|
|
1164
1213
|
mousePosition,
|
|
1165
1214
|
targetConnectPoint,
|
|
1166
1215
|
targetShape,
|
|
1167
|
-
showLine
|
|
1216
|
+
showLine,
|
|
1168
1217
|
},
|
|
1169
1218
|
highlightUtils
|
|
1170
1219
|
);
|
|
@@ -1183,7 +1232,7 @@ const externalCreateDragState: ExternalCreateDragState = {
|
|
|
1183
1232
|
creatingId: null,
|
|
1184
1233
|
pendingShape: null,
|
|
1185
1234
|
isDragging: false,
|
|
1186
|
-
isCheckInFlight: false
|
|
1235
|
+
isCheckInFlight: false,
|
|
1187
1236
|
};
|
|
1188
1237
|
|
|
1189
1238
|
const resetExternalCreateDragState = () => {
|
|
@@ -1198,7 +1247,7 @@ const resetExternalCreateDragState = () => {
|
|
|
1198
1247
|
const cleanupInertShapes = async () => {
|
|
1199
1248
|
const arr = graphStore.shapes as any[];
|
|
1200
1249
|
for (let i = arr.length - 1; i >= 0; i--) {
|
|
1201
|
-
if (
|
|
1250
|
+
if ("inert" in arr[i]) {
|
|
1202
1251
|
arr.splice(i, 1);
|
|
1203
1252
|
}
|
|
1204
1253
|
}
|
|
@@ -1206,99 +1255,140 @@ const cleanupInertShapes = async () => {
|
|
|
1206
1255
|
};
|
|
1207
1256
|
|
|
1208
1257
|
//拖动中添加元素并触发嵌套逻辑,
|
|
1209
|
-
const continueExternalCreateDrag = async (payload: {
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1258
|
+
const continueExternalCreateDrag = async (payload: {
|
|
1259
|
+
clientX: number;
|
|
1260
|
+
clientY: number;
|
|
1261
|
+
shapeData?: any;
|
|
1262
|
+
}) => {
|
|
1263
|
+
externalCreateDragState.isDragging = true;
|
|
1264
|
+
isExternalCreateDragging.value = true;
|
|
1265
|
+
const pt = clientToLocalPoint(
|
|
1266
|
+
payload.clientX,
|
|
1267
|
+
payload.clientY,
|
|
1268
|
+
layerRef.value
|
|
1269
|
+
);
|
|
1213
1270
|
if (payload.shapeData) {
|
|
1214
|
-
const s = payload.shapeData
|
|
1215
|
-
const isCmp = isCompartment(s as Shape)
|
|
1271
|
+
const s = payload.shapeData;
|
|
1272
|
+
const isCmp = isCompartment(s as Shape);
|
|
1216
1273
|
externalCreateDragState.pendingShape = {
|
|
1217
1274
|
...s,
|
|
1218
1275
|
bounds: {
|
|
1219
1276
|
x: pt.x,
|
|
1220
1277
|
y: pt.y,
|
|
1221
1278
|
width: s.bounds?.width ?? 180,
|
|
1222
|
-
height: isCmp ? 120 :
|
|
1279
|
+
height: isCmp ? 120 : s.bounds?.height ?? 80,
|
|
1223
1280
|
},
|
|
1224
1281
|
inert: false,
|
|
1225
|
-
}
|
|
1282
|
+
};
|
|
1226
1283
|
}
|
|
1227
|
-
if (
|
|
1228
|
-
|
|
1284
|
+
if (
|
|
1285
|
+
!externalCreateDragState.creatingId &&
|
|
1286
|
+
externalCreateDragState.pendingShape &&
|
|
1287
|
+
isInsideCanvasClient(payload.clientX, payload.clientY, layerRef.value)
|
|
1288
|
+
) {
|
|
1289
|
+
const draft = externalCreateDragState.pendingShape;
|
|
1229
1290
|
try {
|
|
1230
|
-
graphStore.addShape(draft)
|
|
1231
|
-
graphStore.startDrag([draft.id], pt)
|
|
1232
|
-
externalCreateDragState.creatingId = draft.id
|
|
1233
|
-
externalCreateDragState.pendingShape = null
|
|
1291
|
+
graphStore.addShape(draft);
|
|
1292
|
+
graphStore.startDrag([draft.id], pt);
|
|
1293
|
+
externalCreateDragState.creatingId = draft.id;
|
|
1294
|
+
externalCreateDragState.pendingShape = null;
|
|
1234
1295
|
} finally {
|
|
1235
|
-
externalCreateDragState.isCheckInFlight = false
|
|
1296
|
+
externalCreateDragState.isCheckInFlight = false;
|
|
1236
1297
|
}
|
|
1237
1298
|
}
|
|
1238
|
-
externalCreateDragState.pendingShape = null
|
|
1299
|
+
externalCreateDragState.pendingShape = null;
|
|
1239
1300
|
|
|
1240
|
-
if (!externalCreateDragState.creatingId) return
|
|
1301
|
+
if (!externalCreateDragState.creatingId) return;
|
|
1241
1302
|
|
|
1242
|
-
let targetPt = pt
|
|
1243
|
-
const s = graphStore.shapes.find(
|
|
1244
|
-
|
|
1303
|
+
let targetPt = pt;
|
|
1304
|
+
const s = graphStore.shapes.find(
|
|
1305
|
+
(x) => x.id === externalCreateDragState.creatingId
|
|
1306
|
+
);
|
|
1307
|
+
if (s && s.shapeType === "pin") {
|
|
1245
1308
|
if (graphStore.hoverContainerId && graphStore.hoverNestable !== false) {
|
|
1246
|
-
const parent = graphStore.shapes.find(
|
|
1309
|
+
const parent = graphStore.shapes.find(
|
|
1310
|
+
(x) => x.id === graphStore.hoverContainerId
|
|
1311
|
+
);
|
|
1247
1312
|
if (parent) {
|
|
1248
|
-
const { x: adjustedX, y: adjustedY } = snapPinToParentEdge(
|
|
1249
|
-
|
|
1313
|
+
const { x: adjustedX, y: adjustedY } = snapPinToParentEdge(
|
|
1314
|
+
pt,
|
|
1315
|
+
parent,
|
|
1316
|
+
s
|
|
1317
|
+
);
|
|
1318
|
+
targetPt = { x: adjustedX, y: adjustedY };
|
|
1250
1319
|
}
|
|
1251
1320
|
}
|
|
1252
1321
|
}
|
|
1253
1322
|
|
|
1254
|
-
graphStore.moveDraggedShape(targetPt)
|
|
1255
|
-
}
|
|
1323
|
+
graphStore.moveDraggedShape(targetPt);
|
|
1324
|
+
};
|
|
1256
1325
|
|
|
1257
1326
|
//拖拽结束后重新发送事件到front中调用接口
|
|
1258
|
-
const finishExternalCreateDrag = async (payload: {
|
|
1327
|
+
const finishExternalCreateDrag = async (payload: {
|
|
1328
|
+
clientX: number;
|
|
1329
|
+
clientY: number;
|
|
1330
|
+
}) => {
|
|
1259
1331
|
try {
|
|
1260
|
-
if (!externalCreateDragState.creatingId) return
|
|
1261
|
-
const pt = clientToLocalPoint(
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1332
|
+
if (!externalCreateDragState.creatingId) return;
|
|
1333
|
+
const pt = clientToLocalPoint(
|
|
1334
|
+
payload.clientX,
|
|
1335
|
+
payload.clientY,
|
|
1336
|
+
layerRef.value
|
|
1337
|
+
);
|
|
1338
|
+
if (
|
|
1339
|
+
isInsideCanvasClient(payload.clientX, payload.clientY, layerRef.value)
|
|
1340
|
+
) {
|
|
1341
|
+
graphStore.moveDraggedShape(pt);
|
|
1342
|
+
await nextTick();
|
|
1343
|
+
const s: any = (graphStore.shapes || []).find(
|
|
1344
|
+
(x: any) => x.id == externalCreateDragState.creatingId
|
|
1345
|
+
);
|
|
1346
|
+
if ((s && s.shapeType == "shape") || s.shapeType == "pin") {
|
|
1347
|
+
const pure = _.omit(s, ["inert"]);
|
|
1348
|
+
pure.bounds = {
|
|
1349
|
+
// 覆盖为新的 bounds
|
|
1350
|
+
...pure.bounds,
|
|
1270
1351
|
x: pt.x,
|
|
1271
1352
|
y: pt.y,
|
|
1272
|
-
}
|
|
1353
|
+
};
|
|
1273
1354
|
// 先推断这次 drop 的“候选父节点”
|
|
1274
|
-
let parent: Shape | null = null
|
|
1355
|
+
let parent: Shape | null = null;
|
|
1275
1356
|
if (graphStore.hoverContainerId && graphStore.hoverNestable !== false) {
|
|
1276
|
-
parent =
|
|
1277
|
-
(
|
|
1278
|
-
|
|
1357
|
+
parent =
|
|
1358
|
+
(graphStore.shapes as any[]).find(
|
|
1359
|
+
(x: any) => x.id === graphStore.hoverContainerId
|
|
1360
|
+
) || null;
|
|
1279
1361
|
}
|
|
1280
1362
|
// 如果是 pin 类型,调整位置吸附到父图元最近的边
|
|
1281
|
-
if (pure.shapeType ===
|
|
1282
|
-
const { x: adjustedX, y: adjustedY } = snapPinToParentEdge(
|
|
1283
|
-
|
|
1284
|
-
|
|
1363
|
+
if (pure.shapeType === "pin" && parent) {
|
|
1364
|
+
const { x: adjustedX, y: adjustedY } = snapPinToParentEdge(
|
|
1365
|
+
pt,
|
|
1366
|
+
parent,
|
|
1367
|
+
pure
|
|
1368
|
+
);
|
|
1369
|
+
pure.bounds.x = adjustedX;
|
|
1370
|
+
pure.bounds.y = adjustedY;
|
|
1285
1371
|
pure.parenShapeId = parent.id;
|
|
1286
1372
|
// 将吸附后的坐标同步回 ghost
|
|
1287
|
-
graphStore.moveDraggedShape({ x: adjustedX, y: adjustedY })
|
|
1373
|
+
graphStore.moveDraggedShape({ x: adjustedX, y: adjustedY });
|
|
1288
1374
|
}
|
|
1289
1375
|
try {
|
|
1290
|
-
const { ok } = await checkNestViaFront(
|
|
1376
|
+
const { ok } = await checkNestViaFront(
|
|
1377
|
+
pure as Shape,
|
|
1378
|
+
parent,
|
|
1379
|
+
graphStore.shapes[0]
|
|
1380
|
+
);
|
|
1291
1381
|
if (!ok) {
|
|
1292
|
-
graphStore.setHoverState(null, false)
|
|
1293
|
-
await cleanupInertShapes()
|
|
1294
|
-
resetExternalCreateDragState()
|
|
1295
|
-
return
|
|
1382
|
+
graphStore.setHoverState(null, false);
|
|
1383
|
+
await cleanupInertShapes();
|
|
1384
|
+
resetExternalCreateDragState();
|
|
1385
|
+
return;
|
|
1296
1386
|
} else {
|
|
1297
|
-
graphStore.canDropOnCanvas = true
|
|
1387
|
+
graphStore.canDropOnCanvas = true;
|
|
1298
1388
|
}
|
|
1299
1389
|
} catch (error) {
|
|
1300
|
-
await cleanupInertShapes()
|
|
1301
|
-
resetExternalCreateDragState()
|
|
1390
|
+
await cleanupInertShapes();
|
|
1391
|
+
resetExternalCreateDragState();
|
|
1302
1392
|
}
|
|
1303
1393
|
// 同步对外通知
|
|
1304
1394
|
// 先构造基础数据
|
|
@@ -1311,70 +1401,92 @@ const finishExternalCreateDrag = async (payload: { clientX: number; clientY: num
|
|
|
1311
1401
|
type: s.type,
|
|
1312
1402
|
nodeType: s.shapeKey,
|
|
1313
1403
|
icon: s.icon,
|
|
1314
|
-
}
|
|
1404
|
+
};
|
|
1315
1405
|
// 如果是 pin 类型,更新 coordinate 为吸附后的 client 坐标
|
|
1316
|
-
if (pure.shapeType ===
|
|
1317
|
-
const adjustedClientPt = localToClientPoint(
|
|
1318
|
-
|
|
1319
|
-
|
|
1406
|
+
if (pure.shapeType === "pin" && parent) {
|
|
1407
|
+
const adjustedClientPt = localToClientPoint(
|
|
1408
|
+
pure.bounds.x,
|
|
1409
|
+
pure.bounds.y,
|
|
1410
|
+
layerRef.value
|
|
1411
|
+
);
|
|
1412
|
+
payloadData.coordinate.clientX = adjustedClientPt.clientX;
|
|
1413
|
+
payloadData.coordinate.clientY = adjustedClientPt.clientY;
|
|
1320
1414
|
}
|
|
1321
1415
|
// 如果当前图元的shapeKey存在于ownerRequiredShapeKeys当中,再补 ownerId 字段
|
|
1322
1416
|
// @todo OperationalPort合并到ownerRequiredShapeKeys
|
|
1323
1417
|
if (graphStore.ownerRequiredShapeKeys.includes(pure.shapeKey)) {
|
|
1324
|
-
payloadData.ownerId = parent?.modelId
|
|
1418
|
+
payloadData.ownerId = parent?.modelId;
|
|
1325
1419
|
}
|
|
1326
1420
|
// 发送事件
|
|
1327
1421
|
await new Promise<void>((resolve, reject) => {
|
|
1328
|
-
eventBus.emit(
|
|
1422
|
+
eventBus.emit("addShape", {
|
|
1329
1423
|
...payloadData,
|
|
1330
1424
|
resolve,
|
|
1331
1425
|
reject,
|
|
1332
|
-
})
|
|
1333
|
-
})
|
|
1334
|
-
if (pure.shapeType ===
|
|
1335
|
-
graphStore.endDragShape(
|
|
1426
|
+
});
|
|
1427
|
+
});
|
|
1428
|
+
if (pure.shapeType === "pin") {
|
|
1429
|
+
graphStore.endDragShape("pinDrop");
|
|
1336
1430
|
} else {
|
|
1337
|
-
graphStore.endDragShape(
|
|
1431
|
+
graphStore.endDragShape("addEntity"); // 提交拖拽(触发嵌套/吸附等 finalize)
|
|
1338
1432
|
}
|
|
1339
1433
|
}
|
|
1340
1434
|
}
|
|
1341
1435
|
} catch (error) {
|
|
1342
|
-
graphStore.setHoverState(null, false)
|
|
1343
|
-
await cleanupInertShapes()
|
|
1436
|
+
graphStore.setHoverState(null, false);
|
|
1437
|
+
await cleanupInertShapes();
|
|
1344
1438
|
} finally {
|
|
1345
|
-
await nextTick()
|
|
1346
|
-
await cleanupInertShapes()
|
|
1347
|
-
graphStore.setHoverState(null, false)
|
|
1348
|
-
resetExternalCreateDragState()
|
|
1439
|
+
await nextTick();
|
|
1440
|
+
await cleanupInertShapes();
|
|
1441
|
+
graphStore.setHoverState(null, false);
|
|
1442
|
+
resetExternalCreateDragState();
|
|
1349
1443
|
}
|
|
1350
|
-
}
|
|
1444
|
+
};
|
|
1351
1445
|
// 根据 graphStore.canDropOnCanvas 决定是否显示禁用放置图标
|
|
1352
1446
|
const onCanvasDragOver = (e: DragEvent) => {
|
|
1353
|
-
e.preventDefault()
|
|
1354
|
-
if (!e.dataTransfer) return
|
|
1447
|
+
e.preventDefault(); // 必须,否则不会触发 drop
|
|
1448
|
+
if (!e.dataTransfer) return;
|
|
1355
1449
|
if (graphStore.canDropOnCanvas) {
|
|
1356
|
-
e.dataTransfer.dropEffect =
|
|
1450
|
+
e.dataTransfer.dropEffect = "copy"; // 显示带 + 的复制光标
|
|
1357
1451
|
} else {
|
|
1358
|
-
e.dataTransfer.dropEffect =
|
|
1452
|
+
e.dataTransfer.dropEffect = "none"; //显示禁止的圈圈光标
|
|
1359
1453
|
}
|
|
1360
|
-
}
|
|
1454
|
+
};
|
|
1361
1455
|
|
|
1362
1456
|
const onCanvasDrop = (e: DragEvent) => {
|
|
1363
1457
|
if (!graphStore.canDropOnCanvas) {
|
|
1364
1458
|
// 不允许丢,直接 return
|
|
1365
|
-
return
|
|
1459
|
+
return;
|
|
1366
1460
|
}
|
|
1367
|
-
}
|
|
1461
|
+
};
|
|
1462
|
+
|
|
1368
1463
|
// 创建键盘事件处理器
|
|
1369
1464
|
const keyboardHandler = createKeyboardHandler({
|
|
1370
1465
|
onDelete: () => { },
|
|
1371
1466
|
onEditProperty: () => onLayerDblClick(true),
|
|
1372
1467
|
onCancelConnection: cancelConnection,
|
|
1373
|
-
isEditingName: () => isEditingName.value
|
|
1468
|
+
isEditingName: () => isEditingName.value,
|
|
1469
|
+
onCopy: () => {
|
|
1470
|
+
// 获取当前选中的图元
|
|
1471
|
+
const selectedShapes = graphStore.selectedIds
|
|
1472
|
+
.map((id) => graphStore.shapes.find((s) => s.id === id))
|
|
1473
|
+
.filter(Boolean) as Shape[];
|
|
1474
|
+
|
|
1475
|
+
if (selectedShapes.length === 0) {
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
// 使用ContextMenuUtils存储复制的图元
|
|
1480
|
+
ContextMenuUtils.setCopiedShapes(selectedShapes);
|
|
1481
|
+
},
|
|
1482
|
+
onPaste: () => {
|
|
1483
|
+
// 使用ContextMenuUtils处理粘贴
|
|
1484
|
+
ContextMenuUtils.handlePaste(graphStore.selectedShape);
|
|
1485
|
+
},
|
|
1374
1486
|
});
|
|
1375
1487
|
|
|
1376
1488
|
onMounted(() => {
|
|
1377
|
-
window.addEventListener(
|
|
1489
|
+
window.addEventListener("keydown", keyboardHandler);
|
|
1378
1490
|
// 添加连接层相关的事件监听
|
|
1379
1491
|
if (props.connectShapeData) {
|
|
1380
1492
|
document.addEventListener("mousemove", handleMouseMove);
|
|
@@ -1383,17 +1495,30 @@ onMounted(() => {
|
|
|
1383
1495
|
}
|
|
1384
1496
|
|
|
1385
1497
|
//拖动结束后更新情景菜单
|
|
1386
|
-
eventBus.on(
|
|
1498
|
+
eventBus.on("shape-drag-end-updateScenarioMenu", actionButtonsStyle);
|
|
1499
|
+
|
|
1500
|
+
// 监听粘贴图元事件
|
|
1501
|
+
eventBus.on("paste-shapes", (shapes: Shape[]) => {
|
|
1502
|
+
shapes.forEach((shape) => {
|
|
1503
|
+
graphStore.addShape(shape);
|
|
1504
|
+
});
|
|
1505
|
+
});
|
|
1506
|
+
|
|
1507
|
+
// 监听选择图元事件
|
|
1508
|
+
eventBus.on("select-shapes", (ids: string[]) => {
|
|
1509
|
+
graphStore.clearSelection();
|
|
1510
|
+
graphStore.selectMany(ids);
|
|
1511
|
+
});
|
|
1387
1512
|
});
|
|
1388
1513
|
onUnmounted(() => {
|
|
1389
1514
|
offDrag?.();
|
|
1390
1515
|
// 清理连接层相关的事件监听
|
|
1391
1516
|
document.removeEventListener("mousemove", handleMouseMove);
|
|
1392
1517
|
document.removeEventListener("mouseleave", handleMouseLeave);
|
|
1393
|
-
window.removeEventListener(
|
|
1518
|
+
window.removeEventListener("keydown", keyboardHandler);
|
|
1394
1519
|
// 重置名称编辑状态
|
|
1395
1520
|
nameEditManager.reset();
|
|
1396
|
-
eventBus.off(
|
|
1521
|
+
eventBus.off("shape-drag-end-updateScenarioMenu", actionButtonsStyle);
|
|
1397
1522
|
highlightUtils.clearHighlightTimeout();
|
|
1398
1523
|
// 清理高亮工具实例
|
|
1399
1524
|
highlightUtils.dispose();
|
|
@@ -1404,7 +1529,7 @@ defineExpose({
|
|
|
1404
1529
|
finishExternalCreateDrag,
|
|
1405
1530
|
handleEdgeClick,
|
|
1406
1531
|
getBoundingClientRect: () => layerRef.value?.getBoundingClientRect(),
|
|
1407
|
-
})
|
|
1532
|
+
});
|
|
1408
1533
|
</script>
|
|
1409
1534
|
|
|
1410
1535
|
<style scoped>
|
|
@@ -1416,22 +1541,11 @@ defineExpose({
|
|
|
1416
1541
|
height: 100%;
|
|
1417
1542
|
/* 应用与画布相同的缩放变换 */
|
|
1418
1543
|
transform-origin: 0 0;
|
|
1419
|
-
transform: scale(v-bind(
|
|
1544
|
+
transform: scale(v-bind("graphStore.currentScale"));
|
|
1420
1545
|
pointer-events: all;
|
|
1421
1546
|
z-index: 999;
|
|
1422
1547
|
}
|
|
1423
1548
|
|
|
1424
|
-
.selection-box {
|
|
1425
|
-
pointer-events: none;
|
|
1426
|
-
background: transparent;
|
|
1427
|
-
}
|
|
1428
|
-
|
|
1429
|
-
.resize-handles {
|
|
1430
|
-
position: relative;
|
|
1431
|
-
width: 100%;
|
|
1432
|
-
height: 100%;
|
|
1433
|
-
}
|
|
1434
|
-
|
|
1435
1549
|
.hover-container-outline {
|
|
1436
1550
|
position: absolute;
|
|
1437
1551
|
pointer-events: none;
|
|
@@ -1450,122 +1564,7 @@ defineExpose({
|
|
|
1450
1564
|
background: rgba(240, 237, 237, 0.842);
|
|
1451
1565
|
}
|
|
1452
1566
|
|
|
1453
|
-
|
|
1454
|
-
position: absolute;
|
|
1455
|
-
width: 10px;
|
|
1456
|
-
height: 10px;
|
|
1457
|
-
background-color: #007bff;
|
|
1458
|
-
border: 2px solid #fff;
|
|
1459
|
-
border-radius: 50%;
|
|
1460
|
-
pointer-events: all;
|
|
1461
|
-
transition: all 0.2s ease;
|
|
1462
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
1463
|
-
z-index: 999;
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
.resize-handle.is-disabled {
|
|
1467
|
-
cursor: default !important;
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
.resize-handle:hover {
|
|
1471
|
-
background-color: #0056b3;
|
|
1472
|
-
transform: scale(1.2);
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
.action-buttons {
|
|
1476
|
-
display: flex;
|
|
1477
|
-
flex-direction: column;
|
|
1478
|
-
gap: 4px;
|
|
1479
|
-
pointer-events: all;
|
|
1480
|
-
background: rgba(255, 255, 255, 0.95);
|
|
1481
|
-
padding: 6px;
|
|
1482
|
-
border-radius: 4px;
|
|
1483
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
1484
|
-
border: 1px solid #e0e0e0;
|
|
1485
|
-
backdrop-filter: blur(2px);
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
.action-btn {
|
|
1489
|
-
width: 28px;
|
|
1490
|
-
height: 28px;
|
|
1491
|
-
border: 1px solid #d0d0d0;
|
|
1492
|
-
border-radius: 3px;
|
|
1493
|
-
background: linear-gradient(to bottom, #f8f9fa, #e9ecef);
|
|
1494
|
-
cursor: pointer;
|
|
1495
|
-
display: flex;
|
|
1496
|
-
align-items: center;
|
|
1497
|
-
justify-content: center;
|
|
1498
|
-
font-size: 12px;
|
|
1499
|
-
font-weight: bold;
|
|
1500
|
-
font-family: "Arial", sans-serif;
|
|
1501
|
-
color: #495057;
|
|
1502
|
-
transition: all 0.2s ease;
|
|
1503
|
-
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
.action-btn:hover {
|
|
1507
|
-
background: linear-gradient(to bottom, #e3f2fd, #bbdefb);
|
|
1508
|
-
border-color: #90caf9;
|
|
1509
|
-
transform: translateY(-1px);
|
|
1510
|
-
box-shadow: 0 2px 4px rgba(33, 150, 243, 0.3);
|
|
1511
|
-
color: #1976d2;
|
|
1512
|
-
}
|
|
1513
|
-
|
|
1514
|
-
.edit-btn:hover {
|
|
1515
|
-
background: #e3f2fd;
|
|
1516
|
-
}
|
|
1517
|
-
|
|
1518
|
-
.delete-btn:hover {
|
|
1519
|
-
background: #ffebee;
|
|
1520
|
-
border-color: #f44336;
|
|
1521
|
-
}
|
|
1522
|
-
|
|
1523
|
-
.name-editor-container {
|
|
1524
|
-
pointer-events: all;
|
|
1525
|
-
}
|
|
1526
|
-
|
|
1527
|
-
.name-input {
|
|
1528
|
-
width: calc(100% - 20px);
|
|
1529
|
-
padding: 2px 4px;
|
|
1530
|
-
border: 2px solid #007bff;
|
|
1531
|
-
border-radius: 6px;
|
|
1532
|
-
font-size: 12px;
|
|
1533
|
-
font-weight: 600;
|
|
1534
|
-
background: #fff;
|
|
1535
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
1536
|
-
outline: none;
|
|
1537
|
-
text-align: center;
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
.name-input:focus {
|
|
1541
|
-
border-color: #0056b3;
|
|
1542
|
-
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
|
|
1543
|
-
}
|
|
1544
|
-
|
|
1545
|
-
.name-text-box-container {
|
|
1546
|
-
pointer-events: all;
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
.name-text-box {
|
|
1550
|
-
border: 1px dashed #007bff;
|
|
1551
|
-
background: rgba(255, 255, 255, 0.2);
|
|
1552
|
-
cursor: pointer;
|
|
1553
|
-
pointer-events: all;
|
|
1554
|
-
transition: all 0.2s ease;
|
|
1555
|
-
border-radius: 4px;
|
|
1556
|
-
box-shadow: 0 0 0 1px rgba(0, 123, 255, 0.1);
|
|
1557
|
-
height: 100%;
|
|
1558
|
-
display: flex;
|
|
1559
|
-
align-items: center;
|
|
1560
|
-
justify-content: center;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
.name-text-box:hover {
|
|
1564
|
-
border-color: #0056b3;
|
|
1565
|
-
background: rgba(0, 123, 255, 0.05);
|
|
1566
|
-
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.2);
|
|
1567
|
-
transform: scale(1.02);
|
|
1568
|
-
}
|
|
1567
|
+
/* 删除了选择框、调整大小手柄和操作按钮相关的样式,这些样式已经移到了 SelectionBox 组件中 */
|
|
1569
1568
|
|
|
1570
1569
|
.resize-ghost {
|
|
1571
1570
|
position: absolute;
|
|
@@ -1610,9 +1609,4 @@ defineExpose({
|
|
|
1610
1609
|
pointer-events: none;
|
|
1611
1610
|
z-index: 1000;
|
|
1612
1611
|
}
|
|
1613
|
-
|
|
1614
|
-
.border-btn {
|
|
1615
|
-
padding-bottom: 4px;
|
|
1616
|
-
border-bottom: 1px solid #e0e0e0;
|
|
1617
|
-
}
|
|
1618
1612
|
</style>
|