From e76af9b8f579d1b68f737b1a08324c2fa2111c14 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Fri, 20 Dec 2024 14:04:55 +0800 Subject: [PATCH] 1 --- .../Workflow/Definition/Design/index.tsx | 201 ++++++++---------- .../Definition/Design/utils/validator.ts | 1 + .../src/pages/Workflow/Definition/types.ts | 49 +++-- 3 files changed, 122 insertions(+), 129 deletions(-) diff --git a/frontend/src/pages/Workflow/Definition/Design/index.tsx b/frontend/src/pages/Workflow/Definition/Design/index.tsx index 88d4e04d..3956df50 100644 --- a/frontend/src/pages/Workflow/Definition/Design/index.tsx +++ b/frontend/src/pages/Workflow/Definition/Design/index.tsx @@ -23,11 +23,11 @@ import '@antv/x6-plugin-keyboard'; import '@antv/x6-plugin-history'; import '@antv/x6-plugin-clipboard'; import '@antv/x6-plugin-transform'; -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 { Transform } from '@antv/x6-plugin-transform'; +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 {Transform} from '@antv/x6-plugin-transform'; import {getDefinitionDetail, saveDefinition} from '../service'; import {getNodeDefinitionList} from './service'; import NodePanel from './components/NodePanel'; @@ -69,12 +69,12 @@ const WorkflowDesign: React.FC = () => { const container = graphContainerRef.current; const containerWidth = container.clientWidth; const containerHeight = container.clientHeight; - + // 计算主画布和小地图的尺寸比例 const MINIMAP_BASE_WIDTH = 200; const minimapWidth = MINIMAP_BASE_WIDTH; const minimapHeight = Math.round((MINIMAP_BASE_WIDTH * containerHeight) / containerWidth); - + // 计算缩放比例 const scale = minimapWidth / containerWidth; @@ -132,10 +132,10 @@ const WorkflowDesign: React.FC = () => { }); return !exists; }, - validateMagnet({ magnet }) { + validateMagnet({magnet}) { return magnet.getAttribute('port-group') !== 'top'; }, - validateEdge({ edge }) { + validateEdge({edge}) { return true; } }, @@ -184,7 +184,6 @@ const WorkflowDesign: React.FC = () => { const history = new History({ enabled: true, beforeAddCommand(event: any, args: any) { - console.log('History command added:', event, args); return true; }, afterExecuteCommand: () => { @@ -200,7 +199,7 @@ const WorkflowDesign: React.FC = () => { setForceUpdate(prev => !prev); }, }); - + // 初始化Selection插件 const selection = new Selection({ enabled: true, @@ -216,9 +215,7 @@ const WorkflowDesign: React.FC = () => { showAnchorSelectionBox: false, pointerEvents: 'auto' }); - console.log('Initializing Selection plugin:', selection); graph.use(selection); - graph.use(new MiniMap({ container: minimapContainerRef.current!, width: minimapWidth, @@ -238,12 +235,7 @@ const WorkflowDesign: React.FC = () => { async: true, frozen: true, interacting: false, - grid: false, - getCellView(cell) { - if (cell.isNode()) { - return SimpleNodeView; - } - }, + grid: false }, viewport: { padding: 0, @@ -268,20 +260,14 @@ const WorkflowDesign: React.FC = () => { (graph as any).history = history; // 监听图形变化 - graph.on('cell:added', ({ cell }) => { + graph.on('cell:added', ({cell}) => { const canUndo = history.canUndo(); const canRedo = history.canRedo(); - console.log('Cell added:', { - cell, - canUndo, - canRedo, - stackSize: history.stackSize, - }); // 强制更新组件状态 setForceUpdate(prev => !prev); }); - - graph.on('cell:removed', ({ cell }) => { + + graph.on('cell:removed', ({cell}) => { const canUndo = history.canUndo(); const canRedo = history.canRedo(); console.log('Cell removed:', { @@ -293,17 +279,10 @@ const WorkflowDesign: React.FC = () => { // 强制更新组件状态 setForceUpdate(prev => !prev); }); - - graph.on('cell:changed', ({ cell, options }) => { + + graph.on('cell:changed', ({cell, options}) => { const canUndo = history.canUndo(); const canRedo = history.canRedo(); - console.log('Cell changed:', { - cell, - options, - canUndo, - canRedo, - stackSize: history.stackSize, - }); // 强制更新组件状态 setForceUpdate(prev => !prev); }); @@ -319,9 +298,9 @@ const WorkflowDesign: React.FC = () => { }); // 处理连线重新连接 - graph.on('edge:moved', ({ edge, terminal, previous }) => { + graph.on('edge:moved', ({edge, terminal, previous}) => { if (!edge || !terminal) return; - + const isSource = terminal.type === 'source'; const source = isSource ? terminal : edge.getSource(); const target = isSource ? edge.getTarget() : terminal; @@ -355,7 +334,7 @@ const WorkflowDesign: React.FC = () => { }); // 处理连线更改 - graph.on('edge:change:source edge:change:target', ({ edge, current, previous }) => { + graph.on('edge:change:source edge:change:target', ({edge, current, previous}) => { if (edge && current) { edge.setAttrs({ line: { @@ -383,13 +362,13 @@ const WorkflowDesign: React.FC = () => { console.error('History plugin not initialized'); return; } - + const beforeState = { canUndo: history.canUndo(), canRedo: history.canRedo(), stackSize: history.stackSize, }; - + if (history.canUndo()) { history.undo(); const afterState = { @@ -415,13 +394,13 @@ const WorkflowDesign: React.FC = () => { console.error('History plugin not initialized'); return; } - + const beforeState = { canUndo: history.canUndo(), canRedo: history.canRedo(), stackSize: history.stackSize, }; - + if (history.canRedo()) { history.redo(); const afterState = { @@ -501,13 +480,13 @@ const WorkflowDesign: React.FC = () => { graph.on('node:mouseenter', ({node}) => { // 保存原始样式 saveNodeOriginalStyle(node); - + // 显示连接桩 const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`); ports.forEach((port) => { port.setAttribute('style', 'visibility: visible; fill: #fff; stroke: #85ca6d;'); }); - + // 显示悬停样式 node.setAttrByPath('body/stroke', hoverStyle.stroke); node.setAttrByPath('body/strokeWidth', hoverStyle.strokeWidth); @@ -519,7 +498,7 @@ const WorkflowDesign: React.FC = () => { ports.forEach((port) => { port.setAttribute('style', 'visibility: hidden'); }); - + // 恢复原始样式 resetNodeStyle(node); }); @@ -541,15 +520,15 @@ const WorkflowDesign: React.FC = () => { }); // 节点点击事件 - graph.on('node:click', ({ node }) => { + graph.on('node:click', ({node}) => { // 获取当前选中的节点 const selectedNode = graph.getSelectedCells()[0]; - + // 如果有其他节点被选中,恢复其样式 if (selectedNode && selectedNode.isNode() && selectedNode.id !== node.id) { resetNodeStyle(selectedNode); } - + // 更新选中状态 graph.resetSelection(); graph.select(node); @@ -559,12 +538,12 @@ const WorkflowDesign: React.FC = () => { graph.on('blank:click', () => { // 获取当前选中的节点 const selectedNode = graph.getSelectedCells()[0]; - + // 如果有节点被选中,恢复其样式 if (selectedNode && selectedNode.isNode()) { resetNodeStyle(selectedNode); } - + // 清除选中状态 graph.resetSelection(); }); @@ -595,11 +574,11 @@ const WorkflowDesign: React.FC = () => { const root = createRoot(dropdownContainer); let isOpen = true; - + const closeMenu = () => { isOpen = false; root.render( - { + { if (!open) { setTimeout(() => { root.unmount(); @@ -607,7 +586,7 @@ const WorkflowDesign: React.FC = () => { }, 100); } }}> -
+
); }; @@ -640,8 +619,8 @@ const WorkflowDesign: React.FC = () => { ]; root.render( - -
+ +
); @@ -668,11 +647,11 @@ const WorkflowDesign: React.FC = () => { const root = createRoot(dropdownContainer); let isOpen = true; - + const closeMenu = () => { isOpen = false; root.render( - { + { if (!open) { setTimeout(() => { root.unmount(); @@ -680,7 +659,7 @@ const WorkflowDesign: React.FC = () => { }, 100); } }}> -
+
); }; @@ -703,8 +682,8 @@ const WorkflowDesign: React.FC = () => { ]; root.render( - -
+ +
); @@ -718,17 +697,17 @@ const WorkflowDesign: React.FC = () => { }); // 禁用默认的右键菜单 - graph.on('blank:contextmenu', ({ e }) => { + graph.on('blank:contextmenu', ({e}) => { e.preventDefault(); }); // 禁用节点的右键菜单 - graph.on('node:contextmenu', ({ e }) => { + graph.on('node:contextmenu', ({e}) => { e.preventDefault(); }); // 禁用边的右键菜单 - graph.on('edge:contextmenu', ({ e }) => { + graph.on('edge:contextmenu', ({e}) => { e.preventDefault(); }); @@ -736,20 +715,20 @@ const WorkflowDesign: React.FC = () => { graph.on('node:mouseenter', ({node}) => { // 保存原始样式 saveNodeOriginalStyle(node); - + // 显示连接桩 const ports = document.querySelectorAll(`[data-cell-id="${node.id}"] .x6-port-body`); ports.forEach((port) => { port.setAttribute('style', 'visibility: visible; fill: #fff; stroke: #85ca6d;'); }); - + // 显示悬停样式 node.setAttrByPath('body/stroke', hoverStyle.stroke); node.setAttrByPath('body/strokeWidth', hoverStyle.strokeWidth); }); // 连线开始时的处理 - graph.on('edge:connected', ({ edge }) => { + graph.on('edge:connected', ({edge}) => { // 设置连线样式 edge.setAttrs({ line: { @@ -764,7 +743,7 @@ const WorkflowDesign: React.FC = () => { }); // 连线悬停效果 - graph.on('edge:mouseenter', ({ edge }) => { + graph.on('edge:mouseenter', ({edge}) => { edge.setAttrs({ line: { stroke: '#52c41a', @@ -773,7 +752,7 @@ const WorkflowDesign: React.FC = () => { }); }); - graph.on('edge:mouseleave', ({ edge }) => { + graph.on('edge:mouseleave', ({edge}) => { edge.setAttrs({ line: { stroke: '#5F95FF', @@ -783,7 +762,7 @@ const WorkflowDesign: React.FC = () => { }); // 允许拖动连线中间的点和端点 - graph.on('edge:selected', ({ edge }) => { + graph.on('edge:selected', ({edge}) => { edge.addTools([ { name: 'source-arrowhead', @@ -835,12 +814,12 @@ const WorkflowDesign: React.FC = () => { }); // 连线工具移除 - graph.on('edge:unselected', ({ edge }) => { + graph.on('edge:unselected', ({edge}) => { edge.removeTools(); }); // 连线移动到其他连接桩时的样式 - graph.on('edge:connected', ({ edge }) => { + graph.on('edge:connected', ({edge}) => { edge.setAttrs({ line: { stroke: '#5F95FF', @@ -854,7 +833,7 @@ const WorkflowDesign: React.FC = () => { }); // 连线悬停在连接桩上时的样式 - graph.on('edge:mouseenter', ({ edge }) => { + graph.on('edge:mouseenter', ({edge}) => { const ports = document.querySelectorAll('.x6-port-body'); ports.forEach((port) => { const portGroup = port.getAttribute('port-group'); @@ -864,7 +843,7 @@ const WorkflowDesign: React.FC = () => { }); }); - graph.on('edge:mouseleave', ({ edge }) => { + graph.on('edge:mouseleave', ({edge}) => { const ports = document.querySelectorAll('.x6-port-body'); ports.forEach((port) => { port.setAttribute('style', 'visibility: hidden'); @@ -903,7 +882,7 @@ const WorkflowDesign: React.FC = () => { message.info('剪贴板为空'); return; } - const cells = graph.paste({ offset: 32 }); + const cells = graph.paste({offset: 32}); graph.cleanSelection(); graph.select(cells); message.success('已粘贴'); @@ -944,7 +923,7 @@ const WorkflowDesign: React.FC = () => { response.graph?.nodes?.forEach((workflowDefinitionNode: any) => { const node = addNodeToGraph(false, graphInstance, workflowDefinitionNode, nodeDefinitions); // 保存节点配置 - node.setProp('config', workflowDefinitionNode.config); + node.setProp('workflowDefinitionNode', workflowDefinitionNode); nodeMap.set(workflowDefinitionNode.id, node); }); @@ -962,10 +941,10 @@ const WorkflowDesign: React.FC = () => { // 获取源节点的输出端口(一定是out组) const sourcePort = getPortByGroup(sourceNode, 'out'); - + // 获取目标节点的输入端口(一定是in组) const targetPort = getPortByGroup(targetNode, 'in'); - + if (!sourcePort || !targetPort) { console.error('无法找到正确的端口:', edge); return; @@ -1014,7 +993,7 @@ const WorkflowDesign: React.FC = () => { const newGraph = initGraph(); if (newGraph) { setGraph(newGraph); - + // 在图形初始化完成后加载数据 if (id) { loadDefinitionDetail(newGraph, id); @@ -1060,6 +1039,7 @@ const WorkflowDesign: React.FC = () => { const handleNodeConfigUpdate = (values: any) => { if (!selectedNode) return; // 更新节点配置 + console.log("// 更新节点配置", values); selectedNode.setProp('config', values); // 更新节点显示名称 if (values.name) { @@ -1094,17 +1074,18 @@ const WorkflowDesign: React.FC = () => { type: nodeType, name: node.attr('label/text'), graph: { - shape: nodeDefinition?.graphConfig.uiSchema.shape, - size: { - width: node.size().width, - height: node.size().height - }, - style: nodeDefinition?.graphConfig.uiSchema.style, - ports: nodeDefinition?.graphConfig.uiSchema.ports, - position: { - x: position.x, - y: position.y - } + // shape: nodeDefinition?.graphConfig.uiSchema.shape, + // size: { + // width: node.size().width, + // height: node.size().height + // }, + // style: nodeDefinition?.graphConfig.uiSchema.style, + // ports: nodeDefinition?.graphConfig.uiSchema.ports, + // position: { + // x: position.x, + // y: position.y + // } + uiVariables: nodeDefinition.uiVariables }, config: node.getProp('config') || {} }; @@ -1162,7 +1143,7 @@ const WorkflowDesign: React.FC = () => {
-
-
+
diff --git a/frontend/src/pages/Workflow/Definition/Design/utils/validator.ts b/frontend/src/pages/Workflow/Definition/Design/utils/validator.ts index 83c194f4..bddf2ca7 100644 --- a/frontend/src/pages/Workflow/Definition/Design/utils/validator.ts +++ b/frontend/src/pages/Workflow/Definition/Design/utils/validator.ts @@ -108,6 +108,7 @@ const validateAllNodesConfig = (graph: Graph): ValidationResult => { for (const node of nodes) { const nodeDefinition = node.getProp('nodeDefinition'); + console.log(nodeDefinition) const result = validateNodeConfig(node, nodeDefinition); if (!result.valid) { return result; diff --git a/frontend/src/pages/Workflow/Definition/types.ts b/frontend/src/pages/Workflow/Definition/types.ts index 30e28174..b8664cd0 100644 --- a/frontend/src/pages/Workflow/Definition/types.ts +++ b/frontend/src/pages/Workflow/Definition/types.ts @@ -1,27 +1,38 @@ -import { BaseResponse, BaseQuery } from '@/types/base'; +import {BaseResponse, BaseQuery} from '@/types/base'; export interface WorkflowDefinition extends BaseResponse { - id: number; - name: string; - key: string; - description?: string; - flowVersion?: number; - status?: string; - category: string; - triggers: string[]; - graph: { - nodes: any[]; - edges: any[]; - }; - formConfig: { - formItems: any[]; - }; + id: number; + name: string; + key: string; + description?: string; + flowVersion?: number; + status?: string; + category: string; + triggers: string[]; + graph: { + nodes: WorkflowDefinitionNode[]; + edges: any[]; + }; + formConfig: { + formItems: any[]; + }; +} + +export interface WorkflowDefinitionNode { + id: number; + code: string; + type: string; + name: string; + uiVariables: JSON; + panelVariables: JSON; + localVariables: JSON; + formVariables: JSON; } export interface WorkflowDefinitionQuery extends BaseQuery { - name?: string; - key?: string; - status?: string; + name?: string; + key?: string; + status?: string; } /**