Merge asset analysis exports into main and release v1.2.2
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
shishengliang
2026-09-28 17:05:52 +08:00
19 changed files with 226 additions and 31 deletions
+8
View File
@@ -11,6 +11,7 @@ test('replacement trips are included in delivery counts without inflating totals
stat_date: date, truck_id: '1', plate_number: '测试车牌',
event_time: `${date} 12:00:00`, submit_time: '2026-09-01 12:00:00',
department: null, manager: null, customer_name: null,
contract_no: `CONTRACT-${id}`, project_name: type === 'returned' ? null : `项目-${id}`,
});
t.mock.method(vehicleRepository, 'getFlowDetailRows', async () => [
row('delivered-1', 'delivered', '2026-09-15'),
@@ -28,6 +29,13 @@ test('replacement trips are included in delivery counts without inflating totals
{ date: '2026-09-17', delivered: 0, returned: 0, replaced: 0, total: 0 },
]);
assert.equal(data.details.length, 4);
// The same vehicle can have multiple historical contracts/projects; keep each event's own values.
assert.deepEqual(data.details.map((item: { id: string; contractNo: string; projectName: string | null }) => [item.contractNo, item.projectName]), [
['CONTRACT-delivered-1', '项目-delivered-1'],
['CONTRACT-replaced-2', '项目-replaced-2'],
['CONTRACT-returned-1', null],
['CONTRACT-replaced-3', '项目-replaced-3'],
]);
assert.equal(new Set(data.details.map((x: { id: string }) => x.id)).size, 4);
assert.ok(data.details.filter((x: { type: string }) => x.type === 'replaced')
.every((x: { typeLabel: string }) => x.typeLabel === '替换交车'));
+8 -2
View File
@@ -24,6 +24,8 @@ export interface FlowDetailRow {
department: string | null;
manager: string | null;
customer_name: string | null;
contract_no: string | null;
project_name: string | null;
}
interface WeeklyStats {
@@ -263,7 +265,9 @@ export const FLOW_STATS_SQL = `
DATE_FORMAT(dv.create_time, '%Y-%m-%d %H:%i:%s') AS submit_time,
c.business_department_name AS department,
c.business_manager_name AS manager,
COALESCE(dts.customer_name, c.customer_name) AS customer_name
COALESCE(dts.customer_name, c.customer_name) AS customer_name,
COALESCE(NULLIF(dts.contract_code, ''), c.contract_code) AS contract_no,
COALESCE(NULLIF(dts.project_name, ''), c.project_name) AS project_name
FROM delivery_vehicle dv
LEFT JOIN delivery_task_subject dts
ON dts.id = dv.delivery_task_subject_id
@@ -293,7 +297,9 @@ export const FLOW_STATS_SQL = `
DATE_FORMAT(r.create_time, '%Y-%m-%d %H:%i:%s') AS submit_time,
c.business_department_name AS department,
c.business_manager_name AS manager,
COALESCE(dts.customer_name, c.customer_name) AS customer_name
COALESCE(dts.customer_name, c.customer_name) AS customer_name,
COALESCE(NULLIF(dts.contract_code, ''), c.contract_code) AS contract_no,
COALESCE(NULLIF(dts.project_name, ''), c.project_name) AS project_name
FROM return_vehicle_task r
LEFT JOIN delivery_task_subject dts
ON dts.id = r.delivery_task_subject_id
+2
View File
@@ -634,6 +634,8 @@ app.get('/flow-stats', async (c) => {
department: row.department || '',
manager: row.manager || '',
customerName: maskCustomerName(row.customer_name),
contractNo: row.contract_no || null,
projectName: row.project_name || null,
}));
const dailyMap = new Map<string, { date: string; delivered: number; returned: number; replaced: number; total: number }>();