diff --git a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx
index 0d09c825..18480f8f 100644
--- a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx
+++ b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx
@@ -227,6 +227,7 @@ export function VehicleDetail({
} onClick={() => load(query)} loading={loading}>刷新
} onClick={copyVehicleServiceURL}>复制服务链接
+
diff --git a/vehicle-data-platform/apps/web/src/test/App.test.tsx b/vehicle-data-platform/apps/web/src/test/App.test.tsx
index 0d0742db..9b62cdcd 100644
--- a/vehicle-data-platform/apps/web/src/test/App.test.tsx
+++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx
@@ -3160,6 +3160,82 @@ test('opens history with the currently selected vehicle detail source', async ()
});
});
+test('opens raw history with the currently selected vehicle detail source', async () => {
+ window.history.replaceState(null, '', '/#/detail?keyword=VIN001');
+ vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {
+ const path = String(input);
+ if (path.includes('/api/vehicle-service')) {
+ return {
+ ok: true,
+ json: async () => ({
+ data: {
+ vin: 'VIN001',
+ lookupKey: 'VIN001',
+ lookupResolved: true,
+ resolution: {
+ lookupKey: 'VIN001',
+ resolved: true,
+ vin: 'VIN001',
+ plate: '粤AG18312',
+ phone: '13307795425',
+ oem: 'G7s',
+ protocols: ['GB32960', 'JT808'],
+ online: true,
+ lastSeen: '2026-07-03 20:12:10'
+ },
+ realtimeSummary: {
+ vin: 'VIN001',
+ plate: '粤AG18312',
+ phone: '13307795425',
+ oem: 'G7s',
+ protocols: ['GB32960', 'JT808'],
+ sourceCount: 2,
+ onlineSourceCount: 2,
+ online: true,
+ primaryProtocol: 'GB32960',
+ longitude: 113.2,
+ latitude: 23.1,
+ speedKmh: 30,
+ socPercent: 78,
+ totalMileageKm: 100,
+ lastSeen: '2026-07-03 20:12:10'
+ },
+ sources: ['GB32960', 'JT808'],
+ sourceStatus: [
+ { protocol: 'GB32960', online: true, lastSeen: '2026-07-03 20:12:10', hasRealtime: true, hasHistory: true, hasRaw: true, hasMileage: true },
+ { protocol: 'JT808', online: true, lastSeen: '2026-07-03 20:12:08', hasRealtime: true, hasHistory: true, hasRaw: true, hasMileage: true }
+ ],
+ realtime: [],
+ history: { items: [], total: 0, limit: 20, offset: 0 },
+ raw: { items: [], total: 0, limit: 10, offset: 0 },
+ mileage: { items: [], total: 0, limit: 20, offset: 0 },
+ quality: { items: [], total: 0, limit: 20, offset: 0 }
+ },
+ traceId: 'trace-test',
+ timestamp: 1783094400000
+ })
+ } as Response;
+ }
+ return {
+ ok: true,
+ json: async () => ({
+ data: { items: [], total: 0, limit: 10, offset: 0 },
+ traceId: 'trace-test',
+ timestamp: 1783094400000
+ })
+ } as Response;
+ });
+
+ render();
+
+ fireEvent.click(await screen.findByRole('button', { name: '仅看 JT808' }));
+ fireEvent.click(screen.getByRole('button', { name: '查看 RAW' }));
+
+ await waitFor(() => {
+ expect(window.location.hash).toBe('#/history?keyword=VIN001&protocol=JT808&tab=raw');
+ });
+});
+
test('opens source-specific history directly from vehicle detail source card', async () => {
window.history.replaceState(null, '', '/#/detail?keyword=VIN001');
vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {