feat(platform): use alert events api surface

This commit is contained in:
lingniu
2026-07-04 18:01:45 +08:00
parent 1235e76c32
commit 89e954cad9
5 changed files with 91 additions and 91 deletions

View File

@@ -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);

View File

@@ -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) => {

View File

@@ -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]) => {

View File

@@ -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<string, string> = 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<string, string> = 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);

View File

@@ -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(<App />);
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',