|
|
|
|
@ -2,6 +2,7 @@ import { nodeTypeMap, registerNodeType } from '@/components/FlowEditor/node';
|
|
|
|
|
import LocalNode from '@/components/FlowEditor/node/localNode/LocalNode';
|
|
|
|
|
import LoopNode from '@/components/FlowEditor/node/loopNode/LoopNode';
|
|
|
|
|
import store from '@/store/index';
|
|
|
|
|
import SwitchNode from '@/components/FlowEditor/node/switchNode/SwitchNode';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将提供的数据结构转换为适用于 flow editor 的 nodes 和 edges
|
|
|
|
|
@ -117,7 +118,7 @@ export const convertFlowData = (flowData: any, useDefault = true) => {
|
|
|
|
|
// 注册其他节点类型
|
|
|
|
|
const nodeMap = Array.from(Object.values(nodeTypeMap).map(key => key));
|
|
|
|
|
if (!nodeMap.includes(nodeType) && nodeType !== 'start' && nodeType !== 'end' && nodeType !== 'LOOP') {
|
|
|
|
|
registerNodeType(nodeType, LocalNode, nodeConfig.componentName);
|
|
|
|
|
registerNodeType(nodeType, nodeType === 'SWITCH' ? SwitchNode : LocalNode, nodeConfig.componentName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodes.push(node);
|
|
|
|
|
@ -126,56 +127,175 @@ export const convertFlowData = (flowData: any, useDefault = true) => {
|
|
|
|
|
// 用于存储已添加的边,避免重复
|
|
|
|
|
const addedEdges = new Set<string>();
|
|
|
|
|
|
|
|
|
|
// 处理连接关系 - 只处理下游连接,避免重复创建连接线
|
|
|
|
|
// 创建一个映射来存储所有连接信息
|
|
|
|
|
const connections = new Map<string, { source: string; target: string; sourceHandle: string; targetHandle: string }>();
|
|
|
|
|
|
|
|
|
|
// 遍历所有节点,收集连接信息
|
|
|
|
|
for (const entry of nodeEntries) {
|
|
|
|
|
const nodeId: string = entry[0];
|
|
|
|
|
const nodeConfig: any = entry[1];
|
|
|
|
|
|
|
|
|
|
// 处理 API 下游连接
|
|
|
|
|
// 处理 API 下游连接 - 确定目标节点信息
|
|
|
|
|
if (nodeConfig.apiDownstream && Array.isArray(nodeConfig.apiDownstream)) {
|
|
|
|
|
nodeConfig.apiDownstream.forEach((targetArray: string[]) => {
|
|
|
|
|
// 确保 targetArray 是数组并且包含字符串元素
|
|
|
|
|
if (Array.isArray(targetArray)) {
|
|
|
|
|
targetArray.forEach(target => {
|
|
|
|
|
if (typeof target === 'string' && target.includes('$$')) {
|
|
|
|
|
const [targetNodeId, targetHandle] = target.split('$$');
|
|
|
|
|
const connectionKey = `${nodeId}-${targetNodeId}`;
|
|
|
|
|
|
|
|
|
|
// 存储连接信息
|
|
|
|
|
if (connections.has(connectionKey)) {
|
|
|
|
|
// 如果连接已存在,更新目标句柄
|
|
|
|
|
const existing = connections.get(connectionKey);
|
|
|
|
|
if (existing) {
|
|
|
|
|
connections.set(connectionKey, {
|
|
|
|
|
...existing,
|
|
|
|
|
targetHandle: targetHandle
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 创建新的连接信息
|
|
|
|
|
connections.set(connectionKey, {
|
|
|
|
|
source: nodeId,
|
|
|
|
|
target: targetNodeId,
|
|
|
|
|
sourceHandle: '', // 将根据节点信息填充
|
|
|
|
|
targetHandle: targetHandle
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 动态获取源句柄,而不是使用默认值
|
|
|
|
|
const sourceNode = flowData[nodeId];
|
|
|
|
|
// 统一旧版本逻辑,开始节点的输出句柄是start
|
|
|
|
|
let sourceHandle = sourceNode.id === 'start' ? 'start' : 'done'; // 默认值
|
|
|
|
|
if (sourceNode && sourceNode.component && sourceNode.component.type) {
|
|
|
|
|
// 根据节点类型获取正确的源句柄
|
|
|
|
|
sourceHandle = getNodeApiOutHandle(nodeId, sourceNode);
|
|
|
|
|
// 处理 API 上游连接 - 确定源节点信息
|
|
|
|
|
if (nodeConfig.apiUpstream && Array.isArray(nodeConfig.apiUpstream)) {
|
|
|
|
|
nodeConfig.apiUpstream.forEach((sourceArray: string[]) => {
|
|
|
|
|
if (Array.isArray(sourceArray)) {
|
|
|
|
|
sourceArray.forEach(source => {
|
|
|
|
|
if (typeof source === 'string' && source.includes('$$')) {
|
|
|
|
|
const [sourceNodeId, sourceHandle] = source.split('$$');
|
|
|
|
|
const connectionKey = `${sourceNodeId}-${nodeId}`;
|
|
|
|
|
|
|
|
|
|
// 存储连接信息
|
|
|
|
|
if (connections.has(connectionKey)) {
|
|
|
|
|
// 如果连接已存在,更新源句柄
|
|
|
|
|
const existing = connections.get(connectionKey);
|
|
|
|
|
if (existing) {
|
|
|
|
|
connections.set(connectionKey, {
|
|
|
|
|
...existing,
|
|
|
|
|
sourceHandle: sourceHandle
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 创建新的连接信息
|
|
|
|
|
connections.set(connectionKey, {
|
|
|
|
|
source: sourceNodeId,
|
|
|
|
|
target: nodeId,
|
|
|
|
|
sourceHandle: sourceHandle,
|
|
|
|
|
targetHandle: '' // 将根据节点信息填充
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据收集的连接信息生成实际的边
|
|
|
|
|
const connectionEntries = Array.from(connections.entries());
|
|
|
|
|
for (const [connectionKey, connectionInfo] of connectionEntries) {
|
|
|
|
|
const { source, target, sourceHandle, targetHandle } = connectionInfo;
|
|
|
|
|
|
|
|
|
|
// 获取源节点和目标节点
|
|
|
|
|
const sourceNode = flowData[source];
|
|
|
|
|
const targetNode = flowData[target];
|
|
|
|
|
|
|
|
|
|
// 确定最终的源句柄
|
|
|
|
|
let finalSourceHandle = sourceHandle;
|
|
|
|
|
// 如果源句柄未指定,则根据源节点信息确定
|
|
|
|
|
if (!finalSourceHandle) {
|
|
|
|
|
if (source === 'start') {
|
|
|
|
|
finalSourceHandle = 'start';
|
|
|
|
|
}
|
|
|
|
|
else if (sourceNode && sourceNode.data && sourceNode.data.parameters &&
|
|
|
|
|
sourceNode.data.parameters.apiOuts && sourceNode.data.parameters.apiOuts.length > 0) {
|
|
|
|
|
// 从apiOuts中获取第一个句柄
|
|
|
|
|
sourceHandle = sourceNode.data.parameters.apiOuts[0].name ||
|
|
|
|
|
sourceNode.data.parameters.apiOuts[0].id || sourceHandle;
|
|
|
|
|
// 查找匹配的目标句柄
|
|
|
|
|
const matchingApiOut = sourceNode.data.parameters.apiOuts.find(
|
|
|
|
|
(apiOut: any) => apiOut.name === targetHandle
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (matchingApiOut) {
|
|
|
|
|
finalSourceHandle = matchingApiOut.name;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 如果没有精确匹配,使用第一个apiOut
|
|
|
|
|
finalSourceHandle = sourceNode.data.parameters.apiOuts[0].name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (sourceNode && sourceNode.component && sourceNode.component.type) {
|
|
|
|
|
// 根据节点类型获取正确的源句柄
|
|
|
|
|
finalSourceHandle = getNodeApiOutHandle(source, sourceNode);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 默认句柄
|
|
|
|
|
finalSourceHandle = 'done';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确定最终的目标句柄
|
|
|
|
|
let finalTargetHandle = targetHandle;
|
|
|
|
|
// 如果目标句柄未指定,则根据目标节点信息确定
|
|
|
|
|
if (!finalTargetHandle) {
|
|
|
|
|
if (target === 'end') {
|
|
|
|
|
finalTargetHandle = 'end';
|
|
|
|
|
}
|
|
|
|
|
else if (targetNode && targetNode.data && targetNode.data.parameters &&
|
|
|
|
|
targetNode.data.parameters.apiIns && targetNode.data.parameters.apiIns.length > 0) {
|
|
|
|
|
// 查找匹配的源句柄
|
|
|
|
|
const matchingApiIn = targetNode.data.parameters.apiIns.find(
|
|
|
|
|
(apiIn: any) => apiIn.name === sourceHandle
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (matchingApiIn) {
|
|
|
|
|
finalTargetHandle = matchingApiIn.name;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 如果没有精确匹配,使用第一个apiIn
|
|
|
|
|
finalTargetHandle = targetNode.data.parameters.apiIns[0].name;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 默认句柄
|
|
|
|
|
finalTargetHandle = 'start';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建边的唯一标识符
|
|
|
|
|
const edgeId = `${nodeId}-${targetNodeId}-${sourceHandle}-${targetHandle}`;
|
|
|
|
|
const edgeId = `${source}-${target}-${finalSourceHandle}-${finalTargetHandle}`;
|
|
|
|
|
|
|
|
|
|
// 检查是否已添加此边
|
|
|
|
|
if (!addedEdges.has(edgeId)) {
|
|
|
|
|
addedEdges.add(edgeId);
|
|
|
|
|
edges.push({
|
|
|
|
|
id: `${edgeId}`,
|
|
|
|
|
source: nodeId,
|
|
|
|
|
target: targetNodeId,
|
|
|
|
|
sourceHandle,
|
|
|
|
|
targetHandle
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
source: source,
|
|
|
|
|
target: target,
|
|
|
|
|
sourceHandle: finalSourceHandle,
|
|
|
|
|
targetHandle: finalTargetHandle
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 处理数据下游连接
|
|
|
|
|
for (const entry of nodeEntries) {
|
|
|
|
|
const nodeId: string = entry[0];
|
|
|
|
|
const nodeConfig: any = entry[1];
|
|
|
|
|
|
|
|
|
|
if (nodeConfig.dataDownstream && Array.isArray(nodeConfig.dataDownstream)) {
|
|
|
|
|
nodeConfig.dataDownstream.forEach((connectionGroup: string[]) => {
|
|
|
|
|
// 确保 connectionGroup 是数组并且至少包含两个元素
|
|
|
|
|
@ -382,8 +502,59 @@ const getNodeApiOuts = (nodeId: string, nodeConfig: any, currentProjectCompData:
|
|
|
|
|
return [{ name: 'done', desc: '', dataType: '', defaultValue: '' }];
|
|
|
|
|
}
|
|
|
|
|
else if (nodeConfig.component?.type === 'LOOP_END') {
|
|
|
|
|
// 从customDef中获取apiOutIds数组
|
|
|
|
|
try {
|
|
|
|
|
const customDef = JSON.parse(nodeConfig.component?.customDef || '{}');
|
|
|
|
|
const apiOutIds = customDef.apiOutIds || [];
|
|
|
|
|
|
|
|
|
|
// 从"break"开始的所有项都应该作为apiOut返回
|
|
|
|
|
const breakIndex = apiOutIds.indexOf('break');
|
|
|
|
|
if (breakIndex !== -1) {
|
|
|
|
|
// 返回从"break"开始的所有项
|
|
|
|
|
return apiOutIds.slice(breakIndex).map(id => ({
|
|
|
|
|
name: id,
|
|
|
|
|
id: id,
|
|
|
|
|
desc: id,
|
|
|
|
|
dataType: '',
|
|
|
|
|
defaultValue: ''
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 如果没有找到"break",则返回默认值
|
|
|
|
|
return [{ name: 'break', desc: '', dataType: '', defaultValue: '' }];
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
// 解析失败时返回默认值
|
|
|
|
|
return [{ name: 'break', desc: '', dataType: '', defaultValue: '' }];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (nodeConfig.component?.type === 'SWITCH') {
|
|
|
|
|
// 从customDef中获取apiOutIds数组
|
|
|
|
|
try {
|
|
|
|
|
const customDef = JSON.parse(nodeConfig.component?.customDef || '{}');
|
|
|
|
|
const apiOutIds = customDef.apiOutIds || [];
|
|
|
|
|
|
|
|
|
|
// 从"break"开始的所有项都应该作为apiOut返回
|
|
|
|
|
const breakIndex = apiOutIds.indexOf('default');
|
|
|
|
|
if (breakIndex !== -1) {
|
|
|
|
|
// 返回从"break"开始的所有项
|
|
|
|
|
return apiOutIds.slice(breakIndex).map(id => ({
|
|
|
|
|
name: id,
|
|
|
|
|
id: id,
|
|
|
|
|
desc: id,
|
|
|
|
|
dataType: '',
|
|
|
|
|
defaultValue: ''
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// 如果没有找到"break",则返回默认值
|
|
|
|
|
return [{ name: 'default', desc: '', dataType: '', defaultValue: '' }];
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
// 解析失败时返回默认值
|
|
|
|
|
return [{ name: 'done', desc: '', dataType: '', defaultValue: '' }];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (nodeId === 'start') {
|
|
|
|
|
return [{ name: 'start', desc: '', dataType: '', defaultValue: '' }];
|
|
|
|
|
}
|
|
|
|
|
@ -400,11 +571,11 @@ const getNodeApiOuts = (nodeId: string, nodeConfig: any, currentProjectCompData:
|
|
|
|
|
return [{ name: 'done', desc: '', dataType: '', defaultValue: '' }];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 获取节点的API输出句柄名称
|
|
|
|
|
const getNodeApiOutHandle = (nodeId: string, nodeConfig: any) => {
|
|
|
|
|
console.log('nodeConfig:', nodeConfig);
|
|
|
|
|
if (nodeConfig.component?.type === 'LOOP_START') {
|
|
|
|
|
return 'done';
|
|
|
|
|
}
|
|
|
|
|
|