Compare commits
2 Commits
f4c594742e
...
c99cd51d34
| Author | SHA1 | Date | |
|---|---|---|---|
| c99cd51d34 | |||
| a2cccb09f1 |
85
src/views/flow/components/RuntimeParamsEditor.vue
Normal file
85
src/views/flow/components/RuntimeParamsEditor.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="formRef" :model="formData" label-width="auto">
|
||||||
|
<el-table v-if="formData.tableData.length" :data="formData.tableData" default-expand-all style="width: 100%">
|
||||||
|
<el-table-column type="expand">
|
||||||
|
<template #default="{ row: flowItem, $index: flowIndex }">
|
||||||
|
<el-table v-if="flowItem.config.length" :data="flowItem.config" row-key="name" default-expand-all>
|
||||||
|
<el-table-column prop="name" label="参数名称">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<span>{{ row.name }}</span>
|
||||||
|
<span v-if="row.required" class="required-mark">*</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="type" label="类型" width="90">
|
||||||
|
<template #default="{ row }"><el-tag size="small">{{ row.type }}</el-tag></template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="value" label="本次执行值" min-width="160">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-form-item
|
||||||
|
v-if="row.type !== 'object' && !row.type.includes('array')"
|
||||||
|
label=""
|
||||||
|
:prop="`tableData.${flowIndex}.config${row.propPath}value`"
|
||||||
|
:rules="row.required ? [{ required: true, message: `请输入${row.name}`, trigger: ['blur', 'change'] }] : []"
|
||||||
|
>
|
||||||
|
<el-input v-if="row.type === 'string'" v-model="row.value" />
|
||||||
|
<el-input-number v-else-if="row.type === 'number'" v-model="row.value" :controls="false" />
|
||||||
|
<el-switch v-else-if="row.type === 'boolean'" v-model="row.value" />
|
||||||
|
<el-input v-else v-model="row.value" />
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="执行顺序" prop="orderNum" width="90" align="center" />
|
||||||
|
<el-table-column label="流程项" prop="itemName" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
|
<el-empty v-else description="当前任务没有需要填写的运行参数" :image-size="52" />
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive, ref, watch } from 'vue'
|
||||||
|
import { addValueProperty, formatTableData } from '@/utils/flow'
|
||||||
|
|
||||||
|
const props = defineProps({ items: { type: Array, default: () => [] } })
|
||||||
|
const formRef = ref()
|
||||||
|
const formData = reactive({ tableData: [] })
|
||||||
|
|
||||||
|
const parseConfig = (config) => {
|
||||||
|
if (!config) return []
|
||||||
|
const schema = typeof config === 'string' ? JSON.parse(config) : config
|
||||||
|
return addValueProperty(JSON.parse(JSON.stringify(schema || [])))
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetItems = (items) => {
|
||||||
|
formData.tableData = (items || []).map((item, index) => ({
|
||||||
|
...item,
|
||||||
|
orderNum: item.orderNum ?? index + 1,
|
||||||
|
config: parseConfig(item.config),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const validate = async () => !formRef.value || formRef.value.validate().catch(() => false)
|
||||||
|
|
||||||
|
const getRunParams = () => {
|
||||||
|
const occurrences = new Map()
|
||||||
|
const result = {}
|
||||||
|
formData.tableData.forEach((item) => {
|
||||||
|
const itemId = String(item.itemId)
|
||||||
|
const occurrence = (occurrences.get(itemId) || 0) + 1
|
||||||
|
occurrences.set(itemId, occurrence)
|
||||||
|
result[`${itemId}:${occurrence}`] = formatTableData(item.config, {})
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => props.items, resetItems, { immediate: true, deep: true })
|
||||||
|
defineExpose({ validate, getRunParams, resetItems })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.required-mark { margin-left: 6px; color: var(--el-color-danger); }
|
||||||
|
:deep(.el-form-item) { margin-bottom: 0; }
|
||||||
|
:deep(.el-input-number) { width: 100%; }
|
||||||
|
</style>
|
||||||
@ -139,14 +139,17 @@
|
|||||||
<taskLog :list="logDialogData" :height="300" />
|
<taskLog :list="logDialogData" :height="300" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog title="本次执行安排" v-model="startDialogVisible" width="560px" append-to-body>
|
<el-dialog title="本次执行安排" v-model="startDialogVisible" width="820px" append-to-body>
|
||||||
<div class="start-dialog-content">
|
<div class="start-dialog-content">
|
||||||
|
<div class="start-section-title">机器人和设备</div>
|
||||||
<RuntimeAssignmentsEditor
|
<RuntimeAssignmentsEditor
|
||||||
ref="runtimeEditorRef"
|
ref="runtimeEditorRef"
|
||||||
v-model="runtimeAssignments"
|
v-model="runtimeAssignments"
|
||||||
:roles="runtimeRoles"
|
:roles="runtimeRoles"
|
||||||
:required-map-id="runtimeMapId"
|
:required-map-id="runtimeMapId"
|
||||||
/>
|
/>
|
||||||
|
<div class="start-section-title start-section-title--params">运行参数</div>
|
||||||
|
<RuntimeParamsEditor ref="runtimeParamsEditorRef" :items="runtimeParamItems" />
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="startDialogVisible = false">取消</el-button>
|
<el-button @click="startDialogVisible = false">取消</el-button>
|
||||||
@ -167,10 +170,12 @@ 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 RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
||||||
|
import RuntimeParamsEditor from '@/views/flow/components/RuntimeParamsEditor.vue'
|
||||||
|
import { getFlowParamsApi } from '@/api/device/terminal.js'
|
||||||
import {
|
import {
|
||||||
createRuntimeAssignments,
|
createRuntimeAssignments,
|
||||||
firstAssignedRobotId,
|
firstAssignedRobotId,
|
||||||
loadTaskScopedRuntimeRoles,
|
loadFlowItemScopedRuntimeRoles,
|
||||||
} from '@/utils/flowExecution'
|
} from '@/utils/flowExecution'
|
||||||
|
|
||||||
const topContainerRef = ref();
|
const topContainerRef = ref();
|
||||||
@ -183,6 +188,8 @@ const runtimeRoles = ref([])
|
|||||||
const runtimeAssignments = ref([])
|
const runtimeAssignments = ref([])
|
||||||
const runtimeEditorRef = ref()
|
const runtimeEditorRef = ref()
|
||||||
const runtimeMapId = ref('')
|
const runtimeMapId = ref('')
|
||||||
|
const runtimeParamItems = ref([])
|
||||||
|
const runtimeParamsEditorRef = ref()
|
||||||
|
|
||||||
const taskStatusMap = {
|
const taskStatusMap = {
|
||||||
'0': '已完成',
|
'0': '已完成',
|
||||||
@ -330,10 +337,13 @@ const startTask = async (task) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const roles = await loadTaskScopedRuntimeRoles(taskDefinition.taskConfigId)
|
const paramsResponse = await getFlowParamsApi(taskDefinition.taskConfigId)
|
||||||
|
const paramItems = paramsResponse.rows || []
|
||||||
|
const roles = await loadFlowItemScopedRuntimeRoles(paramItems)
|
||||||
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
|
||||||
|
runtimeParamItems.value = paramItems
|
||||||
pendingStartTask.value = task
|
pendingStartTask.value = task
|
||||||
startDialogVisible.value = true
|
startDialogVisible.value = true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -348,12 +358,18 @@ const confirmStartTask = async () => {
|
|||||||
ElMessage.warning(assignmentError)
|
ElMessage.warning(assignmentError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const paramsValid = await runtimeParamsEditorRef.value?.validate()
|
||||||
|
if (paramsValid === false) {
|
||||||
|
ElMessage.warning('请完整填写运行参数')
|
||||||
|
return
|
||||||
|
}
|
||||||
startSubmitting.value = true
|
startSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
const robotId = firstAssignedRobotId(runtimeAssignments.value)
|
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,
|
||||||
|
runParams: runtimeParamsEditorRef.value?.getRunParams() || {}
|
||||||
})
|
})
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ElMessage.success('任务已开始')
|
ElMessage.success('任务已开始')
|
||||||
@ -460,7 +476,10 @@ const subscribeDebounced = debounce(async (sub) => {
|
|||||||
const callback = (data) => {
|
const callback = (data) => {
|
||||||
if (data !== '500') {
|
if (data !== '500') {
|
||||||
if (data.status !== 0) {
|
if (data.status !== 0) {
|
||||||
let activeStep = pointList_runningTask.value[data.taskId].findIndex(item => item.detectItemId === data.itemId) || 0
|
const steps = pointList_runningTask.value[data.taskId] || []
|
||||||
|
let activeStep = Number.isInteger(data.itemOrder) && data.itemOrder > 0
|
||||||
|
? data.itemOrder - 1
|
||||||
|
: Math.max(steps.findIndex(item => item.detectItemId === data.itemId), 0)
|
||||||
if (data.progress == 100) {
|
if (data.progress == 100) {
|
||||||
activeStep += 1
|
activeStep += 1
|
||||||
}
|
}
|
||||||
@ -661,4 +680,15 @@ onUnmounted(() => {
|
|||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.start-section-title {
|
||||||
|
margin: 16px 0 10px;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-section-title--params {
|
||||||
|
margin-top: 22px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -151,10 +151,13 @@
|
|||||||
<taskLog :list="logDialogData" :height="300" />
|
<taskLog :list="logDialogData" :height="300" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<el-dialog title="本次执行安排" v-model="startDialogVisible" width="560px" append-to-body>
|
<el-dialog title="本次执行安排" v-model="startDialogVisible" width="820px" append-to-body>
|
||||||
<div class="start-dialog-content">
|
<div class="start-dialog-content">
|
||||||
<div class="start-dialog-tip">手机和车辆沿用任务配置,这里只安排执行流程的机器人和设备。</div>
|
<div class="start-dialog-tip">手机和车辆沿用任务配置,这里只安排执行流程的机器人和设备。</div>
|
||||||
|
<div class="start-section-title">机器人和设备</div>
|
||||||
<RuntimeAssignmentsEditor ref="runtimeEditorRef" v-model="runtimeAssignments" :roles="runtimeRoles" />
|
<RuntimeAssignmentsEditor ref="runtimeEditorRef" v-model="runtimeAssignments" :roles="runtimeRoles" />
|
||||||
|
<div class="start-section-title start-section-title--params">运行参数</div>
|
||||||
|
<RuntimeParamsEditor ref="runtimeParamsEditorRef" :items="runtimeParamItems" />
|
||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="startDialogVisible = false">取消</el-button>
|
<el-button @click="startDialogVisible = false">取消</el-button>
|
||||||
@ -186,10 +189,12 @@ 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 RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
import RuntimeAssignmentsEditor from '@/views/flow/components/RuntimeAssignmentsEditor.vue'
|
||||||
|
import RuntimeParamsEditor from '@/views/flow/components/RuntimeParamsEditor.vue'
|
||||||
|
import { getFlowParamsApi } from '@/api/device/terminal.js'
|
||||||
import {
|
import {
|
||||||
createRuntimeAssignments,
|
createRuntimeAssignments,
|
||||||
firstAssignedRobotId,
|
firstAssignedRobotId,
|
||||||
loadTaskScopedRuntimeRoles,
|
loadFlowItemScopedRuntimeRoles,
|
||||||
} from '@/utils/flowExecution'
|
} from '@/utils/flowExecution'
|
||||||
|
|
||||||
const topContainerRef = ref();
|
const topContainerRef = ref();
|
||||||
@ -201,6 +206,8 @@ const pendingStartTask = ref(null)
|
|||||||
const runtimeRoles = ref([])
|
const runtimeRoles = ref([])
|
||||||
const runtimeAssignments = ref([])
|
const runtimeAssignments = ref([])
|
||||||
const runtimeEditorRef = ref()
|
const runtimeEditorRef = ref()
|
||||||
|
const runtimeParamItems = ref([])
|
||||||
|
const runtimeParamsEditorRef = ref()
|
||||||
|
|
||||||
const taskStatusMap = {
|
const taskStatusMap = {
|
||||||
'0': '已完成',
|
'0': '已完成',
|
||||||
@ -372,9 +379,12 @@ const startTask = async (task) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const roles = await loadTaskScopedRuntimeRoles(taskDefinition.taskConfigId)
|
const paramsResponse = await getFlowParamsApi(taskDefinition.taskConfigId)
|
||||||
|
const paramItems = paramsResponse.rows || []
|
||||||
|
const roles = await loadFlowItemScopedRuntimeRoles(paramItems)
|
||||||
runtimeAssignments.value = createRuntimeAssignments(roles)
|
runtimeAssignments.value = createRuntimeAssignments(roles)
|
||||||
runtimeRoles.value = roles
|
runtimeRoles.value = roles
|
||||||
|
runtimeParamItems.value = paramItems
|
||||||
pendingStartTask.value = task
|
pendingStartTask.value = task
|
||||||
startDialogVisible.value = true
|
startDialogVisible.value = true
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -389,12 +399,18 @@ const confirmStartTask = async () => {
|
|||||||
ElMessage.warning(assignmentError)
|
ElMessage.warning(assignmentError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
const paramsValid = await runtimeParamsEditorRef.value?.validate()
|
||||||
|
if (paramsValid === false) {
|
||||||
|
ElMessage.warning('请完整填写运行参数')
|
||||||
|
return
|
||||||
|
}
|
||||||
startSubmitting.value = true
|
startSubmitting.value = true
|
||||||
try {
|
try {
|
||||||
const robotId = firstAssignedRobotId(runtimeAssignments.value)
|
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,
|
||||||
|
runParams: runtimeParamsEditorRef.value?.getRunParams() || {}
|
||||||
})
|
})
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ElMessage.success('任务已开始')
|
ElMessage.success('任务已开始')
|
||||||
@ -502,7 +518,10 @@ const subscribeDebounced = debounce(async (sub) => {
|
|||||||
console.log('data', data)
|
console.log('data', data)
|
||||||
if (data !== '500') {
|
if (data !== '500') {
|
||||||
if (data.status !== 0) {
|
if (data.status !== 0) {
|
||||||
let activeStep = pointList_runningTask.value[data.taskId].findIndex(item => item.detectItemId === data.itemId) || 0
|
const steps = pointList_runningTask.value[data.taskId] || []
|
||||||
|
let activeStep = Number.isInteger(data.itemOrder) && data.itemOrder > 0
|
||||||
|
? data.itemOrder - 1
|
||||||
|
: Math.max(steps.findIndex(item => item.detectItemId === data.itemId), 0)
|
||||||
if (data.progress == 100) {
|
if (data.progress == 100) {
|
||||||
activeStep += 1
|
activeStep += 1
|
||||||
}
|
}
|
||||||
@ -714,4 +733,15 @@ onUnmounted(() => {
|
|||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.start-section-title {
|
||||||
|
margin: 16px 0 10px;
|
||||||
|
color: var(--el-text-color-primary);
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.start-section-title--params {
|
||||||
|
margin-top: 22px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -124,9 +124,13 @@ const confirm = () => {
|
|||||||
.validate()
|
.validate()
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
const runParams = {}
|
const runParams = {}
|
||||||
|
const occurrences = new Map()
|
||||||
formData.value.tableData.forEach(item => {
|
formData.value.tableData.forEach(item => {
|
||||||
const data = formatTableData(item.config)
|
const data = formatTableData(item.config)
|
||||||
runParams[item.itemId] = data
|
const itemId = String(item.itemId)
|
||||||
|
const occurrence = (occurrences.get(itemId) || 0) + 1
|
||||||
|
occurrences.set(itemId, occurrence)
|
||||||
|
runParams[`${itemId}:${occurrence}`] = data
|
||||||
})
|
})
|
||||||
const assignmentError = runtimeEditorRef.value?.validate()
|
const assignmentError = runtimeEditorRef.value?.validate()
|
||||||
if (assignmentError) {
|
if (assignmentError) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user