From 1858334fbc347e284a55b29693a0695ec19694bf Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 02 九月 2026 22:08:34 +0800
Subject: [PATCH] 展示完整实时快照字段
---
src/api/tests.ts | 7 +++
src/components/ConsoleChartPanel.vue | 3 +
tests/test-console-step-chart.contract.test.mjs | 5 ++
src/components/ConsoleDataListPanel.vue | 49 ++++++++++++++++++------
4 files changed, 50 insertions(+), 14 deletions(-)
diff --git a/src/api/tests.ts b/src/api/tests.ts
index 0deaabf..f568da0 100644
--- a/src/api/tests.ts
+++ b/src/api/tests.ts
@@ -326,7 +326,7 @@
id: number | string
stableIdentity?: string
sampleId?: number
- sourceType?: 'CABINET' | 'COLLECTOR' | string
+ sourceType?: 'CABINET' | 'COLLECTOR' | 'SNAPSHOT' | string
metricCode?: string
metricValue?: number | string | null
unit?: string | null
@@ -340,6 +340,7 @@
stepName: string
stepType?: string
sequenceId: number
+ cabinetSequenceId?: number | null
recordedAt: string
absoluteTime: string
deviceTime?: string
@@ -348,6 +349,10 @@
current: number | string | null
capacity: number | string | null
energy: number | string | null
+ temperature?: number | string | null
+ positivePotential?: number | string | null
+ negativePotential?: number | string | null
+ extensionMeasurementsJson?: string | Record<string, unknown> | null
deviceId: number
channelId: number
adapterId?: number
diff --git a/src/components/ConsoleChartPanel.vue b/src/components/ConsoleChartPanel.vue
index cc3d2a0..db48b69 100644
--- a/src/components/ConsoleChartPanel.vue
+++ b/src/components/ConsoleChartPanel.vue
@@ -227,8 +227,10 @@
}
function metricMatches(metric: CompareMetricKey, record: PersistedTestRecord) {
+ const snapshot = record.sourceType === 'SNAPSHOT'
if (metric === 'voltage') return record.sourceType !== 'COLLECTOR' && record.voltage != null
if (metric === 'current') return record.sourceType !== 'COLLECTOR' && record.current != null
+ if (snapshot) return ({ temperature: record.temperature, positiveVoltage: record.positivePotential, negativeVoltage: record.negativePotential }[metric] != null)
if (record.sourceType !== 'COLLECTOR') return false
const code = String(record.metricCode || '').toUpperCase()
if (metric === 'temperature') return code === 'TEMPERATURE' || code.includes('TEMPERATURE')
@@ -240,6 +242,7 @@
function metricValue(metric: CompareMetricKey, record: PersistedTestRecord) {
if (metric === 'voltage') return Number(record.voltage)
if (metric === 'current') return Number(record.current)
+ if (record.sourceType === 'SNAPSHOT') return Number(({ temperature: record.temperature, positiveVoltage: record.positivePotential, negativeVoltage: record.negativePotential }[metric]))
return Number(record.metricValue)
}
diff --git a/src/components/ConsoleDataListPanel.vue b/src/components/ConsoleDataListPanel.vue
index aff4b9f..25a42fa 100644
--- a/src/components/ConsoleDataListPanel.vue
+++ b/src/components/ConsoleDataListPanel.vue
@@ -44,6 +44,10 @@
current: string
capacity: string
energy: string
+ temperature: string
+ positivePotential: string
+ negativePotential: string
+ extensionMeasurements: string
chargeCapacity: string
dischargeCapacity: string
efficiency: string
@@ -83,6 +87,9 @@
{ label: '电流(A)', value: 'current' },
{ label: '容量(Ah)', value: 'capacity' },
{ label: '能量(Wh)', value: 'energy' },
+ { label: '温度(℃)', value: 'temperature' },
+ { label: '正电位(V)', value: 'positivePotential' },
+ { label: '负电位(V)', value: 'negativePotential' },
]
: activeTab.value === 'step'
? [
@@ -111,13 +118,24 @@
: '-'
}
function emptyRow(base: Partial<DataRow>): DataRow {
- return { id: '', sourceType: 'CABINET', metricCode: '-', metricValue: '-', unit: '-', collectorCode: '-', channelCode: '-', recordNo: '', batteryNo: '', cycleNo: 0, stepNo: 0, stepName: '', actualStepLabel: '-', sequenceId: 0, recordedAt: '', absoluteTime: '', serverReceivedAt: '', stepDuration: '-', startVoltage: '-', endVoltage: '-', chargePeakVoltage: '-', dischargeValleyVoltage: '-', voltage: '-', current: '-', capacity: '-', energy: '-', chargeCapacity: '-', dischargeCapacity: '-', efficiency: '-', chargeEnergy: '-', dischargeEnergy: '-', ...base }
+ return { id: '', sourceType: 'CABINET', metricCode: '-', metricValue: '-', unit: '-', collectorCode: '-', channelCode: '-', recordNo: '', batteryNo: '', cycleNo: 0, stepNo: 0, stepName: '', actualStepLabel: '-', sequenceId: 0, recordedAt: '', absoluteTime: '', serverReceivedAt: '', stepDuration: '-', startVoltage: '-', endVoltage: '-', chargePeakVoltage: '-', dischargeValleyVoltage: '-', voltage: '-', current: '-', capacity: '-', energy: '-', temperature: '-', positivePotential: '-', negativePotential: '-', extensionMeasurements: '-', chargeCapacity: '-', dischargeCapacity: '-', efficiency: '-', chargeEnergy: '-', dischargeEnergy: '-', ...base }
}
function mapRecord(record: PersistedTestRecord): DataRow {
const deviceTime = formatTime(record.deviceTime || record.recordedAt)
const identity = record.stableIdentity || [record.adapterId, record.devtype, record.deviceId, record.subdevid, record.channelId, record.sequenceId].join(':')
const collector = record.sourceType === 'COLLECTOR'
- return emptyRow({ id: identity, sourceType: record.sourceType || 'CABINET', metricCode: record.metricCode || '-', metricValue: record.metricValue == null ? '-' : String(record.metricValue), unit: record.unit || '-', collectorCode: record.collectorCode || '-', channelCode: record.channelCode || '-', recordNo: record.recordNo, batteryNo: record.batteryNo || '-', cycleNo: Number(record.cycleNo || 0), stepNo: Number(record.stepNo || 0), stepName: collector ? '-' : (record.stepName || '-'), sequenceId: Number(record.sequenceId), recordedAt: deviceTime, absoluteTime: deviceTime, serverReceivedAt: formatTime(record.serverReceivedAt), voltage: collector ? '-' : (record.voltage == null ? '-' : Number(record.voltage).toFixed(4)), current: collector ? '-' : (record.current == null ? '-' : Number(record.current).toFixed(4)), capacity: collector ? '-' : (record.capacity == null ? '-' : Number(record.capacity).toFixed(4)), energy: collector ? '-' : (record.energy == null ? '-' : Number(record.energy).toFixed(4)) })
+ const snapshot = record.sourceType === 'SNAPSHOT'
+ const metricCode = String(record.metricCode || '').toUpperCase()
+ const extensionValue = record.metricValue == null ? '-' : String(record.metricValue)
+ const extension = (name: string) => collector && metricCode.includes(name) ? extensionValue : '-'
+ let extensionMeasurements = '-'
+ if (snapshot && record.extensionMeasurementsJson) {
+ try {
+ const parsed = typeof record.extensionMeasurementsJson === 'string' ? JSON.parse(record.extensionMeasurementsJson) : record.extensionMeasurementsJson
+ extensionMeasurements = Object.entries(parsed as Record<string, any>).map(([code, value]) => `${code}=${value?.value ?? value?.metricValue ?? '-'}${value?.unit ? ` ${value.unit}` : ''}`).join('; ') || '-'
+ } catch { extensionMeasurements = String(record.extensionMeasurementsJson) }
+ }
+ return emptyRow({ id: identity, sourceType: record.sourceType || 'CABINET', metricCode: record.metricCode || '-', metricValue: extensionValue, unit: record.unit || '-', collectorCode: record.collectorCode || '-', channelCode: record.channelCode || '-', recordNo: record.recordNo, batteryNo: record.batteryNo || '-', cycleNo: Number(record.cycleNo || 0), stepNo: Number(record.stepNo || 0), stepName: collector ? '-' : (record.stepName || '-'), sequenceId: Number(record.sequenceId || record.cabinetSequenceId || 0), recordedAt: deviceTime, absoluteTime: deviceTime, serverReceivedAt: formatTime(record.serverReceivedAt), voltage: collector ? '-' : (record.voltage == null ? '-' : Number(record.voltage).toFixed(4)), current: collector ? '-' : (record.current == null ? '-' : Number(record.current).toFixed(4)), capacity: collector ? '-' : (record.capacity == null ? '-' : Number(record.capacity).toFixed(4)), energy: collector ? '-' : (record.energy == null ? '-' : Number(record.energy).toFixed(4)), temperature: snapshot ? (record.temperature == null ? '-' : Number(record.temperature).toFixed(4)) : extension('TEMPERATURE'), positivePotential: snapshot ? (record.positivePotential == null ? '-' : Number(record.positivePotential).toFixed(4)) : extension('POSITIVE_POTENTIAL'), negativePotential: snapshot ? (record.negativePotential == null ? '-' : Number(record.negativePotential).toFixed(4)) : extension('NEGATIVE_POTENTIAL'), extensionMeasurements })
}
function mapStep(record: PersistedTestStep): DataRow {
const startedAt = formatTime(record.recordedAt)
@@ -206,8 +224,11 @@
function templateHeaders() {
return activeTab.value === 'cycle' ? ['记录编号', '电池号', '循环序号', '充放电容量(Ah)', '效率(%)', '能量(Wh)'] : activeTab.value === 'step' ? ['记录编号', '电池号', '循环序号', '工步序号', '工步', '工步时间', '容量(Ah)', '能量(Wh)', '起止电压(V)', '充电峰值电压(V)', '放电谷值电压(V)'] : ['记录编号', '电池号', '设备时间', '循环序号', '工步序号', '工步名称', '记录序号', '服务器接收时间', '电压(V)', '电流(A)', '容量(Ah)', '能量(Wh)']
}
+function realtimeTemplateHeaders() {
+ return [...templateHeaders(), '温度(℃)', '正电位(V)', '负电位(V)']
+}
function downloadTemplate() {
- const worksheet = XLSX.utils.aoa_to_sheet([templateHeaders()])
+ const worksheet = XLSX.utils.aoa_to_sheet([activeTab.value === 'realtime' ? realtimeTemplateHeaders() : templateHeaders()])
const workbook = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(workbook, worksheet, `${activeTab.value}模板`)
XLSX.writeFile(workbook, `测试${activeTab.value}数据导入模板.xlsx`)
@@ -326,8 +347,8 @@
ElMessage.warning('没有可下载的数据')
return
}
- const headers = activeTab.value === 'cycle' ? ['记录编号', '电池', '循环号', '充电容量(Ah)', '放电容量(Ah)', '充放电效率(%)', '充电能量(Wh)', '放电能量(Wh)'] : activeTab.value === 'step' ? ['记录编号', '电池', '循环号', '工步序号', '工步', '工步时间', '容量(Ah)', '能量(Wh)', '起始电压(V)', '终止电压(V)', '充电峰值(V)', '放电谷值(V)'] : ['记录编号', '电池', '循环号', '实际工步号', '实际工步名称', '记录序号', '设备时间', '服务器接收时间', '电压(V)', '电流(A)', '容量(Ah)', '能量(Wh)']
- const records = activeTab.value === 'cycle' ? filteredRows.value.map(row => [row.recordNo, row.batteryNo, row.cycleNo, row.chargeCapacity, row.dischargeCapacity, row.efficiency, row.chargeEnergy, row.dischargeEnergy]) : activeTab.value === 'step' ? filteredRows.value.map(row => [row.recordNo, row.batteryNo, row.cycleNo, row.stepNo, row.stepName, row.stepDuration, row.capacity, row.energy, row.startVoltage, row.endVoltage, row.chargePeakVoltage, row.dischargeValleyVoltage]) : filteredRows.value.map(row => [row.recordNo, row.batteryNo, row.cycleNo, row.stepNo, row.stepName, row.sequenceId, row.recordedAt, row.serverReceivedAt, row.voltage, row.current, row.capacity, row.energy])
+ const headers = activeTab.value === 'cycle' ? ['记录编号', '电池', '循环号', '充电容量(Ah)', '放电容量(Ah)', '充放电效率(%)', '充电能量(Wh)', '放电能量(Wh)'] : activeTab.value === 'step' ? ['记录编号', '电池', '循环号', '工步序号', '工步', '工步时间', '容量(Ah)', '能量(Wh)', '起始电压(V)', '终止电压(V)', '充电峰值(V)', '放电谷值(V)'] : ['记录编号', '电池', '循环号', '实际工步号', '实际工步名称', '记录序号', '设备时间', '服务器接收时间', '电压(V)', '电流(A)', '容量(Ah)', '能量(Wh)', '温度(℃)', '正电位(V)', '负电位(V)', '其他采集字段']
+ const records = activeTab.value === 'cycle' ? filteredRows.value.map(row => [row.recordNo, row.batteryNo, row.cycleNo, row.chargeCapacity, row.dischargeCapacity, row.efficiency, row.chargeEnergy, row.dischargeEnergy]) : activeTab.value === 'step' ? filteredRows.value.map(row => [row.recordNo, row.batteryNo, row.cycleNo, row.stepNo, row.stepName, row.stepDuration, row.capacity, row.energy, row.startVoltage, row.endVoltage, row.chargePeakVoltage, row.dischargeValleyVoltage]) : filteredRows.value.map(row => [row.recordNo, row.batteryNo, row.cycleNo, row.stepNo, row.stepName, row.sequenceId, row.recordedAt, row.serverReceivedAt, row.voltage, row.current, row.capacity, row.energy, row.temperature, row.positivePotential, row.negativePotential, row.extensionMeasurements])
const blob = new Blob([`\uFEFF${[headers, ...records].map(item => item.map(escapeCsv).join(',')).join('\n')}`], { type: 'text/csv;charset=utf-8' })
const url = URL.createObjectURL(blob)
const anchor = document.createElement('a')
@@ -415,9 +436,10 @@
<th>设备时间</th>
<th>服务器接收时间</th>
<th>来源</th>
- <th>指标编码</th>
- <th>值</th>
- <th>单位</th>
+ <th>温度(℃)</th>
+ <th>正电位(V)</th>
+ <th>负电位(V)</th>
+ <th>其他采集字段</th>
<th>电压(V)</th>
<th>电流(A)</th>
<th>容量(Ah)</th>
@@ -472,10 +494,11 @@
<td>{{ row.sequenceId }}</td>
<td>{{ row.recordedAt }}</td>
<td>{{ row.serverReceivedAt }}</td>
- <td>{{ row.sourceType === 'COLLECTOR' ? `采集器 ${row.collectorCode}` : '检测柜' }}<small v-if="row.sourceType === 'COLLECTOR'">{{ row.channelCode }}</small></td>
- <td>{{ row.metricCode }}</td>
- <td>{{ row.metricValue }}</td>
- <td>{{ row.unit }}</td>
+ <td>{{ row.sourceType === 'COLLECTOR' ? `采集器 ${row.collectorCode}` : row.sourceType === 'SNAPSHOT' ? '检测柜 + 采集器' : '检测柜' }}<small v-if="row.sourceType === 'COLLECTOR'">{{ row.channelCode }}</small></td>
+ <td><el-input v-if="editing && draftRows[row.id]" v-model="draftRows[row.id].temperature" size="small" /><span v-else>{{ row.temperature }}</span></td>
+ <td><el-input v-if="editing && draftRows[row.id]" v-model="draftRows[row.id].positivePotential" size="small" /><span v-else>{{ row.positivePotential }}</span></td>
+ <td><el-input v-if="editing && draftRows[row.id]" v-model="draftRows[row.id].negativePotential" size="small" /><span v-else>{{ row.negativePotential }}</span></td>
+ <td>{{ row.extensionMeasurements }}</td>
<td>
<el-input v-if="editing && draftRows[row.id]" v-model="draftRows[row.id].voltage" size="small" />
<span v-else>{{ row.voltage }}</span>
@@ -577,7 +600,7 @@
</tr></template
>
<tr v-if="!loading && !pagedRows.length">
- <td :colspan="activeTab === 'realtime' ? 18 : activeTab === 'step' ? 15 : 12" class="empty-cell">
+ <td :colspan="activeTab === 'realtime' ? 19 : activeTab === 'step' ? 15 : 12" class="empty-cell">
{{ loadError || '暂无检测柜记录' }}
</td>
</tr>
diff --git a/tests/test-console-step-chart.contract.test.mjs b/tests/test-console-step-chart.contract.test.mjs
index 2098855..8836504 100644
--- a/tests/test-console-step-chart.contract.test.mjs
+++ b/tests/test-console-step-chart.contract.test.mjs
@@ -3,6 +3,7 @@
const chart = await readFile(new URL('../src/components/ConsoleChartPanel.vue', import.meta.url), 'utf8')
const consoleView = await readFile(new URL('../src/views/TestConsole.vue', import.meta.url), 'utf8')
+const dataList = await readFile(new URL('../src/components/ConsoleDataListPanel.vue', import.meta.url), 'utf8')
assert.match(chart, /PersistedTestRecord/)
assert.match(chart, /metricCode/)
@@ -16,5 +17,9 @@
assert.doesNotMatch(chart, /function seriesValues\(/)
assert.match(consoleView, /getPersistedTestRecords/)
assert.match(consoleView, /:records="realtimeRecords"/)
+assert.match(dataList, /<th>温度\(℃\)<\/th>/)
+assert.match(dataList, /<th>正电位\(V\)<\/th>/)
+assert.match(dataList, /<th>负电位\(V\)<\/th>/)
+assert.match(dataList, /temperature: (?:extension\('TEMPERATURE'\)|snapshot \?)/)
console.log('Ticket02/03 工步图表实时数据契约通过')
--
Gitblit v1.7.1