123 lines
5.8 KiB
Vue
123 lines
5.8 KiB
Vue
<!--
|
||
* 文件说明:运行参数编辑器,把流程项中声明的参数 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>
|