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 { Button, Space, Card, Row, Col, message } from 'antd';
import { ArrowLeftOutlined, SaveOutlined, PlayCircleOutlined } from '@ant-design/icons'; import { ArrowLeftOutlined, SaveOutlined, PlayCircleOutlined } from '@ant-design/icons';
import { Graph, Cell } from '@antv/x6'; import { Graph, Cell } from '@antv/x6';
import { DagreLayout } from '@antv/layout';
import { getDefinitionDetail, saveDefinition } from '../service'; import { getDefinitionDetail, saveDefinition } from '../service';
import NodePanel from './components/NodePanel'; import NodePanel from './components/NodePanel';
import NodeConfigDrawer from './components/NodeConfigModal'; import NodeConfigDrawer from './components/NodeConfigModal';
import { NodeDefinition } from './types'; import { NodeDefinition } from './types';
import { validateWorkflow } from './utils/validator'; import { validateWorkflow } from './utils/validator';
import { import {
NODE_REGISTRY_CONFIG,
GRID_CONFIG, GRID_CONFIG,
CONNECTING_CONFIG, CONNECTING_CONFIG,
HIGHLIGHTING_CONFIG, HIGHLIGHTING_CONFIG,
@ -27,59 +27,13 @@ const WorkflowDesign: React.FC = () => {
const [configModalVisible, setConfigModalVisible] = useState(false); const [configModalVisible, setConfigModalVisible] = useState(false);
const [definitionData, setDefinitionData] = useState<any>(null); const [definitionData, setDefinitionData] = useState<any>(null);
useEffect(() => {
if (id) {
loadDefinitionDetail();
}
}, [id]);
useEffect(() => { useEffect(() => {
if (graphContainerRef.current) { if (graphContainerRef.current) {
// 注册自定义节点
Object.entries(NODE_REGISTRY_CONFIG).forEach(([name, config]) => {
Graph.registerNode(name, config, true);
});
const graph = new Graph({ const graph = new Graph({
container: graphContainerRef.current, container: graphContainerRef.current,
grid: GRID_CONFIG, grid: GRID_CONFIG,
connecting: { connecting: CONNECTING_CONFIG,
...CONNECTING_CONFIG, highlighting: HIGHLIGHTING_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,
},
},
},
},
snapline: true, snapline: true,
history: true, history: true,
clipboard: true, clipboard: true,
@ -115,19 +69,110 @@ const WorkflowDesign: React.FC = () => {
setGraph(graph); setGraph(graph);
// 在 graph 初始化完成后加载数据
if (id) {
loadDefinitionDetail(graph, id);
}
return () => { return () => {
graph.dispose(); graph.dispose();
}; };
} }
}, [graphContainerRef]); }, [graphContainerRef, id]);
const loadDefinitionDetail = async () => { const loadDefinitionDetail = async (graphInstance: Graph, definitionId: number) => {
try { try {
const response = await getDefinitionDetail(id); const response = await getDefinitionDetail(definitionId);
console.log('加载到的工作流数据:', response);
setTitle(`工作流设计 - ${response.name}`); setTitle(`工作流设计 - ${response.name}`);
setDefinitionData(response); 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) { } 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 node = JSON.parse(nodeData);
const { clientX, clientY } = e; const { clientX, clientY } = e;
const point = graph.clientToLocal({ x: clientX, y: clientY }); const point = graph.clientToLocal({ x: clientX, y: clientY });
const nodeConfig = { const nodeConfig = {
shape: node.graphConfig.uiSchema.shape, shape: node.graphConfig.uiSchema.shape,
width: node.graphConfig.uiSchema.size.width, width: node.graphConfig.uiSchema.size.width,
@ -193,21 +238,21 @@ const WorkflowDesign: React.FC = () => {
const handleNodeConfigUpdate = (values: any) => { const handleNodeConfigUpdate = (values: any) => {
if (!selectedNode) return; if (!selectedNode) return;
// 更新节点配置 // 更新节点配置
selectedNode.setProp('config', values); selectedNode.setProp('config', values);
// 更新节点显示名称 // 更新节点显示名称
if (values.name) { if (values.name) {
selectedNode.attr('label/text', values.name); selectedNode.attr('label/text', values.name);
} }
setConfigModalVisible(false); setConfigModalVisible(false);
message.success('节点配置已更新'); message.success('节点配置已更新');
}; };
const handleSaveWorkflow = async () => { const handleSaveWorkflow = async () => {
if (!graph || !definitionData) return; if (!graph || !definitionData) return;
try { try {
// 校验流程图 // 校验流程图
const validationResult = validateWorkflow(graph); const validationResult = validateWorkflow(graph);
@ -220,7 +265,7 @@ const WorkflowDesign: React.FC = () => {
const nodes = graph.getNodes().map(node => { const nodes = graph.getNodes().map(node => {
const nodeDefinition = node.getProp('nodeDefinition'); const nodeDefinition = node.getProp('nodeDefinition');
const nodeType = node.getProp('type'); const nodeType = node.getProp('type');
return { return {
id: node.id, id: node.id,
code: nodeType, code: nodeType,