@yh7iku/vue-tree-flow 0.1.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.
- package/dist/components/FlowDesigner/FlowDesigner.vue.d.ts +85 -0
- package/dist/components/FlowDesigner/FlowLinesCanvas.vue.d.ts +17 -0
- package/dist/components/FlowDesigner/FlowNode.vue.d.ts +43 -0
- package/dist/components/FlowDesigner/SingleLineCanvas.vue.d.ts +28 -0
- package/dist/components/FlowDesigner/TempLineCanvas.vue.d.ts +35 -0
- package/dist/components/FlowDesigner/index.d.ts +7 -0
- package/dist/components/FlowDesigner/types.d.ts +108 -0
- package/dist/components/FlowDesigner/utils.d.ts +108 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/utils/treeToFlow.d.ts +68 -0
- package/dist/vue-tree-flow.css +2 -0
- package/dist/vue-tree-flow.js +1344 -0
- package/dist/vue-tree-flow.umd.cjs +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { IFlowNode, IFlowLine } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 组件属性
|
|
4
|
+
* @property nodes - 外部传入的节点数组(可选,不传则使用内置示例数据)
|
|
5
|
+
* @property lines - 外部传入的连线数组(可选,不传则使用内置示例数据)
|
|
6
|
+
* @property theme - 主题:dark 深色 / light 浅色(默认 dark)
|
|
7
|
+
*/
|
|
8
|
+
interface Props {
|
|
9
|
+
nodes?: IFlowNode[];
|
|
10
|
+
lines?: IFlowLine[];
|
|
11
|
+
theme?: 'dark' | 'light';
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 新增节点的配置参数
|
|
15
|
+
*/
|
|
16
|
+
interface AddNodeOptions {
|
|
17
|
+
x?: number;
|
|
18
|
+
y?: number;
|
|
19
|
+
name?: string;
|
|
20
|
+
desc?: string;
|
|
21
|
+
pic?: string;
|
|
22
|
+
width?: number;
|
|
23
|
+
height?: number;
|
|
24
|
+
}
|
|
25
|
+
declare const __VLS_export: import('vue').DefineComponent<Props, {
|
|
26
|
+
/**
|
|
27
|
+
* 获取当前节点数组
|
|
28
|
+
* @returns IFlowNode[]
|
|
29
|
+
*/
|
|
30
|
+
getNodes: () => IFlowNode[];
|
|
31
|
+
/**
|
|
32
|
+
* 获取当前连线数组
|
|
33
|
+
* @returns IFlowLine[]
|
|
34
|
+
*/
|
|
35
|
+
getLines: () => IFlowLine[];
|
|
36
|
+
/**
|
|
37
|
+
* 导出完整画布数据
|
|
38
|
+
* @returns { nodes: IFlowNode[]; lines: IFlowLine[] }
|
|
39
|
+
*/
|
|
40
|
+
exportData: () => {
|
|
41
|
+
nodes: IFlowNode[];
|
|
42
|
+
lines: IFlowLine[];
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* 新增节点
|
|
46
|
+
* @param options - { x, y, name, desc, pic, width, height }
|
|
47
|
+
* @returns 新建的节点对象
|
|
48
|
+
*/
|
|
49
|
+
addNode: (options?: AddNodeOptions) => IFlowNode;
|
|
50
|
+
/**
|
|
51
|
+
* 删除指定节点及其关联连线
|
|
52
|
+
* @param nodeId - 节点ID
|
|
53
|
+
*/
|
|
54
|
+
deleteNode: (nodeId: string) => void;
|
|
55
|
+
/**
|
|
56
|
+
* 删除指定连线
|
|
57
|
+
* @param lineId - 连线ID
|
|
58
|
+
*/
|
|
59
|
+
deleteLine: (lineId: string) => void;
|
|
60
|
+
/**
|
|
61
|
+
* 切换线条动画开关
|
|
62
|
+
* @returns 切换后的动画状态
|
|
63
|
+
*/
|
|
64
|
+
toggleAnimation: () => boolean;
|
|
65
|
+
/**
|
|
66
|
+
* 将整个内容平移到画布中心
|
|
67
|
+
*/
|
|
68
|
+
centerView: () => void;
|
|
69
|
+
}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
70
|
+
"update:nodes": (nodes: IFlowNode[]) => any;
|
|
71
|
+
"update:lines": (lines: IFlowLine[]) => any;
|
|
72
|
+
beforeDeleteNode: (nodeId: string) => any;
|
|
73
|
+
beforeDeleteLine: (lineId: string) => any;
|
|
74
|
+
beforeAddNode: (options: AddNodeOptions) => any;
|
|
75
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
76
|
+
"onUpdate:nodes"?: ((nodes: IFlowNode[]) => any) | undefined;
|
|
77
|
+
"onUpdate:lines"?: ((lines: IFlowLine[]) => any) | undefined;
|
|
78
|
+
onBeforeDeleteNode?: ((nodeId: string) => any) | undefined;
|
|
79
|
+
onBeforeDeleteLine?: ((lineId: string) => any) | undefined;
|
|
80
|
+
onBeforeAddNode?: ((options: AddNodeOptions) => any) | undefined;
|
|
81
|
+
}>, {
|
|
82
|
+
theme: "dark" | "light";
|
|
83
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
84
|
+
declare const _default: typeof __VLS_export;
|
|
85
|
+
export default _default;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IFlowNode, IFlowLine, TempLine } from './types';
|
|
2
|
+
interface Props {
|
|
3
|
+
nodes: IFlowNode[];
|
|
4
|
+
lines: IFlowLine[];
|
|
5
|
+
scale: number;
|
|
6
|
+
tempLine: TempLine;
|
|
7
|
+
selectedLineId?: string;
|
|
8
|
+
animated?: boolean;
|
|
9
|
+
theme?: 'dark' | 'light';
|
|
10
|
+
}
|
|
11
|
+
declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
12
|
+
animated: boolean;
|
|
13
|
+
theme: "dark" | "light";
|
|
14
|
+
selectedLineId: string;
|
|
15
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Anchor } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 组件属性接口
|
|
4
|
+
* @property id - 节点唯一标识
|
|
5
|
+
* @property name - 节点名称
|
|
6
|
+
* @property desc - 节点描述(可选)
|
|
7
|
+
* @property x - 节点X坐标
|
|
8
|
+
* @property y - 节点Y坐标
|
|
9
|
+
* @property width - 节点宽度
|
|
10
|
+
* @property height - 节点高度
|
|
11
|
+
* @property pic - 节点图片地址(可选)
|
|
12
|
+
* @property isDragging - 是否正在拖动
|
|
13
|
+
*/
|
|
14
|
+
interface Props {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
desc?: string;
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
width?: number;
|
|
21
|
+
height?: number;
|
|
22
|
+
pic?: string;
|
|
23
|
+
isDragging?: boolean;
|
|
24
|
+
}
|
|
25
|
+
declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
26
|
+
dragStart: (nodeId: string, e: MouseEvent, initialX: number, initialY: number) => any;
|
|
27
|
+
anchorClick: (anchor: Anchor, e: MouseEvent) => any;
|
|
28
|
+
contextMenu: (nodeId: string, e: MouseEvent) => any;
|
|
29
|
+
anchorHover: (anchorType: "top" | "bottom" | "left" | "right") => any;
|
|
30
|
+
anchorLeave: () => any;
|
|
31
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
32
|
+
onDragStart?: ((nodeId: string, e: MouseEvent, initialX: number, initialY: number) => any) | undefined;
|
|
33
|
+
onAnchorClick?: ((anchor: Anchor, e: MouseEvent) => any) | undefined;
|
|
34
|
+
onContextMenu?: ((nodeId: string, e: MouseEvent) => any) | undefined;
|
|
35
|
+
onAnchorHover?: ((anchorType: "top" | "bottom" | "left" | "right") => any) | undefined;
|
|
36
|
+
onAnchorLeave?: (() => any) | undefined;
|
|
37
|
+
}>, {
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
isDragging: boolean;
|
|
41
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
42
|
+
declare const _default: typeof __VLS_export;
|
|
43
|
+
export default _default;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Anchor } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 组件属性接口
|
|
4
|
+
* @property lineId - 连线唯一标识
|
|
5
|
+
* @property fromAnchor - 起始锚点
|
|
6
|
+
* @property toAnchor - 目标锚点
|
|
7
|
+
* @property scale - 缩放比例
|
|
8
|
+
* @property isSelected - 是否选中
|
|
9
|
+
* @property isHovered - 是否悬停
|
|
10
|
+
* @property animated - 是否启用动画
|
|
11
|
+
*/
|
|
12
|
+
interface Props {
|
|
13
|
+
lineId: string;
|
|
14
|
+
fromAnchor: Anchor;
|
|
15
|
+
toAnchor: Anchor;
|
|
16
|
+
scale: number;
|
|
17
|
+
isSelected: boolean;
|
|
18
|
+
animated?: boolean;
|
|
19
|
+
theme?: 'dark' | 'light';
|
|
20
|
+
}
|
|
21
|
+
declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
22
|
+
scale: number;
|
|
23
|
+
isSelected: boolean;
|
|
24
|
+
animated: boolean;
|
|
25
|
+
theme: "dark" | "light";
|
|
26
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
27
|
+
declare const _default: typeof __VLS_export;
|
|
28
|
+
export default _default;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 组件属性接口
|
|
3
|
+
* @property visible - 是否可见
|
|
4
|
+
* @property startX - 起始X坐标
|
|
5
|
+
* @property startY - 起始Y坐标
|
|
6
|
+
* @property endX - 目标X坐标
|
|
7
|
+
* @property endY - 目标Y坐标
|
|
8
|
+
* @property scale - 缩放比例
|
|
9
|
+
* @property startType - 起始锚点类型
|
|
10
|
+
* @property endType - 目标锚点类型
|
|
11
|
+
*/
|
|
12
|
+
interface Props {
|
|
13
|
+
visible: boolean;
|
|
14
|
+
startX: number;
|
|
15
|
+
startY: number;
|
|
16
|
+
endX: number;
|
|
17
|
+
endY: number;
|
|
18
|
+
scale: number;
|
|
19
|
+
startType?: string;
|
|
20
|
+
endType?: string;
|
|
21
|
+
theme?: 'dark' | 'light';
|
|
22
|
+
}
|
|
23
|
+
declare const __VLS_export: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{}>, {
|
|
24
|
+
scale: number;
|
|
25
|
+
theme: "dark" | "light";
|
|
26
|
+
visible: boolean;
|
|
27
|
+
startX: number;
|
|
28
|
+
startY: number;
|
|
29
|
+
endX: number;
|
|
30
|
+
endY: number;
|
|
31
|
+
startType: string;
|
|
32
|
+
endType: string;
|
|
33
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
34
|
+
declare const _default: typeof __VLS_export;
|
|
35
|
+
export default _default;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { default as FlowDesigner } from './FlowDesigner.vue';
|
|
2
|
+
export { default as FlowNode } from './FlowNode.vue';
|
|
3
|
+
export { default as FlowLinesCanvas } from './FlowLinesCanvas.vue';
|
|
4
|
+
export { default as SingleLineCanvas } from './SingleLineCanvas.vue';
|
|
5
|
+
export { default as TempLineCanvas } from './TempLineCanvas.vue';
|
|
6
|
+
export * from './types';
|
|
7
|
+
export * from './utils';
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 锚点类型:定义节点上的锚点位置
|
|
3
|
+
*/
|
|
4
|
+
export type AnchorType = 'top' | 'bottom' | 'left' | 'right';
|
|
5
|
+
/**
|
|
6
|
+
* 锚点接口:表示节点上的连接点
|
|
7
|
+
* @property id - 锚点唯一标识
|
|
8
|
+
* @property nodeId - 所属节点ID
|
|
9
|
+
* @property type - 锚点类型(top、bottom、left、right)
|
|
10
|
+
* @property x - 锚点X坐标
|
|
11
|
+
* @property y - 锚点Y坐标
|
|
12
|
+
*/
|
|
13
|
+
export interface Anchor {
|
|
14
|
+
id: string;
|
|
15
|
+
nodeId: string;
|
|
16
|
+
type: AnchorType;
|
|
17
|
+
x: number;
|
|
18
|
+
y: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 流程节点接口:表示流程图中的节点
|
|
22
|
+
* @property id - 节点唯一标识
|
|
23
|
+
* @property name - 节点名称
|
|
24
|
+
* @property desc - 节点描述(可选)
|
|
25
|
+
* @property x - 节点X坐标
|
|
26
|
+
* @property y - 节点Y坐标
|
|
27
|
+
* @property width - 节点宽度
|
|
28
|
+
* @property height - 节点高度
|
|
29
|
+
* @property anchors - 节点上的锚点数组
|
|
30
|
+
* @property pic - 节点图片地址(可选,有值时节点以图片展示)
|
|
31
|
+
* @property collapsed - 是否已折叠子节点(可选)
|
|
32
|
+
*/
|
|
33
|
+
export interface IFlowNode {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
desc?: string;
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
width: number;
|
|
40
|
+
height: number;
|
|
41
|
+
anchors: Anchor[];
|
|
42
|
+
pic?: string;
|
|
43
|
+
collapsed?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 流程连线接口:表示节点之间的连接
|
|
47
|
+
* @property id - 连线唯一标识
|
|
48
|
+
* @property fromAnchorId - 起始锚点ID
|
|
49
|
+
* @property toAnchorId - 目标锚点ID
|
|
50
|
+
*/
|
|
51
|
+
export interface IFlowLine {
|
|
52
|
+
id: string;
|
|
53
|
+
fromAnchorId: string;
|
|
54
|
+
toAnchorId: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* 临时连线接口:用于绘制中的连线
|
|
58
|
+
* @property visible - 是否可见
|
|
59
|
+
* @property startX - 起始X坐标
|
|
60
|
+
* @property startY - 起始Y坐标
|
|
61
|
+
* @property endX - 结束X坐标
|
|
62
|
+
* @property endY - 结束Y坐标
|
|
63
|
+
* @property startType - 起始锚点类型(可选)
|
|
64
|
+
* @property endType - 结束锚点类型(可选)
|
|
65
|
+
*/
|
|
66
|
+
export interface TempLine {
|
|
67
|
+
visible: boolean;
|
|
68
|
+
startX: number;
|
|
69
|
+
startY: number;
|
|
70
|
+
endX: number;
|
|
71
|
+
endY: number;
|
|
72
|
+
startType?: string;
|
|
73
|
+
endType?: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 上下文菜单类型:定义菜单类型
|
|
77
|
+
*/
|
|
78
|
+
export type ContextMenuType = 'node' | 'line' | 'none';
|
|
79
|
+
/**
|
|
80
|
+
* 上下文菜单状态接口:表示上下文菜单的状态
|
|
81
|
+
* @property type - 菜单类型
|
|
82
|
+
* @property x - 菜单X坐标
|
|
83
|
+
* @property y - 菜单Y坐标
|
|
84
|
+
* @property targetId - 目标ID(节点或连线)
|
|
85
|
+
*/
|
|
86
|
+
export interface ContextMenuState {
|
|
87
|
+
type: ContextMenuType;
|
|
88
|
+
x: number;
|
|
89
|
+
y: number;
|
|
90
|
+
targetId: string | null;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 编辑面板状态接口:表示节点编辑面板的状态
|
|
94
|
+
* @property visible - 是否可见
|
|
95
|
+
* @property nodeId - 正在编辑的节点ID
|
|
96
|
+
* @property x - 面板X坐标
|
|
97
|
+
* @property y - 面板Y坐标
|
|
98
|
+
* @property name - 节点名称
|
|
99
|
+
* @property desc - 节点描述
|
|
100
|
+
*/
|
|
101
|
+
export interface EditPanelState {
|
|
102
|
+
visible: boolean;
|
|
103
|
+
nodeId: string | null;
|
|
104
|
+
x: number;
|
|
105
|
+
y: number;
|
|
106
|
+
name: string;
|
|
107
|
+
desc: string;
|
|
108
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Anchor, IFlowNode, IFlowLine } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* 根据锚点类型计算锚点在节点上的实际坐标
|
|
4
|
+
* @param anchor - 锚点对象
|
|
5
|
+
* @param node - 节点对象
|
|
6
|
+
* @returns 锚点的实际坐标 {x, y}
|
|
7
|
+
*/
|
|
8
|
+
export declare const getAnchorPosition: (anchor: Anchor, node: IFlowNode) => {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* 根据锚点类型计算连线端点在节点边界上的坐标
|
|
14
|
+
* 用于绘制连线,端点正好对齐到节点边界
|
|
15
|
+
* @param anchor - 锚点对象
|
|
16
|
+
* @param node - 节点对象
|
|
17
|
+
* @returns 连线端点的坐标 {x, y}
|
|
18
|
+
*/
|
|
19
|
+
export declare const getLineEndpoint: (anchor: Anchor, node: IFlowNode) => {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* 检测鼠标是否命中锚点
|
|
25
|
+
* @param mouseX - 鼠标X坐标
|
|
26
|
+
* @param mouseY - 鼠标Y坐标
|
|
27
|
+
* @param nodes - 节点数组
|
|
28
|
+
* @param canvasPos - 画布位置
|
|
29
|
+
* @param scale - 缩放比例
|
|
30
|
+
* @param canvasRect - 画布矩形
|
|
31
|
+
* @returns 命中的锚点,未命中返回null
|
|
32
|
+
*/
|
|
33
|
+
export declare const hitTestAnchor: (mouseX: number, mouseY: number, nodes: IFlowNode[], canvasPos: {
|
|
34
|
+
x: number;
|
|
35
|
+
y: number;
|
|
36
|
+
}, scale: number, canvasRect: DOMRect) => Anchor | null;
|
|
37
|
+
/**
|
|
38
|
+
* 生成连线唯一ID
|
|
39
|
+
* @returns 连线ID字符串
|
|
40
|
+
*/
|
|
41
|
+
export declare const generateLineId: () => string;
|
|
42
|
+
/**
|
|
43
|
+
* 停止事件传播和默认行为
|
|
44
|
+
* @param e - 事件对象
|
|
45
|
+
*/
|
|
46
|
+
export declare const stopEvent: (e: Event) => void;
|
|
47
|
+
/**
|
|
48
|
+
* 检测鼠标是否命中连线(使用改进的贝塞尔曲线检测)
|
|
49
|
+
* @param line - 连线对象
|
|
50
|
+
* @param nodes - 节点数组
|
|
51
|
+
* @param mx - 鼠标X坐标
|
|
52
|
+
* @param my - 鼠标Y坐标
|
|
53
|
+
* @param canvasPos - 画布位置
|
|
54
|
+
* @param scale - 缩放比例
|
|
55
|
+
* @param canvasRect - 画布矩形
|
|
56
|
+
* @param hitRadius - 命中半径,默认8
|
|
57
|
+
* @param anchorMap - 预构建的锚点映射(可选,用于性能优化)
|
|
58
|
+
* @returns 是否命中
|
|
59
|
+
*/
|
|
60
|
+
export declare const isHit: (line: IFlowLine, nodes: IFlowNode[], mx: number, my: number, canvasPos: {
|
|
61
|
+
x: number;
|
|
62
|
+
y: number;
|
|
63
|
+
}, scale: number, canvasRect: DOMRect, hitRadius?: number, anchorMap?: Map<string, {
|
|
64
|
+
anchor: Anchor;
|
|
65
|
+
node: IFlowNode;
|
|
66
|
+
}>) => boolean;
|
|
67
|
+
/**
|
|
68
|
+
* 预构建锚点映射,用于优化性能
|
|
69
|
+
* @param nodes - 节点数组
|
|
70
|
+
* @returns 锚点映射 Map<anchorId, {anchor, node}>
|
|
71
|
+
*/
|
|
72
|
+
export declare const buildAnchorMap: (nodes: IFlowNode[]) => Map<string, {
|
|
73
|
+
anchor: Anchor;
|
|
74
|
+
node: IFlowNode;
|
|
75
|
+
}>;
|
|
76
|
+
/**
|
|
77
|
+
* 切换选中的连线
|
|
78
|
+
* @param lines - 所有连线
|
|
79
|
+
* @param hitLines - 命中的连线
|
|
80
|
+
* @param currentSelectedId - 当前选中的连线ID
|
|
81
|
+
* @returns 新选中的连线ID
|
|
82
|
+
*/
|
|
83
|
+
export declare const toggleSelectedLine: (lines: IFlowLine[], hitLines: IFlowLine[], currentSelectedId: string) => string;
|
|
84
|
+
/**
|
|
85
|
+
* 检测是否为重复连线
|
|
86
|
+
* @param lines - 所有连线
|
|
87
|
+
* @param fromAnchorId - 起始锚点ID
|
|
88
|
+
* @param toAnchorId - 目标锚点ID
|
|
89
|
+
* @returns 是否为重复连线
|
|
90
|
+
*/
|
|
91
|
+
export declare const isDuplicateLine: (lines: IFlowLine[], fromAnchorId: string, toAnchorId: string) => boolean;
|
|
92
|
+
/**
|
|
93
|
+
* 树形重新布局:基于连线关系将节点重新排布为自上而下的树
|
|
94
|
+
*
|
|
95
|
+
* 算法:
|
|
96
|
+
* - 通过连线重建父子关系(fromAnchorId 为父,toAnchorId 为子)
|
|
97
|
+
* - 按子树叶子数量分配水平空间(兄弟子树不重叠)
|
|
98
|
+
* - y 坐标按层级递增
|
|
99
|
+
* - 以原根节点位置为基准整体平移,避免布局后整体跑偏
|
|
100
|
+
*
|
|
101
|
+
* 仅当数据可构成唯一根的树结构时才会重排;
|
|
102
|
+
* 存在多根或循环引用时返回 null(放弃重排,保持原位置)。
|
|
103
|
+
*
|
|
104
|
+
* @param nodes - 节点数组
|
|
105
|
+
* @param lines - 连线数组
|
|
106
|
+
* @returns 重新布局后的新节点数组;无法构成树时返回 null
|
|
107
|
+
*/
|
|
108
|
+
export declare const relayoutTree: (nodes: IFlowNode[], lines: IFlowLine[]) => IFlowNode[] | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './FlowDesigner';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { IFlowNode, IFlowLine } from '../components/FlowDesigner/types';
|
|
2
|
+
/**
|
|
3
|
+
* 树节点接口:树形数据的通用结构
|
|
4
|
+
* @property id - 节点唯一标识
|
|
5
|
+
* @property name - 节点名称(可选,缺省时使用 id)
|
|
6
|
+
* @property pic - 节点图片路径(可选)
|
|
7
|
+
* @property children - 子节点数组(null 或空数组表示叶子节点)
|
|
8
|
+
*/
|
|
9
|
+
export interface TreeNode {
|
|
10
|
+
id: string;
|
|
11
|
+
name?: string;
|
|
12
|
+
pic?: string;
|
|
13
|
+
children?: TreeNode[] | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 布局配置项
|
|
17
|
+
* @property nodeWidth - 节点宽度,默认 140
|
|
18
|
+
* @property nodeHeight - 节点高度,默认 200
|
|
19
|
+
* @property hGap - 兄弟节点间距(纵向布局为水平间距,横向布局为垂直间距),默认 100
|
|
20
|
+
* @property vGap - 父子层级间距(纵向布局为垂直间距,横向布局为水平间距),默认 120
|
|
21
|
+
* @property offsetX - 画布整体 X 偏移,默认 0
|
|
22
|
+
* @property offsetY - 画布整体 Y 偏移,默认 0
|
|
23
|
+
* @property direction - 布局方向:vertical 自上而下 / horizontal 自左向右,默认 vertical
|
|
24
|
+
*/
|
|
25
|
+
export interface TreeLayoutOptions {
|
|
26
|
+
nodeWidth?: number;
|
|
27
|
+
nodeHeight?: number;
|
|
28
|
+
hGap?: number;
|
|
29
|
+
vGap?: number;
|
|
30
|
+
offsetX?: number;
|
|
31
|
+
offsetY?: number;
|
|
32
|
+
direction?: 'vertical' | 'horizontal';
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 转换结果
|
|
36
|
+
* @property nodes - 流程设计器节点数组
|
|
37
|
+
* @property lines - 流程设计器连线数组
|
|
38
|
+
*/
|
|
39
|
+
export interface TreeToFlowResult {
|
|
40
|
+
nodes: IFlowNode[];
|
|
41
|
+
lines: IFlowLine[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 树结构转流程设计器数据(中间转换层)
|
|
45
|
+
*
|
|
46
|
+
* 布局规则:
|
|
47
|
+
* - 统计每棵子树的叶子节点数量,按其比例分配兄弟方向空间,保证兄弟子树不重叠
|
|
48
|
+
* - vertical(自上而下):父节点水平居中,y 按层级递增,连线 bottom → top
|
|
49
|
+
* - horizontal(自左向右):父节点垂直居中,x 按层级递增,连线 right → left
|
|
50
|
+
*
|
|
51
|
+
* @param tree - 树形数据(如 doc/data/tree.json)
|
|
52
|
+
* @param options - 布局配置项(direction 控制布局方向)
|
|
53
|
+
* @returns 可直接用于 FlowDesigner 的节点与连线数据
|
|
54
|
+
*/
|
|
55
|
+
export declare const treeToFlow: (tree: TreeNode, options?: TreeLayoutOptions) => TreeToFlowResult;
|
|
56
|
+
/**
|
|
57
|
+
* 流程设计器数据转回树结构(treeToFlow 的逆向转换)
|
|
58
|
+
*
|
|
59
|
+
* 转换规则:
|
|
60
|
+
* - 根据连线(lines)重建父子关系:fromAnchorId 所属节点为父,toAnchorId 所属节点为子
|
|
61
|
+
* - 通过连线无入边的节点识别为根节点(若存在多个根则取第一个)
|
|
62
|
+
* - 节点上的自定义额外字段(如 pic)会原样透传,便于还原原始 tree.json
|
|
63
|
+
*
|
|
64
|
+
* @param nodes - 流程设计器节点数组
|
|
65
|
+
* @param lines - 流程设计器连线数组
|
|
66
|
+
* @returns 树结构数据;节点为空时返回 null
|
|
67
|
+
*/
|
|
68
|
+
export declare const flowToTree: (nodes: IFlowNode[], lines: IFlowLine[]) => TreeNode | null;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
.node-pic[data-v-2dead940]{object-fit:contain;border-radius:6px;flex:1;width:100%;min-height:0}.node-name[data-v-2dead940]{text-align:center;text-overflow:ellipsis;white-space:nowrap;flex-shrink:0;width:100%;padding:4px 0;font-size:12px;line-height:1.4;overflow:hidden}.flow-designer[data-v-0545e5a3]{--fd-bg:#0f0f1a;--fd-grid:#ffffff0d;--fd-panel-bg:#1e1e2f;--fd-panel-hover:#2d2d44;--fd-panel-border:#333;--fd-text:#fff;--fd-text-secondary:#ccc;--fd-danger:#ff6b6b;--fd-accent:#4299e1;--fd-accent-dark:#3182ce;--fd-node-bg:#121224e6;--fd-node-border:#4299e14d;--fd-node-border-hover:#4299e1cc;--fd-node-text:#fff}.flow-designer--light[data-v-0545e5a3]{--fd-bg:#fcfcfc;--fd-grid:#0000000f;--fd-panel-bg:#fff;--fd-panel-hover:#f0f4f8;--fd-panel-border:#e0e0e0;--fd-text:#333;--fd-text-secondary:#666;--fd-danger:#e53e3e;--fd-accent:#3182ce;--fd-accent-dark:#2b6cb0;--fd-node-bg:#fff;--fd-node-border:#4299e166;--fd-node-border-hover:#4299e1;--fd-node-text:#333}.flow-designer[data-v-0545e5a3]{background-color:var(--fd-bg);background-image:linear-gradient(var(--fd-grid) 1px, transparent 1px), linear-gradient(90deg, var(--fd-grid) 1px, transparent 1px);background-size:20px 20px;width:100%;height:100%;margin:0;padding:0;position:relative;overflow:hidden}.canvas-container[data-v-0545e5a3]{-webkit-user-select:none;user-select:none;cursor:grab;touch-action:none;width:100%;height:100%;position:relative}.canvas-container.is-dragging[data-v-0545e5a3],.canvas-container.is-dragging[data-v-0545e5a3] *{cursor:grabbing!important}.canvas-content[data-v-0545e5a3]{position:absolute}.nodes-container[data-v-0545e5a3]{z-index:6;position:relative}.context-menu[data-v-0545e5a3]{background-color:var(--fd-panel-bg);border:1px solid var(--fd-panel-border);z-index:9999;border-radius:6px;width:180px;padding:8px 0;position:absolute;box-shadow:0 4px 12px #00000080}.context-menu-item[data-v-0545e5a3]{color:var(--fd-text);cursor:pointer;padding:8px 16px;font-size:14px;transition:background-color .2s}.context-menu-item[data-v-0545e5a3]:hover{background-color:var(--fd-accent);color:#fff}.context-menu-item.danger[data-v-0545e5a3]{color:var(--fd-danger)}.context-menu-divider[data-v-0545e5a3]{background-color:var(--fd-panel-border);height:1px;margin:4px 0}.edit-panel[data-v-0545e5a3]{background-color:var(--fd-panel-bg);border:1px solid var(--fd-accent);z-index:9999;border-radius:8px;width:320px;padding:20px;position:absolute;box-shadow:0 8px 24px #0009}.edit-panel-title[data-v-0545e5a3]{color:var(--fd-text);border-bottom:1px solid var(--fd-panel-border);margin:0 0 16px;padding-bottom:8px;font-size:16px}.edit-panel-field[data-v-0545e5a3]{margin-bottom:16px}.edit-panel-label[data-v-0545e5a3]{color:var(--fd-text-secondary);margin-bottom:8px;font-size:14px;display:block}.edit-panel-input[data-v-0545e5a3]{background-color:var(--fd-panel-hover);border:1px solid var(--fd-panel-border);width:100%;color:var(--fd-text);box-sizing:border-box;border-radius:4px;outline:none;padding:10px 12px;font-size:14px}.edit-panel-actions[data-v-0545e5a3]{justify-content:flex-end;gap:10px;margin-top:20px;display:flex}.edit-panel-btn[data-v-0545e5a3]{cursor:pointer;border:none;border-radius:4px;padding:8px 16px;font-size:14px;transition:background-color .2s}.edit-panel-btn.cancel[data-v-0545e5a3]{background-color:var(--fd-panel-border);color:var(--fd-text)}.edit-panel-btn.cancel[data-v-0545e5a3]:hover{background-color:var(--fd-panel-hover)}.edit-panel-btn.save[data-v-0545e5a3]{background-color:var(--fd-accent);color:#fff}.edit-panel-btn.save[data-v-0545e5a3]:hover{background-color:var(--fd-accent-dark)}
|
|
2
|
+
/*$vite$:1*/
|