From 4780b1c1627e1588a5c09fd36c402c003ca01ca7 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期一, 07 九月 2026 00:00:19 +0800
Subject: [PATCH] 接入对比报表字段模板

---
 src/views/ReportCompareForm.vue |   24 +++++++++++++++++++++++-
 src/api/compareReports.ts       |    7 +++++++
 2 files changed, 30 insertions(+), 1 deletions(-)

diff --git a/src/api/compareReports.ts b/src/api/compareReports.ts
index 2dd46b3..4d295b8 100644
--- a/src/api/compareReports.ts
+++ b/src/api/compareReports.ts
@@ -68,6 +68,13 @@
   units: Record<string, string>
   displayUnits: Record<string, string>
 }
+export interface CompareFieldTemplate { id: number; name: string; type: string; fields: Array<{ key?: string; name: string; unit?: string; category?: string }>; creator: string; updatedAt: number }
+export async function listCompareFieldTemplates() {
+  return (await request<ApiResponse & { data: CompareFieldTemplate[] }>('/system/compare-report/templates')).data
+}
+export async function createCompareFieldTemplate(name: string, fields: CompareFieldTemplate['fields']) {
+  return (await request<ApiResponse & { id: number }>('/system/compare-report/templates', { method: 'POST', body: JSON.stringify({ name, fields }) })).id
+}
 
 /** 按报表新增权限读取检测完成测试中的可选来源。 */
 export async function getCompareSources() {
diff --git a/src/views/ReportCompareForm.vue b/src/views/ReportCompareForm.vue
index 26aedaf..a886623 100644
--- a/src/views/ReportCompareForm.vue
+++ b/src/views/ReportCompareForm.vue
@@ -12,6 +12,7 @@
 import type { CompareMetricKey, CompareTestSelection } from '@/stores/compareReports'
 import { compareSelectionKey, createCompareReport, editCompareReport, getCompareReport, getCompareSources, previewCompareReport, refreshCompareSource,
   type CompareCandidate, type CompareItem, type CompareSelection, type SavedCompareReport } from '@/api/compareReports'
+import { listCompareFieldTemplates, createCompareFieldTemplate, type CompareFieldTemplate } from '@/api/compareReports'
 import { compareMetricDefinitions as metricDefinitions, openCompareReportPrint } from '@/utils/compareReportPrint'
 import { compareChartOption } from '@/utils/compareReportChart'
 
@@ -76,11 +77,14 @@
 const selectedBatteryTemplateFieldIds = ref<number[]>([])
 
 const specialTemplateSelections = reactive<Record<string, string[]>>({})
+const persistedTemplates = ref<CompareFieldTemplate[]>([])
+const templateLoading = ref(false)
 
 const fieldTemplates = computed<FieldTemplate[]>(() => [
   { key: 'cycle', name: '循环寿命模板', fields: ['容量保持率', '能量效率', '循环次数', '内阻变化'] },
   { key: 'thermal', name: '热特性模板', fields: ['最高温度', '温差', '温升速率'] },
   ...Object.entries(specialTemplateSelections).map(([name, fields]) => ({ key: `saved:${name}`, name, fields })),
+  ...persistedTemplates.value.map(item => ({ key: `remote:${item.id}`, name: item.name, fields: item.fields.filter(field => field.category !== 'battery').map(field => field.name) })),
 ])
 
 const metricVisible = reactive<Record<CompareMetricKey, boolean>>({
@@ -127,6 +131,13 @@
   } finally {
     candidatesLoading.value = false
   }
+}
+
+async function loadFieldTemplates() {
+  templateLoading.value = true
+  try { persistedTemplates.value = await listCompareFieldTemplates() }
+  catch (error) { ElMessage.error(error instanceof Error ? error.message : '字段模板加载失败') }
+  finally { templateLoading.value = false }
 }
 
 function detailKey(item: SelectedTest) {
@@ -219,6 +230,7 @@
       canCreate.value = Boolean(info.permissions?.some(item => item === '*:*:*' || item === 'system:compare-report:add'))
       if (!canCreate.value) throw new Error('无新增对比报表权限')
       await loadCandidates()
+      await loadFieldTemplates()
     }
   } catch (error) { if (!cancelled) loadError.value = error instanceof Error ? error.message : '报表加载失败' }
   finally { if (!cancelled) reportLoading.value = false }
@@ -236,6 +248,14 @@
     detailFields.value.forEach(ensureDetailFieldValues)
   } catch (error) { previewError.value = error instanceof Error ? error.message : '曲线预览失败' }
   finally { previewLoading.value = false }
+}
+
+async function saveCurrentFieldTemplate() {
+  const result = await ElMessageBox.prompt('请输入模板名称', '保存对比字段模板', { inputValidator: value => value.trim() ? true : '请输入模板名称', confirmButtonText: '保存', cancelButtonText: '取消' })
+  const name = result.value.trim()
+  const fields = [...batteryFields.value.map(name => ({ name, category: 'battery', unit: '' })), ...specialFields.value.map(name => ({ name, category: 'special', unit: '' }))]
+  try { await createCompareFieldTemplate(name, fields); await loadFieldTemplates(); ElMessage.success('字段模板已保存') }
+  catch (error) { ElMessage.error(error instanceof Error ? error.message : '模板保存失败') }
 }
 
 function openAddTest() {
@@ -355,6 +375,8 @@
   } else {
     const nextFields = selectedTemplate.value.fields
     specialFields.value = nextFields.filter(field => !batteryFields.value.includes(field))
+    const remote = persistedTemplates.value.find(item => `remote:${item.id}` === selectedTemplateKey.value)
+    if (remote) batteryFields.value = remote.fields.filter(field => field.category === 'battery').map(field => field.name)
     detailFields.value.forEach(ensureDetailFieldValues)
   }
   templateDialogVisible.value = false
@@ -534,7 +556,7 @@
         <div v-else class="template-empty">暂无字段,请先到电池组字段管理中添加字段</div>
       </div>
       <el-radio-group v-else v-model="selectedTemplateKey" class="template-options"><el-radio v-for="item in fieldTemplates" :key="item.key" :value="item.key" border>{{ item.name }}({{ item.fields.join('、') }})</el-radio></el-radio-group>
-      <template #footer><div v-if="templateMode === 'battery'" class="battery-template-actions"><button class="primary-button" type="button" @click="applyFieldTemplate"><el-icon><Check /></el-icon>确认</button></div><div v-else><button class="secondary-button" type="button" @click="templateDialogVisible = false">取消</button><button class="primary-button" type="button" @click="applyFieldTemplate">应用字段</button></div></template>
+      <template #footer><div v-if="templateMode === 'battery'" class="battery-template-actions"><button class="secondary-button" type="button" @click="saveCurrentFieldTemplate" :disabled="templateLoading">保存为模板</button><button class="primary-button" type="button" @click="applyFieldTemplate"><el-icon><Check /></el-icon>确认</button></div><div v-else><button class="secondary-button" type="button" @click="saveCurrentFieldTemplate" :disabled="templateLoading">保存为模板</button><button class="secondary-button" type="button" @click="templateDialogVisible = false">取消</button><button class="primary-button" type="button" @click="applyFieldTemplate">应用字段</button></div></template>
     </el-dialog>
   </div>
 </template>

--
Gitblit v1.7.1