1
This commit is contained in:
parent
f1583c8b7b
commit
c2a460d7d1
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user