| | |
| | | import * as XLSX from 'xlsx' |
| | | import { Download, EditPen, Refresh, Search, UploadFilled, Clock, Check } from '@element-plus/icons-vue' |
| | | import { getPersistedTestCycles, getPersistedTestRecords, getPersistedTestSteps, type PersistedTestCycle, type PersistedTestRecord, type PersistedTestStep } from '@/api/tests' |
| | | import { getConsoleDataOverrides, submitConsoleDataAction, type ConsoleDataType } from '@/api/consoleData' |
| | | import { submitConsoleDataAction, type ConsoleDataType } from '@/api/consoleData' |
| | | |
| | | type DataTab = 'realtime' | 'step' | 'cycle' |
| | | interface ConsoleCell { |
| | |
| | | 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) }) |
| | | } |
| | | function applyOverrides(list: DataRow[], overrides: Awaited<ReturnType<typeof getConsoleDataOverrides>>) { |
| | | const byIdentity = new Map(overrides.map(item => [item.stableIdentity, item])) |
| | | const known = new Set(list.map(row => row.id)) |
| | | const result = list.flatMap(row => { |
| | | const override = byIdentity.get(row.id) |
| | | if (!override) return [row] |
| | | if (override.deleted) return [] |
| | | try { |
| | | return [{ ...row, ...(override.fieldValues ? JSON.parse(override.fieldValues) : {}) }] |
| | | } catch { |
| | | return [row] |
| | | } |
| | | }) |
| | | overrides |
| | | .filter(item => !known.has(item.stableIdentity) && !item.deleted && item.fieldValues) |
| | | .forEach(item => { |
| | | try { |
| | | result.push(emptyRow({ ...JSON.parse(item.fieldValues || '{}'), id: item.stableIdentity, recordNo: item.stableIdentity })) |
| | | } catch { |
| | | /* 忽略无法解析的历史覆盖 */ |
| | | } |
| | | }) |
| | | return result |
| | | } |
| | | async function loadRecords() { |
| | | loading.value = true |
| | | loadError.value = '' |
| | |
| | | cycleRows.value = [] |
| | | return |
| | | } |
| | | const [records, steps, cycles, ...overrides] = await Promise.all([getPersistedTestRecords(props.testId), getPersistedTestSteps(props.testId), getPersistedTestCycles(props.testId), ...(['REALTIME', 'STEP', 'CYCLE'] as ConsoleDataType[]).map(type => getConsoleDataOverrides(props.testId, type))]) |
| | | rows.value = applyOverrides(records.map(mapRecord), overrides[0]).sort((a, b) => b.absoluteTime.localeCompare(a.absoluteTime) || b.sequenceId - a.sequenceId) |
| | | stepRows.value = applyOverrides(steps.map(mapStep), overrides[1]) |
| | | cycleRows.value = applyOverrides(cycles.map(mapCycle), overrides[2]) |
| | | const [records, steps, cycles] = await Promise.all([getPersistedTestRecords(props.testId), getPersistedTestSteps(props.testId), getPersistedTestCycles(props.testId)]) |
| | | // 后端查询接口已经返回当前有效数据,前端不再读取覆盖表或拼接伪造行。 |
| | | rows.value = records.map(mapRecord).sort((a, b) => b.absoluteTime.localeCompare(a.absoluteTime) || b.sequenceId - a.sequenceId) |
| | | stepRows.value = steps.map(mapStep) |
| | | cycleRows.value = cycles.map(mapCycle) |
| | | } catch (error) { |
| | | rows.value = [] |
| | | stepRows.value = [] |