From 8327eeb2f58cad9d280bc6ee61c45742879e825c Mon Sep 17 00:00:00 2001 From: lingniu Date: Sat, 4 Jul 2026 11:37:01 +0800 Subject: [PATCH] feat(platform): add realtime map actions --- vehicle-data-platform/apps/web/src/App.tsx | 2 +- .../apps/web/src/pages/Realtime.tsx | 13 +++- .../apps/web/src/test/App.test.tsx | 73 +++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/vehicle-data-platform/apps/web/src/App.tsx b/vehicle-data-platform/apps/web/src/App.tsx index cbc50726..21b3b853 100644 --- a/vehicle-data-platform/apps/web/src/App.tsx +++ b/vehicle-data-platform/apps/web/src/App.tsx @@ -347,7 +347,7 @@ export default function App() { const pages: Record = { dashboard: , vehicles: , - realtime: , + realtime: , detail: , history: , mileage: , diff --git a/vehicle-data-platform/apps/web/src/pages/Realtime.tsx b/vehicle-data-platform/apps/web/src/pages/Realtime.tsx index e2afbe3e..2d9c903e 100644 --- a/vehicle-data-platform/apps/web/src/pages/Realtime.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Realtime.tsx @@ -47,6 +47,11 @@ function isValidCoordinate(row: VehicleRealtimeRow) { return Number.isFinite(row.longitude) && Number.isFinite(row.latitude) && row.longitude !== 0 && row.latitude !== 0; } +function amapMarkerURL(row: VehicleRealtimeRow) { + const name = encodeURIComponent(row.plate || row.vin || '车辆位置'); + return `https://uri.amap.com/marker?position=${row.longitude},${row.latitude}&name=${name}&src=lingniu-vehicle-platform`; +} + const onlineLabel: Record = { online: '在线', offline: '离线' @@ -61,10 +66,12 @@ const serviceStatusLabel: Record = { export function Realtime({ onOpenVehicle, + onOpenHistory, onFiltersChange, initialFilters = {} }: { onOpenVehicle: (vin: string, protocol?: string) => void; + onOpenHistory?: (vin: string, protocol?: string) => void; onFiltersChange?: (filters: Record) => void; initialFilters?: Record; }) { @@ -222,7 +229,11 @@ export function Realtime({
{row.lastSeen || '-'} - + + + + +
); 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 e3bb1cd3..7a9e708c 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -4678,6 +4678,79 @@ test('opens vehicle service from realtime map service queue', async () => { }); }); +test('opens amap coordinate and trajectory playback from realtime map service queue', async () => { + window.history.replaceState(null, '', '/#/realtime'); + const openSpy = vi.spyOn(window, 'open').mockImplementation(() => null); + vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => { + const path = String(input); + if (path.includes('/api/realtime/vehicles')) { + return { + ok: true, + json: async () => ({ + data: { + items: [{ + vin: 'VIN-MAP-LINK', + plate: '粤AMAP02', + phone: '', + oem: 'G7s', + protocols: ['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:11:10', hasRealtime: true, hasHistory: true, hasRaw: true, hasMileage: true } + ], + sourceCount: 2, + onlineSourceCount: 2, + online: true, + primaryProtocol: 'GB32960', + longitude: 113.24567, + latitude: 23.12345, + speedKmh: 30, + socPercent: 78, + totalMileageKm: 119925, + lastSeen: '2026-07-03 20:12:10', + bindingStatus: 'bound', + serviceStatus: { + status: 'healthy', + severity: 'ok', + title: '服务正常', + detail: '2/2 来源在线', + sourceCount: 2, + onlineSourceCount: 2 + } + }], + total: 1, + limit: 50, + 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(); + + expect(await screen.findByText('地图车辆服务队列')).toBeInTheDocument(); + fireEvent.click(screen.getByRole('button', { name: '高德坐标' })); + expect(openSpy).toHaveBeenCalledWith( + expect.stringContaining('https://uri.amap.com/marker?position=113.24567,23.12345'), + '_blank', + 'noopener,noreferrer' + ); + + fireEvent.click(screen.getByRole('button', { name: '轨迹回放' })); + expect(window.location.hash).toBe('#/history?keyword=VIN-MAP-LINK&protocol=GB32960'); +}); + test('loads realtime vehicles from shareable source filter hash', async () => { window.history.replaceState(null, '', '/#/realtime?keyword=%E7%B2%A4ART002&protocol=JT808&online=online&serviceStatus=degraded'); const fetchMock = vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {