feat(flow): 实现应用流程数据转换与边渲染逻辑

master
钟良源 4 months ago
parent c6ffb01e57
commit 3d7037ba62

@ -5,6 +5,9 @@ import EdgeAddNodeButton from '@/pages/flowEditor/components/edgeAddNodeButton';
type DataDisplayEdgeData = { type DataDisplayEdgeData = {
label?: string; label?: string;
value?: any; value?: any;
name?: string;
topic?: string;
eventId?: string;
}; };
const DataDisplayEdge: React.FC<EdgeProps> = ({ const DataDisplayEdge: React.FC<EdgeProps> = ({
@ -99,9 +102,9 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
textAlign: 'center' textAlign: 'center'
}} }}
> >
{displayData.label && ( {displayData.name && (
<div style={{ fontWeight: 'bold', marginBottom: 2 }}> <div style={{ fontWeight: 'bold', marginBottom: 2 }}>
{displayData.label} {displayData.name}
</div> </div>
)} )}
{displayData.value !== undefined && ( {displayData.value !== undefined && (
@ -114,7 +117,7 @@ const DataDisplayEdge: React.FC<EdgeProps> = ({
</div> </div>
)} )}
{hovered && ( {hovered && Object.keys(displayData).length === 0 && (
<EdgeAddNodeButton <EdgeAddNodeButton
onClick={(e) => handleEdgeAddNode(e)} onClick={(e) => handleEdgeAddNode(e)}
/> />

@ -145,6 +145,7 @@ const FlowEditor: React.FC<{ initialData?: any, useDefault?: boolean }> = ({ ini
// 节点双击处理 // 节点双击处理
const onNodeDoubleClick = useCallback( const onNodeDoubleClick = useCallback(
(event: React.MouseEvent, node: Node) => { (event: React.MouseEvent, node: Node) => {
if (!useDefault) return;
// 不可编辑的类型 // 不可编辑的类型
if (['AND', 'OR', 'JSON2STR', 'STR2JSON', 'IMAGE', 'RESULT'].includes(node.type)) return; if (['AND', 'OR', 'JSON2STR', 'STR2JSON', 'IMAGE', 'RESULT'].includes(node.type)) return;
// 循环开始的节点不展示编辑框 // 循环开始的节点不展示编辑框

@ -8,7 +8,6 @@ import { Edge } from '@xyflow/react';
import { updateCanvasDataMap } from '@/store/ideContainer'; import { updateCanvasDataMap } from '@/store/ideContainer';
export const appFLowHandle = (initialData, useDefault, setNodes, setEdges, dispatch) => { export const appFLowHandle = (initialData, useDefault, setNodes, setEdges, dispatch) => {
console.log('应用编排处理', initialData);
const { const {
nodes: convertedNodes, nodes: convertedNodes,
edges: convertedEdges edges: convertedEdges

@ -1,9 +1,23 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import FlowEditor from '@/pages/flowEditor/index'; import FlowEditor from '@/pages/flowEditor/index';
import { useSelector } from 'react-redux';
import { getAppEventData, getAppEventList } from '@/api/appEvent';
const ApplicationContainer = () => { 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 ( return (
<FlowEditor useDefault={false} /> <FlowEditor initialData={appFlowList} useDefault={false} />
); );
}; };

@ -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<api|data>',
data: {
displayData: {
name: '事件1',
eventId: 'eventId',
topic: 'topic'
}
}
});
}
});
});
}
}
}
return { nodes, edges };
};
Loading…
Cancel
Save