This commit is contained in:
dengqichen 2024-12-13 10:38:59 +08:00
parent 2df3cb3074
commit 0893ea614a

View File

@ -3,13 +3,13 @@ import { useParams, useNavigate } from 'react-router-dom';
import { Button, Space, Card, Row, Col, message } from 'antd';
import { ArrowLeftOutlined, SaveOutlined, PlayCircleOutlined } from '@ant-design/icons';
import { Graph, Cell } from '@antv/x6';
import { DagreLayout } from '@antv/layout';
import { getDefinitionDetail, saveDefinition } from '../service';
import NodePanel from './components/NodePanel';
import NodeConfigDrawer from './components/NodeConfigModal';
import { NodeDefinition } from './types';
import { validateWorkflow } from './utils/validator';
import {
NODE_REGISTRY_CONFIG,
GRID_CONFIG,
CONNECTING_CONFIG,
HIGHLIGHTING_CONFIG,
@ -27,59 +27,13 @@ const WorkflowDesign: React.FC = () => {
const [configModalVisible, setConfigModalVisible] = useState(false);
const [definitionData, setDefinitionData] = useState<any>(null);
useEffect(() => {
if (id) {
loadDefinitionDetail();
}
}, [id]);
useEffect(() => {
if (graphContainerRef.current) {
// 注册自定义节点
Object.entries(NODE_REGISTRY_CONFIG).forEach(([name, config]) => {
Graph.registerNode(name, config, true);
});
const graph = new Graph({
container: graphContainerRef.current,
grid: GRID_CONFIG,
connecting: {
...CONNECTING_CONFIG,
validateConnection({ sourceView, targetView, sourceMagnet, targetMagnet }) {
if (!sourceMagnet || !targetMagnet) {
return false;
}
if (sourceView === targetView) {
return false;
}
return true;
},
validateMagnet({ magnet }) {
const portGroup = magnet?.getAttribute('port-group');
return !!portGroup;
},
createEdge() {
return this.createEdge({
attrs: {
line: DEFAULT_STYLES.edge,
},
zIndex: -1,
});
},
},
highlighting: {
...HIGHLIGHTING_CONFIG,
magnetAdsorbed: {
name: 'stroke',
args: {
attrs: {
fill: '#fff',
stroke: '#31d0c6',
strokeWidth: 4,
},
},
},
},
connecting: CONNECTING_CONFIG,
highlighting: HIGHLIGHTING_CONFIG,
snapline: true,
history: true,
clipboard: true,
@ -115,19 +69,110 @@ const WorkflowDesign: React.FC = () => {
setGraph(graph);
// 在 graph 初始化完成后加载数据
if (id) {
loadDefinitionDetail(graph, id);
}
return () => {
graph.dispose();
};
}
}, [graphContainerRef]);
}, [graphContainerRef, id]);
const loadDefinitionDetail = async () => {
const loadDefinitionDetail = async (graphInstance: Graph, definitionId: number) => {
try {
const response = await getDefinitionDetail(id);
const response = await getDefinitionDetail(definitionId);
console.log('加载到的工作流数据:', response);
setTitle(`工作流设计 - ${response.name}`);
setDefinitionData(response);
// 清空画布
graphInstance.clearCells();
const nodeMap = new Map();
// 动态注册节点类型
response.graph.nodes.forEach((nodeData: any) => {
// 根据节点类型动态注册
const nodeConfig = {
inherit: 'rect', // 使用基础的矩形节点作为默认继承
width: nodeData.graph.size.width,
height: nodeData.graph.size.height,
attrs: {
body: nodeData.graph.style,
},
ports: nodeData.graph.ports
};
// 根据形状选择不同的基础节点类型
if (nodeData.graph.shape === 'circle') {
nodeConfig.inherit = 'circle';
} else if (nodeData.graph.shape === 'polygon') {
nodeConfig.inherit = 'polygon';
}
// 注册节点类型
Graph.registerNode(nodeData.code, nodeConfig, true);
// 创建节点
const node = graphInstance.addNode({
id: nodeData.id,
shape: nodeData.code,
position: nodeData.graph.position || { x: 100, y: 100 },
attrs: {
body: nodeData.graph.style,
label: {
text: nodeData.name,
fill: '#000000',
fontSize: 12,
}
},
nodeDefinition: nodeData,
});
nodeMap.set(nodeData.id, node);
});
// 创建边
response.graph.edges.forEach((edge: any) => {
const sourceNode = nodeMap.get(edge.from);
const targetNode = nodeMap.get(edge.to);
if (sourceNode && targetNode) {
graphInstance.addEdge({
source: { cell: sourceNode.id },
target: { cell: targetNode.id },
attrs: {
line: DEFAULT_STYLES.edge
},
labels: [
{
attrs: {
label: {
text: edge.name || '',
},
},
},
],
});
}
});
// 自动布局
const layout = new DagreLayout({
type: 'dagre',
rankdir: 'LR',
align: 'UL',
ranksep: 80,
nodesep: 50,
});
const cells = graphInstance.getCells();
layout.layout(cells);
graphInstance.resetCells(cells);
graphInstance.centerContent();
} catch (error) {
console.error('Failed to load workflow definition:', error);
console.error('加载工作流定义失败:', error);
message.error('加载工作流定义失败');
}
};
@ -143,7 +188,7 @@ const WorkflowDesign: React.FC = () => {
const node = JSON.parse(nodeData);
const { clientX, clientY } = e;
const point = graph.clientToLocal({ x: clientX, y: clientY });
const nodeConfig = {
shape: node.graphConfig.uiSchema.shape,
width: node.graphConfig.uiSchema.size.width,
@ -193,21 +238,21 @@ const WorkflowDesign: React.FC = () => {
const handleNodeConfigUpdate = (values: any) => {
if (!selectedNode) return;
// 更新节点配置
selectedNode.setProp('config', values);
// 更新节点显示名称
if (values.name) {
selectedNode.attr('label/text', values.name);
}
setConfigModalVisible(false);
message.success('节点配置已更新');
};
const handleSaveWorkflow = async () => {
if (!graph || !definitionData) return;
try {
// 校验流程图
const validationResult = validateWorkflow(graph);
@ -220,7 +265,7 @@ const WorkflowDesign: React.FC = () => {
const nodes = graph.getNodes().map(node => {
const nodeDefinition = node.getProp('nodeDefinition');
const nodeType = node.getProp('type');
return {
id: node.id,
code: nodeType,