From 0893ea614a3d4cda7a402ec7662027f153f9dfd8 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Fri, 13 Dec 2024 10:38:59 +0800 Subject: [PATCH] 1 --- .../Workflow/Definition/Design/index.tsx | 161 +++++++++++------- 1 file changed, 103 insertions(+), 58 deletions(-) diff --git a/frontend/src/pages/Workflow/Definition/Design/index.tsx b/frontend/src/pages/Workflow/Definition/Design/index.tsx index b5487793..469af120 100644 --- a/frontend/src/pages/Workflow/Definition/Design/index.tsx +++ b/frontend/src/pages/Workflow/Definition/Design/index.tsx @@ -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(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,