From a7b245a670ccce2c5e2c55de0b7f41dd4a4f6484 Mon Sep 17 00:00:00 2001 From: v-zhangjc9 Date: Tue, 15 Jul 2025 16:27:00 +0800 Subject: [PATCH] =?UTF-8?q?refractor(web):=20=E4=BF=AE=E5=A4=8D=E5=85=A5?= =?UTF-8?q?=E5=8F=82=E8=A7=A3=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../client/src/components/flow/Helper.tsx | 105 ++++++++---------- .../src/components/flow/NodeRegistry.tsx | 10 +- .../client/src/components/flow/types.ts | 12 +- 3 files changed, 55 insertions(+), 72 deletions(-) diff --git a/service-web/client/src/components/flow/Helper.tsx b/service-web/client/src/components/flow/Helper.tsx index 861fd58..9eeafba 100644 --- a/service-web/client/src/components/flow/Helper.tsx +++ b/service-web/client/src/components/flow/Helper.tsx @@ -1,10 +1,10 @@ import {type Edge, getIncomers, type Node} from '@xyflow/react' import type {Option} from 'amis/lib/Schema' -import {find, has, isEmpty, isEqual, max, min, unique} from 'licia' +import {find, has, isEqual, max, min, unique} from 'licia' import {type DependencyList, type MouseEvent as ReactMouseEvent, useCallback, useRef} from 'react' import Queue from 'yocto-queue' import {useFlowStore} from './store/FlowStore.ts' -import type {InputFormOptions, InputFormOptionsGroup} from './types.ts' +import type {OutputVariable} from './types.ts' export const getAllIncomerNodeById: (id: string, nodes: Node[], edges: Edge[]) => string[] = (id, nodes, edges) => { let queue = new Queue() @@ -20,36 +20,16 @@ export const getAllIncomerNodeById: (id: string, nodes: Node[], edges: Edge[]) = return unique(result, (a, b) => isEqual(a, b)) } -export const getAllIncomerNodeOutputVariables: (id: string, nodes: Node[], edges: Edge[], data: any) => { - id: string, - variable: string -}[] = (id, nodes, edges, data) => { - let incomerIds = getAllIncomerNodeById(id, nodes, edges) - let incomerVariables: { id: string, variable: string }[] = [] - for (const incomerId of incomerIds) { - let nodeData = data[incomerId] ?? {} - if (has(nodeData, 'outputs')) { - let outputs = nodeData?.outputs ?? [] - for (const output of Object.keys(outputs)) { - incomerVariables.push({ - id: incomerId, - variable: output, - }) - } - } - } - return incomerVariables -} - -export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSchema: Record>, nodes: Node[], edges: Edge[], data: any) => Option[] = (id, inputSchema, nodes, edges, data) => { - let inputSchemaVariables: InputFormOptions[] = Object.keys(inputSchema).map(key => ({ - label: `${key} (${inputSchema[key]?.label ?? ''})`, - value: key, +export const getAllIncomerNodeOutputVariables: (id: string, inputSchema: Record>, nodes: Node[], edges: Edge[], data: any) => OutputVariable[] = (id, inputSchema, nodes, edges, data) => { + let inputSchemaVariables: OutputVariable[] = Object.keys(inputSchema).map(key => ({ + group: '流程入参', + name: `${key}${inputSchema[key]?.label ? ` (${inputSchema[key].label})` : ''}`, + variable: key, })) let currentNode = find(nodes, n => isEqual(id, n.id)) if (!currentNode) { - return [] + return inputSchemaVariables } let incomerIds = getAllIncomerNodeById(id, nodes, edges) @@ -60,7 +40,7 @@ export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSch ] } - let incomerVariables: InputFormOptionsGroup[] = [] + let incomerVariables: OutputVariable[] = [] for (const incomerId of incomerIds) { let nodeData = data[incomerId] ?? {} let group = incomerId @@ -68,48 +48,51 @@ export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSch group = `${nodeData.node.name} ${incomerId}` } if (has(nodeData, 'outputs')) { - let outputs = nodeData?.outputs ?? [] - incomerVariables.push({ - group: group, - variables: Object.keys(outputs).map(key => ({ - value: `${incomerId}.${key}`, - label: key, - })), - }) + let outputs = nodeData?.outputs ?? {} + for (const key of Object.keys(outputs)) { + incomerVariables.push({ + group: group, + name: key, + variable: `${incomerId}.${key}`, + }) + } } } - let inputVariables = [ - ...(isEmpty(inputSchemaVariables) ? [] : [ - { - group: '流程入参', - variables: inputSchemaVariables, - }, - ]), + return [ + ...inputSchemaVariables, ...(currentNode.parentId ? [ { group: '循环入参', - variables: [ - { - label: 'loopIndex (当前迭代索引)', - value: 'loopIndex', - }, - { - label: 'loopItem (当前迭代对象)', - value: 'loopItem', - } - ] - } + name: 'loopIndex (当前迭代索引)', + variable: 'loopIndex', + }, + { + group: '循环入参', + name: 'loopItem (当前迭代对象)', + variable: 'loopItem', + }, ] : []), ...incomerVariables, ] +} - return [ - ...inputVariables.map(item => ({ - label: item.group, - children: item.variables, - })), - ] +export const generateAllIncomerOutputVariablesFormOptions: (id: string, inputSchema: Record>, nodes: Node[], edges: Edge[], data: any) => Option[] = (id, inputSchema, nodes, edges, data) => { + let optionMap: Record = {} + for (const item of getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data)) { + if (!optionMap[item.group]) { + optionMap[item.group] = [] + } + optionMap[item.group].push({ + label: item.name, + value: item.variable, + }) + } + return Object.keys(optionMap) + .map(key => ({ + label: key, + children: optionMap[key], + })) } // 处理循环节点的边界问题 diff --git a/service-web/client/src/components/flow/NodeRegistry.tsx b/service-web/client/src/components/flow/NodeRegistry.tsx index 41e517c..097a0cc 100644 --- a/service-web/client/src/components/flow/NodeRegistry.tsx +++ b/service-web/client/src/components/flow/NodeRegistry.tsx @@ -15,10 +15,7 @@ const inputSingleVariableChecker: (field: string) => NodeChecker = field => { if (has(nodeData, field)) { let expression = nodeData?.[field] ?? '' if (!isEmpty(expression)) { - let outputVariables = new Set([ - ...getAllIncomerNodeOutputVariables(id, nodes, edges, data).map(i => `${i.id}.${i.variable}`), - ...Object.keys(inputSchema), - ]) + let outputVariables = new Set(getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data).map(i => i.variable)) if (!outputVariables.has(expression)) { return { error: true, @@ -36,10 +33,7 @@ const inputMultiVariableChecker: NodeChecker = (id, inputSchema, nodes, edges, d if (has(nodeData, 'inputs')) { let inputs = nodeData?.inputs ?? {} if (!isEmpty(inputs)) { - let outputVariables = new Set([ - ...getAllIncomerNodeOutputVariables(id, nodes, edges, data).map(i => `${i.id}.${i.variable}`), - ...Object.keys(inputSchema), - ]) + let outputVariables = new Set(getAllIncomerNodeOutputVariables(id, inputSchema, nodes, edges, data).map(i => i.variable)) for (const key of Object.keys(inputs)) { let variable = inputs[key]?.variable ?? '' if (!outputVariables.has(variable)) { diff --git a/service-web/client/src/components/flow/types.ts b/service-web/client/src/components/flow/types.ts index 39d3523..18ee66a 100644 --- a/service-web/client/src/components/flow/types.ts +++ b/service-web/client/src/components/flow/types.ts @@ -1,8 +1,8 @@ import type {Edge, Node} from '@xyflow/react' import type {JSX} from 'react' -export const flowBackgroundColor = "#fafafa" -export const flowDotColor = "#dedede" +export const flowBackgroundColor = '#fafafa' +export const flowDotColor = '#dedede' export type InputFormOptions = { label: string @@ -37,4 +37,10 @@ export type NodeDefine = { description: string, component: any, checkers: NodeChecker[], -} \ No newline at end of file +} + +export type OutputVariable = { + group: string, + name: string | undefined, + variable: string, +}