From 9640c7ba9ed86c79fc08050e5d5a63e085672b80 Mon Sep 17 00:00:00 2001 From: shaohuzhang1 <80892890+shaohuzhang1@users.noreply.github.com> Date: Fri, 26 Sep 2025 17:03:45 +0800 Subject: [PATCH] fix: Allow variables to be assigned as the end node of the loop node (#4125) --- ui/src/workflow/common/validate.ts | 36 ++++++++++++++++--- .../workflow/nodes/loop-body-node/index.vue | 2 +- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/ui/src/workflow/common/validate.ts b/ui/src/workflow/common/validate.ts index b1ccef27e..2fa816796 100644 --- a/ui/src/workflow/common/validate.ts +++ b/ui/src/workflow/common/validate.ts @@ -1,4 +1,5 @@ -import { WorkflowType } from '@/enums/application' +import { WorkflowType, WorkflowMode } from '@/enums/application' + import { t } from '@/locales' const end_nodes: Array = [ @@ -18,14 +19,39 @@ const end_nodes: Array = [ WorkflowType.LoopNode, WorkflowType.LoopBreakNode, ] + +const loop_end_nodes: Array = [ + WorkflowType.AiChat, + WorkflowType.Reply, + WorkflowType.ToolLib, + WorkflowType.ToolLibCustom, + WorkflowType.ImageUnderstandNode, + WorkflowType.Application, + WorkflowType.SpeechToTextNode, + WorkflowType.TextToSpeechNode, + WorkflowType.ImageGenerateNode, + WorkflowType.ImageToVideoGenerateNode, + WorkflowType.TextToVideoGenerateNode, + WorkflowType.ImageGenerateNode, + WorkflowType.LoopBodyNode, + WorkflowType.LoopNode, + WorkflowType.LoopBreakNode, + WorkflowType.VariableAssignNode, +] +const end_nodes_dict = { + [WorkflowMode.Application]: end_nodes, + [WorkflowMode.ApplicationLoop]: loop_end_nodes, +} export class WorkFlowInstance { nodes edges workFlowNodes: Array - constructor(workflow: { nodes: Array; edges: Array }) { + workflowModel: WorkflowMode + constructor(workflow: { nodes: Array; edges: Array }, workflowModel?: WorkflowMode) { this.nodes = workflow.nodes this.edges = workflow.edges this.workFlowNodes = [] + this.workflowModel = workflowModel ? workflowModel : WorkflowMode.Application } /** * 校验开始节点 @@ -124,7 +150,8 @@ export class WorkFlowInstance { const node_list = edge_list .map((edge) => this.nodes.filter((node) => node.id == edge.targetNodeId)) .reduce((x, y) => [...x, ...y], []) - if (node_list.length == 0 && !end_nodes.includes(node.type)) { + const end = end_nodes_dict[this.workflowModel] + if (node_list.length == 0 && !end.includes(node.type)) { throw t('views.applicationWorkflow.validate.noNextNode') } return node_list @@ -161,7 +188,8 @@ export class WorkFlowInstance { } } else { const edge_list = this.edges.filter((edge) => edge.sourceNodeId == node.id) - if (edge_list.length == 0 && !end_nodes.includes(node.type)) { + const end = end_nodes_dict[this.workflowModel] + if (edge_list.length == 0 && !end.includes(node.type)) { throw `${node.properties.stepName} ${t('views.applicationWorkflow.validate.cannotEndNode')}` } } diff --git a/ui/src/workflow/nodes/loop-body-node/index.vue b/ui/src/workflow/nodes/loop-body-node/index.vue index bc0330b59..b11503e44 100644 --- a/ui/src/workflow/nodes/loop-body-node/index.vue +++ b/ui/src/workflow/nodes/loop-body-node/index.vue @@ -19,7 +19,7 @@ const props = defineProps<{ nodeModel: any }>() const containerRef = ref() const validate = () => { - const workflow = new WorkFlowInstance(lf.value.getGraphData()) + const workflow = new WorkFlowInstance(lf.value.getGraphData(), WorkflowMode.ApplicationLoop) return Promise.all(lf.value.graphModel.nodes.map((element: any) => element?.validate?.())) .then(() => { const loop_node_id = props.nodeModel.properties.loop_node_id