feat(platform): copy vehicle diagnostic summary

This commit is contained in:
lingniu
2026-07-04 13:52:57 +08:00
parent c4d25593c1
commit 1365ce2a30
2 changed files with 184 additions and 4 deletions

View File

@@ -8317,6 +8317,145 @@ test('copies shareable vehicle service detail link', async () => {
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('/#/detail?keyword=VIN001&protocol=JT808'));
});
test('copies vehicle service diagnostic summary', async () => {
window.history.replaceState(null, '', '/#/detail?keyword=VIN-SUMMARY-001&protocol=JT808');
const writeText = vi.fn<(value: string) => Promise<void>>(() => Promise.resolve());
Object.defineProperty(navigator, 'clipboard', {
configurable: true,
value: { writeText }
});
vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {
const path = String(input);
if (path.includes('/api/vehicle-service')) {
const serviceStatus = {
status: 'degraded',
severity: 'warning',
title: '来源不完整',
detail: 'JT808 在线GB32960 离线',
sourceCount: 2,
onlineSourceCount: 1
};
const sourceConsistency = {
sourceCount: 2,
onlineSourceCount: 1,
locatedSourceCount: 2,
missingProtocols: ['YUTONG_MQTT'],
mileageDeltaKm: 12.6,
sourceTimeDeltaSeconds: 90,
scope: 'all_sources',
status: 'degraded',
severity: 'warning',
title: '来源不完整',
detail: 'JT808 在线GB32960 离线,需要补齐 MQTT'
};
return {
ok: true,
json: async () => ({
data: {
vin: 'VIN-SUMMARY-001',
lookupKey: 'VIN-SUMMARY-001',
lookupResolved: true,
identity: {
vin: 'VIN-SUMMARY-001',
plate: '粤A诊断1',
phone: '13307795425',
oem: 'G7s',
online: true,
lastSeen: '2026-07-03 20:12:10'
},
realtimeSummary: {
vin: 'VIN-SUMMARY-001',
plate: '粤A诊断1',
phone: '13307795425',
oem: 'G7s',
protocols: ['JT808'],
sourceCount: 2,
onlineSourceCount: 1,
online: true,
primaryProtocol: 'JT808',
lastSeen: '2026-07-03 20:12:10'
},
serviceOverview: {
vin: 'VIN-SUMMARY-001',
plate: '粤A诊断1',
phone: '13307795425',
oem: 'G7s',
protocols: ['GB32960', 'JT808'],
primaryProtocol: 'JT808',
coverageStatus: 'partial',
sourceCount: 2,
onlineSourceCount: 1,
lastSeen: '2026-07-03 20:12:10',
realtimeCount: 2,
historyCount: 12,
rawCount: 34,
mileageCount: 3,
qualityIssueCount: 1
},
sources: ['GB32960', 'JT808'],
sourceStatus: [
{ protocol: 'JT808', online: true, lastSeen: '2026-07-03 20:12:10', hasRealtime: true, hasHistory: true, hasRaw: true, hasMileage: true },
{ protocol: 'GB32960', online: false, lastSeen: '2026-07-03 19:55:10', hasRealtime: true, hasHistory: true, hasRaw: true, hasMileage: true }
],
realtime: [
{ vin: 'VIN-SUMMARY-001', plate: '粤A诊断1', protocol: 'JT808', longitude: 113.2, latitude: 23.1, speedKmh: 32, totalMileageKm: 1200.5, lastSeen: '2026-07-03 20:12:10' }
],
history: { items: [], total: 12, limit: 20, offset: 0 },
raw: { items: [], total: 34, limit: 10, offset: 0 },
mileage: { items: [], total: 3, limit: 20, offset: 0 },
quality: {
items: [
{ vin: 'VIN-SUMMARY-001', plate: '粤A诊断1', protocol: 'JT808', issueType: 'LINK_GAP', severity: 'warning', lastSeen: '2026-07-03 20:12:10', detail: 'JT808 间断' }
],
total: 1,
limit: 20,
offset: 0
},
serviceStatus,
sourceConsistency
},
traceId: 'trace-test',
timestamp: 1783094400000
})
} as Response;
}
return {
ok: true,
json: async () => ({
data: path.includes('/api/ops/health')
? { linkHealth: [], kafkaLag: 0, redisOnlineKeys: 0, tdengineWritable: true, mysqlWritable: true, runtime: { requestTimeoutMs: 5000 } }
: { items: [], total: 0, limit: 10, offset: 0 },
traceId: 'trace-test',
timestamp: 1783094400000
})
} as Response;
});
render(<App />);
expect(await screen.findByText('车辆服务结论')).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: /复制诊断摘要/ }));
expect(writeText).toHaveBeenCalledWith(expect.any(String));
const copied = String(writeText.mock.lastCall?.[0] ?? '');
expect(copied).toContain('【车辆服务诊断摘要】');
expect(copied).toContain('车辆粤A诊断1 / VIN-SUMMARY-001');
expect(copied).toContain('当前范围单一来源JT808');
expect(copied).toContain('服务状态:来源不完整');
expect(copied).toContain('来源证据1/2 来源在线');
expect(copied).toContain('定位证据2 个来源有位置');
expect(copied).toContain('里程差异12.6 km');
expect(copied).toContain('时间差异90 秒');
expect(copied).toContain('数据规模:实时 2 / 历史 12 / RAW 34 / 里程 3 / 质量 1');
expect(copied).toContain('一致性:来源不完整');
expect(copied).toContain('下一步:');
expect(copied).toContain('车辆服务http://localhost:3000/#/detail?keyword=VIN-SUMMARY-001&protocol=JT808');
expect(copied).toContain('实时http://localhost:3000/#/realtime?keyword=VIN-SUMMARY-001&protocol=JT808');
expect(copied).toContain('轨迹http://localhost:3000/#/history?keyword=VIN-SUMMARY-001&protocol=JT808');
expect(copied).toContain('RAWhttp://localhost:3000/#/history?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true');
expect(copied).toContain('里程http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808');
});
test('exports vehicle detail service dossier as csv', async () => {
window.history.replaceState(null, '', '/#/detail?keyword=VIN-REPORT-001&protocol=GB32960');
const createObjectURL = vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:vehicle-report');