From e88a81049b802e8d8ac3b496df26fc9ad3895e5a Mon Sep 17 00:00:00 2001 From: lixiaolong <702156524@qq.com> Date: Wed, 12 Aug 2026 14:13:16 +0800 Subject: [PATCH] =?UTF-8?q?refactor(flow):=20=E4=BC=98=E5=8C=96=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=8F=82=E6=95=B0=E5=88=9D=E5=A7=8B=E5=8C=96=E5=92=8C?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6=E5=88=86=E9=85=8D=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改 DeviceUniversal.vue 中的 initData 函数,使用可选链操作符安全访问属性 - 将 setTimeout 替换为 nextTick 确保编辑器值正确设置 - 添加对 props.data 的监听以响应数据变化 - 重构 RobotExecutionTarget.vue 中的初始化函数名称和监听逻辑 - 在 flowExecution.js 中添加 itemOccurrence 字段支持 - 优化 RuntimeAssignmentsEditor.vue 中的设备复用检查逻辑 - 实现基于检测项范围的设备键值生成策略 --- src/utils/flowExecution.js | 2 ++ .../components/RuntimeAssignmentsEditor.vue | 8 ++++++- .../components/params/DeviceUniversal.vue | 24 ++++++++++++------- .../params/RobotExecutionTarget.vue | 9 ++++--- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/utils/flowExecution.js b/src/utils/flowExecution.js index 5f06015..9767f96 100644 --- a/src/utils/flowExecution.js +++ b/src/utils/flowExecution.js @@ -80,6 +80,7 @@ export const loadFlowItemScopedRuntimeRoles = async (items = []) => { roleKey: `${item.itemId}:${occurrence}:${role.roleKey}`, sourceRoleKey: role.roleKey, itemId: item.itemId, + itemOccurrence: occurrence, itemName: item.itemName || String(item.itemId), displayName: `${item.itemName || item.itemId} / ${role.displayName}`, })) @@ -103,6 +104,7 @@ export const createRuntimeAssignments = (roles = [], primaryRobotId = '') => rol roleKey: role.roleKey, ...(role.sourceRoleKey ? { sourceRoleKey: role.sourceRoleKey } : {}), ...(role.itemId != null ? { itemId: role.itemId } : {}), + ...(role.itemOccurrence != null ? { itemOccurrence: role.itemOccurrence } : {}), members: [{ memberKey: `${role.roleKey}_1`, robotId: index === 0 ? primaryRobotId || role.legacyRobotId || '' : role.legacyRobotId || '', diff --git a/src/views/flow/components/RuntimeAssignmentsEditor.vue b/src/views/flow/components/RuntimeAssignmentsEditor.vue index 0876c1d..1fc7dc9 100644 --- a/src/views/flow/components/RuntimeAssignmentsEditor.vue +++ b/src/views/flow/components/RuntimeAssignmentsEditor.vue @@ -156,6 +156,7 @@ const initialize = async () => { roleKey: role.roleKey, ...(role.sourceRoleKey ? { sourceRoleKey: role.sourceRoleKey } : {}), ...(role.itemId != null ? { itemId: role.itemId } : {}), + ...(role.itemOccurrence != null ? { itemOccurrence: role.itemOccurrence } : {}), members: [{ ...existingMember, memberKey: `${role.roleKey}_1`, @@ -182,7 +183,12 @@ const validate = () => { if (slot.required && !member.devices[slot.slotKey]) return `请为“${role.displayName}”选择“${slot.displayName}”` const deviceId = member.devices[slot.slotKey] if (!deviceId) continue - const physicalKey = `${member.robotId}:${deviceId}` + // 不同检测项按顺序独立执行,可以复用同一台机器人及其设备。 + // 仅同一检测项内部的多个角色/用途需要遵守设备复用规则。 + const itemScope = role.itemId == null + ? 'task' + : `${role.itemId}:${role.itemOccurrence || 1}` + const physicalKey = `${itemScope}:${member.robotId}:${deviceId}` const existingUse = physicalDeviceUses.get(physicalKey) if (existingUse && (!slot.allowReuse || !existingUse.allowReuse)) { return `“${existingUse.roleName} / ${existingUse.slotName}”和“${role.displayName} / ${slot.displayName}”不能使用同一个设备` diff --git a/src/views/flow/components/params/DeviceUniversal.vue b/src/views/flow/components/params/DeviceUniversal.vue index 6995dc3..acf0265 100644 --- a/src/views/flow/components/params/DeviceUniversal.vue +++ b/src/views/flow/components/params/DeviceUniversal.vue @@ -356,21 +356,28 @@ const deleteTopLevelItem = (fullPath, propPath) => { * 初始化 initData 对应的数据或交互;作用范围仅限当前组件或模块。 */ const initData = () => { - const nodeParams = JSON.parse(JSON.stringify(props.data.properties.nodeParams || [])) - const outputParams = JSON.parse(JSON.stringify(props.data.properties.outputParams || [])) + const properties = props.data?.properties || {} + const nodeParams = JSON.parse(JSON.stringify(properties.nodeParams || [])) + const outputParams = JSON.parse(JSON.stringify(properties.outputParams || [])) formData.nodeParams = nodeParams; formData.outputParams = outputParams; - formData.executionTarget = JSON.parse(JSON.stringify(props.data.properties.executionTarget || {})); - const codeParams = props.data.properties.nodeParams.find(item => item.name === 'requestJson') + formData.executionTarget = JSON.parse(JSON.stringify(properties.executionTarget || {})); + const codeParams = nodeParams.find(item => item.name === 'requestJson') if (codeParams) { - setTimeout(() => { + nextTick(() => { if (editorInstance) { - setValue(codeParams.input) + setValue(codeParams.input) } - }, 100) + }) } } +watch( + () => props.data, + initData, + { immediate: true, deep: true } +) + // 保存验证 /** * 校验 validateAndSave 对应的数据或交互;作用范围仅限当前组件或模块。 @@ -420,7 +427,8 @@ const validateAndSave = async () => { onMounted(() => { nextTick(() => { initEditor('requestJson') - initData() + const codeParams = formData.nodeParams.find(item => item.name === 'requestJson') + if (codeParams) setValue(codeParams.input) }) }) diff --git a/src/views/flow/components/params/RobotExecutionTarget.vue b/src/views/flow/components/params/RobotExecutionTarget.vue index 5cf6cb2..b87c223 100644 --- a/src/views/flow/components/params/RobotExecutionTarget.vue +++ b/src/views/flow/components/params/RobotExecutionTarget.vue @@ -79,7 +79,7 @@ const handleRoleChange = () => { emitTarget() } -const init = () => { +const syncFromModel = () => { roles.value = getResourceRoles() const value = props.modelValue || {} localTarget.roleKey = roles.value.some((role) => role.roleKey === value.roleKey) @@ -88,10 +88,13 @@ const init = () => { localTarget.dispatchPolicy = value.dispatchPolicy || 'ONE' deviceSlotKey.value = value.deviceSlotKey || value.deviceBindings?.[0]?.slotKey || '' selectDefaultSlot() - emitTarget() } -watch(() => props.data.id, init, { immediate: true }) +watch( + [() => props.data.id, () => props.modelValue], + syncFromModel, + { immediate: true, deep: true } +)