From 483a3b96e773c207bfe1f9a7907498840ba8e725 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Wed, 22 Oct 2025 17:07:16 +0800 Subject: [PATCH] 1 --- .../Workflow/Design/components/FlowCanvas.tsx | 4 +- .../Workflow/Design/hooks/useWorkflowLoad.ts | 46 ++++-------------- frontend/src/pages/Workflow/Design/index.tsx | 4 +- .../Workflow/Design/utils/idGenerator.ts | 48 +++++++++++++++++++ 4 files changed, 62 insertions(+), 40 deletions(-) create mode 100644 frontend/src/pages/Workflow/Design/utils/idGenerator.ts diff --git a/frontend/src/pages/Workflow/Design/components/FlowCanvas.tsx b/frontend/src/pages/Workflow/Design/components/FlowCanvas.tsx index 745f08f2..45dda854 100644 --- a/frontend/src/pages/Workflow/Design/components/FlowCanvas.tsx +++ b/frontend/src/pages/Workflow/Design/components/FlowCanvas.tsx @@ -13,11 +13,11 @@ import { Panel } from '@xyflow/react'; import '@xyflow/react/dist/style.css'; -import { v4 as uuidv4 } from 'uuid'; import type { FlowNode, FlowEdge } from '../types'; import { nodeTypes } from '../nodes'; import CustomEdge from './CustomEdge'; +import { generateEdgeId } from '../utils/idGenerator'; interface FlowCanvasProps { initialNodes?: FlowNode[]; @@ -51,7 +51,7 @@ const FlowCanvas: React.FC = ({ const onConnect = useCallback( (params: Connection | Edge) => { const newEdge: FlowEdge = { - id: uuidv4(), // 使用 UUID 生成唯一 ID + id: generateEdgeId(), // ✅ 生成格式: eid_xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx source: params.source!, target: params.target!, type: 'smoothstep', diff --git a/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts b/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts index 6fbe54a1..bf2d8622 100644 --- a/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts +++ b/frontend/src/pages/Workflow/Design/hooks/useWorkflowLoad.ts @@ -37,6 +37,11 @@ export const useWorkflowLoad = () => { // 根据nodeType查找对应的节点定义 const nodeDefinition = NODE_DEFINITIONS.find(def => def.nodeType === node.nodeType); + // ✅ 使用节点定义中的配置,避免硬编码 + const icon = nodeDefinition?.renderConfig.icon.content || '❓'; + const color = nodeDefinition?.renderConfig.theme.primary || '#6b7280'; + const category = nodeDefinition?.category || getNodeCategory(node.nodeType) as any; + return { id: node.id.toString(), type: node.nodeType, @@ -44,9 +49,9 @@ export const useWorkflowLoad = () => { data: { label: node.nodeName, nodeType: node.nodeType as any, - category: getNodeCategory(node.nodeType) as any, - icon: nodeDefinition?.renderConfig.icon.content || getNodeIcon(node.nodeType), - color: nodeDefinition?.renderConfig.theme.primary || getNodeColor(node.nodeType), + category, + icon, + color, configs: node.configs || {}, inputMapping: node.inputMapping || {}, outputs: node.outputs || [], // ✅ 从后端加载的输出能力定义 @@ -105,39 +110,8 @@ export const useWorkflowLoad = () => { }; }, []); - // 根据节点类型获取图标(图标名称格式) - const getNodeIcon = (nodeType: string): string => { - const iconMap: Record = { - [NodeType.START_EVENT]: 'play-circle', - [NodeType.END_EVENT]: 'stop-circle', - [NodeType.USER_TASK]: 'user', - [NodeType.SERVICE_TASK]: 'api', - [NodeType.SCRIPT_TASK]: 'code', - [NodeType.DEPLOY_NODE]: 'build', - [NodeType.JENKINS_BUILD]: 'jenkins', - [NodeType.GATEWAY_NODE]: 'gateway', - [NodeType.SUB_PROCESS]: 'container', - [NodeType.CALL_ACTIVITY]: 'phone' - }; - return iconMap[nodeType] || 'api'; - }; - - // 根据节点类型获取颜色 - const getNodeColor = (nodeType: string): string => { - const colorMap: Record = { - [NodeType.START_EVENT]: '#52c41a', - [NodeType.END_EVENT]: '#ff4d4f', - [NodeType.USER_TASK]: '#722ed1', - [NodeType.SERVICE_TASK]: '#fa8c16', - [NodeType.SCRIPT_TASK]: '#8b5cf6', - [NodeType.DEPLOY_NODE]: '#1890ff', - [NodeType.JENKINS_BUILD]: '#52c41a', - [NodeType.GATEWAY_NODE]: '#84cc16', - [NodeType.SUB_PROCESS]: '#ec4899', - [NodeType.CALL_ACTIVITY]: '#14b8a6' - }; - return colorMap[nodeType] || '#6b7280'; - }; + // ✅ 已删除硬编码的 getNodeIcon 和 getNodeColor 函数 + // 现在直接从节点定义的 renderConfig 中获取图标和颜色 // 加载工作流定义 const loadWorkflow = useCallback(async (workflowId: number): Promise => { diff --git a/frontend/src/pages/Workflow/Design/index.tsx b/frontend/src/pages/Workflow/Design/index.tsx index dda93eb0..3f2e87ec 100644 --- a/frontend/src/pages/Workflow/Design/index.tsx +++ b/frontend/src/pages/Workflow/Design/index.tsx @@ -2,7 +2,6 @@ import React, { useState, useCallback, useRef, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { message } from 'antd'; import { ReactFlowProvider, useReactFlow } from '@xyflow/react'; -import { v4 as uuidv4 } from 'uuid'; import WorkflowToolbar from './components/WorkflowToolbar'; import NodePanel from './components/NodePanel'; @@ -15,6 +14,7 @@ import { isConfigurableNode } from './nodes/types'; import { useWorkflowSave } from './hooks/useWorkflowSave'; import { useWorkflowLoad } from './hooks/useWorkflowLoad'; import { useHistory } from './hooks/useHistory'; +import { generateNodeId } from './utils/idGenerator'; // 样式 import '@xyflow/react/dist/style.css'; @@ -285,7 +285,7 @@ const WorkflowDesignInner: React.FC = () => { }); const newNode: FlowNode = { - id: uuidv4(), // 使用 UUID 生成唯一 ID + id: generateNodeId(), // ✅ 生成格式: sid_xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx type: nodeType, position, data: { diff --git a/frontend/src/pages/Workflow/Design/utils/idGenerator.ts b/frontend/src/pages/Workflow/Design/utils/idGenerator.ts new file mode 100644 index 00000000..019a0e34 --- /dev/null +++ b/frontend/src/pages/Workflow/Design/utils/idGenerator.ts @@ -0,0 +1,48 @@ +import { v4 as uuidv4 } from 'uuid'; + +/** + * 生成节点ID + * 格式: sid_xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx + * + * @returns 节点唯一标识符 + * + * @example + * generateNodeId() // => "sid_a1b2c3d4_5e6f_7g8h_9i0j_k1l2m3n4o5p6" + */ +export const generateNodeId = (): string => { + return `sid_${uuidv4().replace(/-/g, '_')}`; +}; + +/** + * 生成边ID + * 格式: eid_xxxxxxxx_xxxx_xxxx_xxxx_xxxxxxxxxxxx + * + * @returns 边唯一标识符 + * + * @example + * generateEdgeId() // => "eid_a1b2c3d4_5e6f_7g8h_9i0j_k1l2m3n4o5p6" + */ +export const generateEdgeId = (): string => { + return `eid_${uuidv4().replace(/-/g, '_')}`; +}; + +/** + * 检查是否为有效的节点ID + * + * @param id 待检查的ID + * @returns 是否为有效的节点ID + */ +export const isValidNodeId = (id: string): boolean => { + return /^sid_[a-f0-9_]{36}$/.test(id); +}; + +/** + * 检查是否为有效的边ID + * + * @param id 待检查的ID + * @returns 是否为有效的边ID + */ +export const isValidEdgeId = (id: string): boolean => { + return /^eid_[a-f0-9_]{36}$/.test(id); +}; +