From 3d7037ba6278c61dfccf485e67281a761ec03693 Mon Sep 17 00:00:00 2001 From: ZLY Date: Tue, 21 Oct 2025 10:59:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(flow):=20=E5=AE=9E=E7=8E=B0=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E6=B5=81=E7=A8=8B=E6=95=B0=E6=8D=AE=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E4=B8=8E=E8=BE=B9=E6=B8=B2=E6=9F=93=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../flowEditor/components/customEdge.tsx | 9 +- src/pages/flowEditor/index.tsx | 1 + src/pages/flowEditor/utils/appFlowhandle.ts | 1 - src/pages/orchestration/application/index.tsx | 18 ++- src/utils/convertAppFlowData.ts | 126 ++++++++++++++++++ 5 files changed, 149 insertions(+), 6 deletions(-) create mode 100644 src/utils/convertAppFlowData.ts diff --git a/src/pages/flowEditor/components/customEdge.tsx b/src/pages/flowEditor/components/customEdge.tsx index 22aecde..3119da3 100644 --- a/src/pages/flowEditor/components/customEdge.tsx +++ b/src/pages/flowEditor/components/customEdge.tsx @@ -5,6 +5,9 @@ import EdgeAddNodeButton from '@/pages/flowEditor/components/edgeAddNodeButton'; type DataDisplayEdgeData = { label?: string; value?: any; + name?: string; + topic?: string; + eventId?: string; }; const DataDisplayEdge: React.FC = ({ @@ -99,9 +102,9 @@ const DataDisplayEdge: React.FC = ({ textAlign: 'center' }} > - {displayData.label && ( + {displayData.name && (
- {displayData.label} + {displayData.name}
)} {displayData.value !== undefined && ( @@ -114,7 +117,7 @@ const DataDisplayEdge: React.FC = ({ )} - {hovered && ( + {hovered && Object.keys(displayData).length === 0 && ( handleEdgeAddNode(e)} /> diff --git a/src/pages/flowEditor/index.tsx b/src/pages/flowEditor/index.tsx index 57f03e8..94835d8 100644 --- a/src/pages/flowEditor/index.tsx +++ b/src/pages/flowEditor/index.tsx @@ -145,6 +145,7 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini // 节点双击处理 const onNodeDoubleClick = useCallback( (event: React.MouseEvent, node: Node) => { + if (!useDefault) return; // 不可编辑的类型 if (['AND', 'OR', 'JSON2STR', 'STR2JSON', 'IMAGE', 'RESULT'].includes(node.type)) return; // 循环开始的节点不展示编辑框 diff --git a/src/pages/flowEditor/utils/appFlowhandle.ts b/src/pages/flowEditor/utils/appFlowhandle.ts index e46f527..5dddb09 100644 --- a/src/pages/flowEditor/utils/appFlowhandle.ts +++ b/src/pages/flowEditor/utils/appFlowhandle.ts @@ -8,7 +8,6 @@ import { Edge } from '@xyflow/react'; import { updateCanvasDataMap } from '@/store/ideContainer'; export const appFLowHandle = (initialData, useDefault, setNodes, setEdges, dispatch) => { - console.log('应用编排处理', initialData); const { nodes: convertedNodes, edges: convertedEdges diff --git a/src/pages/orchestration/application/index.tsx b/src/pages/orchestration/application/index.tsx index 235fb79..d147529 100644 --- a/src/pages/orchestration/application/index.tsx +++ b/src/pages/orchestration/application/index.tsx @@ -1,9 +1,23 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import FlowEditor from '@/pages/flowEditor/index'; +import { useSelector } from 'react-redux'; +import { getAppEventData, getAppEventList } from '@/api/appEvent'; const ApplicationContainer = () => { + const { info } = useSelector((state: any) => state.ideContainer); + const [appFlowList, setAppFlowList] = useState([]); + + const getAppFlowList = async () => { + const res: any = await getAppEventList(info.id); + if (res.code === 200) setAppFlowList(res.data); + }; + + useEffect(() => { + getAppFlowList(); + }, []); + return ( - + ); }; diff --git a/src/utils/convertAppFlowData.ts b/src/utils/convertAppFlowData.ts new file mode 100644 index 0000000..9eac62c --- /dev/null +++ b/src/utils/convertAppFlowData.ts @@ -0,0 +1,126 @@ +/** + * 将应用流程数据转换为适用于 flow editor 的 nodes 和 edges + * @param appFlowData - 应用流程原始数据结构,长度为2的数组,每个元素代表一个节点 + * @returns 包含 nodes 和 edges 的对象,格式与 convertFlowData 兼容 + */ +export const convertAppFlowData = (appFlowData: any[]) => { + const nodes: any[] = []; + const edges: any[] = []; + + // 如果没有数据,返回空数组 + if (!appFlowData || appFlowData.length === 0) { + return { nodes, edges }; + } + + // 处理每个应用流程数据项(每个应用作为一个节点) + appFlowData.forEach((app: any, index: number) => { + // 构造节点数据 + const node: any = { + id: app.appId || `app_${index}`, + type: 'APP', + position: { x: 200 + index * 300, y: 200 }, + data: { + title: app.name || `应用${index + 1}`, + parameters: { + // eventListenes 作为 apiIns(输入) + apiIns: app.eventListenes ? app.eventListenes.map((event: any) => ({ + name: event.eventName, + desc: event.description || '', + dataType: '', + defaultValue: '', + topic: event.topic + })) : [], + // eventSends 作为 apiOuts(输出) + apiOuts: app.eventSends ? app.eventSends.map((event: any) => ({ + name: event.eventName, + desc: event.description || '', + dataType: '', + defaultValue: '', + topic: event.topic + })) : [], + // 提取 dataIns 和 dataOuts 属性 + dataIns: [], + dataOuts: [] + }, + type: 'APP', + component: { + type: 'APP', + appId: app.appId, + customDef: JSON.stringify({ + eventListenes: app.eventListenes || [], + eventSends: app.eventSends || [] + }) + } + } + }; + + // 处理 dataIns(来自 eventListenes 的 dataOuts) + if (app.eventListenes && app.eventListenes.length > 0) { + app.eventListenes.forEach((event: any) => { + if (event.dataOuts && event.dataOuts.length > 0) { + node.data.parameters.dataIns = [...node.data.parameters.dataIns, ...event.dataOuts]; + } + }); + } + + // 处理 dataOuts(来自 eventSends 的 dataIns) + if (app.eventSends && app.eventSends.length > 0) { + app.eventSends.forEach((event: any) => { + if (event.dataIns && event.dataIns.length > 0) { + node.data.parameters.dataOuts = [...node.data.parameters.dataOuts, ...event.dataIns]; + } + }); + } + + nodes.push(node); + }); + + // 遍历所有节点对 + for (let i = 0; i < nodes.length; i++) { + for (let j = 0; j < nodes.length; j++) { + if (i !== j) { // 不与自己比较 + const sourceNode = nodes[i]; + const targetNode = nodes[j]; + + // 检查源节点的 eventSends (apiOuts) 和目标节点的 eventListenes (apiIns) + const sourceEvents = sourceNode.data.component?.customDef ? + JSON.parse(sourceNode.data.component.customDef).eventSends || [] : + []; + const targetEvents = targetNode.data.component?.customDef ? + JSON.parse(targetNode.data.component.customDef).eventListenes || [] : + []; + + // 比较事件的 topic 是否匹配 + sourceEvents.forEach((sourceEvent: any, outIndex: number) => { + targetEvents.forEach((targetEvent: any, inIndex: number) => { + // 当 topic 匹配且不是 **empty** 占位符时创建边 + if (sourceEvent.topic && + targetEvent.topic && + sourceEvent.topic === targetEvent.topic && + !sourceEvent.topic.includes('**empty**') && + !targetEvent.topic.includes('**empty**')) { + edges.push({ + id: `e-${sourceNode.id}-${targetNode.id}-${outIndex}-${inIndex}`, + source: sourceNode.id, + target: targetNode.id, + sourceHandle: sourceEvent.eventName, + targetHandle: targetEvent.eventName, + type: 'custom', + lineType: 'lineType', + data: { + displayData: { + name: '事件1', + eventId: 'eventId', + topic: 'topic' + } + } + }); + } + }); + }); + } + } + } + + return { nodes, edges }; +}; \ No newline at end of file