feat(platform): add alert evidence package

This commit is contained in:
lingniu
2026-07-04 19:53:28 +08:00
parent 9e38112ece
commit b0451982a1
2 changed files with 45 additions and 0 deletions

View File

@@ -341,6 +341,35 @@ function priorityIssueTicketText(row: PriorityIssueRow) {
].join('\n');
}
function priorityIssueEvidencePackageText(row: PriorityIssueRow) {
const lookup = qualityIssueVehicleLookup(row);
const dateFrom = issueEvidenceDate(row.lastSeen);
const dateTo = nextDate(dateFrom);
const evidenceFilters = {
...(dateFrom ? { dateFrom } : {}),
...(dateTo ? { dateTo } : {})
};
return [
'【告警证据包】',
`优先级:${row.priority}`,
`车辆:${row.vehicleLabel}`,
`数据来源:${qualityProtocolLabel(row.protocol)}`,
`来源地址:${row.sourceEndpoint || '-'}`,
`问题:${qualityIssueLabel(row.issueType)}`,
`建议动作:${row.actionLabel}`,
`SLA${row.sla}`,
`最后时间:${row.lastSeen || '-'}`,
`详情:${row.detail || '-'}`,
`验收标准:${acceptanceCriteria(row)}`,
`实时定位:${appURL(buildAppHash({ page: 'realtime', keyword: lookup.key, protocol: row.protocol }))}`,
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: lookup.key, protocol: row.protocol, filters: evidenceFilters }))}`,
`RAW证据${appURL(buildAppHash({ page: 'history-query', keyword: lookup.key, protocol: row.protocol, filters: { tab: 'raw', ...evidenceFilters, includeFields: 'true' } }))}`,
`里程复核:${appURL(buildAppHash({ page: 'mileage', keyword: lookup.key, protocol: row.protocol, filters: evidenceFilters }))}`,
`车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: lookup.key, protocol: row.protocol }))}`,
`告警筛选:${qualityShareURL()}`
].join('\n');
}
function priorityDigestPolicyLines(policies?: QualityNotificationPolicy[]) {
const policy = policies?.find((item) => item.name.startsWith('P0')) ?? policies?.[0];
if (!policy) return [];
@@ -762,6 +791,7 @@ export function Quality({
<Button size="small" disabled={!lookup.key || !onOpenHistory} onClick={() => openIssueHistory(row)}></Button>
<Button size="small" disabled={!lookup.key || !onOpenRaw} onClick={() => openIssueRaw(row)}>RAW证据</Button>
<Button size="small" onClick={() => copyText(row.notificationText || priorityIssueNotificationText(row), '告警通知')}></Button>
<Button size="small" onClick={() => copyText(priorityIssueEvidencePackageText(row), '告警证据包')}></Button>
<Button size="small" onClick={() => copyText(priorityIssueTicketText(row), '处置工单')}></Button>
<Button size="small" disabled={!lookup.key} onClick={() => onOpenVehicle(lookup.key, row.protocol)}></Button>
</Space>
@@ -971,6 +1001,7 @@ export function Quality({
<Button size="small" disabled={!lookup.key || !onOpenRaw} onClick={() => openIssueRaw(row)}> RAW</Button>
<Button size="small" disabled={!lookup.key || !onOpenMileage} onClick={() => openIssueMileage(row)}></Button>
<Button size="small" onClick={() => copyText(priorityIssueNotificationText(priorityIssueFromRow(row)), '告警通知')}></Button>
<Button size="small" onClick={() => copyText(priorityIssueEvidencePackageText(priorityIssueFromRow(row)), '告警证据包')}></Button>
<Button size="small" disabled={!lookup.key} onClick={() => onOpenVehicle(lookup.key, row.protocol)}>
{lookup.label}
</Button>

View File

@@ -3837,6 +3837,20 @@ test('copies notification text from regular quality issue row', async () => {
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('详情:位置字段缺失,影响轨迹回放'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹证据http://localhost:3000/#/history?keyword=VIN-ROW-NOTIFY&protocol=GB32960&dateFrom=2026-07-03&dateTo=2026-07-04'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务http://localhost:3000/#/detail?keyword=VIN-ROW-NOTIFY&protocol=GB32960'));
const evidenceButtons = screen.getAllByRole('button', { name: '复制证据包' });
expect(evidenceButtons.length).toBeGreaterThanOrEqual(2);
fireEvent.click(evidenceButtons[evidenceButtons.length - 1]);
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【告警证据包】'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('优先级P1'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('验收标准:缺失字段恢复解析,统计、定位或里程依赖的核心字段可查询'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时定位http://localhost:3000/#/realtime?keyword=VIN-ROW-NOTIFY&protocol=GB32960'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹回放http://localhost:3000/#/history?keyword=VIN-ROW-NOTIFY&protocol=GB32960&dateFrom=2026-07-03&dateTo=2026-07-04'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW证据http://localhost:3000/#/history-query?keyword=VIN-ROW-NOTIFY&protocol=GB32960'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程复核http://localhost:3000/#/mileage?keyword=VIN-ROW-NOTIFY&protocol=GB32960&dateFrom=2026-07-03&dateTo=2026-07-04'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务http://localhost:3000/#/detail?keyword=VIN-ROW-NOTIFY&protocol=GB32960'));
});
test('opens realtime map context from quality priority queue', async () => {