From 4b96a6458be622feba3ceef6d785e3ba0f051c7c Mon Sep 17 00:00:00 2001 From: Lemon <1599456917@qq.com> Date: Sat, 22 Feb 2025 19:28:53 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=AE=A1=E6=A0=B8=E8=8A=82=E7=82=B9-?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81-=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E8=B7=B3=E8=BD=AC=E4=BB=BB=E6=84=8F=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ProcessNodeTree.vue | 22 ++++++-- .../SimpleProcessDesignerV2/src/consts.ts | 29 +++++++--- .../SimpleProcessDesignerV2/src/node.ts | 1 + .../src/nodes-config/UserTaskNodeConfig.vue | 53 +++++++++++++++---- .../src/nodes/UserTaskNode.vue | 44 ++++++++++++++- 5 files changed, 129 insertions(+), 20 deletions(-) diff --git a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue index cdb540322..31473c5c2 100644 --- a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue +++ b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue @@ -129,14 +129,28 @@ const recursiveFindParentNode = ( if (!findNode) { return } - if (findNode.type === NodeType.START_USER_NODE) { - nodeList.push(findNode) - return - } + // 检查当前节点 if (findNode.type === nodeType) { nodeList.push(findNode) } + + // 检查子节点 + if (findNode.childNode) { + if (findNode.childNode.type === nodeType) { + nodeList.push(findNode.childNode) + } + recursiveFindParentNode(nodeList, findNode.childNode, nodeType) + } + + // 检查条件分支节点 + if (findNode.type === NodeType.CONDITION_BRANCH_NODE && findNode.conditionNodes) { + findNode.conditionNodes.forEach(conditionNode => { + if (conditionNode.childNode) { + recursiveFindParentNode(nodeList, conditionNode.childNode, nodeType) + } + }) + } emits('find:recursiveFindParentNode', nodeList, props.parentNode, nodeType) } diff --git a/src/components/SimpleProcessDesignerV2/src/consts.ts b/src/components/SimpleProcessDesignerV2/src/consts.ts index 7270b104e..edb676cc8 100644 --- a/src/components/SimpleProcessDesignerV2/src/consts.ts +++ b/src/components/SimpleProcessDesignerV2/src/consts.ts @@ -233,6 +233,8 @@ export type TimeoutHandler = { timeDuration?: string // 执行动作是自动提醒, 最大提醒次数 maxRemindCount?: number + // 执行动作是自动跳转时,跳转的节点ID + returnNodeId?: string } /** @@ -291,6 +293,16 @@ export enum RejectHandlerType { */ RETURN_USER_TASK = 2 } +export enum DelaySettingType { + /** + * 默认开启 + */ + FINISH_PROCESS = 1, + /** + * 延迟器指定节点 + */ + RETURN_USER_TASK = 2 +} // 用户任务超时处理类型枚举 export enum TimeoutHandlerType { /** @@ -304,7 +316,11 @@ export enum TimeoutHandlerType { /** * 自动拒绝 */ - REJECT = 3 + REJECT = 3, + /** + * 自动跳转 + */ + AUTO_JUMP = 4 } // 用户任务的审批人为空时,处理类型枚举 export enum AssignEmptyHandlerType { @@ -570,7 +586,8 @@ export const TIME_UNIT_TYPES: DictDataVO[] = [ export const TIMEOUT_HANDLER_TYPES: DictDataVO[] = [ { label: '自动提醒', value: 1 }, { label: '自动同意', value: 2 }, - { label: '自动拒绝', value: 3 } + { label: '自动拒绝', value: 3 }, + { label: '自动跳转', value: 4 } ] export const REJECT_HANDLER_TYPES: DictDataVO[] = [ { label: '终止流程', value: RejectHandlerType.FINISH_PROCESS }, @@ -695,11 +712,11 @@ export enum ProcessVariableEnum { /** * 延迟设置 */ -export type DelaySetting = { - // 延迟类型 - delayType: number - // 延迟时间表达式 +export interface DelaySetting { + delayType: DelayTypeEnum delayTime: string + autoJumpEnable?: boolean + returnNodeId?: string } /** * 延迟类型 diff --git a/src/components/SimpleProcessDesignerV2/src/node.ts b/src/components/SimpleProcessDesignerV2/src/node.ts index e3ac7c263..bbbca9855 100644 --- a/src/components/SimpleProcessDesignerV2/src/node.ts +++ b/src/components/SimpleProcessDesignerV2/src/node.ts @@ -156,6 +156,7 @@ export type UserTaskFormType = { assignStartUserHandlerType?: AssignStartUserHandlerType timeDuration?: number maxRemindCount?: number + timeoutReturnNodeId?: string buttonsSetting: any[] taskCreateListenerEnable?: boolean taskCreateListenerPath?: string diff --git a/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue b/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue index 433864b02..02ae42120 100644 --- a/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue +++ b/src/components/SimpleProcessDesignerV2/src/nodes-config/UserTaskNodeConfig.vue @@ -347,6 +347,25 @@ > + + + + + {{ nodeTypeName }}人为空时 @@ -729,7 +748,9 @@ const saveConfig = async () => { enable: configForm.value.timeoutHandlerEnable!, type: cTimeoutType.value, timeDuration: isoTimeDuration.value, - maxRemindCount: cTimeoutMaxRemindCount.value + maxRemindCount: cTimeoutMaxRemindCount.value, + returnNodeId: configForm.value.timeoutHandlerType === TimeoutHandlerType.AUTO_JUMP ? + configForm.value.timeoutReturnNodeId : undefined } // 设置审批人为空时 currentNode.value.assignEmptyHandler = { @@ -803,15 +824,24 @@ const showUserTaskNodeConfig = (node: SimpleFlowNode) => { returnTaskList.value = matchNodeList // 2.4 设置审批超时处理 configForm.value.timeoutHandlerEnable = node.timeoutHandler?.enable - if (node.timeoutHandler?.enable && node.timeoutHandler?.timeDuration) { - const strTimeDuration = node.timeoutHandler.timeDuration - let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1) - let parseTimeUnit = strTimeDuration.slice(strTimeDuration.length - 1) - configForm.value.timeDuration = parseInt(parseTime) - timeUnit.value = convertTimeUnit(parseTimeUnit) + if (node.timeoutHandler?.enable) { + configForm.value.timeoutHandlerType = node.timeoutHandler.type + configForm.value.timeoutReturnNodeId = node.timeoutHandler.returnNodeId + + if (node.timeoutHandler.timeDuration) { + const strTimeDuration = node.timeoutHandler.timeDuration + let parseTime = strTimeDuration.slice(2, strTimeDuration.length - 1) + let parseTimeUnit = strTimeDuration.slice(strTimeDuration.length - 1) + configForm.value.timeDuration = parseInt(parseTime) + timeUnit.value = convertTimeUnit(parseTimeUnit) + } + + if (node.timeoutHandler.type === TimeoutHandlerType.AUTO_JUMP) { + const matchNodeList: SimpleFlowNode[] = [] + emits('find:returnTaskNodes', matchNodeList) + returnTaskList.value = matchNodeList + } } - configForm.value.timeoutHandlerType = node.timeoutHandler?.type - configForm.value.maxRemindCount = node.timeoutHandler?.maxRemindCount // 2.5 设置审批人为空时 configForm.value.assignEmptyHandlerType = node.assignEmptyHandler?.type configForm.value.assignEmptyHandlerUserIds = node.assignEmptyHandler?.userIds @@ -902,6 +932,11 @@ function useTimeoutHandler() { const timeoutHandlerTypeChanged = () => { if (configForm.value.timeoutHandlerType === TimeoutHandlerType.REMINDER) { configForm.value.maxRemindCount = 1 // 超时提醒次数,默认为1 + } else if (configForm.value.timeoutHandlerType === TimeoutHandlerType.AUTO_JUMP) { + // 获取可跳转节点列表 + const matchNodeList: SimpleFlowNode[] = [] + emits('find:returnTaskNodes', matchNodeList) + returnTaskList.value = matchNodeList } } diff --git a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue index ae1af6c28..4adae5e4b 100644 --- a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue +++ b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue @@ -169,8 +169,50 @@ const deleteNode = () => { const findReturnTaskNodes = ( matchNodeList: SimpleFlowNode[] // 匹配的节点 ) => { - // 从父节点查找 + // 从父节点查找所有用户任务节点 emits('find:parentNode', matchNodeList, NodeType.USER_TASK_NODE) + + // 递归查找当前节点的子节点 + findChildUserTaskNodes(currentNode.value, matchNodeList) + + // 过滤掉当前节点和重复节点 + const currentNodeId = currentNode.value.id + // 使用 Map 来去重,以节点 id 为 key + const uniqueNodes = new Map() + matchNodeList.forEach(node => { + if (node.id !== currentNodeId) { + uniqueNodes.set(node.id, node) + } + }) + + // 清空原数组并添加去重后的节点 + matchNodeList.length = 0 + matchNodeList.push(...Array.from(uniqueNodes.values())) +} + +// 递归查找子节点中的用户任务节点 +const findChildUserTaskNodes = (node: SimpleFlowNode, matchNodeList: SimpleFlowNode[]) => { + if (!node) return + + // 检查子节点 + if (node.childNode) { + if (node.childNode.type === NodeType.USER_TASK_NODE) { + matchNodeList.push(node.childNode) + } + findChildUserTaskNodes(node.childNode, matchNodeList) + } + + // 检查条件分支节点 + if (node.type === NodeType.CONDITION_BRANCH_NODE && node.conditionNodes) { + node.conditionNodes.forEach(conditionNode => { + if (conditionNode.childNode) { + if (conditionNode.childNode.type === NodeType.USER_TASK_NODE) { + matchNodeList.push(conditionNode.childNode) + } + findChildUserTaskNodes(conditionNode.childNode, matchNodeList) + } + }) + } } // 任务的弹窗显示,用于只读模式 -- Gitee From da7c9e97962d7501fac742cdb8054137fa8c8eb0 Mon Sep 17 00:00:00 2001 From: Lemon <1599456917@qq.com> Date: Mon, 24 Feb 2025 17:00:05 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E8=B6=85=E6=97=B6=E8=8A=82=E7=82=B9=E5=8D=A1=E9=A1=BF=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/nodes/UserTaskNode.vue | 64 ++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue index 4adae5e4b..24d05f2a0 100644 --- a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue +++ b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue @@ -165,53 +165,57 @@ const nodeClick = () => { const deleteNode = () => { emits('update:flowNode', currentNode.value.childNode) } -// 查找可以驳回用户节点 -const findReturnTaskNodes = ( - matchNodeList: SimpleFlowNode[] // 匹配的节点 -) => { - // 从父节点查找所有用户任务节点 +// 优化后的查找可驳回用户节点函数 +const findReturnTaskNodes = (matchNodeList: SimpleFlowNode[]) => { + // 创建 Set 用于去重,提前初始化以避免重复操作 + const uniqueNodes = new Set() + const currentNodeId = currentNode.value.id + + // 从父节点查找用户任务节点 emits('find:parentNode', matchNodeList, NodeType.USER_TASK_NODE) - // 递归查找当前节点的子节点 - findChildUserTaskNodes(currentNode.value, matchNodeList) - - // 过滤掉当前节点和重复节点 - const currentNodeId = currentNode.value.id - // 使用 Map 来去重,以节点 id 为 key - const uniqueNodes = new Map() + // 先将父节点中的有效节点添加到 Set matchNodeList.forEach(node => { if (node.id !== currentNodeId) { - uniqueNodes.set(node.id, node) + uniqueNodes.add(node) } }) - - // 清空原数组并添加去重后的节点 + + // 查找子节点并直接添加到 Set + findChildUserTaskNodes(currentNode.value, uniqueNodes, currentNodeId) + + // 直接用 Set 的值更新数组 matchNodeList.length = 0 - matchNodeList.push(...Array.from(uniqueNodes.values())) + matchNodeList.push(...uniqueNodes) } -// 递归查找子节点中的用户任务节点 -const findChildUserTaskNodes = (node: SimpleFlowNode, matchNodeList: SimpleFlowNode[]) => { +// 优化后的子节点查找函数 +const findChildUserTaskNodes = ( + node: SimpleFlowNode, + uniqueNodes: Set, + currentNodeId: string +) => { if (!node) return - - // 检查子节点 + + // 处理直接子节点 if (node.childNode) { - if (node.childNode.type === NodeType.USER_TASK_NODE) { - matchNodeList.push(node.childNode) + if (node.childNode.type === NodeType.USER_TASK_NODE && node.childNode.id !== currentNodeId) { + uniqueNodes.add(node.childNode) } - findChildUserTaskNodes(node.childNode, matchNodeList) + findChildUserTaskNodes(node.childNode, uniqueNodes, currentNodeId) } - - // 检查条件分支节点 + + // 处理条件分支节点 if (node.type === NodeType.CONDITION_BRANCH_NODE && node.conditionNodes) { - node.conditionNodes.forEach(conditionNode => { + for (const conditionNode of node.conditionNodes) { if (conditionNode.childNode) { - if (conditionNode.childNode.type === NodeType.USER_TASK_NODE) { - matchNodeList.push(conditionNode.childNode) + if (conditionNode.childNode.type === NodeType.USER_TASK_NODE && + conditionNode.childNode.id !== currentNodeId) { + uniqueNodes.add(conditionNode.childNode) } - findChildUserTaskNodes(conditionNode.childNode, matchNodeList) + findChildUserTaskNodes(conditionNode.childNode, uniqueNodes, currentNodeId) } - }) + } } } -- Gitee From dc84312542435f5e7283a99bf50367ea2c0efebf Mon Sep 17 00:00:00 2001 From: Lemon <1599456917@qq.com> Date: Tue, 25 Feb 2025 15:06:38 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E6=B5=81=E7=A8=8B=E8=8A=82=E7=82=B9=E5=A4=9A?= =?UTF-8?q?=20=E6=89=93=E5=BC=80=E5=AE=A1=E6=A0=B8=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=8D=A1=E9=A1=BF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ProcessNodeTree.vue | 55 ++++++++++++++---- .../src/nodes/UserTaskNode.vue | 57 ++++++++++++------- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue index 31473c5c2..942ab11f7 100644 --- a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue +++ b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue @@ -54,8 +54,8 @@ :flow-node="currentNode" @update:flow-node="handleModelValueUpdate" /> - - + diff --git a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue index 24d05f2a0..d24cfb1ae 100644 --- a/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue +++ b/src/components/SimpleProcessDesignerV2/src/nodes/UserTaskNode.vue @@ -41,7 +41,7 @@
@@ -147,12 +147,16 @@ const nodeSetting = ref() const nodeClick = () => { if (readonly) { + console.log('[UserTaskNode] 开始处理只读模式点击, tasks长度:', tasks.value?.length) if (tasks && tasks.value) { dialogTitle.value = currentNode.value.name + console.time('过滤任务耗时') // 只读模式,弹窗显示任务信息 selectTasks.value = tasks.value.filter( (item: any) => item?.taskDefinitionKey === currentNode.value.id ) + console.timeEnd('过滤任务耗时') + console.log('[UserTaskNode] 过滤后的任务数:', selectTasks.value.length) dialogVisible.value = true } } else { @@ -165,55 +169,66 @@ const nodeClick = () => { const deleteNode = () => { emits('update:flowNode', currentNode.value.childNode) } -// 优化后的查找可驳回用户节点函数 +// 优化查找可驳回用户节点函数 const findReturnTaskNodes = (matchNodeList: SimpleFlowNode[]) => { - // 创建 Set 用于去重,提前初始化以避免重复操作 + console.time('findReturnTaskNodes总耗时') + + // 使用Set进行去重 const uniqueNodes = new Set() const currentNodeId = currentNode.value.id + const processedNodes = new Set() // 用于记录已处理的节点 // 从父节点查找用户任务节点 + console.time('父节点查找耗时') emits('find:parentNode', matchNodeList, NodeType.USER_TASK_NODE) - - // 先将父节点中的有效节点添加到 Set + console.timeEnd('父节点查找耗时') + + // 过滤并去重 matchNodeList.forEach(node => { - if (node.id !== currentNodeId) { + if (!processedNodes.has(node.id) && node.id !== currentNodeId) { uniqueNodes.add(node) + processedNodes.add(node.id) } }) - // 查找子节点并直接添加到 Set - findChildUserTaskNodes(currentNode.value, uniqueNodes, currentNodeId) + // 查找子节点 + findChildUserTaskNodes(currentNode.value, uniqueNodes, currentNodeId, processedNodes) - // 直接用 Set 的值更新数组 + // 更新结果数组 matchNodeList.length = 0 - matchNodeList.push(...uniqueNodes) + matchNodeList.push(...Array.from(uniqueNodes)) + + console.log('[findReturnTaskNodes] 最终找到的节点数:', matchNodeList.length) + console.timeEnd('findReturnTaskNodes总耗时') } -// 优化后的子节点查找函数 +// 优化子节点查找函数 const findChildUserTaskNodes = ( - node: SimpleFlowNode, + node: SimpleFlowNode, uniqueNodes: Set, - currentNodeId: string + currentNodeId: string, + processedNodes: Set ) => { - if (!node) return + if (!node || processedNodes.has(node.id)) return + + processedNodes.add(node.id) // 处理直接子节点 if (node.childNode) { - if (node.childNode.type === NodeType.USER_TASK_NODE && node.childNode.id !== currentNodeId) { + if (node.childNode.type === NodeType.USER_TASK_NODE && + node.childNode.id !== currentNodeId && + !processedNodes.has(node.childNode.id)) { uniqueNodes.add(node.childNode) + processedNodes.add(node.childNode.id) } - findChildUserTaskNodes(node.childNode, uniqueNodes, currentNodeId) + findChildUserTaskNodes(node.childNode, uniqueNodes, currentNodeId, processedNodes) } // 处理条件分支节点 if (node.type === NodeType.CONDITION_BRANCH_NODE && node.conditionNodes) { for (const conditionNode of node.conditionNodes) { if (conditionNode.childNode) { - if (conditionNode.childNode.type === NodeType.USER_TASK_NODE && - conditionNode.childNode.id !== currentNodeId) { - uniqueNodes.add(conditionNode.childNode) - } - findChildUserTaskNodes(conditionNode.childNode, uniqueNodes, currentNodeId) + findChildUserTaskNodes(conditionNode.childNode, uniqueNodes, currentNodeId, processedNodes) } } } -- Gitee From 994211e69344766243bf10e27b5550b85ec90a25 Mon Sep 17 00:00:00 2001 From: Lemon <1599456917@qq.com> Date: Tue, 25 Feb 2025 15:18:10 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=AE=A1=E6=A0=B8?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E6=B5=81=E7=A8=8B=E8=8A=82=E7=82=B9=E5=A4=9A?= =?UTF-8?q?=20=E6=89=93=E5=BC=80=E5=AE=A1=E6=A0=B8=E8=8A=82=E7=82=B9?= =?UTF-8?q?=E5=8D=A1=E9=A1=BF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue index 942ab11f7..01f24e239 100644 --- a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue +++ b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue @@ -87,7 +87,7 @@ import DelayTimerNode from './nodes/DelayTimerNode.vue' import RouterNode from './nodes/RouterNode.vue' import TriggerNode from './nodes/TriggerNode.vue' -// 导入流程节点相关的类型定义和工具函数 + import { SimpleFlowNode, NodeType } from './consts' import { useWatchNode } from './node' -- Gitee From 5e3d89e279ae97233ec5259acd763f7baee01d83 Mon Sep 17 00:00:00 2001 From: Lemon <1599456917@qq.com> Date: Tue, 25 Feb 2025 18:55:59 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=8D=A1=E9=A1=BF=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/ProcessNodeTree.vue | 75 +++++++++---------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue index c139468ee..3975c242f 100644 --- a/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue +++ b/src/components/SimpleProcessDesignerV2/src/ProcessNodeTree.vue @@ -144,50 +144,49 @@ const findFromParentNode = (nodeList: SimpleFlowNode[], nodeType: number) => { const nodeCache = new Map() const recursiveFindParentNode = ( - nodeList: SimpleFlowNode[], - findNode: SimpleFlowNode, - nodeType: number + nodeList: SimpleFlowNode[], + findNode: SimpleFlowNode, + nodeType: number ) => { if (!findNode) return - - // 检查缓存 - const cacheKey = `${findNode.id}-${nodeType}` - if (nodeCache.has(cacheKey)) { - const cachedNodes = nodeCache.get(cacheKey) - nodeList.push(...cachedNodes!) - return - } - - const foundNodes: SimpleFlowNode[] = [] - - // 检查当前节点 - if (findNode.type === nodeType) { - foundNodes.push(findNode) - } - - // 检查子节点 - if (findNode.childNode) { - if (findNode.childNode.type === nodeType) { - foundNodes.push(findNode.childNode) - } - recursiveFindParentNode(foundNodes, findNode.childNode, nodeType) - } - - // 检查条件分支节点 - if (findNode.type === NodeType.CONDITION_BRANCH_NODE && findNode.conditionNodes) { - findNode.conditionNodes.forEach(conditionNode => { - if (conditionNode.childNode) { - recursiveFindParentNode(foundNodes, conditionNode.childNode, nodeType) + + // Create a Set to track visited nodes and prevent cycles + const visitedNodes = new Set() + + const findNodesRecursive = (node: SimpleFlowNode) => { + if (!node || visitedNodes.has(node.id)) return + + visitedNodes.add(node.id) + + // Check current node + if (node.type === nodeType) { + if (!nodeList.some(n => n.id === node.id)) { + nodeList.push(node) } - }) + } + + // Check child node + if (node.childNode) { + findNodesRecursive(node.childNode) + } + + // Check condition nodes if present + if (node.type === NodeType.CONDITION_BRANCH_NODE && node.conditionNodes) { + node.conditionNodes.forEach(conditionNode => { + if (conditionNode.childNode) { + findNodesRecursive(conditionNode.childNode) + } + }) + } } - // 存入缓存 - nodeCache.set(cacheKey, foundNodes) - nodeList.push(...foundNodes) + // Start recursive search + findNodesRecursive(findNode) - // 继续向上递归查找 - emits('find:recursiveFindParentNode', nodeList, props.parentNode, nodeType) + // Continue search in parent node + if (props.parentNode) { + emits('find:recursiveFindParentNode', nodeList, props.parentNode, nodeType) + } } -- Gitee