refactor: modularize application domains

This commit is contained in:
kkfluous
2026-08-13 12:03:34 +08:00
parent d610e4b841
commit 06fe75b4c7
142 changed files with 14645 additions and 8885 deletions
+310
View File
@@ -0,0 +1,310 @@
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>): RegionalInventoryStats {
return {
region: '广东',
city: '广州',
brand: '现代',
type: '18T',
model: 'M1',
batch: 'B1',
quantity: 1,
...overrides,
};
}
function manager(overrides: Partial<ManagerStats>): 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>): 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>): 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);
});