weizong song 1 month ago
parent 135158c4b7
commit 889c343f65

1
package-lock.json generated

@ -7,6 +7,7 @@
"": { "": {
"name": "czemc-budget-execution-frontend", "name": "czemc-budget-execution-frontend",
"version": "1.0.0", "version": "1.0.0",
"hasInstallScript": true,
"dependencies": { "dependencies": {
"@antv/g6": "^5.0.50", "@antv/g6": "^5.0.50",
"@element-plus/icons-vue": "^2.3.1", "@element-plus/icons-vue": "^2.3.1",

@ -207,8 +207,8 @@
<!-- 普通字段区域 --> <!-- 普通字段区域 -->
<template v-if="section.fields && Array.isArray(section.fields)"> <template v-if="section.fields && Array.isArray(section.fields)">
<el-form-item <el-form-item
v-for="field in section.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))" v-for="(field, fieldIndex) in section.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))"
:key="field.key" :key="`${sectionKey}-field-${field.key || 'field'}-${fieldIndex}`"
:label="field.label" :label="field.label"
:prop="field.key" :prop="field.key"
:required="field.required" :required="field.required"
@ -556,8 +556,8 @@
> >
<h4 class="round-title"> {{ round.round }} 轮支付</h4> <h4 class="round-title"> {{ round.round }} 轮支付</h4>
<el-form-item <el-form-item
v-for="field in round.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))" v-for="(field, fieldIndex) in round.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))"
:key="field.key" :key="`${sectionKey}-round-${roundIndex}-field-${field.key || 'field'}-${fieldIndex}`"
:label="field.label" :label="field.label"
:prop="field.key" :prop="field.key"
:required="field.required" :required="field.required"
@ -719,8 +719,8 @@
<table class="preview-kv"> <table class="preview-kv">
<tbody> <tbody>
<tr <tr
v-for="field in section.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))" v-for="(field, fieldIndex) in section.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))"
:key="field.key" :key="`${sectionKey}-preview-field-${field.key || 'field'}-${fieldIndex}`"
> >
<td class="preview-k">{{ field.label }}</td> <td class="preview-k">{{ field.label }}</td>
<td v-html="formatPreviewFieldValue(formData[field.key], field.element_type, field)"></td> <td v-html="formatPreviewFieldValue(formData[field.key], field.element_type, field)"></td>
@ -744,8 +744,8 @@
<table class="preview-kv"> <table class="preview-kv">
<tbody> <tbody>
<tr <tr
v-for="field in round.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))" v-for="(field, fieldIndex) in round.fields.filter(f => f.visible !== false && checkFieldDisplayConditions(f))"
:key="field.key" :key="`${sectionKey}-preview-round-${roundIndex}-field-${field.key || 'field'}-${fieldIndex}`"
> >
<td class="preview-k">{{ field.label }}</td> <td class="preview-k">{{ field.label }}</td>
<td v-html="formatPreviewFieldValue(formData[field.key], field.element_type, field)"></td> <td v-html="formatPreviewFieldValue(formData[field.key], field.element_type, field)"></td>
@ -3158,6 +3158,60 @@ const sortConfigByGroupOrder = async (config) => {
} }
} }
// key key
const normalizeTemplateFieldKeys = (config) => {
if (!config || typeof config !== 'object') return config
const usedKeys = new Set()
let autoKeySeed = 1
const nextAutoKey = () => {
let candidate = `field_${autoKeySeed++}`
while (usedKeys.has(candidate)) {
candidate = `field_${autoKeySeed++}`
}
return candidate
}
const normalizeOneField = (field) => {
if (!field || typeof field !== 'object') return
let baseKey = String(field.key || '').trim()
if (!baseKey) {
baseKey = nextAutoKey()
}
let finalKey = baseKey
let seq = 2
while (usedKeys.has(finalKey)) {
finalKey = `${baseKey}__${seq}`
seq += 1
}
field.key = finalKey
usedKeys.add(finalKey)
}
Object.keys(config).forEach(sectionKey => {
const section = config[sectionKey]
if (!section) return
if (Array.isArray(section.fields)) {
section.fields.forEach(normalizeOneField)
}
if (Array.isArray(section.rounds)) {
section.rounds.forEach(round => {
if (Array.isArray(round?.fields)) {
round.fields.forEach(normalizeOneField)
}
})
}
})
return config
}
// //
const loadTemplateForCategory = async (categoryId) => { const loadTemplateForCategory = async (categoryId) => {
try { try {
@ -3172,6 +3226,7 @@ const loadTemplateForCategory = async (categoryId) => {
// sort_order // sort_order
config = await sortConfigByGroupOrder(config) config = await sortConfigByGroupOrder(config)
config = normalizeTemplateFieldKeys(config)
templateConfig.value = config templateConfig.value = config
// options // options

@ -445,6 +445,7 @@ const normalizeFieldConfig = (config) => {
field.key = field.label.toLowerCase().replace(/\s+/g, '_') field.key = field.label.toLowerCase().replace(/\s+/g, '_')
} }
}) })
normalizeFieldKeysInList(section.fields)
} }
// payment rounds // payment rounds
@ -467,6 +468,7 @@ const normalizeFieldConfig = (config) => {
field.key = field.label.toLowerCase().replace(/\s+/g, '_') field.key = field.label.toLowerCase().replace(/\s+/g, '_')
} }
}) })
normalizeFieldKeysInList(round.fields)
} }
}) })
} }
@ -755,12 +757,64 @@ const deleteElement = (index) => {
}).catch(() => {}) }).catch(() => {})
} }
const getUniqueFieldKey = (baseKey, editingIndex = null) => {
const normalizedBase = String(baseKey || '').trim()
if (!normalizedBase) return ''
const usedKeys = new Set()
currentSectionFields.value.forEach((field, idx) => {
if (editingIndex !== null && idx === editingIndex) return
const key = String(field?.key || '').trim()
if (key) {
usedKeys.add(key)
}
})
if (!usedKeys.has(normalizedBase)) {
return normalizedBase
}
let seq = 2
let candidate = `${normalizedBase}__${seq}`
while (usedKeys.has(candidate)) {
seq += 1
candidate = `${normalizedBase}__${seq}`
}
return candidate
}
const normalizeFieldKeysInList = (fields = []) => {
const usedKeys = new Set()
let autoKeySeed = 1
fields.forEach((field) => {
if (!field || typeof field !== 'object') return
let baseKey = String(field.key || '').trim()
if (!baseKey) {
baseKey = `field_${autoKeySeed++}`
}
let candidate = baseKey
let seq = 2
while (usedKeys.has(candidate)) {
candidate = `${baseKey}__${seq}`
seq += 1
}
field.key = candidate
usedKeys.add(candidate)
})
return fields
}
// //
const onElementSelectChange = () => { const onElementSelectChange = () => {
const selectedElement = availableElements.value.find(e => e.id === elementForm.value.element_id) const selectedElement = availableElements.value.find(e => e.id === elementForm.value.element_id)
if (selectedElement) { if (selectedElement) {
elementForm.value.label = selectedElement.name elementForm.value.label = selectedElement.name
elementForm.value.key = `element_${selectedElement.id}` elementForm.value.key = getUniqueFieldKey(`element_${selectedElement.id}`, editingElementIndex.value)
// categorytypeelement_type // categorytypeelement_type
if (selectedElement.category === 'form_field') { if (selectedElement.category === 'form_field') {
@ -806,9 +860,12 @@ const saveElement = async () => {
return return
} }
if (!elementForm.value.key) { const baseKey = String(elementForm.value.key || '').trim() || `element_${selectedElement.id}`
elementForm.value.key = `element_${selectedElement.id}` const uniqueKey = getUniqueFieldKey(baseKey, editingElementIndex.value)
if (uniqueKey !== baseKey) {
ElMessage.warning(`字段键名重复,已自动调整为 ${uniqueKey}`)
} }
elementForm.value.key = uniqueKey
const element = { const element = {
key: elementForm.value.key, key: elementForm.value.key,
@ -1011,6 +1068,8 @@ const loadDefaultTemplateFromGroups = async () => {
return field return field
}) })
normalizeFieldKeysInList(fields)
// 使IDkeytitle // 使IDkeytitle
const sectionKey = group.code || `group_${group.id}` const sectionKey = group.code || `group_${group.id}`
config[sectionKey] = { config[sectionKey] = {
@ -1135,6 +1194,8 @@ const saveFieldConfig = () => {
return return
} }
normalizeFieldKeysInList(currentSectionFields.value)
// roundsrounds[0].fields // roundsrounds[0].fields
if (section.rounds && Array.isArray(section.rounds)) { if (section.rounds && Array.isArray(section.rounds)) {
if (section.rounds.length === 0) { if (section.rounds.length === 0) {
@ -1242,6 +1303,8 @@ const reloadGroupsOnly = async () => {
return field return field
}) })
normalizeFieldKeysInList(fields)
newConfig[sectionKey] = { newConfig[sectionKey] = {
title: group.name, title: group.name,
fields: fields, fields: fields,
@ -1927,4 +1990,3 @@ onMounted(async () => {
} }
} }
</style> </style>

Loading…
Cancel
Save