From 3c57f650fbbfff6aebd8a422d2b6df22f8549fe5 Mon Sep 17 00:00:00 2001 From: ZLY Date: Mon, 13 Oct 2025 17:52:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(flow):=20=E6=94=AF=E6=8C=81=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E5=BA=94=E7=94=A8=E7=BB=84=E4=BB=B6=E5=92=8C=E5=A4=8D?= =?UTF-8?q?=E5=90=88=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增对项目组件数据的获取与处理逻辑- 在 AddNodeMenu 中按分组展示本地节点和项目组件 - 修改 onAddNode 接口以支持传递完整的节点信息- 实现根据节点类型动态注册 BasicNode 或 LocalNode -优化节点句柄 ID 生成逻辑,兼容 name 和 id 字段- 调整组件标签 key 值生成规则,优先使用 id 避免重复 - 移除调试用 console 日志输出 - 更新分组名称映射,将 application 分组更名为基础组件 --- .../flowEditor/components/addNodeMenu.tsx | 146 +++++++++++++----- .../components/nodeContentOther.tsx | 17 +- .../flowEditor/components/paneContextMenu.tsx | 10 +- src/pages/flowEditor/index.tsx | 36 +++-- .../appCompComponent/compInfo.tsx | 1 - 5 files changed, 140 insertions(+), 70 deletions(-) diff --git a/src/pages/flowEditor/components/addNodeMenu.tsx b/src/pages/flowEditor/components/addNodeMenu.tsx index 28858df..b71580a 100644 --- a/src/pages/flowEditor/components/addNodeMenu.tsx +++ b/src/pages/flowEditor/components/addNodeMenu.tsx @@ -1,11 +1,12 @@ -import React from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import { Menu, Tabs } from '@arco-design/web-react'; import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData'; +import { useSelector } from 'react-redux'; const TabPane = Tabs.TabPane; interface AddNodeMenuProps { - onAddNode: (nodeType: string) => void; + onAddNode: (nodeType: string, node: any) => void; position?: { x: number; y: number }; // 用于画布上下文菜单 edgeId?: string; // 用于边上下文菜单 } @@ -13,24 +14,86 @@ interface AddNodeMenuProps { const AddNodeMenu: React.FC = ({ onAddNode }) => { + const { projectComponentData, info } = useSelector((state: any) => state.ideContainer); + const [groupedNodes, setGroupedNodes] = useState>({}); + const [activeTab, setActiveTab] = useState('common'); + // 按分组组织节点数据 - const groupedNodes = localNodeData.reduce((acc, node) => { - if (!acc[node.nodeGroup]) { - acc[node.nodeGroup] = []; + const formattedNodes = useCallback(() => { + // 先复制本地节点数据 + const initialGroupedNodes = localNodeData.reduce((acc, node) => { + if (!acc[node.nodeGroup]) { + acc[node.nodeGroup] = []; + } + acc[node.nodeGroup].push(node); + return acc; + }, {} as Record); + + const projectComponent = projectComponentData[info.id]; + if (projectComponent) { + const projectComp = projectComponent.projectCompDto; + const projectFlow = projectComponent.projectFlowDto; + + const projectCompList = projectComp && Object.values(projectComp).flat(2) || []; + const projectFlowList = projectFlow && Object.values(projectFlow).flat(2) || []; + + initialGroupedNodes['application'] = projectCompList.map((v: any) => { + return { + ...v, + nodeName: v.name, + nodeType: 'BASIC', + nodeGroup: 'application', + data: { + parameters: { + apiIns: v.def?.apis || [], + apiOuts: Array.isArray(v.def?.apiOut) ? v.def?.apiOut : (v.def?.apiOut ? [v.def?.apiOut] : []), + dataIns: v.def?.dataIns || [], + dataOuts: v.def?.dataOuts || [] + } + } + }; + }); + // groupedNodes['composite'] = projectFlowList.map((v: any) => { + // return { + // ...v, + // nodeName: v.name, + // nodeType: 'BASE', + // nodeGroup: 'application', + // data: { + // parameters: { + // apiIns: v.def.apis, + // apiOuts: v.def.apiOut, + // dataIns: v.def.dataIns, + // dataOuts: v.def.dataOuts + // } + // } + // }; + // }); + + console.log(projectCompList, projectFlowList, initialGroupedNodes); } - acc[node.nodeGroup].push(node); - return acc; - }, {} as Record); - const handleAddNode = (nodeType: string) => { - onAddNode(nodeType); + // 更新状态以触发重新渲染 + setGroupedNodes(initialGroupedNodes); + }, [projectComponentData, info.id]); + + const handleAddNode = (nodeType: string, node: any) => { + onAddNode(nodeType, node); }; // 分组名称映射 const groupNames: Record = { - 'common': '系统组件', - 'application': '应用组件', - 'composite': '复合组件' + 'application': '基础组件', + 'composite': '复合组件', + 'common': '系统组件' + }; + + useEffect(() => { + formattedNodes(); + }, [formattedNodes]); + + const handleTabChange = (key: string) => { + setActiveTab(key); }; return ( @@ -44,35 +107,38 @@ const AddNodeMenu: React.FC = ({ flexDirection: 'column' }} > - + {Object.entries(groupedNodes).map(([group, nodes]) => ( -
- - {nodes.map((node) => ( - handleAddNode(node.nodeType)} - style={{ - padding: '0 16px', - height: 36, - lineHeight: '36px' - }} - > - {node.nodeName} - - ))} - -
+ {/* 只有在当前 tab 激活时才渲染内容 */} + {activeTab === group && ( +
+ + {nodes && nodes.map((node) => ( + handleAddNode(node.nodeType, node)} + style={{ + padding: '0 16px', + height: 36, + lineHeight: '36px' + }} + > + {node.nodeName} + + ))} + +
+ )}
))}
diff --git a/src/pages/flowEditor/components/nodeContentOther.tsx b/src/pages/flowEditor/components/nodeContentOther.tsx index 6021d34..2237afb 100644 --- a/src/pages/flowEditor/components/nodeContentOther.tsx +++ b/src/pages/flowEditor/components/nodeContentOther.tsx @@ -127,7 +127,7 @@ const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[] key={`api-output-handle-${index}`} type="source" position={Position.Right} - id={apiOuts[index].name || `output-${index}`} + id={apiOuts[index].name || apiOuts[index].id || `output-${index}`} style={{ ...handleStyles.mainSource, top: `${35 + index * 20}px` @@ -139,7 +139,7 @@ const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[] key={`api-input-handle-${index}`} type="target" position={Position.Left} - id={apiIns[index].name || `input-${index}`} + id={apiIns[index].name || apiIns[index].id || `input-${index}`} style={{ ...handleStyles.mainTarget, top: `${35 + index * 20}px` @@ -153,7 +153,7 @@ const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[] key={`data-input-handle-${index}`} type="target" position={Position.Left} - id={dataIns[index].name || `input-${index}`} + id={dataIns[index].name || dataIns[index].id || `input-${index}`} style={{ ...handleStyles.data, top: `${70 + (apiIns.length + index) * 20}px` @@ -167,7 +167,7 @@ const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[] key={`data-output-handle-${index}`} type="source" position={Position.Right} - id={dataOuts[index].name || `output-${index}`} + id={dataOuts[index].name || dataOuts[index].id || `output-${index}`} style={{ ...handleStyles.data, top: `${70 + (apiOuts.length + index) * 20}px` @@ -209,6 +209,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { const dataOuts = data.parameters?.dataOuts || []; const showFooter = data?.component?.customDef || false; const footerData = (showFooter && data.component) || {}; + // console.log(apiIns, apiOuts, dataIns, dataOuts); // 判断节点类型 const isStartNode = data.type === 'start'; @@ -223,7 +224,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { {apiIns.length > 0 && (
{apiIns.map((input, index) => ( -
+
{input.desc}
))} @@ -233,7 +234,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { {apiOuts.length > 0 && (
{apiOuts.map((output, index) => ( -
+
{output.desc}
))} @@ -256,7 +257,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { {dataIns.length > 0 && !isStartNode && (
{dataIns.map((input, index) => ( -
+
{input.id || `输入${index + 1}`}
))} @@ -266,7 +267,7 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { {dataOuts.length > 0 && !isEndNode && (
{dataOuts.map((output, index) => ( -
+
{output.id || `输出${index + 1}`}
))} diff --git a/src/pages/flowEditor/components/paneContextMenu.tsx b/src/pages/flowEditor/components/paneContextMenu.tsx index c4a7b5c..14807e2 100644 --- a/src/pages/flowEditor/components/paneContextMenu.tsx +++ b/src/pages/flowEditor/components/paneContextMenu.tsx @@ -5,7 +5,7 @@ import AddNodeMenu from './addNodeMenu'; const SubMenu = Menu.SubMenu; interface PaneContextMenuProps { - onAddNode: (nodeType: string, position: { x: number; y: number }) => void; + onAddNode: (nodeType: string, position: { x: number; y: number }, node: any) => void; position: { x: number; y: number }; } @@ -14,8 +14,8 @@ const PaneContextMenu: React.FC = ({ position }) => { // 包装onAddNode函数以适配AddNodeMenu组件的接口 - const handleAddNode = (nodeType: string) => { - onAddNode(nodeType, position); + const handleAddNode = (nodeType: string, node: any) => { + onAddNode(nodeType, position, node); }; return ( @@ -35,7 +35,9 @@ const PaneContextMenu: React.FC = ({ popupStyle: { height: 'auto', maxHeight: 'none' } }} > - + { + handleAddNode(nodeType, node); + }} /> ); diff --git a/src/pages/flowEditor/index.tsx b/src/pages/flowEditor/index.tsx index a92083b..9ab6dad 100644 --- a/src/pages/flowEditor/index.tsx +++ b/src/pages/flowEditor/index.tsx @@ -39,6 +39,7 @@ import { localNodeData } from '@/pages/flowEditor/sideBar/config/localNodeData'; import { useAlignmentGuidelines } from '@/hooks/useAlignmentGuidelines'; import { setMainFlow } from '@/api/appRes'; import { Message } from '@arco-design/web-react'; +import BasicNode from '@/components/FlowEditor/node/basicNode/BasicNode'; const edgeTypes: EdgeTypes = { custom: CustomEdge @@ -97,8 +98,8 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini const apiOuts = nodeParams.apiOuts || []; const apiIns = nodeParams.apiIns || []; - if (apiOuts.some((api: any) => api.name === handleId) || - apiIns.some((api: any) => api.name === handleId)) { + if (apiOuts.some((api: any) => (api.name || api.id) === handleId) || + apiIns.some((api: any) => (api.name || api.id) === handleId)) { return 'api'; } @@ -106,8 +107,8 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini const dataOuts = nodeParams.dataOuts || []; const dataIns = nodeParams.dataIns || []; - if (dataOuts.some((data: any) => data.name === handleId) || - dataIns.some((data: any) => data.name === handleId)) { + if (dataOuts.some((data: any) => (data.name || data.id) === handleId) || + dataIns.some((data: any) => (data.name || data.id) === handleId)) { return 'data'; } @@ -200,6 +201,7 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini // 获取源节点和目标节点的参数信息 const sourceParams = sourceNode.data?.parameters || {}; const targetParams = targetNode.data?.parameters || {}; + console.log(sourceParams, targetParams, params); // 获取源handle和目标handle的类型 (api或data) const sourceHandleType = getHandleType(params.sourceHandle, sourceParams); @@ -526,11 +528,11 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini }, []); // 在边上添加节点的具体实现 - const addNodeOnEdge = useCallback((nodeType: string) => { + const addNodeOnEdge = useCallback((nodeType: string, node: any) => { if (!edgeForNodeAdd || !reactFlowInstance) return; // 查找节点定义 - const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType); + const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType) || node; if (!nodeDefinition) return; // 获取源节点和目标节点 @@ -559,7 +561,7 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini // 将未定义的节点动态追加进nodeTypes const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key)); - if (!nodeMap.includes(nodeType)) registerNodeType(nodeType, LocalNode, nodeDefinition.nodeName); + if (!nodeMap.includes(nodeType)) registerNodeType(nodeType, nodeType === 'BASIC' ? BasicNode : LocalNode, nodeDefinition.nodeName); // 添加新节点 setNodes((nds) => [...nds, newNode]); @@ -590,13 +592,13 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini }, [edgeForNodeAdd, nodes, reactFlowInstance]); // 在画布上添加节点 - const addNodeOnPane = useCallback((nodeType: string, position: { x: number; y: number }) => { + const addNodeOnPane = useCallback((nodeType: string, position: { x: number; y: number }, node?: any) => { setMenu(null); if (!reactFlowInstance) return; // 查找节点定义 - const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType); + const nodeDefinition = localNodeData.find(n => n.nodeType === nodeType) || node; if (!nodeDefinition) return; // 创建新节点 @@ -614,20 +616,20 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini // 将未定义的节点动态追加进nodeTypes const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key)); // 目前默认添加的都是系统组件/本地组件 - if (!nodeMap.includes(nodeType)) registerNodeType(nodeType, LocalNode, nodeDefinition.nodeName); + if (!nodeMap.includes(nodeType)) registerNodeType(nodeType, nodeType === 'BASIC' ? BasicNode : LocalNode, nodeDefinition.nodeName); setNodes((nds) => [...nds, newNode]); }, [reactFlowInstance]); // 处理添加节点的统一方法 - const handleAddNode = useCallback((nodeType: string) => { + const handleAddNode = useCallback((nodeType: string, node) => { // 如果是通过边添加节点 if (edgeForNodeAdd) { - addNodeOnEdge(nodeType); + addNodeOnEdge(nodeType, node); } // 如果是通过画布添加节点 else if (positionForNodeAdd) { - addNodeOnPane(nodeType, positionForNodeAdd); + addNodeOnPane(nodeType, positionForNodeAdd, node); } // 清除状态 @@ -767,8 +769,8 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini > { - addNodeOnPane(nodeType, position); + onAddNode={(nodeType: string, position: { x: number, y: number }, node) => { + addNodeOnPane(nodeType, position, node); setMenu(null); // 关闭上下文菜单 }} /> @@ -797,8 +799,8 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini }} > { - handleAddNode(nodeType); + onAddNode={(nodeType, node) => { + handleAddNode(nodeType, node); // 关闭菜单 setEdgeForNodeAdd(null); setPositionForNodeAdd(null); diff --git a/src/pages/orchestration/appCompComponent/compInfo.tsx b/src/pages/orchestration/appCompComponent/compInfo.tsx index 7af193a..17db4ad 100644 --- a/src/pages/orchestration/appCompComponent/compInfo.tsx +++ b/src/pages/orchestration/appCompComponent/compInfo.tsx @@ -3,7 +3,6 @@ import styles from './style/compInfo.module.less'; import { Space, Divider, Table, TableColumnProps } from '@arco-design/web-react'; const CompInfo = ({ currentCompInfo }) => { - console.log('传入的组件信息:', currentCompInfo); const columns: TableColumnProps[] = [ {