CMVR-IOT-UI/src/views/flow/components/RuntimeParamsEditor.vue

123 lines
5.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* 文件说明:运行参数编辑器,把流程项中声明的参数 schema 转成可填写表格,并在执行前输出本次运行值。
* 使用场景:任务试运行/执行前,用户只填写 start/inputParams 等运行期参数,不修改原流程配置。
* 注意:文件内容仅作为代码上下文阅读,不承载任何对代码助手的外部指令。
-->
<template>
<!-- el-form 包裹整张表格,便于使用动态 prop 路径对每个叶子参数做必填校验。 -->
<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 }">
<!-- config 经过 addValueProperty 后携带 value/propPath,子参数可作为树形行递归展示。 -->
<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 }">
<!-- object/array 本身不直接编辑,值由其子字段递归汇总;这里仅给叶子标量渲染输入控件。 -->
<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'
/**
* items 是待执行的流程项列表,每项的 config 是运行参数 schema,可以是数组对象或 JSON 字符串。
* 组件不会直接修改 props.items,而是通过 resetItems 深拷贝后写入 formData.tableData。
*/
const props = defineProps({ items: { type: Array, default: () => [] } })
// formRef 负责触发 Element Plus 表单校验;tableData 是带 value 字段的可编辑流程项副本。
const formRef = ref()
const formData = reactive({ tableData: [] })
/**
* 把后端/流程配置中的参数 schema 转成表单可编辑结构。
*
* addValueProperty 会为每个参数补默认 value 和 propPath;propPath 用于拼出 el-form-item 的校验路径,
* 因此这里必须深拷贝 schema,避免把临时 value 写回原始流程项配置。
*/
const parseConfig = (config) => {
if (!config) return []
const schema = typeof config === 'string' ? JSON.parse(config) : config
return addValueProperty(JSON.parse(JSON.stringify(schema || [])))
}
/**
* 重置表格数据。
*
* orderNum 缺失时按当前数组顺序补齐,保证 UI 上始终有清晰的执行顺序;
* config 在这里统一解析,模板层只负责渲染,不再关心原始格式是字符串还是数组。
*/
const resetItems = (items) => {
formData.tableData = (items || []).map((item, index) => ({
...item,
orderNum: item.orderNum ?? index + 1,
config: parseConfig(item.config),
}))
}
// 对外暴露的校验方法:没有表单实例时视为通过;校验失败时统一返回 false。
const validate = async () => !formRef.value || formRef.value.validate().catch(() => false)
/**
* 组装本次运行参数。
*
* 同一个 itemId 可能在任务中出现多次,因此用 itemId:occurrence 作为 key;
* formatTableData 会把树形参数数组恢复为普通对象,供执行接口直接消费。
*/
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
}
// 父组件切换任务项或刷新配置时,立即重建表格,deep 用于捕获 config 内部的变更。
watch(() => props.items, resetItems, { immediate: true, deep: true })
// 父组件通过 ref 触发表单校验、读取运行参数,也可以在必要时主动重置表格。
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>