yeg
2026-08-29 536ad46e3902b3b81e6eb94d8f984a5ea1d5247b
支持模板名称编辑

在电池组模板编辑侧栏增加模板名称输入,保存当前模板时提交新名称并保持另存模板流程。
2个文件已修改
37 ■■■■■ 已修改文件
src/views/BatteryGroupForm.vue 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
tests/battery-group-persistence.contract.test.mjs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/BatteryGroupForm.vue
@@ -40,6 +40,7 @@
const templateSaving = ref(false)
const selectedFieldIds = ref<number[]>([])
const loadedTemplateFieldIds = ref<number[]>([])
const currentTemplateName = ref('')
let batteryKey = 1
const editingId = computed(() => Number(route.params.id) || null)
@@ -64,13 +65,16 @@
async function applyTemplate(templateId: number) {
  if (!templateId) {
    currentTemplateName.value = ''
    selectedFieldIds.value = []
    loadedTemplateFieldIds.value = []
    form.customFields = []
    return
  }
  try {
    currentTemplateName.value = templateOptions.value.find(item => item.id === templateId)?.name || ''
    const template = await getBatteryGroupTemplate(templateId)
    currentTemplateName.value = template.name
    selectedFieldIds.value = [...template.fieldIds]
    loadedTemplateFieldIds.value = [...template.fieldIds]
    syncSelectedFields()
@@ -83,6 +87,7 @@
  if (!editingId.value) return
  const target = await getBatteryGroupDetail(editingId.value)
  const templateId = target.templateFields[0]?.templateId || 0
  currentTemplateName.value = templateOptions.value.find(item => item.id === templateId)?.name || ''
  const templateFields = target.templateFields.map(field => ({
    key: `persisted-field-${field.batteryGroupFieldId}`,
    fieldId: field.batteryGroupFieldId,
@@ -134,10 +139,6 @@
  form.batteries.splice(index, 1)
}
function templateName(templateId: number) {
  return templateOptions.value.find(item => item.id === templateId)?.name || ''
}
async function saveTemplate() {
  if (!form.templateId) {
    ElMessage.warning('自定义字段请使用“另存模板”')
@@ -147,11 +148,19 @@
    ElMessage.warning('请至少选择一个模板字段')
    return
  }
  const name = currentTemplateName.value.trim()
  if (!name) {
    ElMessage.warning('模板名称不能为空')
    return
  }
  templateSaving.value = true
  try {
    await updateBatteryGroupTemplate(form.templateId, templateName(form.templateId), selectedFieldIds.value)
    await updateBatteryGroupTemplate(form.templateId, name, selectedFieldIds.value)
    currentTemplateName.value = name
    const option = templateOptions.value.find(item => item.id === form.templateId)
    if (option) option.name = name
    loadedTemplateFieldIds.value = [...selectedFieldIds.value]
    ElMessage.success(`模板“${templateName(form.templateId)}”已保存`)
    ElMessage.success(`模板“${name}”已保存`)
  } catch (error) {
    ElMessage.error(error instanceof Error ? error.message : '保存模板失败')
  } finally {
@@ -176,6 +185,7 @@
    const created = templateOptions.value.find(item => item.name === name)
    if (!created) throw new Error('模板已保存,但未能重新加载')
    form.templateId = created.id
    currentTemplateName.value = name
    loadedTemplateFieldIds.value = [...selectedFieldIds.value]
    ElMessage.success(`已另存为“${name}”`)
  } catch (error) {
@@ -271,7 +281,10 @@
      <aside class="template-panel" :aria-hidden="!templatePanelOpen">
        <header><div><strong>模板字段</strong><span>TEMPLATE FIELDS</span></div><button type="button" aria-label="关闭模板编辑" title="关闭" @click="templatePanelOpen = false"><el-icon><Close /></el-icon></button></header>
        <label class="template-select"><span>当前模板</span><el-select v-model="form.templateId" @change="applyTemplate"><el-option label="自定义" :value="0" /><el-option v-for="item in templateOptions" :key="item.id" :label="item.name" :value="item.id" /></el-select></label>
        <div class="template-meta">
          <label class="template-select"><span>当前模板</span><el-select v-model="form.templateId" @change="applyTemplate"><el-option label="自定义" :value="0" /><el-option v-for="item in templateOptions" :key="item.id" :label="item.name" :value="item.id" /></el-select></label>
          <label v-if="form.templateId" class="template-name"><span>模板名称</span><el-input v-model="currentTemplateName" maxlength="100" placeholder="输入模板名称" /></label>
        </div>
        <div class="field-checkbox-list">
          <el-checkbox-group v-if="templateFieldOptions.length" v-model="selectedFieldIds" class="field-checkbox-grid" @change="syncSelectedFields">
            <el-checkbox v-for="field in templateFieldOptions" :key="field.id" :value="field.id" :disabled="field.status === '禁用'" :title="`${field.name}(${field.type},${field.status})`">{{ field.name }}</el-checkbox>
@@ -331,7 +344,9 @@
.template-panel header strong { color: var(--ink); font-size: 15px; }
.template-panel header span { color: #82919d; font-size: 9px; }
.template-panel header > button { color: #52606d; }
.template-select { display: grid; grid-template-columns: 68px minmax(0, 1fr); align-items: center; gap: 8px; padding: 16px; border-bottom: 1px solid var(--line); }
.template-meta { border-bottom: 1px solid var(--line); }
.template-select, .template-name { display: grid; grid-template-columns: 68px minmax(0, 1fr); align-items: center; gap: 8px; padding: 16px 16px 0; }
.template-name { padding-bottom: 16px; }
.field-checkbox-list { min-height: 0; padding: 18px 16px; overflow-y: auto; overscroll-behavior: contain; }
.field-checkbox-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 15px 10px; }
.field-checkbox-grid :deep(.el-checkbox) { min-width: 0; margin: 0; overflow: hidden; }
tests/battery-group-persistence.contract.test.mjs
@@ -54,3 +54,9 @@
  assert.match(source, /field-\$\{field\.id\}/)
  assert.match(source, /customFieldValue/)
})
test('template editor submits the editable template name', () => {
  const source = fs.readFileSync(new URL('../src/views/BatteryGroupForm.vue', import.meta.url), 'utf8')
  assert.match(source, /currentTemplateName/)
  assert.match(source, /updateBatteryGroupTemplate\(form\.templateId, name, selectedFieldIds\.value\)/)
})