diff --git a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx index 8a7b9150..699ef2d4 100644 --- a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx +++ b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx @@ -21,7 +21,7 @@ type VehicleQuery = { const sourceCapabilities: Array<{ key: keyof Pick; label: string }> = [ { key: 'hasRealtime', label: '实时' }, { key: 'hasHistory', label: '历史' }, - { key: 'hasRaw', label: 'RAW' }, + { key: 'hasRaw', label: '原始记录' }, { key: 'hasMileage', label: '里程' } ]; @@ -75,7 +75,7 @@ function sourceFusionRow(source: VehicleSourceStatus, realtime: RealtimeLocation source.hasRealtime || realtime ? '实时字段' : '', hasLocation ? '定位证据' : '', source.hasHistory ? '轨迹回放' : '', - source.hasRaw ? 'RAW证据' : '', + source.hasRaw ? '原始记录' : '', hasMileage ? '统计口径' : '' ].filter(Boolean); return { @@ -85,7 +85,7 @@ function sourceFusionRow(source: VehicleSourceStatus, realtime: RealtimeLocation freshness: source.online ? `在线 / ${source.lastSeen || realtime?.lastSeen || '-'}` : source.lastSeen ? `离线 / ${source.lastSeen}` : '未接入', realtimeText: source.hasRealtime || realtime ? `速度 ${formatCompactNumber(realtime?.speedKmh, ' km/h')} / SOC ${formatCompactNumber(realtime?.socPercent, '%')}` : '无实时字段', locationText: hasLocation ? `${realtime?.longitude}, ${realtime?.latitude}` : '无有效坐标', - rawText: source.hasRaw ? '可查 RAW' : '无 RAW 证据', + rawText: source.hasRaw ? '可查原始记录' : '无原始记录', mileageText: hasMileage ? formatCompactNumber(realtime?.totalMileageKm, ' km') : '无里程证据', contribution: contribution.length > 0 ? contribution : ['待补来源'] }; @@ -414,13 +414,13 @@ export function VehicleDetail({ `定位证据:${evidenceLocatedSourceCount > 0 ? `${evidenceLocatedSourceCount} 个来源有位置` : '暂无位置'}`, `里程差异:${formatCompactNumber(evidenceMileageDelta, ' km')}`, `时间差异:${formatSeconds(evidenceTimeDeltaSeconds)}`, - `数据规模:实时 ${overview?.realtimeCount ?? detail.realtime.length} / 历史 ${overview?.historyCount ?? detail.history.total ?? 0} / RAW ${overview?.rawCount ?? detail.raw.total ?? 0} / 里程 ${overview?.mileageCount ?? detail.mileage.total ?? 0} / 质量 ${overview?.qualityIssueCount ?? qualityCount}`, + `服务数据:实时 ${overview?.realtimeCount ?? detail.realtime.length} / 轨迹 ${overview?.historyCount ?? detail.history.total ?? 0} / 原始记录 ${overview?.rawCount ?? detail.raw.total ?? 0} / 里程 ${overview?.mileageCount ?? detail.mileage.total ?? 0} / 告警 ${overview?.qualityIssueCount ?? qualityCount}`, `一致性:${consistencyTitle}`, `一致性说明:${consistencyDetail}`, `车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}`, `实时:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹:${vehicleServiceURL(vehicleServiceHash('history'))}`, - `RAW:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, + `原始记录:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, `里程:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '诊断摘要'); @@ -445,14 +445,14 @@ export function VehicleDetail({ ` 贡献:${row.contribution.join('、')}`, ` 实时:${row.realtimeText}`, ` 定位:${row.locationText}`, - ` RAW:${row.rawText}`, + ` 原始记录:${row.rawText}`, ` 里程:${row.mileageText}` ].join('\n')), '', `车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}`, `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, - `RAW证据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, + `原始记录:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '多源归并矩阵'); @@ -536,7 +536,7 @@ export function VehicleDetail({ color: (overview?.historyCount ?? detail?.history?.total ?? 0) > 0 ? 'blue' as const : 'grey' as const }, { - label: 'RAW', + label: '原始记录', value: formatCompactNumber(overview?.rawCount ?? detail?.raw?.total ?? 0), detail: latestRaw?.frameType || '解析字段', color: (overview?.rawCount ?? detail?.raw?.total ?? 0) > 0 ? 'blue' as const : 'grey' as const @@ -596,13 +596,13 @@ export function VehicleDetail({ `实时主来源:${overview?.primaryProtocol || summary?.primaryProtocol || '-'}`, `来源在线:${evidenceSourceCount > 0 ? `${evidenceOnlineSourceCount}/${evidenceSourceCount}` : '-'}`, `业务可用性:${online ? '在线可用' : hasResolvedVIN ? '离线待查' : '待绑定'}`, - `数据资产:实时 ${overview?.realtimeCount ?? detail.realtime.length} / 轨迹 ${overview?.historyCount ?? detail.history.total ?? 0} / RAW ${overview?.rawCount ?? detail.raw.total ?? 0} / 里程 ${overview?.mileageCount ?? detail.mileage.total ?? 0} / 告警 ${overview?.qualityIssueCount ?? qualityCount}`, + `服务数据:实时 ${overview?.realtimeCount ?? detail.realtime.length} / 轨迹 ${overview?.historyCount ?? detail.history.total ?? 0} / 原始记录 ${overview?.rawCount ?? detail.raw.total ?? 0} / 里程 ${overview?.mileageCount ?? detail.mileage.total ?? 0} / 告警 ${overview?.qualityIssueCount ?? qualityCount}`, `下一步:${serviceActions[0]?.label ?? serviceConclusion.nextStep}`, `车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}`, `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, - `历史RAW:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` + `数据导出:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '统一车辆服务摘要'); }; @@ -628,7 +628,7 @@ export function VehicleDetail({ `车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}`, `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, - `RAW证据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, + `原始记录:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '车辆服务档案'); @@ -650,13 +650,13 @@ export function VehicleDetail({ `在线来源:${evidenceSourceCount > 0 ? `${evidenceOnlineSourceCount}/${evidenceSourceCount}` : '-'}`, `定位来源:${evidenceLocatedSourceCount > 0 ? `${evidenceLocatedSourceCount}` : '0'}`, `质量问题:${qualityCount.toLocaleString()} 项`, - `数据规模:历史 ${overview?.historyCount ?? detail.history.total ?? 0} / RAW ${overview?.rawCount ?? detail.raw.total ?? 0} / 里程 ${overview?.mileageCount ?? detail.mileage.total ?? 0}`, + `服务数据:轨迹 ${overview?.historyCount ?? detail.history.total ?? 0} / 原始记录 ${overview?.rawCount ?? detail.raw.total ?? 0} / 里程 ${overview?.mileageCount ?? detail.mileage.total ?? 0}`, `下一步清单:${actionLines.length > 0 ? '' : '暂无明确处置项,持续观察实时状态。'}`, ...actionLines, `车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}`, `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, - `RAW证据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, + `原始记录:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '运营摘要'); @@ -685,14 +685,14 @@ export function VehicleDetail({ ] }, { - title: 'RAW 证据', + title: '原始记录', value: `${formatCompactNumber(overview?.rawCount ?? detail?.raw?.total ?? 0)} 帧`, - meta: latestRaw?.frameType || '解析字段', + meta: latestRaw?.frameType || '字段明细', color: (overview?.rawCount ?? detail?.raw?.total ?? 0) > 0 ? 'blue' as const : 'grey' as const, - detail: '查看原始报文和解析字段,定位协议解析、来源转发和字段缺失问题。', + detail: '查看原始记录和字段明细,用于复核定位、里程和告警依据。', disabled: !hasResolvedVIN, actions: [ - { label: '查看 RAW', onClick: () => onOpenRaw(resolvedVIN, activeProtocol) } + { label: '查看原始记录', onClick: () => onOpenRaw(resolvedVIN, activeProtocol) } ] }, { @@ -736,10 +736,10 @@ export function VehicleDetail({ onClick: () => onOpenHistory(resolvedVIN, activeProtocol) }, { - title: '核对 RAW 字段', + title: '核对原始记录', evidence: `${formatCompactNumber(overview?.rawCount ?? detail?.raw?.total ?? 0)} 帧,最新类型 ${latestRaw?.frameType || '-'}`, acceptance: '关键字段来自解析字段而不是页面二次推断。', - action: 'RAW 证据', + action: '原始记录', disabled: !hasResolvedVIN, onClick: () => onOpenRaw(resolvedVIN, activeProtocol) }, @@ -762,12 +762,12 @@ export function VehicleDetail({ ]; const copyVehicleRunbook = () => { if (!detail) { - Toast.warning('当前没有可复制的单车Runbook'); + Toast.warning('当前没有可复制的单车处理清单'); return; } const vehicleName = [archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey; const lines = [ - '【单车服务闭环Runbook】', + '【单车服务处理清单】', `车辆:${vehicleName}`, `当前范围:${scopeText}`, `服务状态:${serviceStatus?.title ?? serviceConclusion.status}`, @@ -779,12 +779,12 @@ export function VehicleDetail({ ].join('\n')), `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, - `RAW证据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, + `原始记录:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, `告警事件:${vehicleServiceURL(buildAppHash({ page: 'alert-events', keyword: resolvedVIN, protocol: activeProtocol }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}`, + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}`, `车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}` ]; - copyText(lines.join('\n'), '单车Runbook'); + copyText(lines.join('\n'), '单车处理清单'); }; const qualityTable = ( - +
{ const nextQuery = { keyword: String(values.keyword ?? ''), protocol: String(values.protocol ?? '') }; @@ -863,9 +863,9 @@ export function VehicleDetail({ - - - + + +
@@ -874,7 +874,7 @@ export function VehicleDetail({ 当前查看范围 {scopeText} - {activeProtocol ? '下方实时、历史、RAW 和里程仅展示该来源返回的数据。' : '下方数据按车辆聚合展示全部可用来源。'} + {activeProtocol ? '下方实时、轨迹、原始记录和里程仅展示该数据通道返回的数据。' : '下方数据按车辆聚合展示全部可用数据通道。'} @@ -890,7 +890,7 @@ export function VehicleDetail({ 统一车辆服务视图} + title={车辆运营总览} style={{ marginTop: 16 }} >
@@ -908,8 +908,8 @@ export function VehicleDetail({
- - + +
@@ -984,7 +984,7 @@ export function VehicleDetail({ { key: '覆盖状态', value: {coverageStatusText[overview.coverageStatus] ?? overview.coverageStatus} }, { key: '主来源', value: overview.primaryProtocol || '-' }, { key: '最后上报', value: overview.lastSeen || '-' }, - { key: '数据规模', value: `历史 ${overview.historyCount} / RAW ${overview.rawCount} / 里程 ${overview.mileageCount}` }, + { key: '服务数据', value: `轨迹 ${overview.historyCount} / 原始记录 ${overview.rawCount} / 里程 ${overview.mileageCount}` }, { key: '实时来源', value: overview.realtimeCount }, { key: '质量问题', value: qualityIssueAction(overview.qualityIssueCount) } ]} @@ -1007,7 +1007,7 @@ export function VehicleDetail({
- +
{detailWorkbench.map((item) => (
@@ -1025,7 +1025,7 @@ export function VehicleDetail({ theme="light" type="primary" disabled={item.disabled || (item.title === '告警处置' && !onOpenQuality)} - aria-label={`单车作业台 ${item.title} ${action.label}`} + aria-label={`单车运营工作台 ${item.title} ${action.label}`} onClick={action.onClick} > {action.label} @@ -1039,7 +1039,7 @@ export function VehicleDetail({ 单车服务闭环Runbook} + title={单车服务处理清单} style={{ marginTop: 16 }} >
@@ -1055,7 +1055,7 @@ export function VehicleDetail({ theme="light" type="primary" disabled={item.disabled} - aria-label={`单车Runbook ${item.title} ${item.action}`} + aria-label={`单车处理清单 ${item.title} ${item.action}`} onClick={item.onClick} > {item.action} @@ -1112,7 +1112,7 @@ export function VehicleDetail({ {[ { label: '实时', value: row.realtimeText }, { label: '定位', value: row.locationText }, - { label: 'RAW', value: row.rawText }, + { label: '原始记录', value: row.rawText }, { label: '里程', value: row.mileageText } ].map((item) => (
@@ -1134,7 +1134,7 @@ export function VehicleDetail({ - +
@@ -1209,7 +1209,7 @@ export function VehicleDetail({ {qualityIssueVehicleLabel(priorityQualityIssue, resolvedVIN)} - {priorityQualityIssue.detail || '该车存在质量问题,需要结合轨迹和 RAW 证据确认影响范围。'} + {priorityQualityIssue.detail || '该车存在告警事件,需要结合轨迹和原始记录确认影响范围。'}
@@ -1230,13 +1230,13 @@ export function VehicleDetail({ 轨迹证据
@@ -1276,7 +1276,7 @@ export function VehicleDetail({ }, { key: '在线来源', value: summary ? `${summary.onlineSourceCount}/${summary.sourceCount}` : '-' }, { key: '最后位置时间', value: lastSeen }, - { key: '最新 RAW 时间', value: latestRaw?.serverTime ?? '-' }, + { key: '最新原始记录时间', value: latestRaw?.serverTime ?? '-' }, { key: '质量问题', value: 0 ? 'orange' : 'green'}>{qualityCount > 0 ? `${qualityCount} 项` : '无'} } ]} /> @@ -1374,7 +1374,7 @@ export function VehicleDetail({ disabled={!row.hasHistory} onClick={() => onOpenHistory(resolvedVIN, row.protocol)} > - 查看 {row.protocol} 历史 + 查看 {row.protocol} 轨迹
- 最新 RAW 解析字段 + 最新原始记录字段明细
{JSON.stringify(latestRaw?.parsedFields ?? {}, null, 2)}
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 2baa6a55..6ec98292 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -9587,7 +9587,7 @@ test('opens amap coordinate and trajectory playback from realtime map service qu 'noopener,noreferrer' ); - fireEvent.click(screen.getByRole('button', { name: '轨迹回放' })); + fireEvent.click(screen.getAllByRole('button', { name: '轨迹回放' })[0]); expect(window.location.hash).toBe('#/history?keyword=VIN-MAP-LINK&protocol=GB32960'); }); @@ -10738,11 +10738,11 @@ test('switches vehicle detail to a source from the source matrix', async () => { expect(screen.getAllByText('定位证据').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('统计口径').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('无实时字段')).toBeInTheDocument(); - expect(screen.getByText('无 RAW 证据')).toBeInTheDocument(); + expect(screen.getByText('无原始记录')).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: '复制归并矩阵' })); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【单车多源归并矩阵】')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('1. GB32960 / 主来源')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('贡献:主实时来源、在线心跳、实时字段、定位证据、轨迹回放、RAW证据、统计口径')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('贡献:主实时来源、在线心跳、实时字段、定位证据、轨迹回放、原始记录、统计口径')); expect(screen.getByText('车辆服务角色')).toBeInTheDocument(); expect(screen.getAllByText('主来源').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('在线证据').length).toBeGreaterThanOrEqual(1); @@ -10828,22 +10828,22 @@ test('shows unified service overview on vehicle detail', async () => { expect(await screen.findByText('车辆服务概览')).toBeInTheDocument(); expect(screen.getByText('车辆服务档案总览')).toBeInTheDocument(); expect(screen.getByRole('button', { name: /复制档案/ })).toBeInTheDocument(); - expect(screen.getByText('单车服务作业台')).toBeInTheDocument(); - expect(screen.getByText('单车服务闭环Runbook')).toBeInTheDocument(); + expect(screen.getByText('单车运营工作台')).toBeInTheDocument(); + expect(screen.getByText('单车服务处理清单')).toBeInTheDocument(); expect(screen.getAllByText('档案完整度').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('实时')).toBeInTheDocument(); expect(screen.getAllByText('轨迹').length).toBeGreaterThanOrEqual(1); - expect(screen.getAllByText('RAW').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.getAllByText('轨迹回放').length).toBeGreaterThanOrEqual(1); - expect(screen.getAllByText('RAW 证据').length).toBeGreaterThan(0); + expect(screen.getAllByText('原始记录').length).toBeGreaterThan(0); expect(screen.getByText('告警处置')).toBeInTheDocument(); expect(screen.getByText('里程复核')).toBeInTheDocument(); expect(screen.getByText('确认实时状态')).toBeInTheDocument(); expect(screen.getByText('回放轨迹断点')).toBeInTheDocument(); - expect(screen.getByText('核对 RAW 字段')).toBeInTheDocument(); + expect(screen.getByText('核对原始记录')).toBeInTheDocument(); expect(screen.getByText('处理告警闭环')).toBeInTheDocument(); expect(screen.getByText('复核统计口径')).toBeInTheDocument(); expect(screen.getByText('车辆在线状态、最新时间、有效坐标均可解释。')).toBeInTheDocument(); @@ -10853,8 +10853,8 @@ test('shows unified service overview on vehicle detail', async () => { expect(screen.getAllByText('1 项').length).toBeGreaterThan(0); expect(screen.getByText('7 条统计')).toBeInTheDocument(); expect(screen.getByText('2/3')).toBeInTheDocument(); - expect(screen.getByText('历史 12 / RAW 34 / 里程 7')).toBeInTheDocument(); - fireEvent.click(screen.getByRole('button', { name: '单车作业台 RAW 证据 查看 RAW' })); + expect(screen.getByText('轨迹 12 / 原始记录 34 / 里程 7')).toBeInTheDocument(); + fireEvent.click(screen.getByRole('button', { name: '单车运营工作台 原始记录 查看原始记录' })); expect(window.location.hash).toBe('#/history-query?keyword=VIN001&tab=raw'); }); @@ -11338,7 +11338,7 @@ test('copies vehicle service diagnostic summary', async () => { render(); - expect(await screen.findByText('统一车辆服务视图')).toBeInTheDocument(); + expect(await screen.findByText('车辆运营总览')).toBeInTheDocument(); expect(screen.getByRole('button', { name: /复制归一摘要/ })).toBeInTheDocument(); expect(screen.getByText('车辆身份')).toBeInTheDocument(); expect(screen.getByText('实时主来源')).toBeInTheDocument(); @@ -11358,7 +11358,7 @@ test('copies vehicle service diagnostic summary', async () => { expect(unifiedCopied).toContain('实时主来源:JT808'); expect(unifiedCopied).toContain('来源在线:1/2'); expect(unifiedCopied).toContain('业务可用性:在线可用'); - expect(unifiedCopied).toContain('数据资产:实时 2 / 轨迹 12 / RAW 34 / 里程 3 / 告警 1'); + expect(unifiedCopied).toContain('服务数据:实时 2 / 轨迹 12 / 原始记录 34 / 里程 3 / 告警 1'); expect(unifiedCopied).toContain('车辆服务:http://localhost:3000/#/detail?keyword=VIN-SUMMARY-001&protocol=JT808'); fireEvent.click(screen.getByRole('button', { name: /复制档案/ })); await waitFor(() => { @@ -11370,7 +11370,7 @@ test('copies vehicle service diagnostic summary', async () => { expect(dossierCopied).toContain('当前范围:单一来源:JT808'); expect(dossierCopied).toContain('主来源:JT808'); expect(dossierCopied).toContain('来源在线:1/2'); - expect(dossierCopied).toContain('资产概览:实时 2 / 轨迹 12 / RAW 34 / 里程 3 / 告警 1'); + expect(dossierCopied).toContain('资产概览:实时 2 / 轨迹 12 / 原始记录 34 / 里程 3 / 告警 1'); expect(dossierCopied).toContain('车辆服务:http://localhost:3000/#/detail?keyword=VIN-SUMMARY-001&protocol=JT808'); fireEvent.click(screen.getByRole('button', { name: /复制诊断摘要/ })); @@ -11387,13 +11387,13 @@ test('copies vehicle service diagnostic summary', async () => { expect(copied).toContain('定位证据:2 个来源有位置'); expect(copied).toContain('里程差异:12.6 km'); expect(copied).toContain('时间差异:90 秒'); - expect(copied).toContain('数据规模:实时 2 / 历史 12 / RAW 34 / 里程 3 / 质量 1'); + expect(copied).toContain('服务数据:实时 2 / 轨迹 12 / 原始记录 34 / 里程 3 / 告警 1'); expect(copied).toContain('一致性:来源不完整'); expect(copied).toContain('下一步:'); expect(copied).toContain('车辆服务:http://localhost:3000/#/detail?keyword=VIN-SUMMARY-001&protocol=JT808'); expect(copied).toContain('实时:http://localhost:3000/#/realtime?keyword=VIN-SUMMARY-001&protocol=JT808'); expect(copied).toContain('轨迹:http://localhost:3000/#/history?keyword=VIN-SUMMARY-001&protocol=JT808'); - expect(copied).toContain('RAW:http://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true'); + expect(copied).toContain('原始记录:http://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true'); expect(copied).toContain('里程:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); fireEvent.click(screen.getByRole('button', { name: /复制运营摘要/ })); @@ -11415,25 +11415,25 @@ test('copies vehicle service diagnostic summary', async () => { expect(operationsCopied).toContain('车辆服务:http://localhost:3000/#/detail?keyword=VIN-SUMMARY-001&protocol=JT808'); expect(operationsCopied).toContain('实时监控:http://localhost:3000/#/realtime?keyword=VIN-SUMMARY-001&protocol=JT808'); expect(operationsCopied).toContain('轨迹回放:http://localhost:3000/#/history?keyword=VIN-SUMMARY-001&protocol=JT808'); - expect(operationsCopied).toContain('RAW证据:http://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true'); + expect(operationsCopied).toContain('原始记录:http://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true'); expect(operationsCopied).toContain('里程统计:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); - fireEvent.click(screen.getByRole('button', { name: '复制Runbook' })); + fireEvent.click(screen.getByRole('button', { name: '复制处理清单' })); await waitFor(() => { - expect(writeText.mock.calls.some((call) => String(call[0]).includes('【单车服务闭环Runbook】'))).toBe(true); + expect(writeText.mock.calls.some((call) => String(call[0]).includes('【单车服务处理清单】'))).toBe(true); }); const runbookCopied = String(writeText.mock.lastCall?.[0] ?? ''); - expect(runbookCopied).toContain('【单车服务闭环Runbook】'); + expect(runbookCopied).toContain('【单车服务处理清单】'); expect(runbookCopied).toContain('车辆:粤A诊断1 / VIN-SUMMARY-001'); expect(runbookCopied).toContain('当前范围:单一来源:JT808'); expect(runbookCopied).toContain('1. 确认实时状态'); expect(runbookCopied).toContain('2. 回放轨迹断点'); - expect(runbookCopied).toContain('3. 核对 RAW 字段'); + expect(runbookCopied).toContain('3. 核对原始记录'); expect(runbookCopied).toContain('4. 处理告警闭环'); expect(runbookCopied).toContain('5. 复核统计口径'); expect(runbookCopied).toContain('验收:车辆在线状态、最新时间、有效坐标均可解释。'); expect(runbookCopied).toContain('告警事件:http://localhost:3000/#/alert-events?keyword=VIN-SUMMARY-001&protocol=JT808'); - expect(runbookCopied).toContain('统计查询:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); + expect(runbookCopied).toContain('里程统计:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); }); test('exports vehicle detail service dossier as csv', async () => { @@ -11600,7 +11600,7 @@ test('opens history with the currently selected vehicle detail source', async () render(); fireEvent.click(await screen.findByRole('button', { name: '仅看 JT808' })); - fireEvent.click(screen.getByRole('button', { name: '查看历史' })); + fireEvent.click(screen.getAllByRole('button', { name: '轨迹回放' })[0]); await waitFor(() => { expect(window.location.hash).toBe('#/history?keyword=VIN001&protocol=JT808'); @@ -11676,7 +11676,7 @@ test('opens raw history with the currently selected vehicle detail source', asyn render(); fireEvent.click(await screen.findByRole('button', { name: '仅看 JT808' })); - fireEvent.click(screen.getByRole('button', { name: '查看 RAW' })); + fireEvent.click(screen.getAllByRole('button', { name: '数据导出' })[0]); await waitFor(() => { expect(window.location.hash).toBe('#/history-query?keyword=VIN001&protocol=JT808&tab=raw'); @@ -11827,7 +11827,7 @@ test('opens source-specific history directly from vehicle detail source card', a render(); - fireEvent.click(await screen.findByRole('button', { name: '查看 JT808 历史' })); + fireEvent.click(await screen.findByRole('button', { name: '查看 JT808 轨迹' })); await waitFor(() => { expect(window.location.hash).toBe('#/history?keyword=VIN001&protocol=JT808'); @@ -11902,7 +11902,7 @@ test('opens source-specific raw history directly from vehicle detail source evid render(); - fireEvent.click(await screen.findByRole('button', { name: '查看 JT808 RAW' })); + fireEvent.click(await screen.findByRole('button', { name: '查看 JT808 原始记录' })); await waitFor(() => { expect(window.location.hash).toBe('#/history-query?keyword=VIN001&protocol=JT808&tab=raw');