feat(flow): 新增工作流执行资源配置功能
- 添加了 flowExecution 工具模块用于处理工作流运行时资源配置 - 实现了工作流角色定义的加载、合并和验证功能 - 集成了机器人和设备分配逻辑到任务执行界面 - 更新了 RuntimeAssignmentsEditor 组件以支持动态设备分配 - 移除了静态机器人选择,改为基于流程角色的动态分配 - 优化了工作流资源定义合并逻辑,支持插槽复用配置 - 增强了设备冲突检测和错误处理机制 - 统一了多个视图中的工作流执行资源配置流程
This commit is contained in:
parent
e3a2761683
commit
c54f1da126
82
src/utils/flowExecution.js
Normal file
82
src/utils/flowExecution.js
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import { getFlowParamsApi } from '@/api/device/terminal'
|
||||||
|
import { getDetect } from '@/api/test/detect'
|
||||||
|
import {
|
||||||
|
getResourceRoles,
|
||||||
|
mergeResourceRoleDefinitions,
|
||||||
|
normalizeFlowResourceSchema,
|
||||||
|
validateFlowResources,
|
||||||
|
} from '@/utils/flowResources'
|
||||||
|
|
||||||
|
const clone = (value) => JSON.parse(JSON.stringify(value || []))
|
||||||
|
|
||||||
|
const parseFlowData = (itemId, flowData) => {
|
||||||
|
if (!flowData) throw new Error(`流程项[${itemId}]还没有配置工作流`)
|
||||||
|
try {
|
||||||
|
const graph = typeof flowData === 'string' ? JSON.parse(flowData) : flowData
|
||||||
|
const normalizedGraph = normalizeFlowResourceSchema(graph)
|
||||||
|
const validation = validateFlowResources(normalizedGraph)
|
||||||
|
if (validation.errors.length) {
|
||||||
|
throw new Error(validation.errors[0].message)
|
||||||
|
}
|
||||||
|
return validation.graph
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(`流程项[${itemId}]不可执行:${error.message || '工作流数据无法解析'}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const assertCompatibleDefinitions = (roleGroups) => {
|
||||||
|
const rolesByKey = new Map()
|
||||||
|
roleGroups.flat().forEach((role) => {
|
||||||
|
const existing = rolesByKey.get(role.roleKey)
|
||||||
|
if (!existing) {
|
||||||
|
rolesByKey.set(role.roleKey, clone([role])[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const slotsByKey = new Map((existing.deviceSlots || []).map((slot) => [slot.slotKey, slot]))
|
||||||
|
;(role.deviceSlots || []).forEach((slot) => {
|
||||||
|
const existingSlot = slotsByKey.get(slot.slotKey)
|
||||||
|
if (existingSlot && String(existingSlot.deviceKind ?? '') !== String(slot.deviceKind ?? '')) {
|
||||||
|
throw new Error(`机器人角色“${existing.displayName}”的设备用途“${slot.displayName}”在不同流程中类型不一致`)
|
||||||
|
}
|
||||||
|
if (!existingSlot) existing.deviceSlots.push(clone([slot])[0])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadFlowItemRuntimeRoles = async (items = []) => {
|
||||||
|
if (items.some((item) => !item?.itemId)) throw new Error('任务编排中存在缺少流程项ID的数据')
|
||||||
|
const uniqueItems = Array.from(new Map(
|
||||||
|
items.filter((item) => item?.itemId).map((item) => [item.itemId, item]),
|
||||||
|
).values())
|
||||||
|
if (!uniqueItems.length) throw new Error('当前任务没有编排任何流程项')
|
||||||
|
|
||||||
|
const roleGroups = await Promise.all(uniqueItems.map(async (item) => {
|
||||||
|
const response = await getDetect(item.itemId)
|
||||||
|
const graph = parseFlowData(item.itemName || item.itemId, response.data?.flowData)
|
||||||
|
return getResourceRoles(graph)
|
||||||
|
}))
|
||||||
|
assertCompatibleDefinitions(roleGroups)
|
||||||
|
return mergeResourceRoleDefinitions(roleGroups)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loadTaskRuntimeRoles = async (taskId) => {
|
||||||
|
if (!taskId) throw new Error('任务没有关联流程编排')
|
||||||
|
const response = await getFlowParamsApi(taskId)
|
||||||
|
return loadFlowItemRuntimeRoles(response.rows || [])
|
||||||
|
}
|
||||||
|
|
||||||
|
export const createRuntimeAssignments = (roles = [], primaryRobotId = '') => roles.map((role, index) => ({
|
||||||
|
roleKey: role.roleKey,
|
||||||
|
members: [{
|
||||||
|
memberKey: `${role.roleKey}_1`,
|
||||||
|
robotId: index === 0 ? primaryRobotId || role.legacyRobotId || '' : role.legacyRobotId || '',
|
||||||
|
devices: Object.fromEntries((role.deviceSlots || []).map((slot) => [
|
||||||
|
slot.slotKey,
|
||||||
|
slot.legacyDeviceId || '',
|
||||||
|
])),
|
||||||
|
}],
|
||||||
|
}))
|
||||||
|
|
||||||
|
export const firstAssignedRobotId = (assignments = []) => (
|
||||||
|
clone(assignments).flatMap((item) => item.members || []).find((member) => member.robotId)?.robotId || ''
|
||||||
|
)
|
||||||
@ -313,10 +313,15 @@ export const mergeResourceRoleDefinitions = (roleGroups = []) => {
|
|||||||
merged.push(clone(sourceRole))
|
merged.push(clone(sourceRole))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
role.required = role.required !== false || sourceRole.required !== false
|
||||||
;(sourceRole.deviceSlots || []).forEach((sourceSlot) => {
|
;(sourceRole.deviceSlots || []).forEach((sourceSlot) => {
|
||||||
if (!role.deviceSlots.some((slot) => slot.slotKey === sourceSlot.slotKey)) {
|
const slot = role.deviceSlots.find((item) => item.slotKey === sourceSlot.slotKey)
|
||||||
|
if (!slot) {
|
||||||
role.deviceSlots.push(clone(sourceSlot))
|
role.deviceSlots.push(clone(sourceSlot))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
slot.required = slot.required !== false || sourceSlot.required !== false
|
||||||
|
slot.allowReuse = slot.allowReuse === true && sourceSlot.allowReuse === true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
return merged
|
return merged
|
||||||
|
|||||||
@ -9,13 +9,14 @@
|
|||||||
<el-form-item label="执行机器人" :required="role.required">
|
<el-form-item label="执行机器人" :required="role.required">
|
||||||
<el-select
|
<el-select
|
||||||
:model-value="memberOf(role).robotId"
|
:model-value="memberOf(role).robotId"
|
||||||
|
clearable
|
||||||
filterable
|
filterable
|
||||||
:loading="robotLoading"
|
:loading="robotLoading"
|
||||||
placeholder="请选择机器人"
|
placeholder="请选择机器人"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
@change="(robotId) => changeRobot(role, robotId)"
|
@change="(robotId) => changeRobot(role, robotId)"
|
||||||
>
|
>
|
||||||
<el-option v-for="item in robotOptions" :key="item.value" :label="item.label" :value="item.value" />
|
<el-option v-for="item in robotOptionsOf(role)" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-for="slot in role.deviceSlots" :key="slot.slotKey" :label="slot.displayName" :required="slot.required">
|
<el-form-item v-for="slot in role.deviceSlots" :key="slot.slotKey" :label="slot.displayName" :required="slot.required">
|
||||||
@ -36,18 +37,21 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
<el-alert v-if="loadError" :title="loadError" type="error" :closable="false" show-icon />
|
||||||
<el-empty v-if="!roles.length" :image-size="52" description="当前任务不需要机器人" />
|
<el-empty v-if="!roles.length" :image-size="52" description="当前任务不需要机器人" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, watch } from 'vue'
|
import { computed, reactive, ref, watch } from 'vue'
|
||||||
import { getRobotList, getRobotDevicesByRobotId } from '@/api/inspection/robot'
|
import { getRobotList, getRobotDevicesByRobotId } from '@/api/inspection/robot'
|
||||||
import { toDeviceOptions } from '@/utils/robotDevice'
|
import { toDeviceOptions } from '@/utils/robotDevice'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
roles: { type: Array, default: () => [] },
|
roles: { type: Array, default: () => [] },
|
||||||
modelValue: { type: Array, default: () => [] },
|
modelValue: { type: Array, default: () => [] },
|
||||||
|
robotQuery: { type: Object, default: () => ({}) },
|
||||||
|
requiredMapId: { type: [String, Number], default: '' },
|
||||||
})
|
})
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
@ -56,6 +60,9 @@ const robotOptions = ref([])
|
|||||||
const devicesByRole = reactive({})
|
const devicesByRole = reactive({})
|
||||||
const robotLoading = ref(false)
|
const robotLoading = ref(false)
|
||||||
const loadingRoleKey = ref('')
|
const loadingRoleKey = ref('')
|
||||||
|
const robotLoadError = ref('')
|
||||||
|
const deviceLoadErrors = reactive({})
|
||||||
|
const loadError = computed(() => robotLoadError.value || Object.values(deviceLoadErrors).find(Boolean) || '')
|
||||||
const clone = (value) => JSON.parse(JSON.stringify(value || []))
|
const clone = (value) => JSON.parse(JSON.stringify(value || []))
|
||||||
|
|
||||||
const assignmentOf = (role) => assignments.value.find((item) => item.roleKey === role.roleKey)
|
const assignmentOf = (role) => assignments.value.find((item) => item.roleKey === role.roleKey)
|
||||||
@ -64,35 +71,69 @@ const emitValue = () => emit('update:modelValue', clone(assignments.value))
|
|||||||
|
|
||||||
const loadRobots = async () => {
|
const loadRobots = async () => {
|
||||||
robotLoading.value = true
|
robotLoading.value = true
|
||||||
|
robotLoadError.value = ''
|
||||||
try {
|
try {
|
||||||
const response = await getRobotList({ pageNum: 1, pageSize: 1000 })
|
const response = await getRobotList({
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 1000,
|
||||||
|
connectStatus: '1',
|
||||||
|
...props.robotQuery,
|
||||||
|
})
|
||||||
robotOptions.value = (response.rows || []).map((robot) => ({
|
robotOptions.value = (response.rows || []).map((robot) => ({
|
||||||
label: `${robot.robotName || robot.robotId} (${robot.robotId})`,
|
label: `${robot.robotName || robot.robotId} (${robot.robotId})`,
|
||||||
value: robot.robotId,
|
value: robot.robotId,
|
||||||
|
currentMapId: robot.currentMapId,
|
||||||
}))
|
}))
|
||||||
|
} catch (error) {
|
||||||
|
robotOptions.value = []
|
||||||
|
robotLoadError.value = '机器人列表加载失败,请稍后重试'
|
||||||
} finally {
|
} finally {
|
||||||
robotLoading.value = false
|
robotLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const optionsOf = (role, slot) => toDeviceOptions((devicesByRole[role.roleKey] || []).filter((device) => (
|
const robotOptionsOf = (role) => {
|
||||||
slot.deviceKind == null || Number(device.deviceKind) === Number(slot.deviceKind)
|
const requiresTaskMap = (role.deviceSlots || []).some((slot) => Number(slot.deviceKind) === 1)
|
||||||
)))
|
if (!props.requiredMapId || !requiresTaskMap) return robotOptions.value
|
||||||
|
return robotOptions.value.filter((robot) => String(robot.currentMapId || '') === String(props.requiredMapId))
|
||||||
|
}
|
||||||
|
|
||||||
|
const optionsOf = (role, slot) => {
|
||||||
|
const member = memberOf(role)
|
||||||
|
const unavailableDeviceIds = new Set((role.deviceSlots || [])
|
||||||
|
.filter((otherSlot) => (
|
||||||
|
otherSlot.slotKey !== slot.slotKey
|
||||||
|
&& (!slot.allowReuse || !otherSlot.allowReuse)
|
||||||
|
))
|
||||||
|
.map((otherSlot) => member.devices[otherSlot.slotKey])
|
||||||
|
.filter(Boolean))
|
||||||
|
return toDeviceOptions((devicesByRole[role.roleKey] || []).filter((device) => (
|
||||||
|
(slot.deviceKind == null || Number(device.deviceKind) === Number(slot.deviceKind))
|
||||||
|
&& (!unavailableDeviceIds.has(device.deviceId) || member.devices[slot.slotKey] === device.deviceId)
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
const loadDevices = async (role, preserve = true) => {
|
const loadDevices = async (role, preserve = true) => {
|
||||||
const member = memberOf(role)
|
const member = memberOf(role)
|
||||||
if (!member.robotId) return
|
if (!member.robotId) {
|
||||||
|
devicesByRole[role.roleKey] = []
|
||||||
|
return
|
||||||
|
}
|
||||||
loadingRoleKey.value = role.roleKey
|
loadingRoleKey.value = role.roleKey
|
||||||
|
delete deviceLoadErrors[role.roleKey]
|
||||||
try {
|
try {
|
||||||
const response = await getRobotDevicesByRobotId(member.robotId)
|
const response = await getRobotDevicesByRobotId(member.robotId)
|
||||||
devicesByRole[role.roleKey] = Array.isArray(response.data) ? response.data : []
|
devicesByRole[role.roleKey] = Array.isArray(response.data) ? response.data : []
|
||||||
role.deviceSlots.forEach((slot) => {
|
;(role.deviceSlots || []).forEach((slot) => {
|
||||||
const options = optionsOf(role, slot)
|
const options = optionsOf(role, slot)
|
||||||
if (!preserve || !options.some((option) => option.value === member.devices[slot.slotKey])) {
|
if (!preserve || !options.some((option) => option.value === member.devices[slot.slotKey])) {
|
||||||
member.devices[slot.slotKey] = options.length === 1 ? options[0].value : ''
|
member.devices[slot.slotKey] = options.length === 1 ? options[0].value : ''
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
emitValue()
|
emitValue()
|
||||||
|
} catch (error) {
|
||||||
|
devicesByRole[role.roleKey] = []
|
||||||
|
deviceLoadErrors[role.roleKey] = `“${role.displayName}”的设备列表加载失败,请重新选择机器人`
|
||||||
} finally {
|
} finally {
|
||||||
loadingRoleKey.value = ''
|
loadingRoleKey.value = ''
|
||||||
}
|
}
|
||||||
@ -101,37 +142,61 @@ const loadDevices = async (role, preserve = true) => {
|
|||||||
const changeRobot = async (role, robotId) => {
|
const changeRobot = async (role, robotId) => {
|
||||||
const member = memberOf(role)
|
const member = memberOf(role)
|
||||||
member.robotId = robotId
|
member.robotId = robotId
|
||||||
member.devices = Object.fromEntries(role.deviceSlots.map((slot) => [slot.slotKey, '']))
|
member.devices = Object.fromEntries((role.deviceSlots || []).map((slot) => [slot.slotKey, '']))
|
||||||
await loadDevices(role, false)
|
await loadDevices(role, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialize = async () => {
|
const initialize = async () => {
|
||||||
|
Object.keys(deviceLoadErrors).forEach((roleKey) => delete deviceLoadErrors[roleKey])
|
||||||
const existing = clone(props.modelValue)
|
const existing = clone(props.modelValue)
|
||||||
assignments.value = props.roles.map((role) => existing.find((item) => item.roleKey === role.roleKey) || ({
|
assignments.value = props.roles.map((role) => {
|
||||||
roleKey: role.roleKey,
|
const existingAssignment = existing.find((item) => item.roleKey === role.roleKey)
|
||||||
members: [{
|
const existingMember = existingAssignment?.members?.[0]
|
||||||
memberKey: `${role.roleKey}_1`,
|
return {
|
||||||
robotId: role.legacyRobotId || '',
|
roleKey: role.roleKey,
|
||||||
devices: Object.fromEntries((role.deviceSlots || []).map((slot) => [slot.slotKey, slot.legacyDeviceId || ''])),
|
members: [{
|
||||||
}],
|
...existingMember,
|
||||||
}))
|
memberKey: `${role.roleKey}_1`,
|
||||||
|
robotId: existingMember?.robotId || role.legacyRobotId || '',
|
||||||
|
devices: Object.fromEntries((role.deviceSlots || []).map((slot) => [
|
||||||
|
slot.slotKey,
|
||||||
|
existingMember?.devices?.[slot.slotKey] || slot.legacyDeviceId || '',
|
||||||
|
])),
|
||||||
|
}],
|
||||||
|
}
|
||||||
|
})
|
||||||
emitValue()
|
emitValue()
|
||||||
await loadRobots()
|
await loadRobots()
|
||||||
await Promise.all(props.roles.filter((role) => memberOf(role).robotId).map((role) => loadDevices(role)))
|
await Promise.all(props.roles.filter((role) => memberOf(role).robotId).map((role) => loadDevices(role)))
|
||||||
}
|
}
|
||||||
|
|
||||||
const validate = () => {
|
const validate = () => {
|
||||||
|
const physicalDeviceUses = new Map()
|
||||||
for (const role of props.roles) {
|
for (const role of props.roles) {
|
||||||
const member = memberOf(role)
|
const member = memberOf(role)
|
||||||
if (role.required && !member.robotId) return `请为“${role.displayName}”选择机器人`
|
if (role.required && !member.robotId) return `请为“${role.displayName}”选择机器人`
|
||||||
|
if (!member.robotId) continue
|
||||||
for (const slot of role.deviceSlots || []) {
|
for (const slot of role.deviceSlots || []) {
|
||||||
if (slot.required && !member.devices[slot.slotKey]) return `请为“${role.displayName}”选择“${slot.displayName}”`
|
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 existingUse = physicalDeviceUses.get(physicalKey)
|
||||||
|
if (existingUse && (!slot.allowReuse || !existingUse.allowReuse)) {
|
||||||
|
return `“${existingUse.roleName} / ${existingUse.slotName}”和“${role.displayName} / ${slot.displayName}”不能使用同一个设备`
|
||||||
|
}
|
||||||
|
physicalDeviceUses.set(physicalKey, {
|
||||||
|
allowReuse: slot.allowReuse,
|
||||||
|
roleName: role.displayName,
|
||||||
|
slotName: slot.displayName,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (loadError.value) return loadError.value
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.roles, initialize, { immediate: true, deep: true })
|
watch([() => props.roles, () => props.robotQuery, () => props.requiredMapId], initialize, { immediate: true, deep: true })
|
||||||
defineExpose({ validate })
|
defineExpose({ validate })
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@
|
|||||||
@click="removeTask(task)" />
|
@click="removeTask(task)" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="robot">机器人:{{ task.robotName }}</div>
|
<div class="robot">主要机器人:{{ task.robotName || '执行时安排' }}</div>
|
||||||
<el-progress :color="customColorMethod"
|
<el-progress :color="customColorMethod"
|
||||||
:percentage="parseFloat(taskRunningInfo[task.id]?.progress?.toFixed(2)) || 0" />
|
:percentage="parseFloat(taskRunningInfo[task.id]?.progress?.toFixed(2)) || 0" />
|
||||||
</div>
|
</div>
|
||||||
@ -44,7 +44,7 @@
|
|||||||
<div class="id">ID: {{ runTask.taskId }}</div>
|
<div class="id">ID: {{ runTask.taskId }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="robot">
|
<div class="robot">
|
||||||
<div>机器人:{{ runTask.robotName }}</div>
|
<div>主要机器人:{{ runTask.robotName || '按流程角色安排' }}</div>
|
||||||
<div>开始时间: {{ formatDate(runTask.startTime) }}</div>
|
<div>开始时间: {{ formatDate(runTask.startTime) }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -84,7 +84,9 @@
|
|||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column align="center" label="机器人" prop="robotName" show-overflow-tooltip />
|
<el-table-column align="center" label="主要机器人" prop="robotName" show-overflow-tooltip>
|
||||||
|
<template #default="scope">{{ scope.row.robotName || '按流程角色安排' }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column align="center" label="开始时间" prop="startTime">
|
<el-table-column align="center" label="开始时间" prop="startTime">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
{{ formatDate(scope.row.startTime) }}
|
{{ formatDate(scope.row.startTime) }}
|
||||||
@ -117,17 +119,10 @@
|
|||||||
<el-dialog title="添加任务" v-model="open" width="500px" append-to-body>
|
<el-dialog title="添加任务" v-model="open" width="500px" append-to-body>
|
||||||
<el-form ref="runTaskRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="runTaskRef" :model="form" :rules="rules" label-width="100px">
|
||||||
<el-form-item label="选择任务" prop="taskId">
|
<el-form-item label="选择任务" prop="taskId">
|
||||||
<el-select v-model="form.taskId" placeholder="请选择任务" clearable style="width: 100%"
|
<el-select v-model="form.taskId" placeholder="请选择任务" clearable style="width: 100%">
|
||||||
@change="taskChange">
|
|
||||||
<el-option v-for="task in taskList" :key="task.id" :label="task.taskName" :value="task.id" />
|
<el-option v-for="task in taskList" :key="task.id" :label="task.taskName" :value="task.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="选择机器人" prop="robotId">
|
|
||||||
<el-select v-model="form.robotId" placeholder="请选择机器人" clearable style="width: 100%">
|
|
||||||
<el-option v-for="robot in robotList" :key="robot.id" :label="robot.robotName"
|
|
||||||
:value="robot.id" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="备注" prop="remark">
|
<el-form-item label="备注" prop="remark">
|
||||||
<el-input type="textarea" v-model="form.remark" />
|
<el-input type="textarea" v-model="form.remark" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -145,7 +140,12 @@
|
|||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog title="本次执行安排" v-model="startDialogVisible" width="560px" append-to-body>
|
<el-dialog title="本次执行安排" v-model="startDialogVisible" width="560px" append-to-body>
|
||||||
<RuntimeAssignmentsEditor ref="runtimeEditorRef" v-model="runtimeAssignments" :roles="runtimeRoles" />
|
<RuntimeAssignmentsEditor
|
||||||
|
ref="runtimeEditorRef"
|
||||||
|
v-model="runtimeAssignments"
|
||||||
|
:roles="runtimeRoles"
|
||||||
|
:required-map-id="runtimeMapId"
|
||||||
|
/>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="startDialogVisible = false">取消</el-button>
|
<el-button @click="startDialogVisible = false">取消</el-button>
|
||||||
<el-button type="primary" :loading="startSubmitting" @click="confirmStartTask">开始执行</el-button>
|
<el-button type="primary" :loading="startSubmitting" @click="confirmStartTask">开始执行</el-button>
|
||||||
@ -159,16 +159,17 @@ import taskSteps from "./task-steps.vue";
|
|||||||
import taskLog from "./task-log.vue";
|
import taskLog from "./task-log.vue";
|
||||||
import { useContainerHeight } from "@/hooks/tableHeight";
|
import { useContainerHeight } from "@/hooks/tableHeight";
|
||||||
import { getTaskList, getWaypointByTaskId } from "@/api/inspection/task";
|
import { getTaskList, getWaypointByTaskId } from "@/api/inspection/task";
|
||||||
import { getRobotList } from "@/api/inspection/robot";
|
|
||||||
import { onMounted, onUnmounted } from "vue";
|
import { onMounted, onUnmounted } from "vue";
|
||||||
import { addRunTask, getRunTaskList, startRunTask, pauseRunTask, stopRunTask, resumeRunTask, deleteRunTask, getTaskLogListApi } from "@/api/inspection/runTask";
|
import { addRunTask, getRunTaskList, startRunTask, pauseRunTask, stopRunTask, resumeRunTask, deleteRunTask, getTaskLogListApi } from "@/api/inspection/runTask";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { formatDate } from "@/utils/index";
|
import { formatDate } from "@/utils/index";
|
||||||
import { debounce } from 'lodash'; // 引入 lodash 的防抖函数
|
import { debounce } from 'lodash'; // 引入 lodash 的防抖函数
|
||||||
import { getFlowParamsApi } from '@/api/device/terminal'
|
|
||||||
import { getDetect } from '@/api/test/detect'
|
|
||||||
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
||||||
import { getResourceRoles, mergeResourceRoleDefinitions, normalizeFlowResourceSchema } from '@/utils/flowResources'
|
import {
|
||||||
|
createRuntimeAssignments,
|
||||||
|
firstAssignedRobotId,
|
||||||
|
loadTaskRuntimeRoles,
|
||||||
|
} from '@/utils/flowExecution'
|
||||||
|
|
||||||
const topContainerRef = ref();
|
const topContainerRef = ref();
|
||||||
const containerHeight = useContainerHeight(topContainerRef);
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
@ -179,6 +180,7 @@ const pendingStartTask = ref(null)
|
|||||||
const runtimeRoles = ref([])
|
const runtimeRoles = ref([])
|
||||||
const runtimeAssignments = ref([])
|
const runtimeAssignments = ref([])
|
||||||
const runtimeEditorRef = ref()
|
const runtimeEditorRef = ref()
|
||||||
|
const runtimeMapId = ref('')
|
||||||
|
|
||||||
const taskStatusMap = {
|
const taskStatusMap = {
|
||||||
'0': '已完成',
|
'0': '已完成',
|
||||||
@ -191,17 +193,13 @@ const taskStatusMap = {
|
|||||||
|
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
taskId: null,
|
taskId: null,
|
||||||
robotId: null,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
taskId: [{ required: true, message: '请选择任务', trigger: 'change' }],
|
taskId: [{ required: true, message: '请选择任务', trigger: 'change' }],
|
||||||
robotId: [{ required: true, message: '请选择机器人', trigger: 'change' }],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const taskList = ref([]);
|
const taskList = ref([]);
|
||||||
const robotList = ref([]);
|
|
||||||
|
|
||||||
const runTaskList = ref([]);
|
const runTaskList = ref([]);
|
||||||
|
|
||||||
const getTaskData = () => {
|
const getTaskData = () => {
|
||||||
@ -213,30 +211,12 @@ const getTaskData = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getRobotData = (mapId = null) => {
|
|
||||||
getRobotList({
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 10000,
|
|
||||||
currentMapId: mapId
|
|
||||||
}).then((res) => {
|
|
||||||
robotList.value = res.rows;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const open = ref(false);
|
const open = ref(false);
|
||||||
|
|
||||||
const addTask = () => {
|
const addTask = () => {
|
||||||
open.value = true;
|
open.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const taskChange = (value) => {
|
|
||||||
const task = taskList.value.find(item => item.id === value)
|
|
||||||
const mapId = task.mapId
|
|
||||||
form.robotId = null;
|
|
||||||
robotList.value = []
|
|
||||||
getRobotData(mapId)
|
|
||||||
}
|
|
||||||
|
|
||||||
const runTaskRef = ref();
|
const runTaskRef = ref();
|
||||||
/**
|
/**
|
||||||
* 确定添加执行任务
|
* 确定添加执行任务
|
||||||
@ -347,25 +327,16 @@ const startTask = async (task) => {
|
|||||||
ElMessage.warning('当前任务没有关联流程编排')
|
ElMessage.warning('当前任务没有关联流程编排')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const response = await getFlowParamsApi(taskDefinition.taskConfigId)
|
try {
|
||||||
const definitions = await Promise.all((response.rows || []).map(async (item) => {
|
const roles = await loadTaskRuntimeRoles(taskDefinition.taskConfigId)
|
||||||
const flowResponse = await getDetect(item.itemId)
|
runtimeAssignments.value = createRuntimeAssignments(roles, task.robotIdentity)
|
||||||
return flowResponse.data?.flowData
|
runtimeMapId.value = taskDefinition.mapId || ''
|
||||||
? getResourceRoles(normalizeFlowResourceSchema(JSON.parse(flowResponse.data.flowData)))
|
runtimeRoles.value = roles
|
||||||
: []
|
pendingStartTask.value = task
|
||||||
}))
|
startDialogVisible.value = true
|
||||||
const roles = mergeResourceRoleDefinitions(definitions)
|
} catch (error) {
|
||||||
runtimeAssignments.value = roles.map((role, index) => ({
|
ElMessage.error(error.message || '工作流执行资源加载失败')
|
||||||
roleKey: role.roleKey,
|
}
|
||||||
members: [{
|
|
||||||
memberKey: `${role.roleKey}_1`,
|
|
||||||
robotId: index === 0 ? task.robotId || '' : '',
|
|
||||||
devices: {}
|
|
||||||
}]
|
|
||||||
}))
|
|
||||||
runtimeRoles.value = roles
|
|
||||||
pendingStartTask.value = task
|
|
||||||
startDialogVisible.value = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +348,7 @@ const confirmStartTask = async () => {
|
|||||||
}
|
}
|
||||||
startSubmitting.value = true
|
startSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
const robotId = runtimeAssignments.value.flatMap(item => item.members).find(member => member.robotId)?.robotId || ''
|
const robotId = firstAssignedRobotId(runtimeAssignments.value)
|
||||||
const res = await startRunTask(pendingStartTask.value.id, {
|
const res = await startRunTask(pendingStartTask.value.id, {
|
||||||
robotId,
|
robotId,
|
||||||
runtimeAssignments: runtimeAssignments.value
|
runtimeAssignments: runtimeAssignments.value
|
||||||
@ -534,7 +505,6 @@ const handleOpenLog = async (row) => {
|
|||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTaskData();
|
getTaskData();
|
||||||
getRobotData();
|
|
||||||
getList();
|
getList();
|
||||||
getHistoryList();
|
getHistoryList();
|
||||||
subscribeDebounced(true)
|
subscribeDebounced(true)
|
||||||
|
|||||||
@ -183,10 +183,12 @@ import {
|
|||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { formatDate } from "@/utils/index";
|
import { formatDate } from "@/utils/index";
|
||||||
import { debounce } from 'lodash'; // 引入 lodash 的防抖函数
|
import { debounce } from 'lodash'; // 引入 lodash 的防抖函数
|
||||||
import { getFlowParamsApi } from '@/api/device/terminal'
|
|
||||||
import { getDetect } from '@/api/test/detect'
|
|
||||||
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
||||||
import { getResourceRoles, mergeResourceRoleDefinitions, normalizeFlowResourceSchema } from '@/utils/flowResources'
|
import {
|
||||||
|
createRuntimeAssignments,
|
||||||
|
firstAssignedRobotId,
|
||||||
|
loadTaskRuntimeRoles,
|
||||||
|
} from '@/utils/flowExecution'
|
||||||
|
|
||||||
const topContainerRef = ref();
|
const topContainerRef = ref();
|
||||||
const containerHeight = useContainerHeight(topContainerRef);
|
const containerHeight = useContainerHeight(topContainerRef);
|
||||||
@ -367,17 +369,15 @@ const startTask = async (task) => {
|
|||||||
ElMessage.warning('当前任务没有关联流程编排')
|
ElMessage.warning('当前任务没有关联流程编排')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const response = await getFlowParamsApi(taskDefinition.taskConfigId)
|
try {
|
||||||
const definitions = await Promise.all((response.rows || []).map(async (item) => {
|
const roles = await loadTaskRuntimeRoles(taskDefinition.taskConfigId)
|
||||||
const flowResponse = await getDetect(item.itemId)
|
runtimeAssignments.value = createRuntimeAssignments(roles)
|
||||||
return flowResponse.data?.flowData
|
runtimeRoles.value = roles
|
||||||
? getResourceRoles(normalizeFlowResourceSchema(JSON.parse(flowResponse.data.flowData)))
|
pendingStartTask.value = task
|
||||||
: []
|
startDialogVisible.value = true
|
||||||
}))
|
} catch (error) {
|
||||||
runtimeRoles.value = mergeResourceRoleDefinitions(definitions)
|
ElMessage.error(error.message || '工作流执行资源加载失败')
|
||||||
runtimeAssignments.value = []
|
}
|
||||||
pendingStartTask.value = task
|
|
||||||
startDialogVisible.value = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ const confirmStartTask = async () => {
|
|||||||
}
|
}
|
||||||
startSubmitting.value = true
|
startSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
const robotId = runtimeAssignments.value.flatMap(item => item.members).find(member => member.robotId)?.robotId || ''
|
const robotId = firstAssignedRobotId(runtimeAssignments.value)
|
||||||
const res = await startTaskinstance(pendingStartTask.value.id, {
|
const res = await startTaskinstance(pendingStartTask.value.id, {
|
||||||
robotId,
|
robotId,
|
||||||
runtimeAssignments: runtimeAssignments.value
|
runtimeAssignments: runtimeAssignments.value
|
||||||
|
|||||||
@ -68,9 +68,11 @@ import { ref, watch } from "vue";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { addValueProperty, formatTableData } from "@/utils/flow";
|
import { addValueProperty, formatTableData } from "@/utils/flow";
|
||||||
import { getExecuteRunParams, projectExecute } from "@/api/is/project/index.js";
|
import { getExecuteRunParams, projectExecute } from "@/api/is/project/index.js";
|
||||||
import { getDetect } from '@/api/test/detect'
|
|
||||||
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
||||||
import { getResourceRoles, mergeResourceRoleDefinitions, normalizeFlowResourceSchema } from '@/utils/flowResources'
|
import {
|
||||||
|
firstAssignedRobotId,
|
||||||
|
loadFlowItemRuntimeRoles,
|
||||||
|
} from '@/utils/flowExecution'
|
||||||
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -96,13 +98,8 @@ const getProjectParams = async () => {
|
|||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const data = parseConfig(res.data)
|
const data = parseConfig(res.data)
|
||||||
formData.value.tableData = data
|
formData.value.tableData = data
|
||||||
const definitions = await Promise.all(data.map(async (item) => {
|
runtimeAssignments.value = []
|
||||||
const response = await getDetect(item.itemId)
|
roles.value = await loadFlowItemRuntimeRoles(data)
|
||||||
return response.data?.flowData
|
|
||||||
? getResourceRoles(normalizeFlowResourceSchema(JSON.parse(response.data.flowData)))
|
|
||||||
: []
|
|
||||||
}))
|
|
||||||
roles.value = mergeResourceRoleDefinitions(definitions)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,7 +128,7 @@ const confirm = () => {
|
|||||||
ElMessage.warning(assignmentError)
|
ElMessage.warning(assignmentError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const robotId = runtimeAssignments.value.flatMap(item => item.members).find(member => member.robotId)?.robotId || ''
|
const robotId = firstAssignedRobotId(runtimeAssignments.value)
|
||||||
const res = await projectExecute({
|
const res = await projectExecute({
|
||||||
runParams,
|
runParams,
|
||||||
projectId: props.projectId,
|
projectId: props.projectId,
|
||||||
@ -160,7 +157,11 @@ watch(
|
|||||||
() => props.drawer,
|
() => props.drawer,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
getProjectParams()
|
getProjectParams().catch((error) => {
|
||||||
|
roles.value = []
|
||||||
|
runtimeAssignments.value = []
|
||||||
|
ElMessage.error(error.message || '工作流执行资源加载失败')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -68,9 +68,11 @@ import { emitter } from "@/utils/eventBus";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { getFlowParamsApi } from "@/api/device/terminal.js";
|
import { getFlowParamsApi } from "@/api/device/terminal.js";
|
||||||
import { taskExecute } from "@/api/test/config"
|
import { taskExecute } from "@/api/test/config"
|
||||||
import { getDetect } from '@/api/test/detect'
|
|
||||||
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
||||||
import { getResourceRoles, mergeResourceRoleDefinitions, normalizeFlowResourceSchema } from '@/utils/flowResources'
|
import {
|
||||||
|
firstAssignedRobotId,
|
||||||
|
loadFlowItemRuntimeRoles,
|
||||||
|
} from '@/utils/flowExecution'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
drawer: Boolean,
|
drawer: Boolean,
|
||||||
@ -101,12 +103,8 @@ const getFlowParams = async () => {
|
|||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const data = parseConfig(res.rows)
|
const data = parseConfig(res.rows)
|
||||||
formData.value.tableData = data
|
formData.value.tableData = data
|
||||||
const definitions = await Promise.all(data.map(async (item) => {
|
runtimeAssignments.value = []
|
||||||
const response = await getDetect(item.itemId)
|
roles.value = await loadFlowItemRuntimeRoles(data)
|
||||||
if (!response.data?.flowData) return []
|
|
||||||
return getResourceRoles(normalizeFlowResourceSchema(JSON.parse(response.data.flowData)))
|
|
||||||
}))
|
|
||||||
roles.value = mergeResourceRoleDefinitions(definitions)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -135,7 +133,7 @@ const confirm = () => {
|
|||||||
ElMessage.warning(assignmentError)
|
ElMessage.warning(assignmentError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const robotId = runtimeAssignments.value.flatMap(item => item.members).find(member => member.robotId)?.robotId || ''
|
const robotId = firstAssignedRobotId(runtimeAssignments.value)
|
||||||
const res = await taskExecute({
|
const res = await taskExecute({
|
||||||
runParams,
|
runParams,
|
||||||
taskId: props.currentRow.id,
|
taskId: props.currentRow.id,
|
||||||
@ -159,7 +157,11 @@ watch(
|
|||||||
() => props.drawer,
|
() => props.drawer,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
getFlowParams()
|
getFlowParams().catch((error) => {
|
||||||
|
roles.value = []
|
||||||
|
runtimeAssignments.value = []
|
||||||
|
ElMessage.error(error.message || '工作流执行资源加载失败')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -341,17 +341,14 @@ import {
|
|||||||
getTaskParamsById,
|
getTaskParamsById,
|
||||||
listConfig,
|
listConfig,
|
||||||
taskConfig,
|
taskConfig,
|
||||||
taskExecute,
|
|
||||||
updateConfig,
|
updateConfig,
|
||||||
} from "@/api/test/config";
|
} from "@/api/test/config";
|
||||||
|
|
||||||
import { flowExecute } from "@/api/flow/flow";
|
|
||||||
import TableSearch from "@/components/TableSearch/index.vue";
|
import TableSearch from "@/components/TableSearch/index.vue";
|
||||||
import draggable from "vuedraggable";
|
import draggable from "vuedraggable";
|
||||||
import { listDetect } from "@/api/test/detect.js";
|
import { listDetect } from "@/api/test/detect.js";
|
||||||
import { Tools, Delete } from "@element-plus/icons-vue";
|
import { Tools, Delete } from "@element-plus/icons-vue";
|
||||||
import { listGroup } from "@/api/system/group.js";
|
import { listGroup } from "@/api/system/group.js";
|
||||||
import { listTerminal } from "@/api/device/terminal.js";
|
|
||||||
import Run from "./Run.vue";
|
import Run from "./Run.vue";
|
||||||
import { ref, reactive, toRefs, onMounted } from "vue";
|
import { ref, reactive, toRefs, onMounted } from "vue";
|
||||||
|
|
||||||
@ -415,7 +412,6 @@ function cancel() {
|
|||||||
taskExecuteOpen.value = false;
|
taskExecuteOpen.value = false;
|
||||||
taskConfigOpen.value = false;
|
taskConfigOpen.value = false;
|
||||||
executeOpen.value = false;
|
executeOpen.value = false;
|
||||||
selectedTerminal.value = "";
|
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,46 +586,6 @@ const submitTaskForm = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatCode = (arr) => {
|
|
||||||
return arr.map((item) => ({
|
|
||||||
itemId: item.detectId,
|
|
||||||
params: item.params.reduce((acc, param) => {
|
|
||||||
acc[param.paramEnName] = param.sourceValue;
|
|
||||||
return acc;
|
|
||||||
}, {}),
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTaskExecute = (formEl) => {
|
|
||||||
if (!selectedTerminal.value) {
|
|
||||||
proxy.$modal.msgError("请选择执行终端");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const data = Object.assign(
|
|
||||||
{},
|
|
||||||
{ runParams: { robotId: selectedTerminal.value } },
|
|
||||||
{ taskId: currentRow.value.id }
|
|
||||||
);
|
|
||||||
// taskExecute(data).then((res) => {
|
|
||||||
// proxy.$modal.msgSuccess("下发成功")
|
|
||||||
// resetTaskList()
|
|
||||||
// executeOpen.value = false
|
|
||||||
// taskExecuteOpen.value = false
|
|
||||||
// currentRow.value = undefined
|
|
||||||
// selectedTerminal.value = ""
|
|
||||||
// })
|
|
||||||
|
|
||||||
flowExecute(data).then((res) => {
|
|
||||||
console.log("res", res);
|
|
||||||
proxy.$modal.msgSuccess("下发成功");
|
|
||||||
resetTaskList();
|
|
||||||
executeOpen.value = false;
|
|
||||||
taskExecuteOpen.value = false;
|
|
||||||
currentRow.value = undefined;
|
|
||||||
selectedTerminal.value = "";
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleTaskExecuteOpen = (row) => {
|
const handleTaskExecuteOpen = (row) => {
|
||||||
currentRow.value = row;
|
currentRow.value = row;
|
||||||
executeOpen.value = true;
|
executeOpen.value = true;
|
||||||
@ -661,24 +617,6 @@ function handleGetSystemGroup(row) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const terminalGroup = ref([]);
|
|
||||||
const selectedTerminal = ref("");
|
|
||||||
|
|
||||||
/** 获取设备终端列表 */
|
|
||||||
function handleGetTerminalGroup(row) {
|
|
||||||
listTerminal({
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 1000,
|
|
||||||
}).then((response) => {
|
|
||||||
terminalGroup.value = response.rows?.map((item) => {
|
|
||||||
return {
|
|
||||||
label: `${item.name}(${item.host}:${item.port})`,
|
|
||||||
value: item.id,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeFromB = (id) => {
|
const removeFromB = (id) => {
|
||||||
const index = taskRightList.value.findIndex(item => item.id === id)
|
const index = taskRightList.value.findIndex(item => item.id === id)
|
||||||
if (index !== -1) taskRightList.value.splice(index, 1)
|
if (index !== -1) taskRightList.value.splice(index, 1)
|
||||||
|
|||||||
@ -68,9 +68,11 @@ import { ref, watch } from "vue";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { addValueProperty, formatTableData } from "@/utils/flow";
|
import { addValueProperty, formatTableData } from "@/utils/flow";
|
||||||
import { getExecuteRunParams, projectExecute } from "@/api/vi/project.js"
|
import { getExecuteRunParams, projectExecute } from "@/api/vi/project.js"
|
||||||
import { getDetect } from '@/api/test/detect'
|
|
||||||
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
||||||
import { getResourceRoles, mergeResourceRoleDefinitions, normalizeFlowResourceSchema } from '@/utils/flowResources'
|
import {
|
||||||
|
firstAssignedRobotId,
|
||||||
|
loadFlowItemRuntimeRoles,
|
||||||
|
} from '@/utils/flowExecution'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
drawer: Boolean,
|
drawer: Boolean,
|
||||||
@ -94,13 +96,8 @@ const getProjectParams = async () => {
|
|||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
const data = parseConfig(res.data)
|
const data = parseConfig(res.data)
|
||||||
formData.value.tableData = data
|
formData.value.tableData = data
|
||||||
const definitions = await Promise.all(data.map(async (item) => {
|
runtimeAssignments.value = []
|
||||||
const response = await getDetect(item.itemId)
|
roles.value = await loadFlowItemRuntimeRoles(data)
|
||||||
return response.data?.flowData
|
|
||||||
? getResourceRoles(normalizeFlowResourceSchema(JSON.parse(response.data.flowData)))
|
|
||||||
: []
|
|
||||||
}))
|
|
||||||
roles.value = mergeResourceRoleDefinitions(definitions)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -129,7 +126,7 @@ const confirm = () => {
|
|||||||
ElMessage.warning(assignmentError)
|
ElMessage.warning(assignmentError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const robotId = runtimeAssignments.value.flatMap(item => item.members).find(member => member.robotId)?.robotId || ''
|
const robotId = firstAssignedRobotId(runtimeAssignments.value)
|
||||||
const res = await projectExecute({
|
const res = await projectExecute({
|
||||||
runParams,
|
runParams,
|
||||||
projectId: props.projectId,
|
projectId: props.projectId,
|
||||||
@ -158,7 +155,11 @@ watch(
|
|||||||
() => props.drawer,
|
() => props.drawer,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
getProjectParams()
|
getProjectParams().catch((error) => {
|
||||||
|
roles.value = []
|
||||||
|
runtimeAssignments.value = []
|
||||||
|
ElMessage.error(error.message || '工作流执行资源加载失败')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user