feat(assets): 完成故障维修运维 BI 与 Excel 报表导出
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { mapFault, faultHandlers } from '../../../server/routes/asset-faults/model.js';
|
||||
import type { FaultAnalysisRecord, FaultOption } from '../../../shared/assets/faults';
|
||||
import { analyzeFaultRecords, filterFaultRecords, faultDimensionValues, faultParentTotals, FAULT_ANALYSIS_DIMENSIONS, FAULT_ANALYSIS_LABELS } from './analysis-model.js';
|
||||
function fault(id: string, handlers: FaultOption[], manager = '客户业务经理', city = '上海市'): FaultAnalysisRecord {
|
||||
const row = mapFault({ id, business_manager: manager, city_name: city }, new Map());
|
||||
return { ...row, handlers, cell: row.assetCell };
|
||||
}
|
||||
const a = { value: 'id:1234567890123456789', label: '处置甲' };
|
||||
const b = { value: 'id:2234567890123456789', label: '处置乙' };
|
||||
const data = [fault('shared', [a, b, a]), fault('single', [a]), fault('none', [])];
|
||||
|
||||
test('运维处置人是独立维度,未分配不以业务负责人兜底', () => {
|
||||
assert.ok(FAULT_ANALYSIS_DIMENSIONS.includes('handler')); assert.ok(FAULT_ANALYSIS_DIMENSIONS.includes('manager'));
|
||||
assert.equal(FAULT_ANALYSIS_LABELS.handler, '运维处置人');
|
||||
assert.deepEqual(faultDimensionValues(data[0], 'handler'), [a.value, b.value]);
|
||||
assert.deepEqual(faultDimensionValues(data[0], 'manager'), ['客户业务经理']);
|
||||
assert.deepEqual(faultDimensionValues(data[2], 'handler'), ['unassigned']);
|
||||
assert.deepEqual(faultHandlers({ business_manager: '客户业务经理' }, new Map()), [{ value: 'unassigned', label: '未指派' }]);
|
||||
});
|
||||
test('多人各自成组,总数和组内明细按故障ID去重,父级小计取并集', () => {
|
||||
const result = analyzeFaultRecords([...data, data[0]], ['city', 'handler']);
|
||||
assert.equal(result.total, 3);
|
||||
assert.equal(result.rows.find(row => row.values.handler === a.value)?.count, 2);
|
||||
assert.equal(result.rows.find(row => row.values.handler === b.value)?.count, 1);
|
||||
assert.equal(result.rows.reduce((n, row) => n + row.count, 0), 4);
|
||||
assert.ok(faultParentTotals(result.rows, ['city', 'handler']).every(row => row[0] === 3));
|
||||
for (const group of result.rows) assert.equal(new Set(group.recordIds).size, group.count);
|
||||
});
|
||||
test('多选处置人取并集,不分组时不放大;筛选甲后不出现共享故障的乙分组', () => {
|
||||
assert.equal(filterFaultRecords(data, { handler: [a.value, b.value] }).length, 2);
|
||||
assert.equal(analyzeFaultRecords(data, ['city'], { handler: [a.value, b.value] }).rows[0].count, 2);
|
||||
const result = analyzeFaultRecords(data, ['handler'], { handler: [a.value] });
|
||||
assert.equal(result.total, 2); assert.equal(result.rows.length, 1); assert.equal(result.rows[0].values.handler, a.value);
|
||||
assert.equal(filterFaultRecords(data, { handler: [a.value], manager: ['其他业务经理'] }).length, 0);
|
||||
assert.equal(filterFaultRecords(data, { handler: ['unassigned'] })[0].id, 'none');
|
||||
});
|
||||
test('同名处置人保持ID独立,组合筛选与组明细对应,空数据安全', () => {
|
||||
const rows = [fault('one', [{ ...a, label: '同名' }]), fault('two', [{ ...b, label: '同名' }])];
|
||||
const result = analyzeFaultRecords(rows, ['manager', 'handler']);
|
||||
assert.equal(result.rows.length, 2);
|
||||
for (const group of result.rows) {
|
||||
const matched = filterFaultRecords(rows, { manager: [group.values.manager!], handler: [group.values.handler!] });
|
||||
assert.deepEqual(matched.map(row => row.id), group.recordIds);
|
||||
}
|
||||
assert.deepEqual(analyzeFaultRecords([], ['handler']), { total: 0, rows: [] });
|
||||
});
|
||||
|
||||
|
||||
test('故障工单状态按归档闭环,与车辆运营状态独立;组合分组、筛选和去重口径一致', () => {
|
||||
const states = ['已归档', '待处理', '处理中', '挂起', '未知状态'];
|
||||
const rows = states.map((status, i) => ({ ...fault(String(i), i === 0 ? [a, b] : [a]), status }));
|
||||
assert.deepEqual(rows.map(row => faultDimensionValues(row, 'faultStatus')), [['closed'], ['unclosed'], ['unclosed'], ['unclosed'], ['unclosed']]);
|
||||
const result = analyzeFaultRecords(rows, ['handler', 'faultStatus']);
|
||||
assert.equal(result.total, 5);
|
||||
assert.equal(result.rows.find(row => row.values.handler === a.value && row.values.faultStatus === 'closed')?.count, 1);
|
||||
assert.equal(result.rows.find(row => row.values.handler === a.value && row.values.faultStatus === 'unclosed')?.count, 4);
|
||||
const parentTotals = faultParentTotals(result.rows, ['handler', 'faultStatus']);
|
||||
result.rows.forEach((row, i) => assert.equal(parentTotals[i][0], row.values.handler === a.value ? 5 : 1));
|
||||
assert.deepEqual(filterFaultRecords(rows, { faultStatus: ['closed'], handler: [a.value, b.value] }).map(row => row.id), ['0']);
|
||||
assert.equal(filterFaultRecords(rows, { faultStatus: ['closed', 'unclosed'] }).length, 5);
|
||||
assert.deepEqual(filterFaultRecords(rows, { faultStatus: ['unclosed'], handler: [b.value] }), []);
|
||||
for (const group of result.rows) assert.deepEqual(filterFaultRecords(rows, { handler: [group.values.handler!], faultStatus: [group.values.faultStatus!] }).map(row => row.id), group.recordIds);
|
||||
});
|
||||
|
||||
|
||||
test('车牌位于第三个维度,同车多故障按单计数,支持组合筛选和缺失车牌', () => {
|
||||
assert.equal(FAULT_ANALYSIS_DIMENSIONS[2], 'plate');
|
||||
const rows = [{ ...fault('1', [a]), plate: '沪A12345' }, { ...fault('2', [b]), plate: '沪A12345' }, { ...fault('3', [a]), plate: '粤A12345' }, { ...fault('4', []), plate: '' }];
|
||||
const grouped = analyzeFaultRecords(rows, ['plate']);
|
||||
assert.equal(grouped.total, 4);
|
||||
assert.equal(grouped.rows.find(row => row.values.plate === '沪A12345')?.count, 2);
|
||||
assert.deepEqual(filterFaultRecords(rows, { plate: ['沪A12345'], handler: [b.value] }).map(row => row.id), ['2']);
|
||||
assert.equal(filterFaultRecords(rows, { plate: ['沪A12345', '粤A12345'] }).length, 3);
|
||||
assert.deepEqual(filterFaultRecords(rows, { plate: ['未关联车辆'] }).map(row => row.id), ['4']);
|
||||
});
|
||||
Reference in New Issue
Block a user