@flowgram-vue/free-layout-core 0.2.0

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.
Files changed (68) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +0 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +0 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/typings.cjs +46 -0
  8. package/dist/typings.cjs.map +1 -0
  9. package/dist/typings.d.ts +1 -0
  10. package/dist/typings.js +40 -0
  11. package/dist/typings.js.map +1 -0
  12. package/package.json +78 -0
  13. package/src/composables/index.ts +24 -0
  14. package/src/composables/typings.ts +97 -0
  15. package/src/composables/use-current-dom-node.ts +18 -0
  16. package/src/composables/use-current-entity.ts +15 -0
  17. package/src/composables/use-node-render-context.ts +18 -0
  18. package/src/composables/use-node-render.ts +192 -0
  19. package/src/composables/use-playground-readonly-state.ts +25 -0
  20. package/src/composables/use-workflow-document.ts +12 -0
  21. package/src/constants.ts +17 -0
  22. package/src/entities/index.ts +8 -0
  23. package/src/entities/workflow-line-entity.ts +640 -0
  24. package/src/entities/workflow-node-entity.ts +17 -0
  25. package/src/entities/workflow-port-entity.ts +340 -0
  26. package/src/entity-datas/index.ts +8 -0
  27. package/src/entity-datas/workflow-line-render-data.ts +136 -0
  28. package/src/entity-datas/workflow-node-lines-data.ts +166 -0
  29. package/src/entity-datas/workflow-node-ports-data.ts +253 -0
  30. package/src/env.d.ts +10 -0
  31. package/src/index.ts +18 -0
  32. package/src/layout/free-layout.ts +166 -0
  33. package/src/layout/index.ts +6 -0
  34. package/src/service/index.ts +10 -0
  35. package/src/service/workflow-drag-service.ts +969 -0
  36. package/src/service/workflow-hover-service.ts +106 -0
  37. package/src/service/workflow-operation-base-service.ts +118 -0
  38. package/src/service/workflow-reset-layout-service.ts +87 -0
  39. package/src/service/workflow-select-service.ts +128 -0
  40. package/src/typings/index.ts +19 -0
  41. package/src/typings/workflow-drag.ts +51 -0
  42. package/src/typings/workflow-edge.ts +15 -0
  43. package/src/typings/workflow-json.ts +64 -0
  44. package/src/typings/workflow-line.ts +71 -0
  45. package/src/typings/workflow-node.ts +52 -0
  46. package/src/typings/workflow-operation.ts +40 -0
  47. package/src/typings/workflow-registry.ts +34 -0
  48. package/src/typings/workflow-sub-canvas.ts +15 -0
  49. package/src/utils/build-group-json.ts +47 -0
  50. package/src/utils/compose.ts +6 -0
  51. package/src/utils/fit-view.ts +21 -0
  52. package/src/utils/flow-node-form-data.ts +45 -0
  53. package/src/utils/get-anti-overlap-position.ts +44 -0
  54. package/src/utils/get-line-center.ts +22 -0
  55. package/src/utils/get-url-params.ts +50 -0
  56. package/src/utils/index.ts +29 -0
  57. package/src/utils/layout-to-positions.ts +65 -0
  58. package/src/utils/location-config-to-point.ts +40 -0
  59. package/src/utils/nanoid.ts +10 -0
  60. package/src/utils/statics.ts +27 -0
  61. package/src/vue/index.ts +6 -0
  62. package/src/vue/node-render-provider.vue +16 -0
  63. package/src/workflow-commands.ts +14 -0
  64. package/src/workflow-document-container-module.ts +50 -0
  65. package/src/workflow-document-contribution.ts +31 -0
  66. package/src/workflow-document-option.ts +148 -0
  67. package/src/workflow-document.ts +873 -0
  68. package/src/workflow-lines-manager.ts +596 -0
@@ -0,0 +1,640 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { isEqual } from 'lodash-es';
7
+ import { domUtils, type IPoint, Rectangle, Emitter, Disposable } from '@flowgram-vue/utils';
8
+ import { Entity, type EntityOpts } from '@flowgram-vue/core';
9
+
10
+ import { type WorkflowLinesManager } from '../workflow-lines-manager';
11
+ import { type WorkflowDocument } from '../workflow-document';
12
+ import { WORKFLOW_LINE_ENTITY } from '../utils/statics';
13
+ import {
14
+ LineRenderType,
15
+ type LinePosition,
16
+ LinePoint,
17
+ LineCenterPoint,
18
+ } from '../typings/workflow-line';
19
+ import { type WorkflowEdgeJSON } from '../typings';
20
+ import { WorkflowLineRenderData } from '../entity-datas';
21
+ import { type WorkflowPortEntity } from './workflow-port-entity';
22
+ import { type WorkflowNodeEntity } from './workflow-node-entity';
23
+
24
+ export const LINE_HOVER_DISTANCE = 8; // 线条 hover 的最小检测距离
25
+ export const POINT_RADIUS = 10;
26
+
27
+ export interface WorkflowLinePortInfo {
28
+ from?: string; // 前置节点 id
29
+ to?: string; // 后置节点 id
30
+ fromPort?: string | number; // 连线的 port 位置
31
+ toPort?: string | number; // 连线的 port 位置
32
+ data?: any;
33
+ }
34
+
35
+ export interface WorkflowLineEntityOpts extends EntityOpts, WorkflowLinePortInfo {
36
+ document: WorkflowDocument;
37
+ linesManager: WorkflowLinesManager;
38
+ drawingTo?: LinePoint;
39
+ drawingFrom?: LinePoint;
40
+ uiState?: Partial<WorkflowLineUIState>;
41
+ }
42
+
43
+ export interface WorkflowLineInfo extends WorkflowLinePortInfo {
44
+ drawingTo?: LinePoint; // 正在画中的元素
45
+ drawingFrom?: LinePoint;
46
+ }
47
+
48
+ export interface WorkflowLineUIState {
49
+ /**
50
+ * 是否出错
51
+ */
52
+ hasError: boolean;
53
+ /**
54
+ * 流动
55
+ */
56
+ flowing: boolean;
57
+ /**
58
+ * 禁用
59
+ */
60
+ disabled: boolean;
61
+ /**
62
+ * 箭头反转
63
+ */
64
+ reverse: boolean;
65
+ /**
66
+ * 隐藏箭头
67
+ */
68
+ hideArrow: boolean;
69
+ /**
70
+ * 线条宽度
71
+ * @default 2
72
+ */
73
+ strokeWidth?: number;
74
+ /**
75
+ * 选中后的线条宽度
76
+ * @default 3
77
+ */
78
+ strokeWidthSelected?: number;
79
+ /**
80
+ * 收缩
81
+ * @default 10
82
+ */
83
+ shrink: number;
84
+ /**
85
+ * @deprecated use `lockedColor` instead
86
+ */
87
+ highlightColor: string;
88
+ /**
89
+ * 曲率
90
+ * only for Bezier,
91
+ * @default 0.25
92
+ */
93
+ curvature: number;
94
+ /**
95
+ * Line locked color
96
+ */
97
+ lockedColor: string;
98
+ /**
99
+ * className
100
+ */
101
+ className?: string;
102
+ /**
103
+ * style
104
+ */
105
+ style?: Record<string, string | number>;
106
+ }
107
+
108
+ /**
109
+ * 线条
110
+ */
111
+ export class WorkflowLineEntity extends Entity<WorkflowLineEntityOpts> {
112
+ static type = WORKFLOW_LINE_ENTITY;
113
+
114
+ /**
115
+ * 转成线条 id
116
+ * @param info
117
+ */
118
+ static portInfoToLineId(info: WorkflowLinePortInfo): string {
119
+ const { from, to, fromPort, toPort } = info;
120
+ return `${from}_${fromPort || ''}-${to || ''}_${toPort || ''}`;
121
+ }
122
+
123
+ private _onLineDataChangeEmitter = new Emitter<{ oldValue: any; newValue: any }>();
124
+
125
+ readonly document: WorkflowDocument;
126
+
127
+ readonly linesManager: WorkflowLinesManager;
128
+
129
+ readonly onLineDataChange = this._onLineDataChangeEmitter.event;
130
+
131
+ private _from?: WorkflowNodeEntity;
132
+
133
+ private _to?: WorkflowNodeEntity;
134
+
135
+ private _lineData: any;
136
+
137
+ private _uiState: WorkflowLineUIState = {
138
+ hasError: false,
139
+ flowing: false,
140
+ disabled: false,
141
+ hideArrow: false,
142
+ reverse: false,
143
+ shrink: 10,
144
+ curvature: 0.25,
145
+ highlightColor: '',
146
+ lockedColor: '',
147
+ };
148
+
149
+ /**
150
+ * 线条的 UI 状态
151
+ */
152
+ get uiState(): WorkflowLineUIState {
153
+ return this._uiState;
154
+ }
155
+
156
+ /**
157
+ * 更新线条的 ui 状态
158
+ * @param newState
159
+ */
160
+ updateUIState(newState: Partial<WorkflowLineUIState>): void {
161
+ let changed = false;
162
+ Object.keys(newState).forEach((key: string) => {
163
+ const value: any = newState[key as keyof WorkflowLineUIState] as any;
164
+ if (this._uiState[key as keyof WorkflowLineUIState] !== value) {
165
+ (this._uiState as any)[key as keyof WorkflowLineUIState] = value;
166
+ changed = true;
167
+ }
168
+ });
169
+ if (changed) {
170
+ this.fireChange();
171
+ }
172
+ }
173
+
174
+ /**
175
+ * 线条的扩展数据
176
+ */
177
+ get lineData(): any {
178
+ return this._lineData;
179
+ }
180
+
181
+ /**
182
+ * 更新线条扩展数据
183
+ * @param data
184
+ */
185
+ set lineData(newValue: any) {
186
+ const oldValue = this._lineData;
187
+ if (!isEqual(oldValue, newValue)) {
188
+ this._lineData = newValue;
189
+ this._onLineDataChangeEmitter.fire({ oldValue, newValue });
190
+ this.fireChange();
191
+ }
192
+ }
193
+
194
+ public stackIndex = 0;
195
+
196
+ /**
197
+ * 线条数据
198
+ */
199
+ info: WorkflowLineInfo = {
200
+ from: '',
201
+ };
202
+
203
+ readonly isDrawing: boolean;
204
+
205
+ /**
206
+ * 线条 Portal 挂载的 div
207
+ */
208
+ private _node?: HTMLDivElement;
209
+
210
+ constructor(opts: WorkflowLineEntityOpts) {
211
+ super(opts);
212
+ this.document = opts.document;
213
+ this.linesManager = opts.linesManager;
214
+ // 初始化
215
+ this.initInfo({
216
+ from: opts.from,
217
+ to: opts.to,
218
+ drawingTo: opts.drawingTo,
219
+ fromPort: opts.fromPort,
220
+ drawingFrom: opts.drawingFrom,
221
+ toPort: opts.toPort,
222
+ data: opts.data,
223
+ });
224
+ if (opts.uiState) {
225
+ this._uiState = {
226
+ ...this._uiState,
227
+ ...opts.uiState,
228
+ };
229
+ }
230
+ if (opts.drawingTo || opts.drawingFrom) {
231
+ this.isDrawing = true;
232
+ }
233
+ this.onEntityChange(() => {
234
+ this.fromPort?.validate();
235
+ this.toPort?.validate();
236
+ });
237
+ this.onDispose(() => {
238
+ this.fromPort?.validate();
239
+ this.toPort?.validate();
240
+ });
241
+ this.toDispose.push(this._onLineDataChangeEmitter);
242
+ this.preDispose.push(
243
+ Disposable.create(() => this.linesManager.rebindLinePorts(this, this.info, undefined))
244
+ );
245
+ // this.onDispose(() => {
246
+ // this._infoDispose.dispose();
247
+ // });
248
+ }
249
+
250
+ /**
251
+ * 获取线条的前置节点
252
+ */
253
+ get from(): WorkflowNodeEntity | undefined {
254
+ return this._from;
255
+ }
256
+
257
+ /**
258
+ * 获取线条的后置节点
259
+ */
260
+ get to(): WorkflowNodeEntity | undefined {
261
+ return this._to;
262
+ }
263
+
264
+ get isHidden(): boolean {
265
+ return this.highlightColor === this.linesManager.lineColor.hidden;
266
+ }
267
+
268
+ get inContainer(): boolean {
269
+ const nodeInContainer = (node?: WorkflowNodeEntity) =>
270
+ !!node?.parent && node.parent.flowNodeType !== 'root';
271
+ return nodeInContainer(this.from) || nodeInContainer(this.to);
272
+ }
273
+
274
+ /**
275
+ * 获取是否 testrun processing
276
+ * @deprecated use `flowing` instead
277
+ */
278
+ get processing(): boolean {
279
+ return this._uiState.flowing;
280
+ }
281
+
282
+ /**
283
+ * 设置 testrun processing 状态
284
+ * @deprecated use `flowing` instead
285
+ */
286
+ set processing(status: boolean) {
287
+ this.flowing = status;
288
+ }
289
+
290
+ // 获取连线是否为错误态
291
+ get hasError() {
292
+ return this.uiState.hasError;
293
+ }
294
+
295
+ // 设置连线的错误态
296
+ set hasError(hasError: boolean) {
297
+ this.updateUIState({
298
+ hasError,
299
+ });
300
+ if (this._node) {
301
+ this._node.dataset.hasError = this.hasError ? 'true' : 'false';
302
+ }
303
+ }
304
+
305
+ /**
306
+ * 设置线条的后置节点
307
+ */
308
+ setToPort(toPort?: WorkflowPortEntity) {
309
+ // 只有绘制中的线条才允许设置 port, 主要用于吸附到点
310
+ if (!this.isDrawing) {
311
+ throw new Error('[setToPort] only support drawing line.');
312
+ }
313
+ if (this.toPort === toPort) {
314
+ return;
315
+ }
316
+ const prePort = this.toPort;
317
+ if (
318
+ toPort &&
319
+ toPort.portType === 'input' &&
320
+ this.linesManager.canAddLine(this.fromPort!, toPort, true)
321
+ ) {
322
+ const { node, portID } = toPort;
323
+ this.updateInfo((nextInfo) => {
324
+ nextInfo.drawingTo = undefined;
325
+ nextInfo.to = node.id;
326
+ nextInfo.toPort = portID;
327
+ });
328
+ } else {
329
+ this.updateInfo((nextInfo) => {
330
+ nextInfo.to = undefined;
331
+ nextInfo.toPort = '';
332
+ });
333
+ }
334
+ /**
335
+ * 移动到端口又快速移出,需要更新 prePort 的状态
336
+ */
337
+ if (prePort) {
338
+ prePort.validate();
339
+ }
340
+ }
341
+
342
+ setFromPort(fromPort?: WorkflowPortEntity) {
343
+ // 只有绘制中的线条才允许设置 port, 主要用于吸附到点
344
+ if (!this.isDrawing) {
345
+ throw new Error('[setFromPort] only support drawing line.');
346
+ }
347
+ if (this.fromPort === fromPort) {
348
+ return;
349
+ }
350
+ const prePort = this.fromPort;
351
+ if (
352
+ fromPort &&
353
+ fromPort.portType === 'output' &&
354
+ this.linesManager.canAddLine(fromPort, this.toPort!, true)
355
+ ) {
356
+ const { node, portID } = fromPort;
357
+ this.updateInfo((nextInfo) => {
358
+ nextInfo.drawingFrom = undefined;
359
+ nextInfo.from = node.id;
360
+ nextInfo.fromPort = portID;
361
+ });
362
+ } else {
363
+ this.updateInfo((nextInfo) => {
364
+ nextInfo.from = undefined;
365
+ nextInfo.fromPort = '';
366
+ });
367
+ }
368
+ /**
369
+ * 移动到端口又快速移出,需要更新 prePort 的状态
370
+ */
371
+ if (prePort) {
372
+ prePort.validate();
373
+ }
374
+ }
375
+
376
+ /**
377
+ * 设置线条画线时的目标位置
378
+ */
379
+ set drawingTo(pos: LinePoint | undefined) {
380
+ const oldDrawingTo = this.info.drawingTo;
381
+ if (!pos) {
382
+ if (oldDrawingTo === undefined) {
383
+ this.fireChange();
384
+ return;
385
+ }
386
+ this.updateInfo((nextInfo) => {
387
+ nextInfo.drawingTo = undefined;
388
+ });
389
+ return;
390
+ }
391
+ if (!oldDrawingTo || pos.x !== oldDrawingTo.x || pos.y !== oldDrawingTo.y) {
392
+ this.updateInfo((nextInfo) => {
393
+ nextInfo.to = undefined;
394
+ nextInfo.toPort = '';
395
+ nextInfo.drawingTo = pos;
396
+ });
397
+ }
398
+ }
399
+
400
+ set drawingFrom(pos: LinePoint | undefined) {
401
+ const oldDrawingFrom = this.info.drawingFrom;
402
+ if (!pos) {
403
+ if (oldDrawingFrom === undefined) {
404
+ this.fireChange();
405
+ return;
406
+ }
407
+ this.updateInfo((nextInfo) => {
408
+ nextInfo.drawingFrom = undefined;
409
+ });
410
+ return;
411
+ }
412
+ if (!oldDrawingFrom || pos.x !== oldDrawingFrom.x || pos.y !== oldDrawingFrom.y) {
413
+ this.updateInfo((nextInfo) => {
414
+ nextInfo.from = undefined;
415
+ nextInfo.fromPort = '';
416
+ nextInfo.drawingFrom = pos;
417
+ });
418
+ }
419
+ }
420
+
421
+ get drawingFrom(): LinePoint | undefined {
422
+ return this.info.drawingFrom;
423
+ }
424
+
425
+ /**
426
+ * 获取线条正在画线的位置
427
+ */
428
+ get drawingTo(): LinePoint | undefined {
429
+ return this.info.drawingTo;
430
+ }
431
+
432
+ get highlightColor(): string {
433
+ return this.uiState.highlightColor || '';
434
+ }
435
+
436
+ set highlightColor(highlightColor) {
437
+ this.updateUIState({
438
+ highlightColor,
439
+ });
440
+ }
441
+
442
+ get lockedColor(): string {
443
+ return this.uiState.lockedColor;
444
+ }
445
+
446
+ set lockedColor(lockedColor: string) {
447
+ this.updateUIState({
448
+ lockedColor,
449
+ });
450
+ }
451
+
452
+ /**
453
+ * 获取线条的边框位置大小
454
+ */
455
+ get bounds(): Rectangle {
456
+ return this.getData(WorkflowLineRenderData).bounds;
457
+ }
458
+
459
+ get center(): LineCenterPoint {
460
+ return this.getData(WorkflowLineRenderData).center;
461
+ }
462
+
463
+ /**
464
+ * 获取点和线最接近的距离
465
+ */
466
+ getHoverDist(pos: IPoint): number {
467
+ return this.getData(WorkflowLineRenderData).calcDistance(pos);
468
+ }
469
+
470
+ get fromPort(): WorkflowPortEntity | undefined {
471
+ if (!this.from) {
472
+ return undefined;
473
+ }
474
+ return this.from.ports.getPortEntityByKey('output', this.info.fromPort);
475
+ }
476
+
477
+ get toPort(): WorkflowPortEntity | undefined {
478
+ if (!this.to) {
479
+ return undefined;
480
+ }
481
+ return this.to.ports.getPortEntityByKey('input', this.info.toPort);
482
+ }
483
+
484
+ /**
485
+ * 获取线条真实的输入输出节点坐标
486
+ */
487
+ get position(): LinePosition {
488
+ return this.getData(WorkflowLineRenderData).position;
489
+ }
490
+
491
+ /** 是否反转箭头 */
492
+ get reverse(): boolean {
493
+ return this.linesManager.isReverseLine(this, this.uiState.reverse);
494
+ }
495
+
496
+ /** 是否隐藏箭头 */
497
+ get hideArrow(): boolean {
498
+ return this.linesManager.isHideArrowLine(this, this.uiState.hideArrow);
499
+ }
500
+
501
+ /** 是否流动 */
502
+ get flowing(): boolean {
503
+ return this.linesManager.isFlowingLine(this, this.uiState.flowing);
504
+ }
505
+
506
+ set flowing(flowing: boolean) {
507
+ if (this._uiState.flowing !== flowing) {
508
+ this._uiState.flowing = flowing;
509
+ this.fireChange();
510
+ }
511
+ }
512
+
513
+ /** 是否禁用 */
514
+ get disabled(): boolean {
515
+ return this.linesManager.isDisabledLine(this, this.uiState.disabled);
516
+ }
517
+
518
+ /**
519
+ * @deprecated
520
+ */
521
+ get vertical(): boolean {
522
+ const fromLocation = this.fromPort?.location;
523
+ const toLocation = this.toPort?.location;
524
+ if (toLocation) {
525
+ return toLocation === 'top';
526
+ } else {
527
+ return fromLocation === 'bottom';
528
+ }
529
+ }
530
+
531
+ /** 获取线条渲染器类型 */
532
+ get renderType(): LineRenderType | undefined {
533
+ return this.linesManager.setLineRenderType(this);
534
+ }
535
+
536
+ /** 获取线条样式 */
537
+ get className(): string {
538
+ return [this.linesManager.setLineClassName(this), this._uiState.className]
539
+ .filter((s) => !!s)
540
+ .join(' ');
541
+ }
542
+
543
+ get color(): string | undefined {
544
+ return this.linesManager.getLineColor(this);
545
+ }
546
+
547
+ /**
548
+ * 初始化线条
549
+ * @param info 线条信息
550
+ */
551
+ protected initInfo(info: WorkflowLineInfo): void {
552
+ this.applyInfo(info);
553
+ }
554
+
555
+ private updateInfo(mutator: (nextInfo: WorkflowLineInfo) => void): void {
556
+ const nextInfo = {
557
+ ...this.info,
558
+ };
559
+ mutator(nextInfo);
560
+ this.applyInfo(nextInfo);
561
+ }
562
+
563
+ private applyInfo(nextInfo: WorkflowLineInfo): void {
564
+ if (isEqual(nextInfo, this.info)) {
565
+ return;
566
+ }
567
+ const prevInfo = this.info;
568
+ this.info = nextInfo;
569
+ this._from = nextInfo.from ? this.document.getNode(nextInfo.from) : undefined;
570
+ this._to = nextInfo.to ? this.document.getNode(nextInfo.to) : undefined;
571
+ this._lineData = nextInfo.data;
572
+ this.linesManager.rebindLinePorts(this, prevInfo, nextInfo);
573
+ this.fireChange();
574
+ }
575
+
576
+ // 校验连线是否为错误态
577
+ validate() {
578
+ this.validateSelf();
579
+ }
580
+
581
+ /**
582
+ * use `validate` instead
583
+ * @deprecated
584
+ */
585
+ protected validateSelf() {
586
+ const { fromPort, toPort } = this;
587
+
588
+ if (fromPort) {
589
+ this.hasError = this.linesManager.isErrorLine(fromPort, toPort, this.uiState.hasError);
590
+ }
591
+ }
592
+
593
+ is(line: WorkflowLineEntity | WorkflowLinePortInfo): boolean {
594
+ if (line instanceof WorkflowLineEntity) {
595
+ return this === line;
596
+ }
597
+ return WorkflowLineEntity.portInfoToLineId(line as WorkflowLinePortInfo) === this.id;
598
+ }
599
+
600
+ canRemove(newLineInfo?: Required<WorkflowLinePortInfo>): boolean {
601
+ return this.linesManager.canRemove(this, newLineInfo);
602
+ }
603
+
604
+ get node(): HTMLDivElement {
605
+ if (this._node) return this._node;
606
+ this._node = domUtils.createDivWithClass('gedit-flow-activity-line');
607
+ this._node.dataset.testid = 'sdk.workflow.canvas.line';
608
+ this._node.dataset.lineId = this.id;
609
+ this._node.dataset.fromNodeId = this.from?.id ?? '';
610
+ this._node.dataset.fromPortId = this.fromPort?.id ?? '';
611
+ this._node.dataset.toNodeId = this.to?.id ?? '';
612
+ this._node.dataset.toPortId = this.toPort?.id ?? '';
613
+ this._node.dataset.hasError = this.hasError ? 'true' : 'false';
614
+ return this._node;
615
+ }
616
+
617
+ toJSON(): WorkflowEdgeJSON {
618
+ const json: WorkflowEdgeJSON = {
619
+ sourceNodeID: this.info.from!,
620
+ targetNodeID: this.info.to!,
621
+ sourcePortID: this.info.fromPort,
622
+ targetPortID: this.info.toPort,
623
+ };
624
+ if (this._lineData !== undefined) {
625
+ json.data = this._lineData;
626
+ }
627
+ if (!json.sourcePortID) {
628
+ delete json.sourcePortID;
629
+ }
630
+ if (!json.targetPortID) {
631
+ delete json.targetPortID;
632
+ }
633
+ return json;
634
+ }
635
+
636
+ /** 触发线条渲染 */
637
+ fireRender(): void {
638
+ this.fireChange();
639
+ }
640
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { FlowNodeEntity } from '@flowgram-vue/document';
7
+
8
+ import type { WorkflowNodeLinesData, WorkflowNodePortsData } from '../entity-datas';
9
+
10
+ declare module '@flowgram-vue/document' {
11
+ interface FlowNodeEntity {
12
+ lines: WorkflowNodeLinesData;
13
+ ports: WorkflowNodePortsData;
14
+ }
15
+ }
16
+ export type WorkflowNodeEntity = FlowNodeEntity;
17
+ export const WorkflowNodeEntity = FlowNodeEntity;