diff --git a/frontend/src/pages/Workflow/Definition/Design/index.tsx b/frontend/src/pages/Workflow/Definition/Design/index.tsx index e2c3b327..bf68173b 100644 --- a/frontend/src/pages/Workflow/Definition/Design/index.tsx +++ b/frontend/src/pages/Workflow/Definition/Design/index.tsx @@ -21,6 +21,7 @@ import '@antv/x6-plugin-history'; import { Selection } from '@antv/x6-plugin-selection'; import { MiniMap } from '@antv/x6-plugin-minimap'; import { Clipboard } from '@antv/x6-plugin-clipboard'; +import { History } from '@antv/x6-plugin-history'; import {getDefinitionDetail, saveDefinition} from '../service'; import {getNodeDefinitionList} from './service'; import NodePanel from './components/NodePanel'; @@ -51,6 +52,107 @@ const WorkflowDesign: React.FC = () => { const [nodeDefinitions, setNodeDefinitions] = useState([]); const [isNodeDefinitionsLoaded, setIsNodeDefinitionsLoaded] = useState(false); + // 初始化图形 + const initGraph = () => { + if (!graphContainerRef.current) return null; + + const graph = new Graph({ + container: graphContainerRef.current, + grid: GRID_CONFIG, + connecting: CONNECTING_CONFIG, + highlighting: HIGHLIGHTING_CONFIG, + clipboard: { + enabled: true, + }, + selecting: { + enabled: true, + multiple: true, + rubberband: true, + movable: true, + showNodeSelectionBox: true, + }, + snapline: true, + keyboard: { + enabled: true, + }, + mousewheel: { + enabled: true, + modifiers: ['ctrl', 'meta'], + }, + }); + + // 注册插件 + const history = new History({ + enabled: true, + }); + + graph.use(new Selection()); + graph.use(new MiniMap({ + container: minimapContainerRef.current!, + width: 200, + height: 200, + })); + graph.use(new Clipboard()); + graph.use(history); + + // 扩展 graph 对象,添加 history 属性 + (graph as any).history = history; + + // 监听图形变化 + graph.on('cell:added', ({ cell }) => { + const canUndo = history.canUndo(); + console.log('Cell added, history:', canUndo, cell); + }); + + graph.on('cell:removed', ({ cell }) => { + const canUndo = history.canUndo(); + console.log('Cell removed, history:', canUndo, cell); + }); + + graph.on('cell:changed', ({ cell, options }) => { + const canUndo = history.canUndo(); + console.log('Cell changed, history:', canUndo, cell, options); + }); + + registerEventHandlers(graph); + + return graph; + }; + + // 处理撤销操作 + const handleUndo = () => { + if (!graph) return; + const history = (graph as any).history; + if (!history) { + console.error('History plugin not initialized'); + return; + } + console.log('Can undo:', history.canUndo()); + if (history.canUndo()) { + history.undo(); + message.success('已撤销'); + } else { + message.info('没有可撤销的操作'); + } + }; + + // 处理重做操作 + const handleRedo = () => { + if (!graph) return; + const history = (graph as any).history; + if (!history) { + console.error('History plugin not initialized'); + return; + } + console.log('Can redo:', history.canRedo()); + if (history.canRedo()) { + history.redo(); + message.success('已重做'); + } else { + message.info('没有可重做的操作'); + } + }; + // 注册事件处理器 const registerEventHandlers = (graph: Graph) => { // 显示/隐藏连接桩 @@ -131,7 +233,9 @@ const WorkflowDesign: React.FC = () => { Modal.confirm({ title: '确认删除', content: '确定要删除该节点吗?', - onOk: () => cell.remove() + onOk: () => { + cell.remove(); + } }); } } @@ -205,99 +309,18 @@ const WorkflowDesign: React.FC = () => { loadNodeDefinitions(); }, []); - // 等待节点定义加载完成后再初始化图形 - useEffect(() => { - if (!isNodeDefinitionsLoaded || !graphContainerRef.current) { - return; - } - - const graph = new Graph({ - container: graphContainerRef.current, - grid: GRID_CONFIG, - connecting: CONNECTING_CONFIG, - highlighting: HIGHLIGHTING_CONFIG, - snapline: true, - history: true, - clipboard: true, - keyboard: true, - background: { - color: '#f5f5f5', - }, - width: graphContainerRef.current.clientWidth, - height: graphContainerRef.current.clientHeight, - }); - - // 注册选择插件 - graph.use( - new Selection({ - enabled: true, - multiple: true, - rubberband: true, - showNodeSelectionBox: true, - showEdgeSelectionBox: true, - className: 'node-selected', - pointerEvents: 'none', - }) - ); - - // 注册小地图插件 - if (minimapContainerRef.current) { - graph.use( - new MiniMap({ - container: minimapContainerRef.current, - width: 200, - height: 150, - padding: 10, - scalable: true, - minScale: 0.01, - maxScale: 16, - graphOptions: { - async: true, - getCellView(cell) { - if (cell.isNode()) { - return graph.findViewByCell(cell); - } - }, - createCellView(cell) { - if (cell.isEdge()) { - return null; - } - }, - }, - }) - ); - } - - // 注册剪贴板插件 - graph.use(new Clipboard({ - enabled: true, - })); - - registerEventHandlers(graph); - - setGraph(graph); - - // 在 graph 初始化完成后加载数据 - if (id) { - loadDefinitionDetail(graph, id); - } - - return () => { - graph.dispose(); - }; - }, [graphContainerRef, id, nodeDefinitions, isNodeDefinitionsLoaded]); - - useEffect(() => { - if (!graph || !minimapContainerRef.current) return; - - }, [graph]); - + // 加载工作流定义详情 const loadDefinitionDetail = async (graphInstance: Graph, definitionId: string) => { try { const response = await getDefinitionDetail(Number(definitionId)); setTitle(`工作流设计 - ${response.name}`); setDefinitionData(response); + if (!graphInstance) { + console.error('Graph instance is not initialized'); + return; + } + // 清空画布 graphInstance.clearCells(); const nodeMap = new Map(); @@ -334,10 +357,33 @@ const WorkflowDesign: React.FC = () => { } }; + // 初始化图形和加载数据 + useEffect(() => { + if (!graphContainerRef.current || !isNodeDefinitionsLoaded) { + return; + } + + const newGraph = initGraph(); + if (newGraph) { + setGraph(newGraph); + + // 在图形初始化完成后加载数据 + if (id) { + loadDefinitionDetail(newGraph, id); + } + } + + return () => { + graph?.dispose(); + }; + }, [graphContainerRef, id, nodeDefinitions, isNodeDefinitionsLoaded]); + + // 处理节点拖拽开始 const handleNodeDragStart = (node: NodeDefinition, e: React.DragEvent) => { e.dataTransfer.setData('node', JSON.stringify(node)); }; + // 处理节点拖拽结束 const handleDrop = (e: React.DragEvent) => { e.preventDefault(); if (!graph) return; @@ -356,10 +402,12 @@ const WorkflowDesign: React.FC = () => { } }; + // 处理拖拽过程中 const handleDragOver = (e: React.DragEvent) => { e.preventDefault(); }; + // 处理节点配置更新 const handleNodeConfigUpdate = (values: any) => { if (!selectedNode) return; // 更新节点配置 @@ -373,6 +421,7 @@ const WorkflowDesign: React.FC = () => { message.success('节点配置已更新'); }; + // 处理保存工作流 const handleSaveWorkflow = async () => { if (!graph || !definitionData) return; @@ -476,14 +525,20 @@ const WorkflowDesign: React.FC = () => {