From 6ac980adade231bfed3678582e233a279455f86e Mon Sep 17 00:00:00 2001 From: lingniu Date: Sat, 4 Jul 2026 05:34:17 +0800 Subject: [PATCH] feat(platform): filter dashboard by missing source --- .../apps/web/src/pages/Dashboard.tsx | 18 +++++++- .../apps/web/src/test/App.test.tsx | 46 +++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx index 5bcbbd44..5bcf0e39 100644 --- a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx @@ -29,6 +29,12 @@ const serviceStatusTitle: Record = { identity_required: '身份未绑定' }; +const missingProtocolTitle: Record = { + GB32960: '缺 GB32960', + JT808: '缺 JT808', + YUTONG_MQTT: '缺 YUTONG_MQTT' +}; + function formatLag(value?: number | null) { return value == null ? '未接入' : value.toLocaleString(); } @@ -69,10 +75,15 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on const loadCoverage = (values?: Record) => { setCoverageLoading(true); - setCoverageServiceStatusTitle(values?.serviceStatus ? serviceStatusTitle[values.serviceStatus] ?? values.serviceStatus : ''); + const scopeTitle = [ + values?.serviceStatus ? serviceStatusTitle[values.serviceStatus] ?? values.serviceStatus : '', + values?.missingProtocol ? missingProtocolTitle[values.missingProtocol] ?? `缺 ${values.missingProtocol}` : '' + ].filter(Boolean).join(' / '); + setCoverageServiceStatusTitle(scopeTitle); const params = new URLSearchParams({ limit: '8' }); if (values?.keyword) params.set('keyword', values.keyword); if (values?.coverage) params.set('coverage', values.coverage); + if (values?.missingProtocol) params.set('missingProtocol', values.missingProtocol); if (values?.online) params.set('online', values.online); if (values?.bindingStatus) params.set('bindingStatus', values.bindingStatus); if (values?.serviceStatus) params.set('serviceStatus', values.serviceStatus); @@ -230,6 +241,11 @@ export function Dashboard({ onOpenVehicle, onOpenQuality, onOpenVehicles }: { on 单源 多源 + + 缺 GB32960 + 缺 JT808 + 缺 YUTONG_MQTT + 在线 离线 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 f30de436..018cc219 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -755,6 +755,52 @@ test('filters dashboard coverage by service status', async () => { expect(screen.getByText('当前筛选:部分来源离线')).toBeInTheDocument(); }); +test('filters dashboard coverage by missing source evidence', async () => { + window.history.replaceState(null, '', '/#/dashboard'); + const fetchMock = vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => { + const path = String(input); + if (path.includes('/api/dashboard/summary')) { + return { + ok: true, + json: async () => ({ + data: { + onlineVehicles: 3, + activeToday: 4, + frameToday: 1286320, + issueVehicles: 7, + kafkaLag: 0, + protocols: [], + serviceStatuses: [], + linkHealth: [] + }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + } + return { + ok: true, + json: async () => ({ + data: { items: [], total: 0, limit: 8, offset: 0 }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + } as Response; + }); + + render(); + + expect(await screen.findByText('车辆服务覆盖')).toBeInTheDocument(); + fireEvent.click(screen.getByTestId('dashboard-missing-protocol-filter')); + fireEvent.click(await screen.findByText('缺 YUTONG_MQTT')); + fireEvent.click(screen.getByRole('button', { name: '筛选' })); + + await waitFor(() => { + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('missingProtocol=YUTONG_MQTT'), undefined); + }); + expect(screen.getByText('当前筛选:缺 YUTONG_MQTT')).toBeInTheDocument(); +}); + test('opens dashboard coverage from service status distribution', async () => { window.history.replaceState(null, '', '/#/dashboard'); const fetchMock = vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {