Merge remote-tracking branch 'origin/lxl-dev' into lxl-dev

This commit is contained in:
lixiaolong 2026-08-12 13:49:33 +08:00
commit 24b3acd2fd
5 changed files with 68 additions and 14 deletions

View File

@ -59,14 +59,50 @@ export const loadFlowItemRuntimeRoles = async (items = []) => {
return mergeResourceRoleDefinitions(roleGroups) return mergeResourceRoleDefinitions(roleGroups)
} }
/**
* Loads runtime roles without merging equal role keys across flow items.
* Task orchestration needs one independent assignment per detection item because
* two items may use different physical robots even when their workflows define
* the same logical role (for example, `default_robot`).
*/
export const loadFlowItemScopedRuntimeRoles = async (items = []) => {
if (items.some((item) => !item?.itemId)) throw new Error('任务编排中存在缺少流程项ID的数据')
if (!items.length) throw new Error('当前任务没有编排任何流程项')
const occurrences = new Map()
const roleGroups = await Promise.all(items.map(async (item) => {
const occurrence = (occurrences.get(String(item.itemId)) || 0) + 1
occurrences.set(String(item.itemId), occurrence)
const response = await getDetect(item.itemId)
const graph = parseFlowData(item.itemName || item.itemId, response.data?.flowData)
return getResourceRoles(graph).map((role) => ({
...clone([role])[0],
roleKey: `${item.itemId}:${occurrence}:${role.roleKey}`,
sourceRoleKey: role.roleKey,
itemId: item.itemId,
itemName: item.itemName || String(item.itemId),
displayName: `${item.itemName || item.itemId} / ${role.displayName}`,
}))
}))
return roleGroups.flat()
}
export const loadTaskRuntimeRoles = async (taskId) => { export const loadTaskRuntimeRoles = async (taskId) => {
if (!taskId) throw new Error('任务没有关联流程编排') if (!taskId) throw new Error('任务没有关联流程编排')
const response = await getFlowParamsApi(taskId) const response = await getFlowParamsApi(taskId)
return loadFlowItemRuntimeRoles(response.rows || []) return loadFlowItemRuntimeRoles(response.rows || [])
} }
export const loadTaskScopedRuntimeRoles = async (taskId) => {
if (!taskId) throw new Error('任务没有关联流程编排')
const response = await getFlowParamsApi(taskId)
return loadFlowItemScopedRuntimeRoles(response.rows || [])
}
export const createRuntimeAssignments = (roles = [], primaryRobotId = '') => roles.map((role, index) => ({ export const createRuntimeAssignments = (roles = [], primaryRobotId = '') => roles.map((role, index) => ({
roleKey: role.roleKey, roleKey: role.roleKey,
...(role.sourceRoleKey ? { sourceRoleKey: role.sourceRoleKey } : {}),
...(role.itemId != null ? { itemId: role.itemId } : {}),
members: [{ members: [{
memberKey: `${role.roleKey}_1`, memberKey: `${role.roleKey}_1`,
robotId: index === 0 ? primaryRobotId || role.legacyRobotId || '' : role.legacyRobotId || '', robotId: index === 0 ? primaryRobotId || role.legacyRobotId || '' : role.legacyRobotId || '',

View File

@ -154,6 +154,8 @@ const initialize = async () => {
const existingMember = existingAssignment?.members?.[0] const existingMember = existingAssignment?.members?.[0]
return { return {
roleKey: role.roleKey, roleKey: role.roleKey,
...(role.sourceRoleKey ? { sourceRoleKey: role.sourceRoleKey } : {}),
...(role.itemId != null ? { itemId: role.itemId } : {}),
members: [{ members: [{
...existingMember, ...existingMember,
memberKey: `${role.roleKey}_1`, memberKey: `${role.roleKey}_1`,

View File

@ -140,12 +140,14 @@
</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 <div class="start-dialog-content">
ref="runtimeEditorRef" <RuntimeAssignmentsEditor
v-model="runtimeAssignments" ref="runtimeEditorRef"
:roles="runtimeRoles" v-model="runtimeAssignments"
:required-map-id="runtimeMapId" :roles="runtimeRoles"
/> :required-map-id="runtimeMapId"
/>
</div>
<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>
@ -168,7 +170,7 @@ import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignments
import { import {
createRuntimeAssignments, createRuntimeAssignments,
firstAssignedRobotId, firstAssignedRobotId,
loadTaskRuntimeRoles, loadTaskScopedRuntimeRoles,
} from '@/utils/flowExecution' } from '@/utils/flowExecution'
const topContainerRef = ref(); const topContainerRef = ref();
@ -328,7 +330,7 @@ const startTask = async (task) => {
return return
} }
try { try {
const roles = await loadTaskRuntimeRoles(taskDefinition.taskConfigId) const roles = await loadTaskScopedRuntimeRoles(taskDefinition.taskConfigId)
runtimeAssignments.value = createRuntimeAssignments(roles, task.robotIdentity) runtimeAssignments.value = createRuntimeAssignments(roles, task.robotIdentity)
runtimeMapId.value = taskDefinition.mapId || '' runtimeMapId.value = taskDefinition.mapId || ''
runtimeRoles.value = roles runtimeRoles.value = roles
@ -653,4 +655,10 @@ onUnmounted(() => {
} }
} }
} }
.start-dialog-content {
max-height: 65vh;
padding-right: 6px;
overflow-y: auto;
}
</style> </style>

View File

@ -152,8 +152,10 @@
</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>
<div class="start-dialog-tip">手机和车辆沿用任务配置,这里只安排执行流程的机器人和设备。</div> <div class="start-dialog-content">
<RuntimeAssignmentsEditor ref="runtimeEditorRef" v-model="runtimeAssignments" :roles="runtimeRoles" /> <div class="start-dialog-tip">手机和车辆沿用任务配置,这里只安排执行流程的机器人和设备。</div>
<RuntimeAssignmentsEditor ref="runtimeEditorRef" v-model="runtimeAssignments" :roles="runtimeRoles" />
</div>
<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>
@ -187,7 +189,7 @@ import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignments
import { import {
createRuntimeAssignments, createRuntimeAssignments,
firstAssignedRobotId, firstAssignedRobotId,
loadTaskRuntimeRoles, loadTaskScopedRuntimeRoles,
} from '@/utils/flowExecution' } from '@/utils/flowExecution'
const topContainerRef = ref(); const topContainerRef = ref();
@ -370,7 +372,7 @@ const startTask = async (task) => {
return return
} }
try { try {
const roles = await loadTaskRuntimeRoles(taskDefinition.taskConfigId) const roles = await loadTaskScopedRuntimeRoles(taskDefinition.taskConfigId)
runtimeAssignments.value = createRuntimeAssignments(roles) runtimeAssignments.value = createRuntimeAssignments(roles)
runtimeRoles.value = roles runtimeRoles.value = roles
pendingStartTask.value = task pendingStartTask.value = task
@ -706,4 +708,10 @@ onUnmounted(() => {
color: var(--el-text-color-secondary); color: var(--el-text-color-secondary);
font-size: 13px; font-size: 13px;
} }
.start-dialog-content {
max-height: 65vh;
padding-right: 6px;
overflow-y: auto;
}
</style> </style>

View File

@ -71,7 +71,7 @@ import { taskExecute } from "@/api/test/config"
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue' import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
import { import {
firstAssignedRobotId, firstAssignedRobotId,
loadFlowItemRuntimeRoles, loadFlowItemScopedRuntimeRoles,
} from '@/utils/flowExecution' } from '@/utils/flowExecution'
const props = defineProps({ const props = defineProps({
@ -104,7 +104,7 @@ const getFlowParams = async () => {
const data = parseConfig(res.rows) const data = parseConfig(res.rows)
formData.value.tableData = data formData.value.tableData = data
runtimeAssignments.value = [] runtimeAssignments.value = []
roles.value = await loadFlowItemRuntimeRoles(data) roles.value = await loadFlowItemScopedRuntimeRoles(data)
} }
}; };