yeg
2026-09-02 281c95751d05a7c18bb09950d067607d62a82682
修正控制台修订入口与删除语义

数据列表展示设备和服务器时间,旧编辑链接复用控制台,导入校验读取后端测试电池,删除改为当前有效视图移除。
4个文件已修改
37 ■■■■■ 已修改文件
src/api/tests.ts 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ConsoleDataListPanel.vue 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.ts 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/ConsoleDataImport.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/tests.ts
@@ -341,6 +341,10 @@
  energy: number | string | null
  deviceId: number
  channelId: number
  adapterId?: number
  adapterCode?: string
  devtype?: number
  subdevid?: number
}
export interface PersistedTestStep extends PersistedTestRecord {
src/components/ConsoleDataListPanel.vue
@@ -109,15 +109,18 @@
}
function mapRecord(record: PersistedTestRecord): DataRow {
  const deviceTime = formatTime(record.deviceTime || record.recordedAt)
  return emptyRow({ id: `${record.deviceId}:${record.channelId}:${record.sequenceId}`, recordNo: record.recordNo, batteryNo: record.batteryNo || '-', cycleNo: Number(record.cycleNo), stepNo: Number(record.stepNo), stepName: record.stepName || '-', sequenceId: Number(record.sequenceId), recordedAt: deviceTime, absoluteTime: deviceTime, serverReceivedAt: formatTime(record.serverReceivedAt), voltage: record.voltage == null ? '-' : Number(record.voltage).toFixed(4), current: record.current == null ? '-' : Number(record.current).toFixed(4), capacity: record.capacity == null ? '-' : Number(record.capacity).toFixed(4), energy: record.energy == null ? '-' : Number(record.energy).toFixed(4) })
  const identity = [record.adapterId, record.devtype, record.deviceId, record.subdevid, record.channelId, record.sequenceId].join(':')
  return emptyRow({ id: identity, recordNo: record.recordNo, batteryNo: record.batteryNo || '-', cycleNo: Number(record.cycleNo), stepNo: Number(record.stepNo), stepName: record.stepName || '-', sequenceId: Number(record.sequenceId), recordedAt: deviceTime, absoluteTime: deviceTime, serverReceivedAt: formatTime(record.serverReceivedAt), voltage: record.voltage == null ? '-' : Number(record.voltage).toFixed(4), current: record.current == null ? '-' : Number(record.current).toFixed(4), capacity: record.capacity == null ? '-' : Number(record.capacity).toFixed(4), energy: record.energy == null ? '-' : Number(record.energy).toFixed(4) })
}
function mapStep(record: PersistedTestStep): DataRow {
  const startedAt = formatTime(record.recordedAt)
  return emptyRow({ id: String(record.id), recordNo: record.recordNo, batteryNo: record.batteryNo, cycleNo: Number(record.cycleNo), stepNo: Number(record.stepNo), stepName: record.stepName || '-', actualStepLabel: record.actualStepLabel || `${record.stepNo} · ${record.stepName || '-'}`, sequenceId: Number(record.sequenceId || 0), recordedAt: startedAt, absoluteTime: formatTime(record.absoluteTime || record.recordedAt), stepDuration: record.stepDuration == null ? '-' : String(record.stepDuration), capacity: record.capacity == null ? '-' : Number(record.capacity).toFixed(4), energy: record.energy == null ? '-' : Number(record.energy).toFixed(4), startVoltage: record.startVoltage == null ? '-' : Number(record.startVoltage).toFixed(4), endVoltage: record.endVoltage == null ? '-' : Number(record.endVoltage).toFixed(4), chargePeakVoltage: record.chargePeakVoltage == null ? '-' : Number(record.chargePeakVoltage).toFixed(4), dischargeValleyVoltage: record.dischargeValleyVoltage == null ? '-' : Number(record.dischargeValleyVoltage).toFixed(4) })
  const identity = `step:${[record.adapterId, record.devtype, record.deviceId, record.subdevid, record.channelId, record.cycleNo, record.stepNo].join(':')}`
  return emptyRow({ id: identity, recordNo: record.recordNo, batteryNo: record.batteryNo, cycleNo: Number(record.cycleNo), stepNo: Number(record.stepNo), stepName: record.stepName || '-', actualStepLabel: record.actualStepLabel || `${record.stepNo} · ${record.stepName || '-'}`, sequenceId: Number(record.sequenceId || 0), recordedAt: startedAt, absoluteTime: formatTime(record.absoluteTime || record.recordedAt), serverReceivedAt: formatTime(record.serverReceivedAt), stepDuration: record.stepDuration == null ? '-' : String(record.stepDuration), capacity: record.capacity == null ? '-' : Number(record.capacity).toFixed(4), energy: record.energy == null ? '-' : Number(record.energy).toFixed(4), startVoltage: record.startVoltage == null ? '-' : Number(record.startVoltage).toFixed(4), endVoltage: record.endVoltage == null ? '-' : Number(record.endVoltage).toFixed(4), chargePeakVoltage: record.chargePeakVoltage == null ? '-' : Number(record.chargePeakVoltage).toFixed(4), dischargeValleyVoltage: record.dischargeValleyVoltage == null ? '-' : Number(record.dischargeValleyVoltage).toFixed(4) })
}
function mapCycle(record: PersistedTestCycle): DataRow {
  const startedAt = formatTime(record.recordedAt)
  return emptyRow({ id: String(record.id), recordNo: record.recordNo, batteryNo: record.batteryNo, cycleNo: Number(record.cycleNo), sequenceId: Number(record.sequenceId || 0), recordedAt: startedAt, absoluteTime: formatTime(record.absoluteTime || record.recordedAt), chargeCapacity: record.chargeCapacity == null ? '-' : Number(record.chargeCapacity).toFixed(4), dischargeCapacity: record.dischargeCapacity == null ? '-' : Number(record.dischargeCapacity).toFixed(4), efficiency: record.efficiency == null ? '-' : Number(record.efficiency).toFixed(2), chargeEnergy: record.chargeEnergy == null ? '-' : Number(record.chargeEnergy).toFixed(4), dischargeEnergy: record.dischargeEnergy == null ? '-' : Number(record.dischargeEnergy).toFixed(4) })
  const identity = `cycle:${[record.adapterId, record.devtype, record.deviceId, record.subdevid, record.channelId, record.cycleNo].join(':')}`
  return emptyRow({ id: identity, recordNo: record.recordNo, batteryNo: record.batteryNo, cycleNo: Number(record.cycleNo), sequenceId: Number(record.sequenceId || 0), recordedAt: startedAt, absoluteTime: formatTime(record.absoluteTime || record.recordedAt), serverReceivedAt: formatTime(record.serverReceivedAt), chargeCapacity: record.chargeCapacity == null ? '-' : Number(record.chargeCapacity).toFixed(4), dischargeCapacity: record.dischargeCapacity == null ? '-' : Number(record.dischargeCapacity).toFixed(4), efficiency: record.efficiency == null ? '-' : Number(record.efficiency).toFixed(2), chargeEnergy: record.chargeEnergy == null ? '-' : Number(record.chargeEnergy).toFixed(4), dischargeEnergy: record.dischargeEnergy == null ? '-' : Number(record.dischargeEnergy).toFixed(4) })
}
async function loadRecords() {
  loading.value = true
@@ -280,17 +283,17 @@
  const physicalIds = ids
  let result: { value: string }
  try {
    result = await ElMessageBox.prompt(`确认物理删除 ${ids.length} 条${activeTab.value}数据?删除后不可恢复。`, '删除确认', { inputPlaceholder: '请输入删除原因', inputValidator: value => (value.trim() ? true : '删除原因不能为空') })
    result = await ElMessageBox.prompt(`确认从当前有效视图移除 ${ids.length} 条${activeTab.value}数据?原始设备数据仍会保留。`, '移除数据', { inputPlaceholder: '请输入移除原因', inputValidator: value => (value.trim() ? true : '移除原因不能为空') })
  } catch {
    return
  }
  try {
    await submitConsoleDataAction(props.testId, { dataType: dataType.value, operationType: 'DELETE', scopeSummary: `物理删除${ids.length}条${activeTab.value}数据`, identitySummary: JSON.stringify(physicalIds), changesSummary: null, reason: result.value.trim(), overrides: physicalIds.map(stableIdentity => ({ stableIdentity, fieldValues: null, deleted: true })) })
    await submitConsoleDataAction(props.testId, { dataType: dataType.value, operationType: 'DELETE', scopeSummary: `从当前有效视图移除${ids.length}条${activeTab.value}数据`, identitySummary: JSON.stringify(physicalIds), changesSummary: null, reason: result.value.trim(), overrides: physicalIds.map(stableIdentity => ({ stableIdentity, fieldValues: null, deleted: true })) })
    if (activeTab.value === 'realtime') rows.value = rows.value.filter(row => !ids.includes(row.id))
    else if (activeTab.value === 'step') stepRows.value = stepRows.value.filter(row => !physicalIds.includes(row.id))
    else cycleRows.value = cycleRows.value.filter(row => !ids.includes(row.id))
    selectedIds.value = new Set()
    ElMessage.success(`已物理删除 ${ids.length} 条数据`)
    ElMessage.success(`已从当前有效视图移除 ${ids.length} 条数据`)
  } catch (error) {
    ElMessage.error(error instanceof Error ? error.message : '数据删除失败')
  }
@@ -411,6 +414,8 @@
            <th>电池</th>
            <th>循环号</th>
            <th>工步</th>
            <th>设备时间</th>
            <th>服务器接收时间</th>
            <th>工步时间</th>
            <th>容量(Ah)</th>
            <th>能量(Wh)</th>
@@ -425,6 +430,8 @@
            <th>记录编号</th>
            <th>电池</th>
            <th>循环号</th>
            <th>设备时间</th>
            <th>服务器接收时间</th>
            <th>充电容量(Ah)</th>
            <th>放电容量(Ah)</th>
            <th>充放电效率(%)</th>
@@ -479,6 +486,8 @@
              </td>
              <td>{{ row.cycleNo }}</td>
              <td>{{ row.stepNo }} · {{ row.stepName }}</td>
              <td>{{ row.recordedAt }}</td>
              <td>{{ row.serverReceivedAt }}</td>
              <td>
                <el-input v-if="editing && draftRows[row.id]" v-model="draftRows[row.id].stepDuration" size="small" />
                <span v-else>{{ row.stepDuration }}</span>
@@ -520,6 +529,8 @@
                <strong>{{ row.batteryNo }}</strong>
              </td>
              <td>{{ row.cycleNo }}</td>
              <td>{{ row.recordedAt }}</td>
              <td>{{ row.serverReceivedAt }}</td>
              <td>
                <el-input v-if="editing && draftRows[row.id]" v-model="draftRows[row.id].chargeCapacity" size="small" />
                <span v-else>{{ row.chargeCapacity }}</span>
@@ -546,7 +557,7 @@
            </tr></template
          >
          <tr v-if="!loading && !pagedRows.length">
            <td :colspan="activeTab === 'realtime' ? 14 : activeTab === 'step' ? 13 : 10" class="empty-cell">
            <td :colspan="activeTab === 'realtime' ? 14 : activeTab === 'step' ? 15 : 12" class="empty-cell">
              {{ loadError || '暂无检测柜记录' }}
            </td>
          </tr>
src/router/index.ts
@@ -49,7 +49,8 @@
        {
          path: 'test-list/:id/console/data/:recordId/edit',
          name: 'test-console-data-edit',
          component: () => import('@/views/ConsoleDataEdit.vue'),
          // 兼容旧链接,复用控制台后端修订入口,避免回退到浏览器演示状态。
          component: () => import('@/views/TestConsole.vue'),
          meta: { title: '修改测试数据' },
        },
        {
src/views/ConsoleDataImport.vue
@@ -3,7 +3,7 @@
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import * as XLSX from 'xlsx'
import { consoleDataRowsByTest, type ConsoleDataRow } from '@/stores/consoleTestData'
import type { ConsoleDataRow } from '@/stores/consoleTestData'
import { submitConsoleDataAction, type ConsoleDataType } from '@/api/consoleData'
import { getTestDetail } from '@/api/tests'
@@ -33,7 +33,7 @@
const numericHeaders = requiredHeaders.filter(header => !['记录编号', '电池号', '记录时间', '工步', '工步名称', '工步时间'].includes(header))
const validRows = computed(() => validatedRows.value.filter(row => row.errors.length === 0))
const failedRows = computed(() => validatedRows.value.filter(row => row.errors.length > 0))
const knownBatteries = computed(() => new Set((consoleDataRowsByTest[testId] || []).map(row => row.batteryNo)))
const knownBatteries = ref<Set<string>>(new Set())
function backToDataList() {
  router.push({ path: `/test-list/${testId}/console`, query: { tab: 'data-list', state: canImport.value ? 'ended' : 'running' } })
@@ -42,6 +42,7 @@
onMounted(async () => {
  try {
    const detail = await getTestDetail(testId)
    knownBatteries.value = new Set((detail.batteries || []).map(item => item.batteryNo))
    canImport.value = detail.receptionStatus === 'ENDED' && detail.testStatus === 'COMPLETED'
  } catch {
    canImport.value = false