import assert from 'node:assert/strict'; import test from 'node:test'; import type { FlowStatsResponse, WeeklyDetailItem } from './api'; import type { CustomerStats, DeptGroup, ManagerStats, RegionalInventoryStats, VehicleListItem, } from './types'; import { buildCustomerPieData, buildVehicleModalRequest, deriveCustomerView, deriveDepartmentView, deriveInventoryView, deriveModalVehicleView, formatLocalDate, formatLocalDateTime, getWeeklyFlowRange, groupInventoryByModel, selectFlowDetails, } from './model'; const emptyInventoryFilters = { region: '', city: '', brand: '', type: '', model: '' }; const emptyCustomerFilters = { customer: [], brand: '', department: '', manager: '', region: '' }; const emptyModalFilters = { plateNumber: '', model: '', brand: '', location: '' }; function inventory(overrides: Partial): RegionalInventoryStats { return { region: '广东', city: '广州', brand: '现代', type: '18T', model: 'M1', batch: 'B1', quantity: 1, ...overrides, }; } function manager(overrides: Partial): ManagerStats { return { manager: '负责人甲', department: '业务一部', t4_5: 0, t4_5c: 0, t18: 0, t49: 0, trailer: 0, other: 0, total: 0, ...overrides, }; } function department(name: string, managers: ManagerStats[]): DeptGroup { return { department: name, totalAssets: managers.reduce((sum, item) => sum + item.total, 0), operatingCount: 0, idleCount: 0, attendanceRate: 0, avgMileage: 0, managers, }; } function customer(overrides: Partial): CustomerStats { return { customer: '客户甲', manager: '负责人甲', brand: '现代', department: '业务一部', region: '广东', city: '广州', t4_5: 0, t4_5c: 0, t18: 0, t49: 0, trailer: 0, other: 0, total: 1, ...overrides, }; } function vehicle(overrides: Partial): VehicleListItem { return { id: 1, plateNumber: '粤A00001', vin: 'VIN-1', type: '18T', model: 'M1', location: '广州', province: '广东', city: '广州', status: '运营', ownership: '自营', contractNo: null, customerName: null, subjectOrg: null, departmentName: null, customerManager: null, brandLabel: '现代', orgName: null, ...overrides, }; } test('本地日期格式不引入 UTC 偏移', () => { const date = new Date(2026, 7, 3, 9, 7, 5); assert.equal(formatLocalDate(date), '2026-08-03'); assert.equal(formatLocalDateTime(date), '2026-08-03 09:07:05'); }); test('周流转区间按周六至周五计算', () => { assert.deepEqual(getWeeklyFlowRange(new Date(2026, 7, 12)), { start: '2026-08-08', end: '2026-08-14', }); assert.deepEqual(getWeeklyFlowRange(new Date(2026, 7, 15)), { start: '2026-08-08', end: '2026-08-14', }); assert.deepEqual(getWeeklyFlowRange(new Date(2026, 7, 16)), { start: '2026-08-08', end: '2026-08-14', }); }); test('交还替明细走周接口且原样保留周筛选参数', () => { assert.deepEqual( buildVehicleModalRequest({ batch: 'All', model: 'M1', location: '广州', category: 'Delivered', source: 'asset', }, '主体甲'), { kind: 'weekly', type: 'delivered', filters: { model: 'M1', batch: 'All', location: '广州', source: 'asset' }, }, ); }); test('待交付与车型映射继续走车辆列表参数', () => { assert.deepEqual( buildVehicleModalRequest({ batch: 'B1', model: 'M1', location: '广州', category: 'Pending', type: '4.5T', isColdChain: true, isTrailer: false, manager: '负责人甲', }, '主体甲'), { kind: 'vehicles', params: { batch: 'B1', model: 'M1', location: '广州', category: 'Pending', manager: '负责人甲', vehicleType: '4.5T冷链', subject: '主体甲', }, }, ); assert.deepEqual( buildVehicleModalRequest({ batch: 'All', model: 'All', location: 'All', isColdChain: false, isTrailer: true, }, null), { kind: 'vehicles', params: { isColdChain: 'false', isTrailer: 'true', subject: null }, }, ); }); test('库存筛选与区域、车型分组保持既有顺序', () => { const rows = [ inventory({ region: '广东', city: '广州', type: '18T', model: 'M1', quantity: 2 }), inventory({ region: '浙江', city: '嘉兴', type: '4.5T普货', model: 'M2', quantity: 3 }), inventory({ region: '广东', city: '佛山', type: '18T', model: 'M3', quantity: 4 }), inventory({ region: '广东', city: '广州', type: '新增车型', model: 'M4', quantity: 5 }), ]; const view = deriveInventoryView( rows, { ...emptyInventoryFilters, region: '广东', type: '18T' }, '18T', ); assert.deepEqual(view.filtered.map((item) => item.model), ['M1', 'M3']); assert.deepEqual(view.modelsForType, ['M1', 'M3']); assert.deepEqual(Object.keys(view.byRegion), ['广东']); assert.deepEqual(Object.keys(view.byRegion['广东']), ['广州', '佛山']); assert.deepEqual(Object.keys(view.byModel), ['18T']); assert.deepEqual( Object.keys(groupInventoryByModel(rows)), ['4.5T普货', '18T', '新增车型'], ); }); test('部门负责人去重、分组并按车辆数倒序', () => { const departments = [ department('业务二部', [ manager({ manager: '负责人乙', department: '业务二部', total: 3 }), manager({ manager: '负责人甲', department: '业务二部', total: 8 }), ]), department('业务一部', [manager({ manager: '负责人甲', total: 5 })]), ]; const view = deriveDepartmentView(departments, 'All'); assert.deepEqual(view.managers, ['负责人乙', '负责人甲']); assert.deepEqual(view.groupedManagers, [ { department: '业务二部', managers: ['负责人乙', '负责人甲'] }, { department: '业务一部', managers: ['负责人甲'] }, ]); assert.deepEqual(view.managerStats.map((item) => item.total), [8, 5, 3]); }); test('客户筛选与负责人分组合并部门和客户来源', () => { const departments = [ department('业务二部', [manager({ manager: '负责人乙', department: '业务二部' })]), department('业务一部', [manager({ manager: '负责人甲' })]), ]; const customers = [ customer({ customer: '客户甲', department: '业务一部', manager: '负责人甲', total: 2 }), customer({ customer: '客户乙', department: '业务二部', manager: '负责人丙', region: '浙江', city: '嘉兴', total: 3 }), customer({ customer: '公务车', department: '公务车', manager: '负责人丁', total: 1 }), ]; const view = deriveCustomerView( customers, departments, { ...emptyCustomerFilters, customer: ['客户乙'], region: '浙江' }, ); assert.deepEqual(view.filtered.map((item) => item.customer), ['客户乙']); assert.deepEqual(view.departments, ['业务一部', '业务二部', '公务车']); assert.deepEqual(view.managersByDepartment, [ { department: '业务一部', managers: ['负责人甲'] }, { department: '业务二部', managers: ['负责人乙', '负责人丙'] }, { department: '公务车', managers: ['负责人丁'] }, ]); }); test('弹窗筛选沿用车牌为空时回退 VIN 的规则', () => { const vehicles = [ vehicle({ id: 1 }), vehicle({ id: 2, plateNumber: '', vin: 'VIN-2', model: 'M2', brandLabel: '福田', location: '嘉兴' }), ]; const weeklyDetails: WeeklyDetailItem[] = [ { truck_id: 1, plate_number: '粤A00001', handover_date: null, contract_type: null, customer_name: null }, { truck_id: 2, plate_number: 'VIN-2', handover_date: null, contract_type: null, customer_name: null }, ]; const view = deriveModalVehicleView( vehicles, weeklyDetails, { ...emptyModalFilters, plateNumber: 'VIN-2' }, ); assert.deepEqual(view.plates, ['粤A00001', 'VIN-2']); assert.deepEqual(view.filteredVehicles.map((item) => item.id), [2]); assert.deepEqual(view.filteredWeeklyDetails.map((item) => item.truck_id), [2]); }); test('流转明细按日期和类型同时筛选,客户饼图按区域汇总', () => { const flowStats: FlowStatsResponse = { start: '2026-08-08', end: '2026-08-14', daily: [], totals: { delivered: 1, returned: 1, replaced: 0, total: 2 }, details: [ { id: '1', type: 'delivered', typeLabel: '交车', date: '2026-08-12', truckId: '1', plateNumber: '粤A00001', eventTime: null, submitTime: null, department: '', manager: '', customerName: null, }, { id: '2', type: 'returned', typeLabel: '还车', date: '2026-08-12', truckId: '2', plateNumber: '粤A00002', eventTime: null, submitTime: null, department: '', manager: '', customerName: null, }, ], }; assert.deepEqual( selectFlowDetails(flowStats, { date: '2026-08-12', type: 'delivered' }).map((item) => item.id), ['1'], ); const customers = [ customer({ region: '广东', total: 2 }), customer({ customer: '客户乙', region: '浙江', total: 5 }), customer({ customer: '客户丙', region: '广东', total: 3 }), ]; assert.deepEqual(buildCustomerPieData(customers, 'region', []), [ { name: '广东', value: 5 }, { name: '浙江', value: 5 }, ]); const provinceData = [{ name: '广东省', value: 10 }]; assert.equal(buildCustomerPieData(customers, 'province', provinceData), provinceData); });