feat(assets): release v1.1.18 with two-sheet analysis exports and flow contract details
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
shishengliang
2026-09-28 17:03:59 +08:00
parent 807453b5fd
commit 40ef05d49b
18 changed files with 212 additions and 25 deletions
@@ -0,0 +1,43 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { statisticsExportRows, vehicleExportRows } from './analysis-export';
import type { VehicleListItem } from './types';
test('statistics export retains all ordered groups and repeats parent labels for spreadsheet filtering', () => {
const groups = Array.from({ length: 105 }, (_, i) => ({ values: ['华东', `城市${i}`], count: 1, extra: { 待交车: 0, 异动: Number(i === 104) } }));
const rows = statisticsExportRows(['区域', '城市'], groups, 105);
assert.equal(rows.length, 105);
assert.deepEqual(rows[104], { 区域: '华东', 城市: '城市104', '数量(台)': 1, 待交车: 0, 异动: 1, '占比(%)': 1 });
assert.equal(rows.reduce((n, row) => n + Number(row['数量(台)']), 0), 105);
assert.deepEqual(statisticsExportRows([], [{ values: [], count: 3 }], 3, '车次'), [{ 统计范围: '当前筛选结果', '数量(车次)': 3, '占比(%)': 100 }]);
});
test('vehicle exports preserve full records, server masking and pending/movement fields without treating missing time as zero', () => {
const vehicles = Array.from({ length: 45 }, (_, id) => ({ id, plateNumber: `车-${id}`, vin: '001234', status: 'Inventory', operationStatus: '3', customerName: '测试***公司' } as VehicleListItem));
vehicles[0].pendingDelivery = { contractNo: '001-CONTRACT', customerName: '待交***公司' };
vehicles[44].abnormalMove = { id: 'move', type: '维修', status: '待结束', work: '更换配件', elapsedDays: null } as NonNullable<VehicleListItem['abnormalMove']>;
const rows = vehicleExportRows(vehicles);
assert.equal(rows.length, 45);
assert.equal(rows[0].VIN, '001234');
assert.equal(rows[0].客户, '测试***公司');
assert.equal(rows[0].待交车合同, '001-CONTRACT');
assert.equal(rows[44].异动类型, '维修');
assert.equal(rows[44]['已异动时长(天)'], null);
assert.equal(rows[44].实际完成时间, '未完成');
assert.equal(rows[0].状态, '在库');
assert.equal(rows[0].运营状态, '可运营');
});
test('one Excel workbook contains statistics and all details in two named sheets', async () => {
const { createAnalysisWorkbook } = await import('./analysis-export');
const XLSX = await import('xlsx');
const statistics = statisticsExportRows(['区域'], [{ values: ['华东'], count: 105 }], 105);
const details = Array.from({ length: 105 }, (_, i) => ({ VIN: `000${i}`, 合同: i === 104 ? 'LAST-CONTRACT' : 'CONTRACT', 项目名称: '项目甲' }));
const workbook = await createAnalysisWorkbook(statistics, details);
const saved = XLSX.read(XLSX.write(workbook, { type: 'buffer', bookType: 'xlsx' }), { type: 'buffer' });
assert.deepEqual(saved.SheetNames, ['统计表', '详情表']);
assert.deepEqual(XLSX.utils.sheet_to_json(saved.Sheets['统计表']), statistics);
assert.deepEqual(XLSX.utils.sheet_to_json(saved.Sheets['详情表']), details);
const empty = await createAnalysisWorkbook([], []);
assert.deepEqual(empty.SheetNames, ['统计表', '详情表']);
});