1
This commit is contained in:
parent
091ea4fe7b
commit
e76af9b8f5
@ -23,11 +23,11 @@ import '@antv/x6-plugin-keyboard';
|
|||||||
import '@antv/x6-plugin-history';
|
import '@antv/x6-plugin-history';
|
||||||
import '@antv/x6-plugin-clipboard';
|
import '@antv/x6-plugin-clipboard';
|
||||||
import '@antv/x6-plugin-transform';
|
import '@antv/x6-plugin-transform';
|
||||||
import { Selection } from '@antv/x6-plugin-selection';
|
import {Selection} from '@antv/x6-plugin-selection';
|
||||||
import { MiniMap } from '@antv/x6-plugin-minimap';
|
import {MiniMap} from '@antv/x6-plugin-minimap';
|
||||||
import { Clipboard } from '@antv/x6-plugin-clipboard';
|
import {Clipboard} from '@antv/x6-plugin-clipboard';
|
||||||
import { History } from '@antv/x6-plugin-history';
|
import {History} from '@antv/x6-plugin-history';
|
||||||
import { Transform } from '@antv/x6-plugin-transform';
|
import {Transform} from '@antv/x6-plugin-transform';
|
||||||
import {getDefinitionDetail, saveDefinition} from '../service';
|
import {getDefinitionDetail, saveDefinition} from '../service';
|
||||||
import {getNodeDefinitionList} from './service';
|
import {getNodeDefinitionList} from './service';
|
||||||
import NodePanel from './components/NodePanel';
|
import NodePanel from './components/NodePanel';
|
||||||
@ -69,12 +69,12 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const container = graphContainerRef.current;
|
const container = graphContainerRef.current;
|
||||||
const containerWidth = container.clientWidth;
|
const containerWidth = container.clientWidth;
|
||||||
const containerHeight = container.clientHeight;
|
const containerHeight = container.clientHeight;
|
||||||
|
|
||||||
// 计算主画布和小地图的尺寸比例
|
// 计算主画布和小地图的尺寸比例
|
||||||
const MINIMAP_BASE_WIDTH = 200;
|
const MINIMAP_BASE_WIDTH = 200;
|
||||||
const minimapWidth = MINIMAP_BASE_WIDTH;
|
const minimapWidth = MINIMAP_BASE_WIDTH;
|
||||||
const minimapHeight = Math.round((MINIMAP_BASE_WIDTH * containerHeight) / containerWidth);
|
const minimapHeight = Math.round((MINIMAP_BASE_WIDTH * containerHeight) / containerWidth);
|
||||||
|
|
||||||
// 计算缩放比例
|
// 计算缩放比例
|
||||||
const scale = minimapWidth / containerWidth;
|
const scale = minimapWidth / containerWidth;
|
||||||
|
|
||||||
@ -132,10 +132,10 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
return !exists;
|
return !exists;
|
||||||
},
|
},
|
||||||
validateMagnet({ magnet }) {
|
validateMagnet({magnet}) {
|
||||||
return magnet.getAttribute('port-group') !== 'top';
|
return magnet.getAttribute('port-group') !== 'top';
|
||||||
},
|
},
|
||||||
validateEdge({ edge }) {
|
validateEdge({edge}) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -184,7 +184,6 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const history = new History({
|
const history = new History({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
beforeAddCommand(event: any, args: any) {
|
beforeAddCommand(event: any, args: any) {
|
||||||
console.log('History command added:', event, args);
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
afterExecuteCommand: () => {
|
afterExecuteCommand: () => {
|
||||||
@ -200,7 +199,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
setForceUpdate(prev => !prev);
|
setForceUpdate(prev => !prev);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始化Selection插件
|
// 初始化Selection插件
|
||||||
const selection = new Selection({
|
const selection = new Selection({
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -216,9 +215,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
showAnchorSelectionBox: false,
|
showAnchorSelectionBox: false,
|
||||||
pointerEvents: 'auto'
|
pointerEvents: 'auto'
|
||||||
});
|
});
|
||||||
console.log('Initializing Selection plugin:', selection);
|
|
||||||
graph.use(selection);
|
graph.use(selection);
|
||||||
|
|
||||||
graph.use(new MiniMap({
|
graph.use(new MiniMap({
|
||||||
container: minimapContainerRef.current!,
|
container: minimapContainerRef.current!,
|
||||||
width: minimapWidth,
|
width: minimapWidth,
|
||||||
@ -238,12 +235,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
async: true,
|
async: true,
|
||||||
frozen: true,
|
frozen: true,
|
||||||
interacting: false,
|
interacting: false,
|
||||||
grid: false,
|
grid: false
|
||||||
getCellView(cell) {
|
|
||||||
if (cell.isNode()) {
|
|
||||||
return SimpleNodeView;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
viewport: {
|
viewport: {
|
||||||
padding: 0,
|
padding: 0,
|
||||||
@ -268,20 +260,14 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
(graph as any).history = history;
|
(graph as any).history = history;
|
||||||
|
|
||||||
// 监听图形变化
|
// 监听图形变化
|
||||||
graph.on('cell:added', ({ cell }) => {
|
graph.on('cell:added', ({cell}) => {
|
||||||
const canUndo = history.canUndo();
|
const canUndo = history.canUndo();
|
||||||
const canRedo = history.canRedo();
|
const canRedo = history.canRedo();
|
||||||
console.log('Cell added:', {
|
|
||||||
cell,
|
|
||||||
canUndo,
|
|
||||||
canRedo,
|
|
||||||
stackSize: history.stackSize,
|
|
||||||
});
|
|
||||||
// 强制更新组件状态
|
// 强制更新组件状态
|
||||||
setForceUpdate(prev => !prev);
|
setForceUpdate(prev => !prev);
|
||||||
});
|
});
|
||||||
|
|
||||||
graph.on('cell:removed', ({ cell }) => {
|
graph.on('cell:removed', ({cell}) => {
|
||||||
const canUndo = history.canUndo();
|
const canUndo = history.canUndo();
|
||||||
const canRedo = history.canRedo();
|
const canRedo = history.canRedo();
|
||||||
console.log('Cell removed:', {
|
console.log('Cell removed:', {
|
||||||
@ -293,17 +279,10 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
// 强制更新组件状态
|
// 强制更新组件状态
|
||||||
setForceUpdate(prev => !prev);
|
setForceUpdate(prev => !prev);
|
||||||
});
|
});
|
||||||
|
|
||||||
graph.on('cell:changed', ({ cell, options }) => {
|
graph.on('cell:changed', ({cell, options}) => {
|
||||||
const canUndo = history.canUndo();
|
const canUndo = history.canUndo();
|
||||||
const canRedo = history.canRedo();
|
const canRedo = history.canRedo();
|
||||||
console.log('Cell changed:', {
|
|
||||||
cell,
|
|
||||||
options,
|
|
||||||
canUndo,
|
|
||||||
canRedo,
|
|
||||||
stackSize: history.stackSize,
|
|
||||||
});
|
|
||||||
// 强制更新组件状态
|
// 强制更新组件状态
|
||||||
setForceUpdate(prev => !prev);
|
setForceUpdate(prev => !prev);
|
||||||
});
|
});
|
||||||
@ -319,9 +298,9 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 处理连线重新连接
|
// 处理连线重新连接
|
||||||
graph.on('edge:moved', ({ edge, terminal, previous }) => {
|
graph.on('edge:moved', ({edge, terminal, previous}) => {
|
||||||
if (!edge || !terminal) return;
|
if (!edge || !terminal) return;
|
||||||
|
|
||||||
const isSource = terminal.type === 'source';
|
const isSource = terminal.type === 'source';
|
||||||
const source = isSource ? terminal : edge.getSource();
|
const source = isSource ? terminal : edge.getSource();
|
||||||
const target = isSource ? edge.getTarget() : terminal;
|
const target = isSource ? edge.getTarget() : terminal;
|
||||||
@ -355,7 +334,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 处理连线更改
|
// 处理连线更改
|
||||||
graph.on('edge:change:source edge:change:target', ({ edge, current, previous }) => {
|
graph.on('edge:change:source edge:change:target', ({edge, current, previous}) => {
|
||||||
if (edge && current) {
|
if (edge && current) {
|
||||||
edge.setAttrs({
|
edge.setAttrs({
|
||||||
line: {
|
line: {
|
||||||
@ -383,13 +362,13 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
console.error('History plugin not initialized');
|
console.error('History plugin not initialized');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const beforeState = {
|
const beforeState = {
|
||||||
canUndo: history.canUndo(),
|
canUndo: history.canUndo(),
|
||||||
canRedo: history.canRedo(),
|
canRedo: history.canRedo(),
|
||||||
stackSize: history.stackSize,
|
stackSize: history.stackSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (history.canUndo()) {
|
if (history.canUndo()) {
|
||||||
history.undo();
|
history.undo();
|
||||||
const afterState = {
|
const afterState = {
|
||||||
@ -415,13 +394,13 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
console.error('History plugin not initialized');
|
console.error('History plugin not initialized');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const beforeState = {
|
const beforeState = {
|
||||||
canUndo: history.canUndo(),
|
canUndo: history.canUndo(),
|
||||||
canRedo: history.canRedo(),
|
canRedo: history.canRedo(),
|
||||||
stackSize: history.stackSize,
|
stackSize: history.stackSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (history.canRedo()) {
|
if (history.canRedo()) {
|
||||||
history.redo();
|
history.redo();
|
||||||
const afterState = {
|
const afterState = {
|
||||||
@ -501,13 +480,13 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
graph.on('node:mouseenter', ({node}) => {
|
graph.on('node:mouseenter', ({node}) => {
|
||||||
// 保存原始样式
|
// 保存原始样式
|
||||||
saveNodeOriginalStyle(node);
|
saveNodeOriginalStyle(node);
|
||||||
|
|
||||||
// 显示连接桩
|
// 显示连接桩
|
||||||
const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`);
|
const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`);
|
||||||
ports.forEach((port) => {
|
ports.forEach((port) => {
|
||||||
port.setAttribute('style', 'visibility: visible; fill: #fff; stroke: #85ca6d;');
|
port.setAttribute('style', 'visibility: visible; fill: #fff; stroke: #85ca6d;');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 显示悬停样式
|
// 显示悬停样式
|
||||||
node.setAttrByPath('body/stroke', hoverStyle.stroke);
|
node.setAttrByPath('body/stroke', hoverStyle.stroke);
|
||||||
node.setAttrByPath('body/strokeWidth', hoverStyle.strokeWidth);
|
node.setAttrByPath('body/strokeWidth', hoverStyle.strokeWidth);
|
||||||
@ -519,7 +498,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
ports.forEach((port) => {
|
ports.forEach((port) => {
|
||||||
port.setAttribute('style', 'visibility: hidden');
|
port.setAttribute('style', 'visibility: hidden');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 恢复原始样式
|
// 恢复原始样式
|
||||||
resetNodeStyle(node);
|
resetNodeStyle(node);
|
||||||
});
|
});
|
||||||
@ -541,15 +520,15 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 节点点击事件
|
// 节点点击事件
|
||||||
graph.on('node:click', ({ node }) => {
|
graph.on('node:click', ({node}) => {
|
||||||
// 获取当前选中的节点
|
// 获取当前选中的节点
|
||||||
const selectedNode = graph.getSelectedCells()[0];
|
const selectedNode = graph.getSelectedCells()[0];
|
||||||
|
|
||||||
// 如果有其他节点被选中,恢复其样式
|
// 如果有其他节点被选中,恢复其样式
|
||||||
if (selectedNode && selectedNode.isNode() && selectedNode.id !== node.id) {
|
if (selectedNode && selectedNode.isNode() && selectedNode.id !== node.id) {
|
||||||
resetNodeStyle(selectedNode);
|
resetNodeStyle(selectedNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新选中状态
|
// 更新选中状态
|
||||||
graph.resetSelection();
|
graph.resetSelection();
|
||||||
graph.select(node);
|
graph.select(node);
|
||||||
@ -559,12 +538,12 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
graph.on('blank:click', () => {
|
graph.on('blank:click', () => {
|
||||||
// 获取当前选中的节点
|
// 获取当前选中的节点
|
||||||
const selectedNode = graph.getSelectedCells()[0];
|
const selectedNode = graph.getSelectedCells()[0];
|
||||||
|
|
||||||
// 如果有节点被选中,恢复其样式
|
// 如果有节点被选中,恢复其样式
|
||||||
if (selectedNode && selectedNode.isNode()) {
|
if (selectedNode && selectedNode.isNode()) {
|
||||||
resetNodeStyle(selectedNode);
|
resetNodeStyle(selectedNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 清除选中状态
|
// 清除选中状态
|
||||||
graph.resetSelection();
|
graph.resetSelection();
|
||||||
});
|
});
|
||||||
@ -595,11 +574,11 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
|
|
||||||
const root = createRoot(dropdownContainer);
|
const root = createRoot(dropdownContainer);
|
||||||
let isOpen = true;
|
let isOpen = true;
|
||||||
|
|
||||||
const closeMenu = () => {
|
const closeMenu = () => {
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
root.render(
|
root.render(
|
||||||
<Dropdown menu={{ items }} open={false} onOpenChange={(open) => {
|
<Dropdown menu={{items}} open={false} onOpenChange={(open) => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
root.unmount();
|
root.unmount();
|
||||||
@ -607,7 +586,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<div />
|
<div/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -640,8 +619,8 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<Dropdown menu={{ items }} open={isOpen}>
|
<Dropdown menu={{items}} open={isOpen}>
|
||||||
<div />
|
<div/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -668,11 +647,11 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
|
|
||||||
const root = createRoot(dropdownContainer);
|
const root = createRoot(dropdownContainer);
|
||||||
let isOpen = true;
|
let isOpen = true;
|
||||||
|
|
||||||
const closeMenu = () => {
|
const closeMenu = () => {
|
||||||
isOpen = false;
|
isOpen = false;
|
||||||
root.render(
|
root.render(
|
||||||
<Dropdown menu={{ items }} open={false} onOpenChange={(open) => {
|
<Dropdown menu={{items}} open={false} onOpenChange={(open) => {
|
||||||
if (!open) {
|
if (!open) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
root.unmount();
|
root.unmount();
|
||||||
@ -680,7 +659,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<div />
|
<div/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@ -703,8 +682,8 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<Dropdown menu={{ items }} open={isOpen}>
|
<Dropdown menu={{items}} open={isOpen}>
|
||||||
<div />
|
<div/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -718,17 +697,17 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 禁用默认的右键菜单
|
// 禁用默认的右键菜单
|
||||||
graph.on('blank:contextmenu', ({ e }) => {
|
graph.on('blank:contextmenu', ({e}) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 禁用节点的右键菜单
|
// 禁用节点的右键菜单
|
||||||
graph.on('node:contextmenu', ({ e }) => {
|
graph.on('node:contextmenu', ({e}) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 禁用边的右键菜单
|
// 禁用边的右键菜单
|
||||||
graph.on('edge:contextmenu', ({ e }) => {
|
graph.on('edge:contextmenu', ({e}) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -736,20 +715,20 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
graph.on('node:mouseenter', ({node}) => {
|
graph.on('node:mouseenter', ({node}) => {
|
||||||
// 保存原始样式
|
// 保存原始样式
|
||||||
saveNodeOriginalStyle(node);
|
saveNodeOriginalStyle(node);
|
||||||
|
|
||||||
// 显示连接桩
|
// 显示连接桩
|
||||||
const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`);
|
const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`);
|
||||||
ports.forEach((port) => {
|
ports.forEach((port) => {
|
||||||
port.setAttribute('style', 'visibility: visible; fill: #fff; stroke: #85ca6d;');
|
port.setAttribute('style', 'visibility: visible; fill: #fff; stroke: #85ca6d;');
|
||||||
});
|
});
|
||||||
|
|
||||||
// 显示悬停样式
|
// 显示悬停样式
|
||||||
node.setAttrByPath('body/stroke', hoverStyle.stroke);
|
node.setAttrByPath('body/stroke', hoverStyle.stroke);
|
||||||
node.setAttrByPath('body/strokeWidth', hoverStyle.strokeWidth);
|
node.setAttrByPath('body/strokeWidth', hoverStyle.strokeWidth);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 连线开始时的处理
|
// 连线开始时的处理
|
||||||
graph.on('edge:connected', ({ edge }) => {
|
graph.on('edge:connected', ({edge}) => {
|
||||||
// 设置连线样式
|
// 设置连线样式
|
||||||
edge.setAttrs({
|
edge.setAttrs({
|
||||||
line: {
|
line: {
|
||||||
@ -764,7 +743,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 连线悬停效果
|
// 连线悬停效果
|
||||||
graph.on('edge:mouseenter', ({ edge }) => {
|
graph.on('edge:mouseenter', ({edge}) => {
|
||||||
edge.setAttrs({
|
edge.setAttrs({
|
||||||
line: {
|
line: {
|
||||||
stroke: '#52c41a',
|
stroke: '#52c41a',
|
||||||
@ -773,7 +752,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
graph.on('edge:mouseleave', ({ edge }) => {
|
graph.on('edge:mouseleave', ({edge}) => {
|
||||||
edge.setAttrs({
|
edge.setAttrs({
|
||||||
line: {
|
line: {
|
||||||
stroke: '#5F95FF',
|
stroke: '#5F95FF',
|
||||||
@ -783,7 +762,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 允许拖动连线中间的点和端点
|
// 允许拖动连线中间的点和端点
|
||||||
graph.on('edge:selected', ({ edge }) => {
|
graph.on('edge:selected', ({edge}) => {
|
||||||
edge.addTools([
|
edge.addTools([
|
||||||
{
|
{
|
||||||
name: 'source-arrowhead',
|
name: 'source-arrowhead',
|
||||||
@ -835,12 +814,12 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 连线工具移除
|
// 连线工具移除
|
||||||
graph.on('edge:unselected', ({ edge }) => {
|
graph.on('edge:unselected', ({edge}) => {
|
||||||
edge.removeTools();
|
edge.removeTools();
|
||||||
});
|
});
|
||||||
|
|
||||||
// 连线移动到其他连接桩时的样式
|
// 连线移动到其他连接桩时的样式
|
||||||
graph.on('edge:connected', ({ edge }) => {
|
graph.on('edge:connected', ({edge}) => {
|
||||||
edge.setAttrs({
|
edge.setAttrs({
|
||||||
line: {
|
line: {
|
||||||
stroke: '#5F95FF',
|
stroke: '#5F95FF',
|
||||||
@ -854,7 +833,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 连线悬停在连接桩上时的样式
|
// 连线悬停在连接桩上时的样式
|
||||||
graph.on('edge:mouseenter', ({ edge }) => {
|
graph.on('edge:mouseenter', ({edge}) => {
|
||||||
const ports = document.querySelectorAll('.x6-port-body');
|
const ports = document.querySelectorAll('.x6-port-body');
|
||||||
ports.forEach((port) => {
|
ports.forEach((port) => {
|
||||||
const portGroup = port.getAttribute('port-group');
|
const portGroup = port.getAttribute('port-group');
|
||||||
@ -864,7 +843,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
graph.on('edge:mouseleave', ({ edge }) => {
|
graph.on('edge:mouseleave', ({edge}) => {
|
||||||
const ports = document.querySelectorAll('.x6-port-body');
|
const ports = document.querySelectorAll('.x6-port-body');
|
||||||
ports.forEach((port) => {
|
ports.forEach((port) => {
|
||||||
port.setAttribute('style', 'visibility: hidden');
|
port.setAttribute('style', 'visibility: hidden');
|
||||||
@ -903,7 +882,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
message.info('剪贴板为空');
|
message.info('剪贴板为空');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const cells = graph.paste({ offset: 32 });
|
const cells = graph.paste({offset: 32});
|
||||||
graph.cleanSelection();
|
graph.cleanSelection();
|
||||||
graph.select(cells);
|
graph.select(cells);
|
||||||
message.success('已粘贴');
|
message.success('已粘贴');
|
||||||
@ -944,7 +923,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
response.graph?.nodes?.forEach((workflowDefinitionNode: any) => {
|
response.graph?.nodes?.forEach((workflowDefinitionNode: any) => {
|
||||||
const node = addNodeToGraph(false, graphInstance, workflowDefinitionNode, nodeDefinitions);
|
const node = addNodeToGraph(false, graphInstance, workflowDefinitionNode, nodeDefinitions);
|
||||||
// 保存节点配置
|
// 保存节点配置
|
||||||
node.setProp('config', workflowDefinitionNode.config);
|
node.setProp('workflowDefinitionNode', workflowDefinitionNode);
|
||||||
nodeMap.set(workflowDefinitionNode.id, node);
|
nodeMap.set(workflowDefinitionNode.id, node);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -962,10 +941,10 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
|
|
||||||
// 获取源节点的输出端口(一定是out组)
|
// 获取源节点的输出端口(一定是out组)
|
||||||
const sourcePort = getPortByGroup(sourceNode, 'out');
|
const sourcePort = getPortByGroup(sourceNode, 'out');
|
||||||
|
|
||||||
// 获取目标节点的输入端口(一定是in组)
|
// 获取目标节点的输入端口(一定是in组)
|
||||||
const targetPort = getPortByGroup(targetNode, 'in');
|
const targetPort = getPortByGroup(targetNode, 'in');
|
||||||
|
|
||||||
if (!sourcePort || !targetPort) {
|
if (!sourcePort || !targetPort) {
|
||||||
console.error('无法找到正确的端口:', edge);
|
console.error('无法找到正确的端口:', edge);
|
||||||
return;
|
return;
|
||||||
@ -1014,7 +993,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const newGraph = initGraph();
|
const newGraph = initGraph();
|
||||||
if (newGraph) {
|
if (newGraph) {
|
||||||
setGraph(newGraph);
|
setGraph(newGraph);
|
||||||
|
|
||||||
// 在图形初始化完成后加载数据
|
// 在图形初始化完成后加载数据
|
||||||
if (id) {
|
if (id) {
|
||||||
loadDefinitionDetail(newGraph, id);
|
loadDefinitionDetail(newGraph, id);
|
||||||
@ -1060,6 +1039,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
const handleNodeConfigUpdate = (values: any) => {
|
const handleNodeConfigUpdate = (values: any) => {
|
||||||
if (!selectedNode) return;
|
if (!selectedNode) return;
|
||||||
// 更新节点配置
|
// 更新节点配置
|
||||||
|
console.log("// 更新节点配置", values);
|
||||||
selectedNode.setProp('config', values);
|
selectedNode.setProp('config', values);
|
||||||
// 更新节点显示名称
|
// 更新节点显示名称
|
||||||
if (values.name) {
|
if (values.name) {
|
||||||
@ -1094,17 +1074,18 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
type: nodeType,
|
type: nodeType,
|
||||||
name: node.attr('label/text'),
|
name: node.attr('label/text'),
|
||||||
graph: {
|
graph: {
|
||||||
shape: nodeDefinition?.graphConfig.uiSchema.shape,
|
// shape: nodeDefinition?.graphConfig.uiSchema.shape,
|
||||||
size: {
|
// size: {
|
||||||
width: node.size().width,
|
// width: node.size().width,
|
||||||
height: node.size().height
|
// height: node.size().height
|
||||||
},
|
// },
|
||||||
style: nodeDefinition?.graphConfig.uiSchema.style,
|
// style: nodeDefinition?.graphConfig.uiSchema.style,
|
||||||
ports: nodeDefinition?.graphConfig.uiSchema.ports,
|
// ports: nodeDefinition?.graphConfig.uiSchema.ports,
|
||||||
position: {
|
// position: {
|
||||||
x: position.x,
|
// x: position.x,
|
||||||
y: position.y
|
// y: position.y
|
||||||
}
|
// }
|
||||||
|
uiVariables: nodeDefinition.uiVariables
|
||||||
},
|
},
|
||||||
config: node.getProp('config') || {}
|
config: node.getProp('config') || {}
|
||||||
};
|
};
|
||||||
@ -1162,7 +1143,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
<Tooltip title="返回">
|
<Tooltip title="返回">
|
||||||
<Button
|
<Button
|
||||||
className="back-button"
|
className="back-button"
|
||||||
icon={<ArrowLeftOutlined />}
|
icon={<ArrowLeftOutlined/>}
|
||||||
onClick={() => navigate('/workflow/definition')}
|
onClick={() => navigate('/workflow/definition')}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -1173,7 +1154,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
<Space.Compact>
|
<Space.Compact>
|
||||||
<Tooltip title="撤销">
|
<Tooltip title="撤销">
|
||||||
<Button
|
<Button
|
||||||
icon={<UndoOutlined />}
|
icon={<UndoOutlined/>}
|
||||||
onClick={handleUndo}
|
onClick={handleUndo}
|
||||||
disabled={!(graph as any)?.history?.canUndo()}
|
disabled={!(graph as any)?.history?.canUndo()}
|
||||||
>
|
>
|
||||||
@ -1182,7 +1163,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="重做">
|
<Tooltip title="重做">
|
||||||
<Button
|
<Button
|
||||||
icon={<RedoOutlined />}
|
icon={<RedoOutlined/>}
|
||||||
onClick={handleRedo}
|
onClick={handleRedo}
|
||||||
disabled={!(graph as any)?.history?.canRedo()}
|
disabled={!(graph as any)?.history?.canRedo()}
|
||||||
>
|
>
|
||||||
@ -1193,19 +1174,19 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
<Space.Compact>
|
<Space.Compact>
|
||||||
<Tooltip title="剪切">
|
<Tooltip title="剪切">
|
||||||
<Button
|
<Button
|
||||||
icon={<ScissorOutlined />}
|
icon={<ScissorOutlined/>}
|
||||||
onClick={handleCut}
|
onClick={handleCut}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="复制">
|
<Tooltip title="复制">
|
||||||
<Button
|
<Button
|
||||||
icon={<CopyOutlined />}
|
icon={<CopyOutlined/>}
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="粘贴">
|
<Tooltip title="粘贴">
|
||||||
<Button
|
<Button
|
||||||
icon={<SnippetsOutlined />}
|
icon={<SnippetsOutlined/>}
|
||||||
onClick={handlePaste}
|
onClick={handlePaste}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -1213,7 +1194,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
<Space.Compact>
|
<Space.Compact>
|
||||||
<Tooltip title="放大">
|
<Tooltip title="放大">
|
||||||
<Button
|
<Button
|
||||||
icon={<ZoomInOutlined />}
|
icon={<ZoomInOutlined/>}
|
||||||
onClick={handleZoomIn}
|
onClick={handleZoomIn}
|
||||||
disabled={scale >= 2}
|
disabled={scale >= 2}
|
||||||
>
|
>
|
||||||
@ -1222,7 +1203,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="缩小">
|
<Tooltip title="缩小">
|
||||||
<Button
|
<Button
|
||||||
icon={<ZoomOutOutlined />}
|
icon={<ZoomOutOutlined/>}
|
||||||
onClick={handleZoomOut}
|
onClick={handleZoomOut}
|
||||||
disabled={scale <= 0.2}
|
disabled={scale <= 0.2}
|
||||||
>
|
>
|
||||||
@ -1233,25 +1214,25 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
<Space.Compact>
|
<Space.Compact>
|
||||||
<Tooltip title="全选">
|
<Tooltip title="全选">
|
||||||
<Button
|
<Button
|
||||||
icon={<SelectOutlined />}
|
icon={<SelectOutlined/>}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!graph) return;
|
if (!graph) return;
|
||||||
|
|
||||||
// 添加小延时确保图形已完全初始化
|
// 添加小延时确保图形已完全初始化
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const cells = graph.getCells();
|
const cells = graph.getCells();
|
||||||
console.log('All cells:', cells);
|
console.log('All cells:', cells);
|
||||||
|
|
||||||
if (cells.length === 0) {
|
if (cells.length === 0) {
|
||||||
message.info('当前没有可选择的元素');
|
message.info('当前没有可选择的元素');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打印当前选择状态
|
// 打印当前选择状态
|
||||||
console.log('Current selection before reset:', graph.getSelectedCells());
|
console.log('Current selection before reset:', graph.getSelectedCells());
|
||||||
graph.resetSelection();
|
graph.resetSelection();
|
||||||
console.log('Selection after reset:', graph.getSelectedCells());
|
console.log('Selection after reset:', graph.getSelectedCells());
|
||||||
|
|
||||||
// 尝试选择所有单元格
|
// 尝试选择所有单元格
|
||||||
try {
|
try {
|
||||||
graph.select(cells);
|
graph.select(cells);
|
||||||
@ -1259,7 +1240,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error selecting cells:', error);
|
console.error('Error selecting cells:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查Selection插件是否正确初始化
|
// 检查Selection插件是否正确初始化
|
||||||
const selection = graph.getPlugin('selection');
|
const selection = graph.getPlugin('selection');
|
||||||
console.log('Selection plugin:', selection);
|
console.log('Selection plugin:', selection);
|
||||||
@ -1269,7 +1250,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="删除">
|
<Tooltip title="删除">
|
||||||
<Button
|
<Button
|
||||||
icon={<DeleteOutlined />}
|
icon={<DeleteOutlined/>}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!graph) return;
|
if (!graph) return;
|
||||||
const cells = graph.getSelectedCells();
|
const cells = graph.getSelectedCells();
|
||||||
@ -1291,7 +1272,7 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
<Tooltip title="保存">
|
<Tooltip title="保存">
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<SaveOutlined />}
|
icon={<SaveOutlined/>}
|
||||||
onClick={handleSaveWorkflow}
|
onClick={handleSaveWorkflow}
|
||||||
>
|
>
|
||||||
保存
|
保存
|
||||||
@ -1309,13 +1290,13 @@ const WorkflowDesign: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="main-area">
|
<div className="main-area">
|
||||||
<div className="workflow-container">
|
<div className="workflow-container">
|
||||||
<div
|
<div
|
||||||
ref={graphContainerRef}
|
ref={graphContainerRef}
|
||||||
className="workflow-canvas"
|
className="workflow-canvas"
|
||||||
onDrop={handleDrop}
|
onDrop={handleDrop}
|
||||||
onDragOver={handleDragOver}
|
onDragOver={handleDragOver}
|
||||||
/>
|
/>
|
||||||
<div ref={minimapContainerRef} className="minimap-container" />
|
<div ref={minimapContainerRef} className="minimap-container"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -108,6 +108,7 @@ const validateAllNodesConfig = (graph: Graph): ValidationResult => {
|
|||||||
|
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
const nodeDefinition = node.getProp('nodeDefinition');
|
const nodeDefinition = node.getProp('nodeDefinition');
|
||||||
|
console.log(nodeDefinition)
|
||||||
const result = validateNodeConfig(node, nodeDefinition);
|
const result = validateNodeConfig(node, nodeDefinition);
|
||||||
if (!result.valid) {
|
if (!result.valid) {
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -1,27 +1,38 @@
|
|||||||
import { BaseResponse, BaseQuery } from '@/types/base';
|
import {BaseResponse, BaseQuery} from '@/types/base';
|
||||||
|
|
||||||
export interface WorkflowDefinition extends BaseResponse {
|
export interface WorkflowDefinition extends BaseResponse {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
key: string;
|
key: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
flowVersion?: number;
|
flowVersion?: number;
|
||||||
status?: string;
|
status?: string;
|
||||||
category: string;
|
category: string;
|
||||||
triggers: string[];
|
triggers: string[];
|
||||||
graph: {
|
graph: {
|
||||||
nodes: any[];
|
nodes: WorkflowDefinitionNode[];
|
||||||
edges: any[];
|
edges: any[];
|
||||||
};
|
};
|
||||||
formConfig: {
|
formConfig: {
|
||||||
formItems: any[];
|
formItems: any[];
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WorkflowDefinitionNode {
|
||||||
|
id: number;
|
||||||
|
code: string;
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
uiVariables: JSON;
|
||||||
|
panelVariables: JSON;
|
||||||
|
localVariables: JSON;
|
||||||
|
formVariables: JSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WorkflowDefinitionQuery extends BaseQuery {
|
export interface WorkflowDefinitionQuery extends BaseQuery {
|
||||||
name?: string;
|
name?: string;
|
||||||
key?: string;
|
key?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user