diff --git a/frontend/src/pages/Workflow/Definition/Design/index.tsx b/frontend/src/pages/Workflow/Definition/Design/index.tsx index ff3d598b..0c1062a4 100644 --- a/frontend/src/pages/Workflow/Definition/Design/index.tsx +++ b/frontend/src/pages/Workflow/Definition/Design/index.tsx @@ -29,13 +29,15 @@ const WorkflowDesign: React.FC = () => { const [configModalVisible, setConfigModalVisible] = useState(false); const [definitionData, setDefinitionData] = useState(null); const [nodeDefinitions, setNodeDefinitions] = useState([]); + const [isNodeDefinitionsLoaded, setIsNodeDefinitionsLoaded] = useState(false); - // 加载节点定义列表 + // 首先加载节点定义列表 useEffect(() => { const loadNodeDefinitions = async () => { try { const data = await getNodeDefinitionList(); setNodeDefinitions(data); + setIsNodeDefinitionsLoaded(true); } catch (error) { console.error('加载节点定义失败:', error); message.error('加载节点定义失败'); @@ -44,74 +46,77 @@ const WorkflowDesign: React.FC = () => { loadNodeDefinitions(); }, []); + // 等待节点定义加载完成后再初始化图形 useEffect(() => { - if (graphContainerRef.current) { - const graph = new Graph({ - container: graphContainerRef.current, - grid: GRID_CONFIG, - connecting: CONNECTING_CONFIG, - highlighting: HIGHLIGHTING_CONFIG, - snapline: true, - history: true, - clipboard: true, - selecting: true, - keyboard: true, - background: { - color: '#f5f5f5', - }, - mousewheel: { - enabled: true, - modifiers: ['ctrl', 'meta'], - factor: 1.1, - maxScale: 1.5, - minScale: 0.5, - }, - panning: { - enabled: true, - eventTypes: ['rightMouseDown'], - }, - preventDefaultContextMenu: true, - }); - - // 显示/隐藏连接桩 - graph.on('node:mouseenter', ({ node }) => { - const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`); - ports.forEach((port) => { - port.setAttribute('style', 'visibility: visible'); - }); - }); - - graph.on('node:mouseleave', ({ node }) => { - const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`); - ports.forEach((port) => { - port.setAttribute('style', 'visibility: hidden'); - }); - }); - - // 节点双击事件 - graph.on('node:dblclick', ({ node }) => { - const nodeType = node.getProp('type'); - // 从节点定义列表中找到对应的定义 - const definition = nodeDefinitions.find(def => def.type === nodeType); - if (definition) { - setSelectedNode(node); - setSelectedNodeDefinition(definition); - setConfigModalVisible(true); - } - }); - - setGraph(graph); - - // 在 graph 初始化完成后加载数据 - if (id) { - loadDefinitionDetail(graph, id); - } - - return () => { - graph.dispose(); - }; + if (!isNodeDefinitionsLoaded || !graphContainerRef.current) { + return; } - }, [graphContainerRef, id, nodeDefinitions]); + + const graph = new Graph({ + container: graphContainerRef.current, + grid: GRID_CONFIG, + connecting: CONNECTING_CONFIG, + highlighting: HIGHLIGHTING_CONFIG, + snapline: true, + history: true, + clipboard: true, + selecting: true, + keyboard: true, + background: { + color: '#f5f5f5', + }, + mousewheel: { + enabled: true, + modifiers: ['ctrl', 'meta'], + factor: 1.1, + maxScale: 1.5, + minScale: 0.5, + }, + panning: { + enabled: true, + eventTypes: ['rightMouseDown'], + }, + preventDefaultContextMenu: true, + }); + + // 显示/隐藏连接桩 + graph.on('node:mouseenter', ({ node }) => { + const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`); + ports.forEach((port) => { + port.setAttribute('style', 'visibility: visible'); + }); + }); + + graph.on('node:mouseleave', ({ node }) => { + const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`); + ports.forEach((port) => { + port.setAttribute('style', 'visibility: hidden'); + }); + }); + + // 节点双击事件 + graph.on('node:dblclick', ({ node }) => { + const nodeType = node.getProp('type'); + // 从节点定义列表中找到对应的定义 + const definition = nodeDefinitions.find(def => def.type === nodeType); + if (definition) { + setSelectedNode(node); + setSelectedNodeDefinition(definition); + setConfigModalVisible(true); + } + }); + + setGraph(graph); + + // 在 graph 初始化完成后加载数据 + if (id) { + loadDefinitionDetail(graph, id); + } + + return () => { + graph.dispose(); + }; + }, [graphContainerRef, id, nodeDefinitions, isNodeDefinitionsLoaded]); const loadDefinitionDetail = async (graphInstance: Graph, definitionId: number) => { try { @@ -124,12 +129,13 @@ const WorkflowDesign: React.FC = () => { const nodeMap = new Map(); // 创建节点 - response.graph.nodes.forEach((nodeData: any) => { - console.log('Creating node with data:', nodeData); // 添加日志 - const node = addNodeToGraph(graphInstance, nodeData); + response.graph.nodes.forEach((workflowDefinitionNode: any) => { + console.log('Creating node with data:', workflowDefinitionNode); // 添加日志 + + const node = addNodeToGraph(false, graphInstance, workflowDefinitionNode, nodeDefinitions); // 保存节点配置 - node.setProp('config', nodeData.config); - nodeMap.set(nodeData.id, node); + node.setProp('config', workflowDefinitionNode.config); + nodeMap.set(workflowDefinitionNode.id, node); }); // 创建边 @@ -171,8 +177,7 @@ const WorkflowDesign: React.FC = () => { const node = JSON.parse(nodeData); const { clientX, clientY } = e; const point = graph.clientToLocal({ x: clientX, y: clientY }); - - addNodeToGraph(graph, node, point); + addNodeToGraph(true, graph, node, nodeDefinitions, point); } catch (error) { console.error('创建节点失败:', error); message.error('创建节点失败'); diff --git a/frontend/src/pages/Workflow/Definition/Design/utils/nodeUtils.ts b/frontend/src/pages/Workflow/Definition/Design/utils/nodeUtils.ts index 6b76fcec..741b5076 100644 --- a/frontend/src/pages/Workflow/Definition/Design/utils/nodeUtils.ts +++ b/frontend/src/pages/Workflow/Definition/Design/utils/nodeUtils.ts @@ -1,65 +1,15 @@ -import { Graph } from '@antv/x6'; -import { convertPortConfig } from '../constants'; +import {Graph} from '@antv/x6'; +import {convertPortConfig} from '../constants'; -interface NodeStyle { - shape: string; - style: any; - size: { - width: number; - height: number; - }; - ports: any; -} - -/** - * 统一获取节点样式配置 - * @param node 节点数据 - * @returns 统一的节点样式配置 - */ -const getNodeStyle = (node: any): NodeStyle => { - // 如果是从已保存的定义加载的节点 - if (node.graph) { - return { - shape: node.graph.shape, - style: node.graph.style, - size: node.graph.size, - ports: node.graph.ports - }; - } - // 如果是从面板拖拽创建的新节点 - return { - shape: node.graphConfig.uiSchema.shape, - style: node.graphConfig.uiSchema.style, - size: node.graphConfig.uiSchema.size, - ports: node.graphConfig.uiSchema.ports - }; -}; /** * 创建节点配置 */ -const createNodeConfig = (node: any) => { - const style = getNodeStyle(node); - +const createNodeConfig = (uiGraph: any) => { return { inherit: 'rect', // 默认使用矩形 - width: style.size.width, - height: style.size.height, - attrs: { - body: { - ...style.style, - // 如果是菱形,添加多边形的点 - ...(style.shape === 'diamond' ? { - refPoints: '0,10 10,0 20,10 10,20', - } : {}) - }, - label: { - text: node.name, - fill: '#000000', - fontSize: 12, - } - }, - ports: convertPortConfig(style.ports) + + }; }; @@ -71,33 +21,50 @@ const createNodeConfig = (node: any) => { * @returns 创建的节点实例 */ export const addNodeToGraph = ( - graph: Graph, - node: any, + isNew: Boolean, + graph: Graph, + workflowDefinitionNode: any, + workflowNodeDefinitionList: any, position?: { x: number, y: number } ) => { - const style = getNodeStyle(node); - const nodeConfig = createNodeConfig(node); - + let nodeDefinition = workflowNodeDefinitionList.find(def => def.type === workflowDefinitionNode.type); + console.log(nodeDefinition.graphConfig.uiSchema, workflowDefinitionNode.graph) + let uiGraph = isNew ? nodeDefinition.graphConfig.uiSchema : workflowDefinitionNode.graph; // 根据形状类型设置正确的 shape let shape = 'rect'; // 默认使用矩形 - if (style.shape === 'circle') { + if (uiGraph.shape === 'circle') { shape = 'circle'; - } else if (style.shape === 'diamond') { + } else if (uiGraph.shape === 'diamond') { shape = 'polygon'; } - + const nodeConfig = createNodeConfig(uiGraph); // 创建节点 - const newNode = graph.addNode({ + return graph.addNode({ ...nodeConfig, + width: uiGraph.size.width, + height: uiGraph.size.height, + label: { + text: isNew ? workflowDefinitionNode.name : nodeDefinition.name, + fill: '#000000', + fontSize: 12, + }, + attrs: { + body: { + ...uiGraph.style, + // 如果是菱形,添加多边形的点 + ...(uiGraph.shape === 'diamond' ? { + refPoints: '0,10 10,0 20,10 10,20', + } : {}) + } + }, shape, // 使用映射后的形状 - ...(position && { x: position.x, y: position.y }), + ...(position && {x: position.x, y: position.y}), // 如果是已保存的节点,使用其ID和位置 - ...(node.id && { id: node.id }), - ...(node.graph?.position && { position: node.graph.position }), - type: node.type, - code: node.code, - nodeDefinition: node, + ...(uiGraph.id && {id: uiGraph.id}), + ...(uiGraph.graph?.position && {position: uiGraph.graph.position}), + type: uiGraph.type, + code: uiGraph.code, + ports: convertPortConfig(uiGraph.ports), + nodeDefinition: nodeDefinition, }); - - return newNode; }; \ No newline at end of file