From 339de35256661dcbe04cf3862cb5bab170f0cb10 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期四, 27 八月 2026 21:59:33 +0800
Subject: [PATCH] fix(test): preserve hidden configuration facts

---
 src/api/tests.ts         |    2 
 src/views/TestCreate.vue |  138 +++++----------------------------------------
 2 files changed, 17 insertions(+), 123 deletions(-)

diff --git a/src/api/tests.ts b/src/api/tests.ts
index c7df4ef..967ca14 100644
--- a/src/api/tests.ts
+++ b/src/api/tests.ts
@@ -40,7 +40,7 @@
   minValue: number | null
   maxValue: number | null
   unit: 'A' | 'V' | 'Ah' | 'Wh' | '℃'
-  severity: 'WARNING'
+  severity: string
 }
 
 export interface TestConfigurationPayload {
diff --git a/src/views/TestCreate.vue b/src/views/TestCreate.vue
index 4d22b64..6d3bfb7 100644
--- a/src/views/TestCreate.vue
+++ b/src/views/TestCreate.vue
@@ -1,6 +1,6 @@
 <script setup lang="ts">
 import { computed, onMounted, reactive, ref } from 'vue'
-import { ElMessage, ElMessageBox } from 'element-plus'
+import { ElMessage } from 'element-plus'
 import { useRoute, useRouter } from 'vue-router'
 import {
   createTest,
@@ -9,6 +9,7 @@
   updateTest,
   type TestConfigurationDetail,
   type TestConfigurationOptions,
+  type TestBatteryPayload,
   type TestPlanStepPayload,
 } from '@/api/tests'
 
@@ -21,6 +22,7 @@
   cabinetChannel: number | null
   collector: number | null
   expectedBarcode: string | null
+  preservedFields: TestBatteryPayload['fields']
   temperature1: string
   temperature2: string
   temperature3: string
@@ -34,7 +36,6 @@
 interface CustomChannelColumn {
   key: string
   label: string
-  fieldName: string
 }
 
 interface BatteryGroupOption {
@@ -50,6 +51,7 @@
   min: string
   max: string
   unit: 'A' | 'V' | 'Ah' | 'Wh' | '℃'
+  severity: string
 }
 
 const router = useRouter()
@@ -66,7 +68,6 @@
 const monitorTimeoutMinutes = ref(30)
 let batteryKey = 1
 let thresholdKey = 1
-let customChannelKey = 1
 
 const form = reactive({
   name: '',
@@ -81,7 +82,6 @@
 const testTypes = ref<Array<{ id: number; name: string }>>([])
 const ownersLoading = ref(false)
 const testTypesLoading = ref(false)
-const sensorChannels = Array.from({ length: 12 }, (_, index) => `S-${String(index + 1).padStart(2, '0')}`)
 const thresholdTypes: Array<{
   label: string
   value: string
@@ -95,13 +95,7 @@
   { label: '检测柜返回项(待现场验证)', value: 'CABINET_RETURN', unit: 'V' as const, disabled: true },
 ]
 const fixedSensorFields = ['temperature1', 'temperature2', 'temperature3', 'positive1', 'positive2', 'negative1', 'negative2'] as const
-type FixedSensorField = typeof fixedSensorFields[number]
-const reservedChannelLabels = ['主温度通道', '温度通道 2', '温度通道 3', '正电位主通道', '正电位通道 2', '负电位主通道', '负电位通道 2']
 const customChannelColumns = ref<CustomChannelColumn[]>([])
-const fixedFieldNames: Record<FixedSensorField, string> = {
-  temperature1: 'temperature1', temperature2: 'temperature2', temperature3: 'temperature3',
-  positive1: 'positive1', positive2: 'positive2', negative1: 'negative1', negative2: 'negative2',
-}
 const batteryGroupOptions = ref<BatteryGroupOption[]>([])
 const cabinetOptions = computed(() => {
   const cabinets = new Map<number, string>()
@@ -118,7 +112,7 @@
 function createBatteryRow(batteryNo = '', groupId: number | null = null): BatteryRow {
   return {
     key: batteryKey++, selected: false, groupId, batteryNo, cabinet: null, cabinetChannel: null, collector: null,
-    expectedBarcode: null,
+    expectedBarcode: null, preservedFields: [],
     temperature1: '', temperature2: '', temperature3: '', positive1: '', positive2: '', negative1: '', negative2: '',
     customChannels: Object.fromEntries(customChannelColumns.value.map(column => [column.key, ''])),
   }
@@ -127,7 +121,7 @@
 function createThresholdRow(type = ''): ThresholdRow {
   return {
     key: thresholdKey++, selected: false, type, min: '', max: '',
-    unit: thresholdTypes.find(item => item.value === type)?.unit || 'V',
+    unit: thresholdTypes.find(item => item.value === type)?.unit || 'V', severity: 'WARNING',
   }
 }
 
@@ -196,21 +190,6 @@
   batteries.value = batteries.value.filter(item => !item.selected)
 }
 
-function getSensorSelections(item: BatteryRow) {
-  return [
-    ...fixedSensorFields.map(field => ({ id: field, value: item[field] })),
-    ...customChannelColumns.value.map(column => ({ id: `custom:${column.key}`, value: item.customChannels[column.key] || '' })),
-  ]
-}
-
-function clearSensorSelection(item: BatteryRow, fieldId: string) {
-  if (fieldId.startsWith('custom:')) {
-    item.customChannels[fieldId.slice(7)] = ''
-    return
-  }
-  item[fieldId as FixedSensorField] = ''
-}
-
 function channelsForCabinet(cabinetId: number | null) {
   if (!cabinetId) return []
   return (configurationOptions.value?.channels || []).filter(channel => channel.cabinetId === cabinetId)
@@ -220,69 +199,12 @@
   return batteries.value.some(other => other.key !== item.key && other.cabinetChannel === channelId)
 }
 
-function isSensorChannelUsed(item: BatteryRow, fieldId: string, channel: string) {
-  if (!item.collector) return false
-  return batteries.value.some(other => {
-    if (other.key !== item.key && other.collector !== item.collector) return false
-    return getSensorSelections(other).some(selection => {
-      if (other.key === item.key && selection.id === fieldId) return false
-      return selection.value === channel
-    })
-  })
-}
-
 function handleCabinetChange(item: BatteryRow) {
   item.cabinetChannel = null
 }
 
-function handleCollectorChange(item: BatteryRow) {
-  if (!item.collector) {
-    getSensorSelections(item).forEach(selection => clearSensorSelection(item, selection.id))
-    return
-  }
-  const occupiedChannels = new Set(
-    batteries.value
-      .filter(other => other.key !== item.key && other.collector === item.collector)
-      .flatMap(other => getSensorSelections(other).map(selection => selection.value).filter(Boolean)),
-  )
-  const currentChannels = new Set<string>()
-  let clearedCount = 0
-  getSensorSelections(item).forEach(selection => {
-    if (!selection.value) return
-    if (occupiedChannels.has(selection.value) || currentChannels.has(selection.value)) {
-      clearSensorSelection(item, selection.id)
-      clearedCount += 1
-      return
-    }
-    currentChannels.add(selection.value)
-  })
-  if (clearedCount) ElMessage.warning(`已清空 ${clearedCount} 个重复通道,请重新选择`)
-}
-
-async function addChannelField() {
-  try {
-    const result = await ElMessageBox.prompt('输入字段名称后,将在表格最后新增一个可选择采集器通道的列。', '添加采集器字段', {
-      confirmButtonText: '添加',
-      cancelButtonText: '取消',
-      inputPlaceholder: '例如:壳体温度通道',
-      inputValidator: (value: string) => {
-        const label = value.trim()
-        if (!label) return '请输入字段名称'
-        if (label.length > 16) return '字段名称不能超过 16 个字'
-        const normalizedLabel = label.toLocaleLowerCase()
-        const labelExists = [...reservedChannelLabels, ...customChannelColumns.value.map(column => column.label)]
-          .some(item => item.toLocaleLowerCase() === normalizedLabel)
-        return labelExists ? '字段名称已存在' : true
-      },
-    })
-    const label = result.value.trim()
-    const key = `custom-channel-${customChannelKey++}`
-    customChannelColumns.value.push({ key, label, fieldName: `custom:${label}` })
-    batteries.value.forEach(item => { item.customChannels[key] = '' })
-    ElMessage.success(`已添加“${label}”通道列`)
-  } catch {
-    // 用户取消输入时保持当前配置。
-  }
+function addChannelField() {
+  ElMessage.info('采集器通道结构待现场验证')
 }
 
 function applyOptions(options: TestConfigurationOptions) {
@@ -314,17 +236,6 @@
   monitorTimeoutMinutes.value = detail.monitorTimeoutMinutes || 30
   preservedPlanSteps.value = detail.planSteps || []
 
-  const fixedNames = new Set(Object.values(fixedFieldNames))
-  const customFieldNames = new Set<string>()
-  detail.batteries.forEach(battery => battery.fields.forEach(field => {
-    if (!fixedNames.has(field.fieldName)) customFieldNames.add(field.fieldName)
-  }))
-  customChannelColumns.value = [...customFieldNames].map(fieldName => ({
-    key: `custom-channel-${customChannelKey++}`,
-    label: fieldName.startsWith('custom:') ? fieldName.slice(7) : fieldName,
-    fieldName,
-  }))
-
   batteries.value = detail.batteries.map(battery => {
     const row = createBatteryRow(battery.batteryNo, battery.groupId)
     const channel = configurationOptions.value?.channels.find(item => item.channelId === battery.binding.channelId)
@@ -332,16 +243,14 @@
     row.cabinetChannel = battery.binding.channelId
     row.collector = battery.collectorId
     row.expectedBarcode = battery.binding.expectedBarcode
-    const values = new Map(battery.fields.map(field => [field.fieldName, field.fieldValue]))
-    fixedSensorFields.forEach(field => { row[field] = values.get(fixedFieldNames[field]) || '' })
-    customChannelColumns.value.forEach(column => { row.customChannels[column.key] = values.get(column.fieldName) || '' })
+    row.preservedFields = battery.fields
     return row
   })
   thresholds.value = detail.thresholds.map(item => ({
     key: thresholdKey++, selected: false, type: item.metricCode,
     min: item.minValue === null ? '' : String(item.minValue),
     max: item.maxValue === null ? '' : String(item.maxValue),
-    unit: item.unit,
+    unit: item.unit, severity: item.severity || 'WARNING',
   }))
 }
 
@@ -393,21 +302,12 @@
       const value = batteries.value[index][field]
       if (value === null || value === undefined || !String(value).trim()) return `第 ${index + 1} 行请选择${label}`
     }
-    if (!batteries.value[index].collector && getSensorSelections(batteries.value[index]).some(item => item.value)) {
-      return `第 ${index + 1} 行配置采集器通道前请先选择采集器`
-    }
   }
 
   const groupIds = new Set(batteries.value.map(item => item.groupId))
   if (groupIds.size !== 1) return '同一测试只能选择一个电池组'
   const cabinetChannels = batteries.value.map(item => item.cabinetChannel)
   if (new Set(cabinetChannels).size !== cabinetChannels.length) return '同一检测柜通道不可重复绑定'
-
-  const collectorChannels = batteries.value.flatMap(item => [
-    ...fixedSensorFields.map(field => item[field]),
-    ...customChannelColumns.value.map(column => item.customChannels[column.key]),
-  ].filter(Boolean).map(channel => `${item.collector}/${channel}`))
-  if (new Set(collectorChannels).size !== collectorChannels.length) return '同一采集器的采集通道不可重复'
 
   if (!thresholds.value.length) return '至少需要配置一项预警阈值'
   for (let index = 0; index < thresholds.value.length; index += 1) {
@@ -419,13 +319,7 @@
 }
 
 function buildBatteryFields(item: BatteryRow) {
-  const fixedFields = fixedSensorFields
-    .filter(field => item[field])
-    .map(field => ({ fieldName: fixedFieldNames[field], fieldValue: item[field] }))
-  const customFields = customChannelColumns.value
-    .filter(column => item.customChannels[column.key])
-    .map(column => ({ fieldName: column.fieldName, fieldValue: item.customChannels[column.key] }))
-  return [...fixedFields, ...customFields]
+  return item.preservedFields
 }
 
 async function submit() {
@@ -459,7 +353,7 @@
         minValue: item.min === '' ? null : Number(item.min),
         maxValue: item.max === '' ? null : Number(item.max),
         unit: item.unit,
-        severity: 'WARNING' as const,
+        severity: item.severity,
       })),
     }
     if (testId.value) await updateTest({ ...payload, testId: testId.value })
@@ -506,7 +400,7 @@
       </header>
       <div class="section-actions">
         <div><button class="primary-button" type="button" @click="openBatteryDialog"><el-icon><Plus /></el-icon>添加电池</button><button class="secondary-button" type="button" @click="addChannelField"><el-icon><Plus /></el-icon>添加项</button><button class="secondary-button danger" type="button" @click="removeBatteries"><el-icon><Delete /></el-icon>删除所选</button></div>
-        <span>至少配置一块电池 · 同一采集器通道不可重复</span>
+        <span>至少配置一块电池 · 采集器通道结构待现场验证</span>
       </div>
       <div class="config-table-wrap">
         <table class="config-table battery-table" :style="{ minWidth: `${1700 + customChannelColumns.length * 150}px` }">
@@ -521,12 +415,12 @@
               <td><el-input v-model="item.batteryNo" disabled placeholder="电池号" /></td>
               <td><el-select v-model="item.cabinet" placeholder="选择" @change="handleCabinetChange(item)"><el-option v-for="option in cabinetOptions" :key="option.id" :label="option.label" :value="option.id" /></el-select></td>
               <td><el-select v-model="item.cabinetChannel" clearable :disabled="!item.cabinet" :placeholder="item.cabinet ? '选择' : '请先选择检测柜'"><el-option v-for="option in channelsForCabinet(item.cabinet)" :key="option.channelId" :label="isCabinetChannelUsed(item, option.channelId) ? `${option.displayNo || `CH-${option.chlid}`}(已占用)` : option.displayNo || `CH-${option.chlid}`" :value="option.channelId" :disabled="isCabinetChannelUsed(item, option.channelId)" /></el-select></td>
-              <td><el-select v-model="item.collector" clearable placeholder="选择(选填)" @change="handleCollectorChange(item)"><el-option v-for="option in collectorOptions" :key="option.id" :label="option.label" :value="option.id" /></el-select></td>
+              <td><el-select v-model="item.collector" clearable placeholder="选择(选填)"><el-option v-for="option in collectorOptions" :key="option.id" :label="option.label" :value="option.id" /></el-select></td>
               <td v-for="field in fixedSensorFields" :key="field">
-                <el-select v-model="item[field]" clearable :disabled="!item.collector" :placeholder="item.collector ? '选择' : '请先选择采集器'"><el-option v-for="option in sensorChannels" :key="option" :label="isSensorChannelUsed(item, field, option) ? `${option}(已占用)` : option" :value="option" :disabled="isSensorChannelUsed(item, field, option)" /></el-select>
+                <el-select v-model="item[field]" disabled placeholder="待现场验证" />
               </td>
               <td v-for="column in customChannelColumns" :key="column.key">
-                <el-select v-model="item.customChannels[column.key]" clearable :disabled="!item.collector" :placeholder="item.collector ? '选择' : '请先选择采集器'"><el-option v-for="option in sensorChannels" :key="option" :label="isSensorChannelUsed(item, `custom:${column.key}`, option) ? `${option}(已占用)` : option" :value="option" :disabled="isSensorChannelUsed(item, `custom:${column.key}`, option)" /></el-select>
+                <el-select v-model="item.customChannels[column.key]" disabled placeholder="待现场验证" />
               </td>
             </tr>
             <tr v-if="!batteries.length"><td :colspan="12 + customChannelColumns.length" class="empty-row">尚未配置电池,请点击“添加电池”</td></tr>

--
Gitblit v1.7.1