This commit is contained in:
asp_ly 2024-12-14 14:48:39 +08:00
parent f1583c8b7b
commit c2a460d7d1

View File

@ -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<NodeDefinition[]>([]);
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 = () => {
<Tooltip title="撤销">
<Button
icon={<UndoOutlined />}
onClick={() => graph?.undo()}
/>
onClick={handleUndo}
disabled={!(graph as any)?.history?.canUndo()}
>
</Button>
</Tooltip>
<Tooltip title="重做">
<Button
icon={<RedoOutlined />}
onClick={() => graph?.redo()}
/>
onClick={handleRedo}
disabled={!(graph as any)?.history?.canRedo()}
>
</Button>
</Tooltip>
</Space.Compact>
<Space.Compact>