2026-08-11 16:51:58 +08:00
|
|
|
|
<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()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-12 14:13:16 +08:00
|
|
|
|
const syncFromModel = () => {
|
2026-08-11 16:51:58 +08:00
|
|
|
|
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()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-12 14:13:16 +08:00
|
|
|
|
watch(
|
|
|
|
|
|
[() => props.data.id, () => props.modelValue],
|
|
|
|
|
|
syncFromModel,
|
|
|
|
|
|
{ immediate: true, deep: true }
|
|
|
|
|
|
)
|
2026-08-11 16:51:58 +08:00
|
|
|
|
</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>
|