feat(flowEditor): 增强节点内容显示与事件分组关联

- 引入 useMemo 优化事件分组计算性能- 新增事件分组逻辑,支持按事件 ID 分组并分配颜色
- 添加事件与数据/API 项的关联匹配功能
- 实现节点输入输出标签的颜色标识,提升可视化效果
- 增加对空值(**empty**)的校验处理,避免无效数据显示- 重构原有 footer 格式化逻辑,改为动态事件分组展示方式
master
钟良源 3 months ago
parent 4b6e4b8556
commit d080efff5b

@ -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) => {
// 检查是否为有效的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 {
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 '';
const customDef = isJSON(component.customDef)
? JSON.parse(component.customDef)
: component.customDef;
const groups: Record<string, { event: any; color: string; index: number }> = {};
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.log(e);
console.error('解析customDef时出错:', e);
return {};
}
}, [component?.customDef]);
};
// 根据数据ID查找关联的事件分组
const findRelatedEventGroup = (dataItem: any, eventGroups: Record<string, any>, 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;
}
}
return null;
};
// 根据topic查找API关联的事件分组
const findApiGroupByTopic = (apiItem: any, eventGroups: Record<string, any>) => {
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 }) => {
<div className={styles['node-content-api']}>
{apiIns.length > 0 && (
<div className={styles['node-inputs']}>
{apiIns.map((input, index) => (
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
{!input.topic.includes('**empty') ? input.name : ''}
{apiIns.map((input, index) => {
// 查找关联的事件分组
const group = findApiGroupByTopic(input, eventGroups);
return (
<div
key={input.id || `input-${index}`}
className={styles['node-input-label']}
style={{
color: group ? group.color : '#000'
}}
>
{isValidApi(input) ? input.name : ''}
</div>
))}
);
})}
</div>
)}
{apiOuts.length > 0 && (
<div className={styles['node-outputs-api']}>
{apiOuts.map((output, index) => (
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
{!output.topic.includes('**empty') ? output.name : ''}
{apiOuts.map((output, index) => {
// 查找关联的事件分组
const group = findApiGroupByTopic(output, eventGroups);
return (
<div
key={output.id || `output-${index}`}
className={styles['node-input-label']}
style={{
color: group ? group.color : '#000'
}}
>
{isValidApi(output) ? output.name : ''}
</div>
))}
);
})}
</div>
)}
</div>
@ -253,21 +356,42 @@ const NodeContent = ({ data }: { data: NodeContentData }) => {
<div className={styles['node-content']}>
{dataIns.length > 0 && !isStartNode && (
<div className={styles['node-inputs']}>
{dataIns.map((input, index) => (
<div key={input.id || `input-${index}`} className={styles['node-input-label']}>
{input.id || `输入${index + 1}`}
{dataIns.map((input, index) => {
// 查找关联的事件分组
const group = findRelatedEventGroup(input, eventGroups, 'eventSends');
return (
<div
key={input.id || `input-${index}`}
className={styles['node-input-label']}
style={{
color: group ? group.color : '#000'
}}
>
{isValidData(input) ? (input.name || input.id || `输入${index + 1}`) : ''}
</div>
))}
);
})}
</div>
)}
{dataOuts.length > 0 && !isEndNode && (
<div className={styles['node-outputs']}>
{dataOuts.map((output, index) => (
<div key={output.id || `output-${index}`} className={styles['node-input-label']}>
{output.id || `输出${index + 1}`}
{dataOuts.map((output, index) => {
// 查找关联的事件分组
const group = findRelatedEventGroup(output, eventGroups, 'eventListenes');
return (
<div
key={output.id || `output-${index}`}
className={styles['node-input-label']}
style={{
color: group ? group.color : '#000'
}}
>
{isValidData(output) ? (output.name || output.id || `输出${index + 1}`) : ''}
</div>
))}
);
})}
</div>
)}
</div>

Loading…
Cancel
Save