feat(platform): customerize dashboard operations language

This commit is contained in:
lingniu
2026-07-05 00:50:47 +08:00
parent 4acf86b073
commit 245af2c293
2 changed files with 46 additions and 46 deletions

View File

@@ -149,7 +149,7 @@ function priorityIssueNotificationText(row: QualityIssueRow) {
`详情:${row.detail || '-'}`,
`实时定位:${appURL(buildAppHash({ page: 'realtime', keyword: lookup.key, protocol: row.protocol }))}`,
`轨迹证据:${appURL(buildAppHash({ page: 'history', keyword: filters.keyword, protocol: filters.protocol, filters }))}`,
`RAW证据${appURL(buildAppHash({ page: 'history-query', keyword: rawFilters.keyword, protocol: rawFilters.protocol, filters: rawFilters }))}`,
`原始记录${appURL(buildAppHash({ page: 'history-query', keyword: rawFilters.keyword, protocol: rawFilters.protocol, filters: rawFilters }))}`,
`车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: lookup.key, protocol: row.protocol }))}`,
`告警筛选:${appURL(buildAppHash({ page: 'alert-events', protocol: row.protocol, filters: { issueType: row.issueType } }))}`
].join('\n');
@@ -169,7 +169,7 @@ function focusVehicleFromIssue(row: QualityIssueRow): FocusVehicleService {
realtimeEvidence: `来源 ${qualityProtocolLabel(row.protocol)} / 最后 ${row.lastSeen || '-'}`,
historyEvidence: filters.dateFrom ? `${filters.dateFrom}${filters.dateTo}` : '待确认时间窗',
alertEvidence: row.detail || qualityIssueLabel(row.issueType),
statisticEvidence: '统计查询需回溯车辆口径',
statisticEvidence: '里程统计需回溯车辆口径',
issueType: row.issueType
};
}
@@ -385,7 +385,7 @@ export function Dashboard({
{
title: '历史数据导出',
value: `${formatCount(summary?.frameToday)} 今日数据`,
detail: '按车辆、时间和字段裁剪查询历史位置与 RAW 证据。',
detail: '按车辆、时间和字段裁剪查询历史位置与原始记录。',
action: '查询导出',
onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' })
}
@@ -441,7 +441,7 @@ export function Dashboard({
title: '轨迹回放',
status: `有效定位 ${formatCount(commandLocatedCount)}`,
color: commandLocatedCount > 0 ? 'blue' as const : 'grey' as const,
description: '围绕车辆回放历史位置轨迹,结合高德线路和 RAW 证据定位异常。',
description: '围绕车辆回放历史位置轨迹,结合高德线路和原始记录定位异常。',
action: '打开轨迹',
onClick: () => onOpenHistory()
},
@@ -449,7 +449,7 @@ export function Dashboard({
title: '历史数据查询',
status: `今日帧 ${formatCount(summary?.frameToday)}`,
color: 'blue' as const,
description: '查询位置历史、RAW 帧和解析字段,为车辆问题复盘提供证据链。',
description: '查询位置历史和原始记录字段,为车辆问题复盘提供依据。',
action: '查询历史',
onClick: () => onOpenHistory({ tab: 'raw' })
},
@@ -462,10 +462,10 @@ export function Dashboard({
onClick: () => onOpenQuality()
},
{
title: '统计查询',
title: '里程统计',
status: `统计车辆 ${formatCount(serviceSummary?.totalVehicles)}`,
color: 'green' as const,
description: '提供里程等运营统计查询,保证区间总值与每日统计口径闭合。',
description: '提供里程等运营统计,保证区间总值与每日统计口径闭合。',
action: '查看统计',
onClick: () => onOpenMileage()
}
@@ -497,7 +497,7 @@ export function Dashboard({
title: '接入巡检',
value: unhealthyLinkCount > 0 ? `${unhealthyLinkCount.toLocaleString()} 项关注` : '链路正常',
color: unhealthyLinkCount > 0 ? 'orange' as const : 'green' as const,
detail: '检查平台转发、Kafka、Redis、MySQL、TDengine 等关键链路。',
detail: '检查平台转发、消息队列、缓存和存储等关键链路。',
action: '查看告警',
onClick: () => onOpenQuality()
},
@@ -521,7 +521,7 @@ export function Dashboard({
title: '历史证据',
value: `${formatCount(summary?.frameToday)}`,
color: 'blue' as const,
detail: '查询 RAW 帧和解析字段,形成可追溯的数据据。',
detail: '查询原始记录和字段明细,形成可追溯的数据据。',
action: '历史查询',
onClick: () => onOpenHistory({ tab: 'raw' })
},
@@ -538,7 +538,7 @@ export function Dashboard({
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
color: 'green' as const,
detail: '核对里程统计口径,保证区间统计和每日统计闭合。',
action: '统计查询',
action: '里程统计',
onClick: () => onOpenMileage()
}
];
@@ -579,7 +579,7 @@ export function Dashboard({
{
title: '轨迹回放',
value: `${formatCount(summary?.activeToday)} 今日活跃`,
detail: '按车辆和时间窗回放历史位置,支持打开高德线路和 RAW 证据。',
detail: '按车辆和时间窗回放历史位置,支持打开高德线路和原始记录。',
action: '轨迹回放',
onClick: () => onOpenHistory()
},
@@ -618,7 +618,7 @@ export function Dashboard({
detail: '按车辆回看位置、速度、里程和断点,用于定位异常复盘。',
actions: [
{ label: '打开轨迹回放', onClick: () => onOpenHistory() },
{ label: '查 RAW 证据', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) }
{ label: '查原始记录', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) }
]
},
{
@@ -626,7 +626,7 @@ export function Dashboard({
value: `${formatCount(summary?.frameToday)} 今日帧`,
meta: '字段裁剪与导出',
color: 'blue' as const,
detail: '查询位置历史、RAW 帧和解析字段,为车辆服务提供可追溯据。',
detail: '查询位置历史、原始记录和字段明细,为车辆服务提供可追溯据。',
actions: [
{ label: '查询历史数据', onClick: () => onOpenHistory({ tab: 'location' }) },
{ label: '查询解析字段', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) }
@@ -644,13 +644,13 @@ export function Dashboard({
]
},
{
title: '统计查询',
title: '里程统计',
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆口径`,
meta: '区间闭合复核',
color: 'green' as const,
detail: '里程等指标先按车辆口径闭合,再回溯轨迹和 RAW 证据。',
detail: '里程等指标先按车辆口径闭合,再回溯轨迹和原始记录。',
actions: [
{ label: '打开统计查询', onClick: () => onOpenMileage() },
{ label: '打开里程统计', onClick: () => onOpenMileage() },
{ label: '查看车辆中心', onClick: () => onOpenVehicles({}) }
]
}
@@ -707,7 +707,7 @@ export function Dashboard({
owner: '告警 / 统计',
evidence: `告警 ${formatCount(summary?.issueVehicles)},统计车辆 ${formatCount(serviceSummary?.totalVehicles)}`,
detail: '断链、缺字段、里程异常和离线时长进入通知、统计和复核工作流。',
action: '统计查询',
action: '里程统计',
onClick: () => onOpenMileage()
}
];
@@ -728,13 +728,13 @@ export function Dashboard({
evidence: `高德轨迹底座 / 今日活跃 ${formatCount(summary?.activeToday)}`,
sla: '支持按车辆和时间窗快速回放',
primaryAction: '轨迹回放',
secondaryAction: 'RAW证据',
secondaryAction: '原始记录',
onPrimary: () => onOpenHistory(),
onSecondary: () => onOpenHistory({ tab: 'raw', includeFields: 'true' })
},
{
title: '历史数据查询',
objective: '围绕车辆查询位置、RAW、解析字段,给 BI、运维和业务复盘提供据。',
objective: '围绕车辆查询位置、原始记录和字段明细,给 BI、运维和业务复盘提供据。',
evidence: `今日数据 ${formatCount(summary?.frameToday)} / 支持字段裁剪与导出`,
sla: '优先返回必要字段,避免大 JSON 拖慢查询',
primaryAction: '历史查询',
@@ -753,11 +753,11 @@ export function Dashboard({
onSecondary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {})
},
{
title: '统计查询',
title: '里程统计',
objective: '按车辆口径查询里程等指标,保证区间统计和日统计可闭合。',
evidence: `车辆口径 ${formatCount(serviceSummary?.totalVehicles)} / 区间统计可追溯轨迹证据`,
sla: '统计值必须能追溯轨迹和 RAW 证据',
primaryAction: '统计查询',
sla: '统计值必须能追溯轨迹和原始记录',
primaryAction: '里程统计',
secondaryAction: '车辆中心',
onPrimary: () => onOpenMileage(),
onSecondary: () => onOpenVehicles({})
@@ -782,9 +782,9 @@ export function Dashboard({
`实时监控:${appURL(buildAppHash({ page: 'realtime', filters: { online: 'online' } }))}`,
`实时地图:${appURL(buildAppHash({ page: 'map', filters: { online: 'online' } }))}`,
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: highPriorityFilters?.keyword, protocol: highPriorityFilters?.protocol, filters: highPriorityFilters }))}`,
`历史RAW${appURL(buildAppHash({ page: 'history-query', keyword: highPriorityFilters?.keyword, protocol: highPriorityFilters?.protocol, filters: { ...highPriorityFilters, tab: 'raw', includeFields: 'true' } }))}`,
`原始记录${appURL(buildAppHash({ page: 'history-query', keyword: highPriorityFilters?.keyword, protocol: highPriorityFilters?.protocol, filters: { ...highPriorityFilters, tab: 'raw', includeFields: 'true' } }))}`,
`告警事件:${appURL(buildAppHash({ page: 'alert-events', filters: highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {} }))}`,
`统计查询${appURL(buildAppHash({ page: 'mileage', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}`,
`里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}`,
`车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}`
].filter(Boolean);
copyText(lines.join('\n'), '运营交接摘要');
@@ -824,7 +824,7 @@ export function Dashboard({
`轨迹回放:${appURL(buildAppHash({ page: 'history' }))}`,
`历史查询:${appURL(buildAppHash({ page: 'history-query', filters: { tab: 'raw', includeFields: 'true' } }))}`,
`告警事件:${appURL(buildAppHash({ page: 'alert-events' }))}`,
`统计查询${appURL(buildAppHash({ page: 'mileage' }))}`,
`里程统计:${appURL(buildAppHash({ page: 'mileage' }))}`,
`运维质量:${appURL(buildAppHash({ page: 'ops-quality' }))}`
];
copyText(lines.join('\n'), '数据流转图');
@@ -847,8 +847,8 @@ export function Dashboard({
`车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
`实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
`RAW证据${appURL(buildAppHash({ page: 'history-query', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol, filters: { ...commonFilters, tab: 'raw', includeFields: 'true' } }))}`,
`统计查询${appURL(buildAppHash({ page: 'mileage', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
`原始记录${appURL(buildAppHash({ page: 'history-query', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol, filters: { ...commonFilters, tab: 'raw', includeFields: 'true' } }))}`,
`里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
`告警事件:${appURL(buildAppHash({ page: 'alert-events', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol, filters: focusVehicle.issueType ? { issueType: focusVehicle.issueType } : {} }))}`
];
copyText(lines.join('\n'), '重点车辆服务处置卡');
@@ -1013,8 +1013,8 @@ export function Dashboard({
<div className="vp-time-monitor-grid">
{[
{ title: '今天车辆轨迹', detail: '查看当天活跃车辆的轨迹、速度和里程断点。', action: '查今天', onClick: () => onOpenHistory() },
{ title: '历史时间窗', detail: '按任意起止时间查询位置历史、RAW 字段和证据。', action: '自定义查询', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) },
{ title: '区间里程', detail: '按车辆和时间范围核对区间里程、日统计和异常点。', action: '统计查询', onClick: () => onOpenMileage() },
{ title: '历史时间窗', detail: '按任意起止时间查询位置历史、原始记录和字段明细。', action: '自定义查询', onClick: () => onOpenHistory({ tab: 'raw', includeFields: 'true' }) },
{ title: '区间里程', detail: '按车辆和时间范围核对区间里程、日统计和异常点。', action: '里程统计', onClick: () => onOpenMileage() },
{ title: '告警复盘', detail: '按车辆或事件回放告警发生前后的轨迹和数据证据。', action: '告警事件', onClick: () => onOpenQuality() }
].map((item) => (
<button key={item.title} type="button" className="vp-time-monitor-item" onClick={item.onClick} aria-label={`时间监控 ${item.title}`}>
@@ -1062,7 +1062,7 @@ export function Dashboard({
<div className="vp-focus-service-main">
<Tag color="blue">{focusVehicle.reason}</Tag>
<Typography.Title heading={5} style={{ margin: '8px 0 4px' }}>{focusVehicle.label}</Typography.Title>
<Typography.Text type="secondary">RAW</Typography.Text>
<Typography.Text type="secondary"></Typography.Text>
</div>
<div className="vp-focus-service-evidence">
{[
@@ -1081,14 +1081,14 @@ export function Dashboard({
<Button size="small" theme="solid" type="primary" aria-label="重点车辆 车辆服务" disabled={!focusVehicle.lookupKey} onClick={() => focusVehicle.lookupKey && onOpenVehicle(focusVehicle.lookupKey, focusVehicle.protocol)}></Button>
<Button size="small" theme="light" aria-label="重点车辆 实时监控" disabled={!focusVehicle.lookupKey} onClick={() => onOpenRealtime({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}></Button>
<Button size="small" theme="light" aria-label="重点车辆 轨迹回放" disabled={!focusVehicle.lookupKey} onClick={() => onOpenHistory({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}></Button>
<Button size="small" theme="light" aria-label="重点车辆 RAW证据" disabled={!focusVehicle.lookupKey} onClick={() => onOpenHistory({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '', tab: 'raw', includeFields: 'true' })}>RAW证据</Button>
<Button size="small" theme="light" aria-label="重点车辆 统计查询" disabled={!focusVehicle.lookupKey} onClick={() => onOpenMileage({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}></Button>
<Button size="small" theme="light" aria-label="重点车辆 原始记录" disabled={!focusVehicle.lookupKey} onClick={() => onOpenHistory({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '', tab: 'raw', includeFields: 'true' })}></Button>
<Button size="small" theme="light" aria-label="重点车辆 里程统计" disabled={!focusVehicle.lookupKey} onClick={() => onOpenMileage({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}></Button>
<Button size="small" theme="light" type="warning" aria-label="重点车辆 告警事件" onClick={() => onOpenQuality({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '', ...(focusVehicle.issueType ? { issueType: focusVehicle.issueType } : {}) })}></Button>
</Space>
</div>
</Card>
) : null}
<Card bordered title="车辆服务作业台" style={{ marginBottom: 16 }}>
<Card bordered title="车辆运营工作台" style={{ marginBottom: 16 }}>
<div className="vp-workbench-grid">
{operationWorkbench.map((item) => (
<div key={item.title} className="vp-workbench-item">
@@ -1195,7 +1195,7 @@ export function Dashboard({
disabled={!highPriorityEvidenceFilters?.keyword}
onClick={() => highPriorityEvidenceFilters && onOpenHistory({ ...highPriorityEvidenceFilters, tab: 'raw', includeFields: 'true' })}
>
RAW证据
</Button>
<Button
size="small"
@@ -1212,7 +1212,7 @@ export function Dashboard({
</div>
</Card>
) : null}
<Card bordered title="车辆服务能力矩阵" style={{ marginBottom: 16 }}>
<Card bordered title="车辆运营能力矩阵" style={{ marginBottom: 16 }}>
<div className="vp-capability-grid">
{capabilities.map((item) => (
<div key={item.title} className="vp-capability-item">
@@ -1295,7 +1295,7 @@ export function Dashboard({
</Card>
) : null}
<Card
title={<Space><span></span><Button size="small" onClick={() => onOpenQuality()}></Button></Space>}
title={<Space><span></span><Button size="small" onClick={() => onOpenQuality()}></Button></Space>}
bordered
style={{ marginTop: 16 }}
>

View File

@@ -426,7 +426,7 @@ test('shows vehicle service status distribution on dashboard', async () => {
expect(await screen.findByText('车辆服务覆盖')).toBeInTheDocument();
expect(screen.getAllByText('服务状态').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('质量问题预览')).toBeInTheDocument();
expect(screen.getByText('告警事件预览')).toBeInTheDocument();
});
test('dashboard renders vehicle service summary metrics', async () => {
@@ -781,7 +781,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
const renderDashboard = async () => {
window.history.replaceState(null, '', '/#/dashboard');
render(<App />);
expect(await screen.findByText('车辆服务能力矩阵')).toBeInTheDocument();
expect(await screen.findByText('车辆运营能力矩阵')).toBeInTheDocument();
};
await renderDashboard();
@@ -796,7 +796,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
expect(screen.getByText('历史时间窗')).toBeInTheDocument();
expect(screen.getByText('区间里程')).toBeInTheDocument();
expect(screen.getByText('告警复盘')).toBeInTheDocument();
expect(screen.getByText('车辆服务作业台')).toBeInTheDocument();
expect(screen.getByText('车辆运营工作台')).toBeInTheDocument();
expect(screen.getByText('地图运营能力')).toBeInTheDocument();
expect(screen.getByText('车联网场景导航')).toBeInTheDocument();
expect(screen.getByText('高德 Web JS')).toBeInTheDocument();
@@ -812,7 +812,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
expect(screen.getAllByText('轨迹回放').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('历史数据查询').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('告警事件触发与通知').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('统计查询').length).toBeGreaterThanOrEqual(1);
expect(screen.getAllByText('里程统计').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('告警事件与通知')).toBeInTheDocument();
expect(screen.getByText('区间闭合复核')).toBeInTheDocument();
expect(screen.getByText('高德轨迹证据')).toBeInTheDocument();
@@ -878,7 +878,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
cleanup();
await renderDashboard();
fireEvent.click(screen.getByRole('button', { name: '场景导航 轨迹回放 RAW证据' }));
fireEvent.click(screen.getByRole('button', { name: '场景导航 轨迹回放 原始记录' }));
expect(window.location.hash.startsWith('#/history-query')).toBe(true);
expect(new URLSearchParams(window.location.hash.split('?')[1] ?? '').get('includeFields')).toBe('true');
cleanup();
@@ -911,7 +911,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => {
cleanup();
await renderDashboard();
fireEvent.click(screen.getByRole('button', { name: '能力入口 统计查询' }));
fireEvent.click(screen.getByRole('button', { name: '能力入口 里程统计' }));
expect(window.location.hash.startsWith('#/mileage')).toBe(true);
});
@@ -1447,7 +1447,7 @@ test('dashboard surfaces highest priority quality issue with evidence shortcuts'
render(<App />);
expect(await screen.findByText('重点车辆服务')).toBeInTheDocument();
expect(screen.getByText('把数据来源作为证据把实时、轨迹、RAW、统计和告警集中到同一辆车处理。')).toBeInTheDocument();
expect(screen.getByText('把实时、轨迹、原始记录、里程和告警集中到同一辆车处理。')).toBeInTheDocument();
expect(screen.getByText('实时证据')).toBeInTheDocument();
expect(screen.getAllByText('轨迹证据').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('告警证据')).toBeInTheDocument();
@@ -1456,7 +1456,7 @@ test('dashboard surfaces highest priority quality issue with evidence shortcuts'
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【重点车辆服务处置卡】'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆粤A告警1 / 13307795425'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时监控http://localhost:3000/#/realtime?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW证据http://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('原始记录http://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&includeFields=true'));
expect(await screen.findByText('最高优先级告警')).toBeInTheDocument();
expect(screen.getAllByText('粤A告警1 / 13307795425').length).toBeGreaterThanOrEqual(1);
expect(screen.getByText('VIN 缺失')).toBeInTheDocument();
@@ -1589,7 +1589,7 @@ test('dashboard copies highest priority quality issue notification text', async
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('数据来源JT808'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('详情JT808 数据缺少 VIN 映射'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹证据http://localhost:3000/#/history?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('RAW证据http://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('原始记录http://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
fireEvent.click(screen.getByRole('button', { name: '复制运营交接摘要' }));
@@ -1603,7 +1603,7 @@ test('dashboard copies highest priority quality issue notification text', async
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时监控http://localhost:3000/#/realtime?online=online'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时地图http://localhost:3000/#/map?online=online'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹回放http://localhost:3000/#/history?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('历史RAWhttp://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('原始记录http://localhost:3000/#/history-query?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('告警事件http://localhost:3000/#/alert-events?issueType=VIN_MISSING'));
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务http://localhost:3000/#/detail?keyword=%E7%B2%A4A%E5%91%8A%E8%AD%A61&protocol=JT808'));