diff --git a/web/src/views/Workflow/components/Properties/CaseList/index.tsx b/web/src/views/Workflow/components/Properties/CaseList/index.tsx index d9521059..f76bd7db 100644 --- a/web/src/views/Workflow/components/Properties/CaseList/index.tsx +++ b/web/src/views/Workflow/components/Properties/CaseList/index.tsx @@ -6,7 +6,7 @@ import { Form, Button, Select, Space, Divider, InputNumber, Radio, type SelectPr import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin' import VariableSelect from '../VariableSelect' import Editor from '../../Editor' -import { edgeAttrs } from '../../../constant' +import { edgeAttrs, portArgs } from '../../../constant' interface CaseListProps { value?: Array<{ logical_operator: 'and' | 'or'; expressions: { left: string; operator: string; right: string; input_type?: string; }[] }>; @@ -92,6 +92,7 @@ const CaseList: FC = ({ selectedNode.addPort({ id: 'CASE1', group: 'right', + args: portArgs, attrs: { text: { text: 'IF', fontSize: 12, fill: '#5B6167' }} }); @@ -100,6 +101,7 @@ const CaseList: FC = ({ selectedNode.addPort({ id: `CASE${i + 1}`, group: 'right', + args: portArgs, attrs: { text: { text: 'ELIF', fontSize: 12, fill: '#5B6167' }} }); } @@ -108,6 +110,7 @@ const CaseList: FC = ({ selectedNode.addPort({ id: `CASE${caseCount + 1}`, group: 'right', + args: portArgs, attrs: { text: { text: 'ELSE', fontSize: 12, fill: '#5B6167' }} }); diff --git a/web/src/views/Workflow/components/Properties/CategoryList/index.tsx b/web/src/views/Workflow/components/Properties/CategoryList/index.tsx index aabc3ad3..22163905 100644 --- a/web/src/views/Workflow/components/Properties/CategoryList/index.tsx +++ b/web/src/views/Workflow/components/Properties/CategoryList/index.tsx @@ -5,7 +5,7 @@ import { Graph, Node } from '@antv/x6'; import Editor from '../../Editor'; import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin' -import { edgeAttrs } from '../../../constant' +import { edgeAttrs, portArgs } from '../../../constant' interface CategoryListProps { parentName: string; @@ -55,7 +55,7 @@ const CategoryList: FC = ({ parentName, selectedNode, graphRe selectedNode.addPort({ id: `CASE${i + 1}`, group: 'right', - args: i === 0 ? { dy: 24 } : undefined, + args: portArgs, attrs: { text: { text: `分类${i + 1}`, fontSize: 12, fill: '#5B6167' } } }); } diff --git a/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts b/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts index ab37fec9..16c32b7c 100644 --- a/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts +++ b/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts @@ -190,6 +190,12 @@ export const useVariableList = ( if (iv?.dataType.startsWith('array[')) itemType = iv.dataType.replace(/^array\[(.+)\]$/, '$1'); addVariable(list, keys, `${pid}_item`, 'item', itemType, `${pid}.item`, pd); addVariable(list, keys, `${pid}_index`, 'index', 'number', `${pid}.index`, pd); + } else if (pd.type === 'iteration' && !pd.config.input.defaultValue) { + let itemType = 'object'; + const iv = list.find(v => `{{${v.value}}}` === pd.config.input.defaultValue); + if (iv?.dataType.startsWith('array[')) itemType = iv.dataType.replace(/^array\[(.+)\]$/, '$1'); + addVariable(list, keys, `${pid}_item`, 'item', 'string', `${pid}.item`, pd); + addVariable(list, keys, `${pid}_index`, 'index', 'number', `${pid}.index`, pd); } } diff --git a/web/src/views/Workflow/components/Properties/index.tsx b/web/src/views/Workflow/components/Properties/index.tsx index d55e1d9e..26ad0470 100644 --- a/web/src/views/Workflow/components/Properties/index.tsx +++ b/web/src/views/Workflow/components/Properties/index.tsx @@ -291,7 +291,69 @@ const Properties: FC = ({ return filteredList; } if (nodeType === 'iteration' && key === 'output') { - return variableList.filter(variable => variable.value.includes('sys.')); + let filteredList = variableList.filter(variable => variable.value.includes('sys.')); + // Add child node output variables for loop nodes + if (selectedNode) { + const graph = graphRef.current; + if (graph) { + const nodes = graph.getNodes(); + const childNodes = nodes.filter(node => { + const nodeData = node.getData(); + return nodeData?.cycle === selectedNode.id; + }); + + // Add output variables from child nodes + childNodes.forEach(childNode => { + const childData = childNode.getData(); + const childNodeId = childData.id; + + // Add child node output variables based on their type + switch (childData.type) { + case 'llm': + case 'jinja-render': + case 'tool': + const outputKey = `${childNodeId}_output`; + const existingOutput = filteredList.find(v => v.key === outputKey); + if (!existingOutput) { + filteredList.push({ + key: outputKey, + label: 'output', + type: 'variable', + dataType: 'string', + value: `${childNodeId}.output`, + nodeData: childData, + }); + } + break; + case 'http-request': + const bodyKey = `${childNodeId}_body`; + const statusKey = `${childNodeId}_status_code`; + if (!filteredList.find(v => v.key === bodyKey)) { + filteredList.push({ + key: bodyKey, + label: 'body', + type: 'variable', + dataType: 'string', + value: `${childNodeId}.body`, + nodeData: childData, + }); + } + if (!filteredList.find(v => v.key === statusKey)) { + filteredList.push({ + key: statusKey, + label: 'status_code', + type: 'variable', + dataType: 'number', + value: `${childNodeId}.status_code`, + nodeData: childData, + }); + } + break; + } + }); + } + } + return filteredList; } if (nodeType === 'iteration') { return variableList.filter(variable => variable.dataType.includes('array')); @@ -411,7 +473,7 @@ const Properties: FC = ({ /> : selectedNode?.data?.type === 'tool' ? - : selectedNode?.data.type === 'jinja-render' + : selectedNode?.data?.type === 'jinja-render' ? = { iteration: { width: 240, @@ -591,8 +592,8 @@ export const graphNodeLibrary: Record = { groups: defaultPortGroups, items: [ { group: 'left' }, - { group: 'right', id: 'CASE1', args: { dy: 24 }, attrs: { text: { text: 'IF', fontSize: 12, color: '#5B6167' }} }, - { group: 'right', id: 'CASE2', attrs: { text: { text: 'ELSE', fontSize: 12, color: '#5B6167' }} } + { group: 'right', id: 'CASE1', args: portArgs, attrs: { text: { text: 'IF', fontSize: 12, color: '#5B6167' }} }, + { group: 'right', id: 'CASE2', args: portArgs, attrs: { text: { text: 'ELSE', fontSize: 12, color: '#5B6167' }} } ], }, }, @@ -604,8 +605,8 @@ export const graphNodeLibrary: Record = { groups: defaultPortGroups, items: [ { group: 'left' }, - { group: 'right', id: 'CASE1', args: { dy: 24 }, attrs: { text: { text: '分类1', fontSize: 12, color: '#5B6167' } } }, - { group: 'right', id: 'CASE2', attrs: { text: { text: '分类2', fontSize: 12, color: '#5B6167' } } } + { group: 'right', id: 'CASE1', args: portArgs, attrs: { text: { text: '分类1', fontSize: 12, color: '#5B6167' } } }, + { group: 'right', id: 'CASE2', args: portArgs, attrs: { text: { text: '分类2', fontSize: 12, color: '#5B6167' } } } ], }, }, diff --git a/web/src/views/Workflow/hooks/useWorkflowGraph.ts b/web/src/views/Workflow/hooks/useWorkflowGraph.ts index f8a5a6bc..0cc69fea 100644 --- a/web/src/views/Workflow/hooks/useWorkflowGraph.ts +++ b/web/src/views/Workflow/hooks/useWorkflowGraph.ts @@ -5,7 +5,7 @@ import { App } from 'antd' import { Graph, Node, MiniMap, Snapline, Clipboard, Keyboard, type Edge } from '@antv/x6'; import { register } from '@antv/x6-react-shape'; -import { nodeRegisterLibrary, graphNodeLibrary, nodeLibrary, portMarkup, portAttrs, edgeAttrs, edge_color, edge_selected_color } from '../constant'; +import { nodeRegisterLibrary, graphNodeLibrary, nodeLibrary, portMarkup, portAttrs, edgeAttrs, edge_color, edge_selected_color, portArgs } from '../constant'; import type { WorkflowConfig, NodeProperties, ChatVariable } from '../types'; import { getWorkflowConfig, saveWorkflowConfig } from '@/api/application' import type { PortMetadata } from '@antv/x6/lib/model/port'; @@ -132,7 +132,7 @@ export const useWorkflowGraph = ({ const portItems: PortMetadata[] = [ { group: 'left' }, - { group: 'right', id: 'CASE1', args: { dy: 24 }, attrs: { text: { text: 'IF', fontSize: 12, fill: '#5B6167' }} } + { group: 'right', id: 'CASE1', args: portArgs, attrs: { text: { text: 'IF', fontSize: 12, fill: '#5B6167' }} } ]; // 添加 ELIF 端口 @@ -140,6 +140,7 @@ export const useWorkflowGraph = ({ portItems.push({ group: 'right', id: `CASE${i + 1}`, + args: portArgs, attrs: { text: { text: 'ELIF', fontSize: 12, fill: '#5B6167' }} }); } @@ -148,6 +149,7 @@ export const useWorkflowGraph = ({ portItems.push({ group: 'right', id: `CASE${caseCount + 1}`, + args: portArgs, attrs: { text: { text: 'ELSE', fontSize: 12, fill: '#5B6167' }} }); @@ -173,12 +175,12 @@ export const useWorkflowGraph = ({ ]; // 添加分类端口 - config.categories.forEach((category: any, index: number) => { + config.categories.forEach((_category: any, index: number) => { portItems.push({ group: 'right', id: `CASE${index + 1}`, - args: index === 0 ? { dy: 24 } : undefined, - attrs: { text: { text: category.class_name || `分类${index + 1}`, fontSize: 12, fill: '#5B6167' }} + args: portArgs, + attrs: { text: { text: `分类${index + 1}`, fontSize: 12, fill: '#5B6167' }} }); });