yeg
2026-09-28 6a4ca47df73d99e952d926f6103bcccea1ecea89
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import { test } from 'node:test'
import ts from 'typescript'
import load from './load-typescript.cjs'
const { stepCurveChartOption } = load(new URL('../src/utils/stepCurveChart.ts', import.meta.url))
const { projectCycleChartOption, projectMetrics } = load(new URL('../src/utils/projectCycleChart.ts', import.meta.url))
import { toTestDisplayValue } from '../src/utils/testDataUnits.ts'
 
async function componentFunctions(path, names, bindings) {
  const source = (await readFile(new URL(`../src/${path}`, import.meta.url), 'utf8')).split('<script setup lang="ts">')[1].split('</script>')[0]
  const ast = ts.createSourceFile(path, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)
  const functions = ast.statements.filter(node => ts.isFunctionDeclaration(node) && names.includes(node.name?.text)).map(node => node.getText(ast)).join('\n')
  const script = ts.transpileModule(`${functions}\nreturn { ${names.join(', ')} }`, { compilerOptions: { target: ts.ScriptTarget.ES2022 } }).outputText
  return new Function(...Object.keys(bindings), 'toTestDisplayValue', script)(...Object.values(bindings), toTestDisplayValue)
}
 
const { measurementChartOption } = load(new URL('../src/utils/reportMeasurementChart.ts', import.meta.url))
 
test('工步图电流序列和纵轴同步为 mA,保留负数与零', async () => {
  const records = [-8.1651, 0, -8.1674].map((current, index) => ({ batteryNo: 'BAT-1', current, deviceTime: index * 60000, sourceType: 'SNAPSHOT' }))
  const { metricValue, chartOption } = await componentFunctions('components/ConsoleChartPanel.vue', ['metricValue', 'recordTime', 'chartOption'], {
    stepCurveChartOption, props: { cells: [{ no: 'BAT-1' }] }, selectedRecords: () => records, selectedCells: { value: [{ no: 'BAT-1' }] }, metricMatches: () => true, seriesColors: { value: ['#3978f6'] },
  })
  const option = chartOption({ key: 'current', unit: 'mA' })
  assert.deepEqual(option.series[0].data, [[0,-8165.1], [60,0], [120,-8167.4]])
  assert.equal(option.yAxis[0].name, 'mA')
  assert.ok(option.yAxis[0].min < -8167.4)
  assert.ok(option.yAxis[0].max > 0)
  assert.equal(metricValue('voltage', { voltage: 1.3349 }), 1.3349)
})
 
test('项目图表以 mAh 除以 F,缺失和无效 F 不造点,电压不缩放', async () => {
  const capacityFactor = { value: 2 }
  const funcs = await componentFunctions('components/ConsoleProjectChartPanel.vue', ['numericValue', 'lastStepVoltage', 'dischargeCapacityPerFactor'], {
    props: { cells: [{ no: 'BAT-1' }], cycles: [{ batteryNo: 'BAT-1', cycleNo: 1, dischargeCapacity: 8.5122 }, { batteryNo: 'BAT-1', cycleNo: 2, dischargeCapacity: 0 }], steps: [{ batteryNo: 'BAT-1', cycleNo: 1, stepNo: 1, endVoltage: 0.8999 }] },
    capacityFactor, cycleLabels: { value: ['1', '2', '3'] }, seriesColors: { value: ['#3978f6'] },
  })
  const option = projectCycleChartOption(projectMetrics[2], [{key:'BAT-1',name:'BAT-1',points:[1,2,3].map(position=>({position,values:{dischargeCapacityF:funcs.dischargeCapacityPerFactor('BAT-1',position)}}))}], [1,2,3], [])
  assert.deepEqual(option.series[0].data.map(point=>point.value[1]), [4256.1, 0, null])
  assert.equal(option.yAxis.name, 'mAh / F')
  assert.equal(option.yAxis.axisLabel.formatter(7366.332499999995), '7366.33')
  assert.equal(funcs.lastStepVoltage('BAT-1', 1), 0.8999)
  capacityFactor.value = null
  assert.equal(funcs.dischargeCapacityPerFactor('BAT-1', 1), null)
})
 
test('保存报表共用测量图按真实时间和单位绘制,显隐不改变完整数据范围', () => {
  const items = [
    { name: '测试甲 · 1号', zeroTime: 1000, records: [
      { deviceTime: 1000, collectorDeviceTime: 9000, current: -0.125, voltage: 3.2, temperature: 0 },
      { deviceTime: 18000, collectorDeviceTime: 22000, current: null, voltage: null, temperature: null },
      { deviceTime: 181000, collectorDeviceTime: 182000, current: 0, voltage: 0, temperature: -5 },
    ] },
    { name: '测试乙 · 1号', zeroTime: 3000, records: [{ deviceTime: 7203000, current: 0.25 }] },
  ]
  const before = structuredClone(items)
  const metric = { key: 'current', unit: 'mA' }
  const option = measurementChartOption(metric, items, ['#123456', '#abcdef'])
  assert.deepEqual(option.series[0].data, [[0, -125], [17, null], [180, 0]])
  assert.equal(option.series[0].connectNulls, false)
  assert.equal(option.xAxis.max, 7200)
  assert.equal(option.xAxis.axisLabel.formatter(1800), '0.5')
  assert.deepEqual(option.yAxis.map(axis => [axis.name, axis.min, axis.max]), [['mA', -205, 330], ['mA', -205, 330]])
  const hidden = measurementChartOption(metric, [{ ...items[0], hidden: true }, items[1]], ['#123456', '#abcdef'])
  assert.equal(hidden.legend.selected['测试甲 · 1号'], false)
  assert.equal(hidden.series[1].itemStyle.color, '#abcdef')
  assert.equal(hidden.xAxis.max, option.xAxis.max)
  assert.equal(hidden.yAxis[0].min, option.yAxis[0].min)
  assert.deepEqual(items, before)
  const voltage = measurementChartOption({ key: 'voltage', unit: 'V' }, [items[0]], ['#123456'])
  assert.deepEqual(voltage.series[0].data, [[0, 3.2], [17, null], [180, 0]])
  const temperature = measurementChartOption({ key: 'temperature', unit: '℃' }, [items[0]], ['#123456'])
  assert.deepEqual(temperature.series[0].data, [[8, 0], [21, null], [181, -5]])
})