From 89e954cad90c4f1611775721234f029b39e7514c Mon Sep 17 00:00:00 2001 From: lingniu Date: Sat, 4 Jul 2026 18:01:45 +0800 Subject: [PATCH] feat(platform): use alert events api surface --- vehicle-data-platform/apps/web/src/App.tsx | 2 +- .../apps/web/src/pages/Dashboard.tsx | 2 +- .../apps/web/src/pages/NotificationRules.tsx | 2 +- .../apps/web/src/pages/Quality.tsx | 6 +- .../apps/web/src/test/App.test.tsx | 170 +++++++++--------- 5 files changed, 91 insertions(+), 91 deletions(-) diff --git a/vehicle-data-platform/apps/web/src/App.tsx b/vehicle-data-platform/apps/web/src/App.tsx index 85565d49..f262c2ee 100644 --- a/vehicle-data-platform/apps/web/src/App.tsx +++ b/vehicle-data-platform/apps/web/src/App.tsx @@ -81,7 +81,7 @@ export default function App() { const refreshOpsHealth = useCallback((showError = true) => { return Promise.all([ api.opsHealth(), - api.qualityNotificationPlan(new URLSearchParams({ limit: '5' })).catch(() => null) + api.alertEventNotificationPlan(new URLSearchParams({ limit: '5' })).catch(() => null) ]) .then(([health, notificationPlan]) => { setLinkIssueCount(health.linkHealth.filter((item) => item.status !== 'ok').length); diff --git a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx index b2880a3a..dcbafd65 100644 --- a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx @@ -226,7 +226,7 @@ export function Dashboard({ api.vehicleServiceSummary().then(setServiceSummary), api.vehicleCoverage(new URLSearchParams({ limit: '8' })).then((page) => setCoverage(page.items)), api.vehicleRealtime(new URLSearchParams({ limit: '8' })).then((page) => setLocations(page.items)), - api.qualityIssues(new URLSearchParams({ limit: '5' })).then((page) => setQualityIssues(page.items)) + api.alertEvents(new URLSearchParams({ limit: '5' })).then((page) => setQualityIssues(page.items)) ]; Promise.allSettled(tasks) .then((results) => { diff --git a/vehicle-data-platform/apps/web/src/pages/NotificationRules.tsx b/vehicle-data-platform/apps/web/src/pages/NotificationRules.tsx index 44ee2a8e..9710109a 100644 --- a/vehicle-data-platform/apps/web/src/pages/NotificationRules.tsx +++ b/vehicle-data-platform/apps/web/src/pages/NotificationRules.tsx @@ -73,7 +73,7 @@ export function NotificationRules() { const load = () => { setLoading(true); Promise.all([ - api.qualityNotificationPlan(new URLSearchParams({ limit: '50' })), + api.alertEventNotificationPlan(new URLSearchParams({ limit: '50' })), api.opsHealth().catch(() => null) ]) .then(([nextPlan, nextHealth]) => { diff --git a/vehicle-data-platform/apps/web/src/pages/Quality.tsx b/vehicle-data-platform/apps/web/src/pages/Quality.tsx index cd4201e0..a44b0a76 100644 --- a/vehicle-data-platform/apps/web/src/pages/Quality.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Quality.tsx @@ -539,7 +539,7 @@ export function Quality({ const params = qualityParams(values); params.set('limit', String(pageSize)); params.set('offset', String((page - 1) * pageSize)); - api.qualityIssues(params) + api.alertEvents(params) .then((nextPage) => { setIssues(nextPage.items); setPagination({ currentPage: page, pageSize, total: nextPage.total }); @@ -550,7 +550,7 @@ export function Quality({ const loadSummary = (values: Record = filters) => { setLoadingSummary(true); - api.qualitySummary(qualityParams(values)) + api.alertEventSummary(qualityParams(values)) .then(setSummary) .catch((error: Error) => Toast.error(error.message)) .finally(() => setLoadingSummary(false)); @@ -569,7 +569,7 @@ export function Quality({ const loadNotificationPlan = (values: Record = filters, pageSize = pagination.pageSize) => { const params = qualityParams(values); params.set('limit', String(pageSize)); - api.qualityNotificationPlan(params) + api.alertEventNotificationPlan(params) .then((plan) => { if (Array.isArray(plan.rules) && Array.isArray(plan.policies) && Array.isArray(plan.priorityIssues)) { setNotificationPlan(plan); 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 ed6512ce..6d908443 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -46,7 +46,7 @@ test('exposes AMap operations shortcuts when map key is configured', async () => }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -56,7 +56,7 @@ test('exposes AMap operations shortcuts when map key is configured', async () => }) } as Response; } - if (path.includes('/api/quality/notification-plan')) { + if (path.includes('/api/quality/notification-plan') || path.includes('/api/alert-events/notification-plan')) { return { ok: true, json: async () => ({ @@ -119,7 +119,7 @@ test('shows global alert pressure from notification plan in topbar', async () => }) } as Response; } - if (path.includes('/api/quality/notification-plan')) { + if (path.includes('/api/quality/notification-plan') || path.includes('/api/alert-events/notification-plan')) { return { ok: true, json: async () => ({ @@ -415,7 +415,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -425,7 +425,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => { }) } as Response; } - if (path.includes('/api/quality/notification-plan')) { + if (path.includes('/api/quality/notification-plan') || path.includes('/api/alert-events/notification-plan')) { return { ok: true, json: async () => ({ @@ -593,7 +593,7 @@ test('dashboard exposes vehicle command center map actions', async () => { }) } as Response; } - if (path.includes('/api/quality/notification-plan')) { + if (path.includes('/api/quality/notification-plan') || path.includes('/api/alert-events/notification-plan')) { return { ok: true, json: async () => ({ @@ -617,7 +617,7 @@ test('dashboard exposes vehicle command center map actions', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -799,7 +799,7 @@ test.each([ }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -884,7 +884,7 @@ test('dashboard exposes end-to-end operations workflow entries', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -977,7 +977,7 @@ test('dashboard surfaces highest priority quality issue with evidence shortcuts' }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -1002,7 +1002,7 @@ test('dashboard surfaces highest priority quality issue with evidence shortcuts' }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -1097,7 +1097,7 @@ test('dashboard copies highest priority quality issue notification text', async }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -1122,7 +1122,7 @@ test('dashboard copies highest priority quality issue notification text', async }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -1201,7 +1201,7 @@ test('dashboard keeps core vehicle service metrics when preview requests fail', }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: false, status: 500, @@ -2668,7 +2668,7 @@ test('opens vehicle service from dashboard quality preview with issue source evi }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -2887,7 +2887,7 @@ test('renders quality issues as vehicle-service governance labels', async () => }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -2904,7 +2904,7 @@ test('renders quality issues as vehicle-service governance labels', async () => }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -2976,7 +2976,7 @@ test('shows alert rule and notification policy workspace on quality page', async }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -2997,7 +2997,7 @@ test('shows alert rule and notification policy workspace on quality page', async }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3058,7 +3058,7 @@ test('shows actionable priority queue on quality page', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3075,7 +3075,7 @@ test('shows actionable priority queue on quality page', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3175,7 +3175,7 @@ test('uses backend quality notification plan on quality page', async () => { }) } as Response; } - if (path.includes('/api/quality/notification-plan')) { + if (path.includes('/api/quality/notification-plan') || path.includes('/api/alert-events/notification-plan')) { return { ok: true, json: async () => ({ @@ -3212,7 +3212,7 @@ test('uses backend quality notification plan on quality page', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3222,7 +3222,7 @@ test('uses backend quality notification plan on quality page', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3249,7 +3249,7 @@ test('uses backend quality notification plan on quality page', async () => { expect(screen.getAllByText('10 分钟确认').length).toBeGreaterThan(0); expect(screen.getByText('后端无来源规则')).toBeInTheDocument(); expect(screen.getByText('后端 P0 通知策略')).toBeInTheDocument(); - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/notification-plan?limit=20'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/notification-plan?limit=20'), undefined); }); test('renders notification rules as a standalone operations page', async () => { @@ -3280,7 +3280,7 @@ test('renders notification rules as a standalone operations page', async () => { }) } as Response; } - if (path.includes('/api/quality/notification-plan')) { + if (path.includes('/api/quality/notification-plan') || path.includes('/api/alert-events/notification-plan')) { return { ok: true, json: async () => ({ @@ -3321,7 +3321,7 @@ test('renders notification rules as a standalone operations page', async () => { expect(screen.getByText('P0 实时中断')).toBeInTheDocument(); expect(screen.getByText('接入运维 + 业务责任人')).toBeInTheDocument(); expect(screen.getByText('platform-rules-test')).toBeInTheDocument(); - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/notification-plan?limit=50'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/notification-plan?limit=50'), undefined); fireEvent.click(screen.getByRole('button', { name: '复制通知规则Runbook' })); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【通知规则Runbook】')); @@ -3408,7 +3408,7 @@ test('copies notification text from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3425,7 +3425,7 @@ test('copies notification text from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3497,7 +3497,7 @@ test('copies dispatch ticket from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3514,7 +3514,7 @@ test('copies dispatch ticket from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3588,7 +3588,7 @@ test('copies priority queue notification digest on quality page', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3605,7 +3605,7 @@ test('copies priority queue notification digest on quality page', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3690,7 +3690,7 @@ test('copies notification text from regular quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3707,7 +3707,7 @@ test('copies notification text from regular quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3772,7 +3772,7 @@ test('opens realtime map context from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3789,7 +3789,7 @@ test('opens realtime map context from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3874,7 +3874,7 @@ test('opens same-day trajectory evidence from quality priority queue', async () }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3891,7 +3891,7 @@ test('opens same-day trajectory evidence from quality priority queue', async () }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -3967,7 +3967,7 @@ test('opens same-day raw evidence from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -3984,7 +3984,7 @@ test('opens same-day raw evidence from quality priority queue', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4061,7 +4061,7 @@ test('opens vehicle service from quality issue with issue source evidence', asyn }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4078,7 +4078,7 @@ test('opens vehicle service from quality issue with issue source evidence', asyn }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4161,7 +4161,7 @@ test('opens same-day history evidence from quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4178,7 +4178,7 @@ test('opens same-day history evidence from quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4237,7 +4237,7 @@ test('quality page surfaces escalation clock for priority issues', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4254,7 +4254,7 @@ test('quality page surfaces escalation clock for priority issues', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4324,7 +4324,7 @@ test('opens same-day raw evidence from quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4341,7 +4341,7 @@ test('opens same-day raw evidence from quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4511,7 +4511,7 @@ test('opens same-day mileage statistics from quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4528,7 +4528,7 @@ test('opens same-day mileage statistics from quality issue row', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4642,7 +4642,7 @@ test('drills into quality issues by issue type', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4659,7 +4659,7 @@ test('drills into quality issues by issue type', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4689,9 +4689,9 @@ test('drills into quality issues by issue type', async () => { fireEvent.click(await screen.findByRole('button', { name: /主要问题 暂无数据来源 1/ })); await waitFor(() => { - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/issues?issueType=NO_SOURCE&limit=20&offset=0'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?issueType=NO_SOURCE&limit=20&offset=0'), undefined); }); - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/summary?issueType=NO_SOURCE'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?issueType=NO_SOURCE'), undefined); }); test('drills into quality issues by protocol bucket', async () => { @@ -4708,7 +4708,7 @@ test('drills into quality issues by protocol bucket', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4728,7 +4728,7 @@ test('drills into quality issues by protocol bucket', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4758,9 +4758,9 @@ test('drills into quality issues by protocol bucket', async () => { fireEvent.click(await screen.findByRole('button', { name: '查看 JT808 质量问题' })); await waitFor(() => { - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/issues?protocol=JT808&limit=20&offset=0'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?protocol=JT808&limit=20&offset=0'), undefined); }); - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/summary?protocol=JT808'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?protocol=JT808'), undefined); expect(window.location.hash).toBe('#/alert-events?protocol=JT808'); }); @@ -4778,7 +4778,7 @@ test('drills into quality issues by issue type bucket', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4798,7 +4798,7 @@ test('drills into quality issues by issue type bucket', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4828,9 +4828,9 @@ test('drills into quality issues by issue type bucket', async () => { fireEvent.click(await screen.findByRole('button', { name: '查看 VIN 缺失质量问题' })); await waitFor(() => { - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/issues?issueType=VIN_MISSING&limit=20&offset=0'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?issueType=VIN_MISSING&limit=20&offset=0'), undefined); }); - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/summary?issueType=VIN_MISSING'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?issueType=VIN_MISSING'), undefined); expect(window.location.hash).toBe('#/alert-events?issueType=VIN_MISSING'); }); @@ -4848,7 +4848,7 @@ test('applies shareable quality filters from hash', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4865,7 +4865,7 @@ test('applies shareable quality filters from hash', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4888,9 +4888,9 @@ test('applies shareable quality filters from hash', async () => { render(); await waitFor(() => { - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/issues?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE&limit=20&offset=0'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE&limit=20&offset=0'), undefined); }); - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/summary?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events/summary?keyword=%E7%B2%A4A&protocol=VEHICLE_SERVICE&issueType=NO_SOURCE'), undefined); }); test('shows and clears current quality filters', async () => { @@ -4907,7 +4907,7 @@ test('shows and clears current quality filters', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4924,7 +4924,7 @@ test('shows and clears current quality filters', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -4953,7 +4953,7 @@ test('shows and clears current quality filters', async () => { fireEvent.click(screen.getByRole('button', { name: '清空筛选' })); await waitFor(() => { - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/issues?limit=20&offset=0'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?limit=20&offset=0'), undefined); }); expect(window.location.hash).toBe('#/alert-events'); }); @@ -4977,7 +4977,7 @@ test('copies shareable quality filter link', async () => { }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -4994,7 +4994,7 @@ test('copies shareable quality filter link', async () => { }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -8536,7 +8536,7 @@ test('surfaces multi-source realtime consistency issues with quality drilldown', }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -8546,7 +8546,7 @@ test('surfaces multi-source realtime consistency issues with quality drilldown', }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -8636,7 +8636,7 @@ test('opens quality issues from realtime vehicle row with source evidence', asyn }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -8653,7 +8653,7 @@ test('opens quality issues from realtime vehicle row with source evidence', asyn }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -8786,7 +8786,7 @@ test('opens realtime status from quality issue row with source evidence', async }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -8803,7 +8803,7 @@ test('opens realtime status from quality issue row with source evidence', async }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -9357,7 +9357,7 @@ test('opens quality issues from source-filtered vehicle list with source evidenc }) } as Response; } - if (path.includes('/api/quality/summary')) { + if (path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary')) { return { ok: true, json: async () => ({ @@ -9374,7 +9374,7 @@ test('opens quality issues from source-filtered vehicle list with source evidenc }) } as Response; } - if (path.includes('/api/quality/issues')) { + if (path.includes('/api/quality/issues') || path.includes('/api/alert-events?')) { return { ok: true, json: async () => ({ @@ -9690,7 +9690,7 @@ test('opens quality governance from vehicle detail overview', async () => { json: async () => ({ data: path.includes('/api/ops/health') ? { linkHealth: [], kafkaLag: 0, redisOnlineKeys: 0, tdengineWritable: true, mysqlWritable: true, runtime: { requestTimeoutMs: 5000 } } - : path.includes('/api/quality/summary') + : path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary') ? { issueVehicleCount: 1, issueRecordCount: 3, errorCount: 0, warningCount: 3, protocols: [], issueTypes: [] } : { items: [], total: 3, limit: 20, offset: 0 }, traceId: 'trace-test', @@ -9710,7 +9710,7 @@ test('opens quality governance from vehicle detail overview', async () => { expect(await screen.findByRole('heading', { name: '告警事件' })).toBeInTheDocument(); expect(screen.getByText('告警事件闭环')).toBeInTheDocument(); expect(screen.getByText('事件触发')).toBeInTheDocument(); - expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/quality/issues?keyword=VIN001&limit=20&offset=0'), undefined); + expect(fetchMock).toHaveBeenCalledWith(expect.stringContaining('/api/alert-events?keyword=VIN001&limit=20&offset=0'), undefined); }); test('quality health storage card stays pending before ops health loads', async () => { @@ -9723,7 +9723,7 @@ test('quality health storage card stays pending before ops health loads', async return { ok: true, json: async () => ({ - data: path.includes('/api/quality/summary') + data: path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary') ? { issueVehicleCount: 0, issueRecordCount: 0, errorCount: 0, warningCount: 0, protocols: [], issueTypes: [] } : { items: [], total: 0, limit: 20, offset: 0 }, traceId: 'trace-test', @@ -9749,7 +9749,7 @@ test('quality health shows active connection capacity metric', async () => { json: async () => ({ data: path.includes('/api/ops/health') ? { linkHealth: [], kafkaLag: 0, activeConnections: 120000, redisOnlineKeys: 368, tdengineWritable: true, mysqlWritable: true, runtime: { requestTimeoutMs: 5000, platformRelease: 'platform-20260704153710' } } - : path.includes('/api/quality/summary') + : path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary') ? { issueVehicleCount: 0, issueRecordCount: 0, errorCount: 0, warningCount: 0, protocols: [], issueTypes: [] } : { items: [], total: 0, limit: 20, offset: 0 }, traceId: 'trace-test', @@ -9776,7 +9776,7 @@ test('quality health shows structured capacity findings', async () => { json: async () => ({ data: path.includes('/api/ops/health') ? { linkHealth: [], kafkaLag: 42, activeConnections: 120000, capacityFindings: ['kafka lag 42'], redisOnlineKeys: 368, tdengineWritable: true, mysqlWritable: true, runtime: { requestTimeoutMs: 5000 } } - : path.includes('/api/quality/summary') + : path.includes('/api/quality/summary') || path.includes('/api/alert-events/summary') ? { issueVehicleCount: 0, issueRecordCount: 0, errorCount: 0, warningCount: 0, protocols: [], issueTypes: [] } : { items: [], total: 0, limit: 20, offset: 0 }, traceId: 'trace-test',