From d080efff5b55f5e6fc18677436a1a6ccb29215f5 Mon Sep 17 00:00:00 2001 From: ZLY Date: Mon, 27 Oct 2025 10:57:28 +0800 Subject: [PATCH] =?UTF-8?q?feat(flowEditor):=20=E5=A2=9E=E5=BC=BA=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=86=85=E5=AE=B9=E6=98=BE=E7=A4=BA=E4=B8=8E=E4=BA=8B?= =?UTF-8?q?=E4=BB=B6=E5=88=86=E7=BB=84=E5=85=B3=E8=81=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 引入 useMemo 优化事件分组计算性能- 新增事件分组逻辑,支持按事件 ID 分组并分配颜色 - 添加事件与数据/API 项的关联匹配功能 - 实现节点输入输出标签的颜色标识,提升可视化效果 - 增加对空值(**empty**)的校验处理,避免无效数据显示- 重构原有 footer 格式化逻辑,改为动态事件分组展示方式 --- .../flowEditor/components/nodeContentApp.tsx | 214 ++++++++++++++---- 1 file changed, 169 insertions(+), 45 deletions(-) diff --git a/src/pages/flowEditor/components/nodeContentApp.tsx b/src/pages/flowEditor/components/nodeContentApp.tsx index 46d83a4..8ee00fb 100644 --- a/src/pages/flowEditor/components/nodeContentApp.tsx +++ b/src/pages/flowEditor/components/nodeContentApp.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import styles from '@/components/FlowEditor/node/style/baseOther.module.less'; import { Handle, Position, useStore } from '@xyflow/react'; import { deserializeValue, isJSON } from '@/utils/common'; @@ -13,6 +13,7 @@ interface NodeContentData { }; showFooter?: boolean; type?: string; + component?: any; [key: string]: any; } @@ -178,29 +179,112 @@ const renderRegularNodeHandles = (dataIns: any[], dataOuts: any[], apiIns: any[] ); }; -const formatFooter = (data: any) => { - try { - switch (data?.type) { - case 'WAIT': - const { duration } = deserializeValue(data.customDef); - const hours = Math.floor(duration / 3600); - const minutes = Math.floor((duration % 3600) / 60); - const seconds = Math.floor(duration % 60); - return `${hours}小时${minutes}分钟${seconds}秒`; - case 'CYCLE': - const { intervalSeconds } = deserializeValue(data.customDef); - return cronstrue.toString(intervalSeconds, { locale: 'zh_CN' }); - case 'EVENTSEND': - case 'EVENTLISTENE': - const { name, topic } = isJSON(data.customDef) ? JSON.parse(data.customDef) : data.customDef; - if (topic.includes('**empty**')) return ''; - return `事件: ${name}`; - default: - return ''; +// 检查是否为有效的API(非empty) +const isValidApi = (api: any) => { + return api && !api.topic?.includes('**empty**') && !api.name?.includes('**empty**'); +}; + +// 检查是否为有效的数据(非empty) +const isValidData = (data: any) => { + return data && !data.topic?.includes('**empty**') && !data.name?.includes('**empty**'); +}; + +// 为每组关联的数据定义颜色 +const getGroupColor = (groupId: number) => { + const colors = [ + '#1890ff', // 蓝色 + '#52c41a', // 绿色 + '#faad14', // 黄色 + '#f5222d', // 红色 + '#722ed1', // 紫色 + '#13c2c2' // 青色 + ]; + return colors[groupId % colors.length]; +}; + +// 从customDef中提取事件分组信息 +const useEventGroups = (component: any) => { + return useMemo(() => { + if (!component?.customDef) return {}; + + try { + const customDef = isJSON(component.customDef) + ? JSON.parse(component.customDef) + : component.customDef; + + const groups: Record = {}; + let groupIndex = 0; + + // 处理eventListenes(对应apiOuts) + if (Array.isArray(customDef.eventListenes)) { + customDef.eventListenes + .filter(event => event && !event.topic?.includes('**empty**')) + .forEach(event => { + groups[`eventListenes-${event.eventId}`] = { + event, + color: getGroupColor(groupIndex++), + index: groupIndex - 1 + }; + }); + } + + // 处理eventSends(对应apiIns) + if (Array.isArray(customDef.eventSends)) { + customDef.eventSends + .filter(event => event && !event.topic?.includes('**empty**')) + .forEach(event => { + groups[`eventSends-${event.eventId}`] = { + event, + color: getGroupColor(groupIndex++), + index: groupIndex - 1 + }; + }); + } + console.log('groups:', groups); + return groups; + } catch (e) { + console.error('解析customDef时出错:', e); + return {}; + } + }, [component?.customDef]); +}; + +// 根据数据ID查找关联的事件分组 +const findRelatedEventGroup = (dataItem: any, eventGroups: Record, eventType: string) => { + if (!dataItem || !eventGroups) return null; + + // 查找与数据项关联的事件 + for (const key in eventGroups) { + const group = eventGroups[key]; + const eventDataIns = group.event?.dataIns || []; + const eventDataOuts = group.event?.dataOuts || []; + + // 检查数据项是否属于当前事件的数据输入或输出 + if (eventType === 'eventListenes' && eventDataIns.some((input: any) => input.id === dataItem.id)) { + return group; + } + + if (eventType === 'eventSends' && eventDataOuts.some((output: any) => output.id === dataItem.id)) { + return group; } - } catch (e) { - console.log(e); } + + return null; +}; + +// 根据topic查找API关联的事件分组 +const findApiGroupByTopic = (apiItem: any, eventGroups: Record) => { + if (!apiItem || !apiItem.topic || !eventGroups) return null; + + // 查找与API项topic关联的事件 + for (const key in eventGroups) { + const group = eventGroups[key]; + if (group.event.topic === apiItem.topic) { + return group; + } + } + + return null; }; const NodeContent = ({ data }: { data: NodeContentData }) => { @@ -208,9 +292,8 @@ const NodeContent = ({ data }: { data: NodeContentData }) => { const apiOuts = data.parameters?.apiOuts || []; const dataIns = data.parameters?.dataIns || []; const dataOuts = data.parameters?.dataOuts || []; - const showFooter = formatFooter(data.component) || false; - const footerData = (showFooter && data.component) || {}; - // console.log(apiIns, apiOuts, dataIns, dataOuts); + // 获取事件分组信息 + const eventGroups = useEventGroups(data.component); // 判断节点类型 const isStartNode = data.type === 'start'; @@ -224,21 +307,41 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{apiIns.length > 0 && (
- {apiIns.map((input, index) => ( -
- {!input.topic.includes('**empty') ? input.name : ''} -
- ))} + {apiIns.map((input, index) => { + // 查找关联的事件分组 + const group = findApiGroupByTopic(input, eventGroups); + return ( +
+ {isValidApi(input) ? input.name : ''} +
+ ); + })}
)} {apiOuts.length > 0 && (
- {apiOuts.map((output, index) => ( -
- {!output.topic.includes('**empty') ? output.name : ''} -
- ))} + {apiOuts.map((output, index) => { + // 查找关联的事件分组 + const group = findApiGroupByTopic(output, eventGroups); + return ( +
+ {isValidApi(output) ? output.name : ''} +
+ ); + })}
)}
@@ -253,21 +356,42 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
{dataIns.length > 0 && !isStartNode && (
- {dataIns.map((input, index) => ( -
- {input.id || `输入${index + 1}`} -
- ))} + {dataIns.map((input, index) => { + // 查找关联的事件分组 + const group = findRelatedEventGroup(input, eventGroups, 'eventSends'); + return ( +
+ {isValidData(input) ? (input.name || input.id || `输入${index + 1}`) : ''} +
+ ); + })}
)} {dataOuts.length > 0 && !isEndNode && (
- {dataOuts.map((output, index) => ( -
- {output.id || `输出${index + 1}`} -
- ))} + {dataOuts.map((output, index) => { + // 查找关联的事件分组 + const group = findRelatedEventGroup(output, eventGroups, 'eventListenes'); + + return ( +
+ {isValidData(output) ? (output.name || output.id || `输出${index + 1}`) : ''} +
+ ); + })}
)}