sub_flow 节点引入工作流修复与首页执行工作流重构

- 引入工作流列表字段兼容 flowName,选择弹窗卡片正常展示数据
- 生成次数 maxConcurrency 同步保存到 sub_flow 节点,回显兜底恢复
- valueSource 按后端契约统一 {nodeId, fieldName},表单展示/引用正确保存与回显
- 首页执行工作流 DSL 字段路径改为 .enumValues[i],支持引用上游输出与上传文件名
This commit is contained in:
2026-08-15 18:49:56 +08:00
parent 3b71f144c4
commit 41655fa825
14 changed files with 1620 additions and 356 deletions
@@ -32,39 +32,23 @@
</el-tooltip>
</div>
<div class="mf-array-flat">
<!-- 联合数组enumValues 多模板全部模板平铺固定条数不可增删 -->
<template v-if="isVariantArray">
<div v-for="(item, idx) in getVariantItems()" :key="idx" class="mf-variant">
<div class="mf-variant-head">
<!-- 数组元素直接遍历模板enumValues/attrs值与勾选均落在模板上
保存只留 enumValues 一份即可完整回显不依赖 value 实例 -->
<template v-for="(item, idx) in renderedArrayItems()" :key="idx">
<template v-if="isObjectDef(item)">
<div v-if="isVariantArray" class="mf-variant-head">
<span class="mf-variant-name">{{ variantLabel(idx) }}</span>
</div>
<template v-if="isObjectDef(item)">
<ModelField
v-for="(subDef, subKey) in item.attrs"
:key="subKey"
:field-def="subDef"
:path="path ? `${path}.value[${idx}].attrs.${subKey}` : String(subKey)"
:upstream-nodes="upstreamNodes"
/>
</template>
<el-input v-else :model-value="item" @input="(v: any) => setArrayPrimitive(idx, v)" size="small" />
</div>
</template>
<!-- 同构数组保持现有平铺逻辑 -->
<template v-else>
<template v-for="(item, idx) in getArrayValue()" :key="idx">
<template v-if="isObjectDef(item)">
<div v-if="getArrayValue().length > 1" class="mf-array-flat-index">#{{ idx + 1 }}</div>
<ModelField
v-for="(subDef, subKey) in item.attrs"
:key="subKey"
:field-def="subDef"
:path="path ? `${path}.value[${idx}].attrs.${subKey}` : String(subKey)"
:upstream-nodes="upstreamNodes"
/>
</template>
<el-input v-else :model-value="item" @input="(v: any) => setArrayPrimitive(idx, v)" size="small" />
<div v-else-if="renderedArrayItems().length > 1" class="mf-array-flat-index">#{{ idx + 1 }}</div>
<ModelField
v-for="(subDef, subKey) in item.attrs"
:key="subKey"
:field-def="subDef"
:path="path ? `${path}.enumValues[${idx}].attrs.${subKey}` : String(subKey)"
:upstream-nodes="upstreamNodes"
/>
</template>
<el-input v-else :model-value="getTemplatePrimitive(item)" @input="(v: any) => setTemplatePrimitive(item, v)" size="small" />
</template>
</div>
</div>
@@ -177,7 +161,6 @@
<script setup lang="ts">
import { computed, watch } from 'vue';
import { FolderOpened, List, QuestionFilled, Link } from '@element-plus/icons-vue';
import { deepClone, normalizeArrayItem } from './modelParamUtils';
defineOptions({ name: 'ModelField' });
@@ -312,22 +295,26 @@ const arrayTemplates = computed<any[]>(() => {
return [];
});
const getArrayValue = (): any[] => {
if (!def.value) return [];
if (!Array.isArray(def.value.value)) {
def.value.value = [];
}
// value 为空时(后端仅定义结构未给内容)用模板补一条空结构,保证字段可展示、可填写
if (def.value.value.length === 0 && arrayTemplates.value.length > 0) {
def.value.value.push(normalizeArrayItem(deepClone(arrayTemplates.value[0])));
}
return def.value.value;
};
const isObjectDef = (item: any) => !!item && typeof item === 'object' && item.type === 'object' && item.attrs && typeof item.attrs === 'object';
const setArrayPrimitive = (idx: number, val: any) => {
getArrayValue()[idx] = val ?? '';
// 数组渲染统一以模板(enumValues/attrs)为数据源:值与勾选均落在模板上,
// 不受 props 同步重建 localParams(深拷贝)影响,保存只留 enumValues 一份即可完整回显
const renderedArrayItems = (): any[] => {
const templates = arrayTemplates.value;
// 多模板(variant):懒填 type/role 标识值到模板(幂等),保证展示与保存有标识值
if (templates.length > 1) templates.forEach(autoFillVariant);
return templates;
};
// 原始值数组元素:值直接读写模板原始值对象上的 value
const getTemplatePrimitive = (item: any): any => {
if (!item || typeof item !== 'object') return '';
return item.value !== undefined ? item.value : item.defaultValue ?? '';
};
const setTemplatePrimitive = (item: any, v: any): void => {
if (!item || typeof item !== 'object') return;
item.value = v ?? '';
};
// ===== array:联合数组(enumValues 多模板)→ 全部模板平铺,固定条数,不可增删 =====
@@ -366,25 +353,6 @@ const autoFillVariant = (tpl: any): void => {
}
};
// 联合数组渲染条目:value 与 enumValues 模板按索引一一对应(懒补模板),保证固定条数
const getVariantItems = (): any[] => {
if (!isVariantArray.value || !def.value) return [];
const templates = Array.isArray(def.value.enumValues) ? def.value.enumValues : [];
if (!Array.isArray(def.value.value)) def.value.value = [];
templates.forEach((tpl: any, i: number) => {
const existing = def.value.value[i];
if (!existing || typeof existing !== 'object') {
const item = normalizeArrayItem(deepClone(tpl));
autoFillVariant(item);
def.value.value[i] = item;
}
});
if (def.value.value.length > templates.length) {
def.value.value = def.value.value.slice(0, templates.length);
}
return def.value.value;
};
const variantLabel = (idx: number): string => templateLabel(def.value?.enumValues?.[idx], idx);
</script>