feat(platform): split trajectory replay and history query

This commit is contained in:
lingniu
2026-07-04 17:23:48 +08:00
parent a65db893d2
commit 747894ce1d
11 changed files with 88 additions and 53 deletions

View File

@@ -89,7 +89,9 @@ test('exposes AMap operations shortcuts when map key is configured', async () =>
fireEvent.click(screen.getByRole('button', { name: '顶部轨迹回放' }));
expect(window.location.hash.startsWith('#/history')).toBe(true);
fireEvent.click(screen.getByRole('button', { name: '顶部历史查询' }));
expect(window.location.hash.startsWith('#/history')).toBe(true);
expect(window.location.hash.startsWith('#/history-query')).toBe(true);
expect(new URLSearchParams(window.location.hash.split('?')[1] ?? '').get('tab')).toBe('raw');
expect(await screen.findByRole('heading', { name: '历史查询' })).toBeInTheDocument();
fireEvent.click(screen.getByRole('button', { name: '顶部统计查询' }));
expect(window.location.hash.startsWith('#/mileage')).toBe(true);
fireEvent.click(await screen.findByRole('button', { name: '顶部告警事件正常' }));
@@ -424,7 +426,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
await renderDashboard();
fireEvent.click(screen.getByRole('button', { name: '能力入口 历史数据查询' }));
expect(window.location.hash.startsWith('#/history')).toBe(true);
expect(window.location.hash.startsWith('#/history-query')).toBe(true);
expect(new URLSearchParams(window.location.hash.split('?')[1] ?? '').get('tab')).toBe('raw');
cleanup();
@@ -1096,7 +1098,7 @@ test('dashboard copies highest priority quality issue notification text', async
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('数据来源JT808'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('详情JT808 数据缺少 VIN 映射'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹证据http://localhost:3000/#/history?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW证据http://localhost:3000/#/history?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW证据http://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
});
test('dashboard keeps core vehicle service metrics when preview requests fail', async () => {
@@ -3142,7 +3144,7 @@ test('uses backend quality notification plan on quality page', async () => {
vehicleLabel: '后端车辆标签 / VIN-PLAN-001',
realtimeHash: '#/realtime?keyword=VIN-PLAN-001',
historyHash: '#/history?keyword=VIN-PLAN-001',
rawHash: '#/history?keyword=VIN-PLAN-001&tab=raw',
rawHash: '#/history-query?keyword=VIN-PLAN-001&tab=raw',
vehicleHash: '#/detail?keyword=VIN-PLAN-001',
notificationText: '【P0 告警通知】后端计划'
}],
@@ -3413,7 +3415,7 @@ test('copies notification text from quality priority queue', async () => {
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('详情:手机号未映射 VIN需要维护 binding'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时定位http://localhost:3000/#/realtime?keyword=%E7%B2%A4A%E9%80%9A%E7%9F%A51&protocol=JT808'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹证据http://localhost:3000/#/history?keyword=%E7%B2%A4A%E9%80%9A%E7%9F%A51&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW证据http://localhost:3000/#/history?keyword=%E7%B2%A4A%E9%80%9A%E7%9F%A51&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW证据http://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E9%80%9A%E7%9F%A51&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务http://localhost:3000/#/detail?keyword=%E7%B2%A4A%E9%80%9A%E7%9F%A51&protocol=JT808'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('告警筛选http://localhost:3000/#/quality'));
});
@@ -3975,16 +3977,16 @@ test('opens same-day raw evidence from quality priority queue', async () => {
fireEvent.click(screen.getByRole('button', { name: 'RAW证据' }));
await waitFor(() => {
expect(window.location.hash.startsWith('#/history?')).toBe(true);
expect(window.location.hash.startsWith('#/history-query?')).toBe(true);
});
const params = new URLSearchParams(window.location.hash.slice('#/history?'.length));
const params = new URLSearchParams(window.location.hash.slice('#/history-query?'.length));
expect(params.get('keyword')).toBe('VIN-ALERT-RAW');
expect(params.get('protocol')).toBe('JT808');
expect(params.get('dateFrom')).toBe('2026-07-03');
expect(params.get('dateTo')).toBe('2026-07-04');
expect(params.get('includeFields')).toBe('true');
expect(params.get('tab')).toBe('raw');
expect(await screen.findByRole('heading', { name: '轨迹回放' })).toBeInTheDocument();
expect(await screen.findByRole('heading', { name: '历史查询' })).toBeInTheDocument();
});
test('opens vehicle service from quality issue with issue source evidence', async () => {
@@ -4332,16 +4334,16 @@ test('opens same-day raw evidence from quality issue row', async () => {
fireEvent.click(screen.getByRole('button', { name: '核对 RAW' }));
await waitFor(() => {
expect(window.location.hash.startsWith('#/history?')).toBe(true);
expect(window.location.hash.startsWith('#/history-query?')).toBe(true);
});
const params = new URLSearchParams(window.location.hash.slice('#/history?'.length));
const params = new URLSearchParams(window.location.hash.slice('#/history-query?'.length));
expect(params.get('keyword')).toBe('VIN-QUALITY-RAW');
expect(params.get('protocol')).toBe('GB32960');
expect(params.get('dateFrom')).toBe('2026-07-03');
expect(params.get('dateTo')).toBe('2026-07-04');
expect(params.get('includeFields')).toBe('true');
expect(params.get('tab')).toBe('raw');
expect(await screen.findByRole('heading', { name: '轨迹回放' })).toBeInTheDocument();
expect(await screen.findByRole('heading', { name: '历史查询' })).toBeInTheDocument();
});
test('copies trajectory playback summary from history page', async () => {
@@ -5273,7 +5275,7 @@ test('applies protocol from shareable history hash to API requests', async () =>
});
test('shows and clears current history filters while keeping vehicle scope', async () => {
window.history.replaceState(null, '', '/#/history?keyword=VIN-HISTORY-001&protocol=JT808&dateFrom=2026-07-01+00%3A00%3A00&dateTo=2026-07-01+23%3A59%3A59&includeFields=true&fields=jt808.location.longitude%2Cjt808.location.latitude&tab=raw');
window.history.replaceState(null, '', '/#/history-query?keyword=VIN-HISTORY-001&protocol=JT808&dateFrom=2026-07-01+00%3A00%3A00&dateTo=2026-07-01+23%3A59%3A59&includeFields=true&fields=jt808.location.longitude%2Cjt808.location.latitude&tab=raw');
const fetchMock = vi.spyOn(globalThis, 'fetch').mockImplementation(async (input, init) => {
const path = String(input);
if (path.includes('/api/ops/health')) {
@@ -5330,7 +5332,7 @@ test('shows and clears current history filters while keeping vehicle scope', asy
await waitFor(() => {
expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/history/locations?limit=10&offset=0&keyword=VIN-HISTORY-001'), undefined);
});
expect(window.location.hash).toBe('#/history?keyword=VIN-HISTORY-001&tab=raw');
expect(window.location.hash).toBe('#/history-query?keyword=VIN-HISTORY-001&tab=raw');
});
test('updates history hash when vehicle history filters are submitted', async () => {
@@ -5833,7 +5835,7 @@ test('exports current history location page as csv', async () => {
});
test('exports current raw frame page as csv with parsed fields', async () => {
window.history.replaceState(null, '', '/#/history?keyword=VIN-EXPORT-RAW&protocol=GB32960&includeFields=true&tab=raw');
window.history.replaceState(null, '', '/#/history-query?keyword=VIN-EXPORT-RAW&protocol=GB32960&includeFields=true&tab=raw');
const createObjectURL = vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:history-raw');
const revokeObjectURL = vi.spyOn(URL, 'revokeObjectURL').mockImplementation(() => undefined);
vi.spyOn(HTMLAnchorElement.prototype, 'click').mockImplementation(() => undefined);
@@ -6383,15 +6385,15 @@ test('opens same-day raw frame evidence from mileage row', async () => {
fireEvent.click(screen.getByRole('button', { name: '核对 RAW' }));
await waitFor(() => {
expect(window.location.hash.startsWith('#/history?')).toBe(true);
expect(window.location.hash.startsWith('#/history-query?')).toBe(true);
});
const params = new URLSearchParams(window.location.hash.slice('#/history?'.length));
const params = new URLSearchParams(window.location.hash.slice('#/history-query?'.length));
expect(params.get('keyword')).toBe('VIN-MILEAGE-RAW');
expect(params.get('protocol')).toBe('JT808');
expect(params.get('dateFrom')).toBe('2026-07-03');
expect(params.get('dateTo')).toBe('2026-07-04');
expect(params.get('tab')).toBe('raw');
expect(await screen.findByRole('heading', { name: '轨迹回放' })).toBeInTheDocument();
expect(await screen.findByRole('heading', { name: '历史查询' })).toBeInTheDocument();
});
test('shows mileage anomaly action guidance', async () => {
@@ -7015,9 +7017,9 @@ test('opens same-day raw evidence from history location row', async () => {
fireEvent.click(screen.getByRole('button', { name: '核对 RAW' }));
await waitFor(() => {
expect(window.location.hash.startsWith('#/history?')).toBe(true);
expect(window.location.hash.startsWith('#/history-query?')).toBe(true);
});
const params = new URLSearchParams(window.location.hash.slice('#/history?'.length));
const params = new URLSearchParams(window.location.hash.slice('#/history-query?'.length));
expect(params.get('keyword')).toBe('VIN-HISTORY-RAW');
expect(params.get('protocol')).toBe('JT808');
expect(params.get('dateFrom')).toBe('2026-07-03');
@@ -7119,7 +7121,7 @@ test('opens vehicle service from raw history rows with row source evidence', asy
});
test('opens same-day mileage statistics from raw history row', async () => {
window.history.replaceState(null, '', '/#/history?keyword=VIN-RAW-MILEAGE&protocol=JT808&tab=raw');
window.history.replaceState(null, '', '/#/history-query?keyword=VIN-RAW-MILEAGE&protocol=JT808&tab=raw');
vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {
const path = String(input);
if (path.includes('/api/ops/health')) {
@@ -9960,7 +9962,7 @@ test('copies vehicle service diagnostic summary', async () => {
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('RAWhttp://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true');
expect(copied).toContain('里程http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808');
});
@@ -10207,7 +10209,7 @@ test('opens raw history with the currently selected vehicle detail source', asyn
fireEvent.click(screen.getByRole('button', { name: '查看 RAW' }));
await waitFor(() => {
expect(window.location.hash).toBe('#/history?keyword=VIN001&protocol=JT808&tab=raw');
expect(window.location.hash).toBe('#/history-query?keyword=VIN001&protocol=JT808&tab=raw');
});
});
@@ -10433,7 +10435,7 @@ test('opens source-specific raw history directly from vehicle detail source evid
fireEvent.click(await screen.findByRole('button', { name: '查看 JT808 RAW' }));
await waitFor(() => {
expect(window.location.hash).toBe('#/history?keyword=VIN001&protocol=JT808&tab=raw');
expect(window.location.hash).toBe('#/history-query?keyword=VIN001&protocol=JT808&tab=raw');
});
});