CMVR-IOT-UI/src/views/flow/components/params/RobotExecutionTarget.vue
lixiaolong e88a81049b refactor(flow): 优化流程参数初始化和运行时分配逻辑
- 修改 DeviceUniversal.vue 中的 initData 函数,使用可选链操作符安全访问属性
- 将 setTimeout 替换为 nextTick 确保编辑器值正确设置
- 添加对 props.data 的监听以响应数据变化
- 重构 RobotExecutionTarget.vue 中的初始化函数名称和监听逻辑
- 在 flowExecution.js 中添加 itemOccurrence 字段支持
- 优化 RuntimeAssignmentsEditor.vue 中的设备复用检查逻辑
- 实现基于检测项范围的设备键值生成策略
2026-08-12 14:13:16 +08:00

121 lines
3.8 KiB
Vue

<template>
<div class="execution-target">
<div class="execution-target__heading">执行设置</div>
<el-form label-position="top">
<el-form-item label="由谁执行" required>
<el-select v-model="localTarget.roleKey" style="width: 100%" @change="handleRoleChange">
<el-option
v-for="role in roles"
:key="role.roleKey"
:label="role.displayName"
:value="role.roleKey"
/>
</el-select>
</el-form-item>
<el-form-item v-if="hasDeviceParameter" label="使用设备" required>
<el-select
v-model="deviceSlotKey"
style="width: 100%"
:placeholder="matchingSlots.length ? '请选择设备用途' : '请先在开始节点配置设备用途'"
@change="emitTarget"
>
<el-option
v-for="slot in matchingSlots"
:key="slot.slotKey"
:label="`${slot.displayName} · ${getDeviceKindName(slot.deviceKind)}`"
:value="slot.slotKey"
/>
</el-select>
<div v-if="!matchingSlots.length" class="execution-target__warning">
当前角色没有匹配的设备用途,请先打开开始节点添加。
</div>
</el-form-item>
</el-form>
</div>
</template>
<script setup>
import { computed, reactive, ref, watch } from 'vue'
import { getDeviceKindForAction } from '@/utils/robotDevice'
import { actionRequiresDevice, getDeviceKindName, getResourceRoles } from '@/utils/flowResources'
const props = defineProps({
data: { type: Object, required: true },
modelValue: { type: Object, default: () => ({}) },
})
const emit = defineEmits(['update:modelValue'])
const roles = ref([])
const localTarget = reactive({ roleKey: '', dispatchPolicy: 'ONE', deviceSlotKey: '' })
const deviceSlotKey = ref('')
const hasDeviceParameter = computed(() => (
actionRequiresDevice(props.data.properties?.action)
))
const requiredDeviceKind = computed(() => getDeviceKindForAction(props.data.properties?.action))
const selectedRole = computed(() => roles.value.find((role) => role.roleKey === localTarget.roleKey))
const matchingSlots = computed(() => (selectedRole.value?.deviceSlots || []).filter((slot) => (
requiredDeviceKind.value == null
|| slot.deviceKind == null
|| Number(slot.deviceKind) === Number(requiredDeviceKind.value)
)))
const emitTarget = () => {
emit('update:modelValue', {
roleKey: localTarget.roleKey,
dispatchPolicy: 'ONE',
deviceSlotKey: hasDeviceParameter.value ? deviceSlotKey.value : '',
})
}
const selectDefaultSlot = () => {
const currentValid = matchingSlots.value.some((slot) => slot.slotKey === deviceSlotKey.value)
if (!currentValid) deviceSlotKey.value = matchingSlots.value.length === 1 ? matchingSlots.value[0].slotKey : ''
}
const handleRoleChange = () => {
deviceSlotKey.value = ''
selectDefaultSlot()
emitTarget()
}
const syncFromModel = () => {
roles.value = getResourceRoles()
const value = props.modelValue || {}
localTarget.roleKey = roles.value.some((role) => role.roleKey === value.roleKey)
? value.roleKey
: roles.value[0]?.roleKey || ''
localTarget.dispatchPolicy = value.dispatchPolicy || 'ONE'
deviceSlotKey.value = value.deviceSlotKey || value.deviceBindings?.[0]?.slotKey || ''
selectDefaultSlot()
}
watch(
[() => props.data.id, () => props.modelValue],
syncFromModel,
{ immediate: true, deep: true }
)
</script>
<style scoped lang="scss">
.execution-target {
margin: 12px 0 2px;
padding: 14px 0 2px;
border-bottom: 1px solid var(--el-border-color-lighter);
}
.execution-target__heading {
margin-bottom: 12px;
color: var(--el-text-color-primary);
font-size: 14px;
font-weight: 650;
}
.execution-target__warning {
margin-top: 6px;
color: var(--el-color-warning-dark-2);
font-size: 12px;
line-height: 18px;
}
</style>