From 536d37ca9bcab0aa9166756fad0bd1ff6e6cbcfd Mon Sep 17 00:00:00 2001 From: lingniu Date: Mon, 6 Jul 2026 06:19:40 +0800 Subject: [PATCH] feat(platform): align customer mileage service wording --- vehicle-data-platform/apps/web/src/App.tsx | 2 +- .../apps/web/src/layout/AppShell.tsx | 18 +- .../apps/web/src/pages/Dashboard.tsx | 128 +++++----- .../apps/web/src/pages/History.tsx | 76 +++--- .../apps/web/src/pages/Mileage.tsx | 42 ++-- .../apps/web/src/pages/Realtime.tsx | 46 ++-- .../apps/web/src/pages/VehicleDetail.tsx | 66 ++--- .../apps/web/src/pages/Vehicles.tsx | 28 +-- .../apps/web/src/test/App.test.tsx | 226 +++++++++--------- 9 files changed, 316 insertions(+), 316 deletions(-) diff --git a/vehicle-data-platform/apps/web/src/App.tsx b/vehicle-data-platform/apps/web/src/App.tsx index 8e4a8ced..b2544325 100644 --- a/vehicle-data-platform/apps/web/src/App.tsx +++ b/vehicle-data-platform/apps/web/src/App.tsx @@ -548,7 +548,7 @@ export default function App() { `实时地图:${customerScopeURL('map', { keyword, protocol })}`, `实时监控:${customerScopeURL('realtime', { keyword, protocol })}`, `轨迹回放:${customerScopeURL('history', scopedFilters)}`, - `统计查询:${customerScopeURL('mileage', scopedFilters)}`, + `里程统计:${customerScopeURL('mileage', scopedFilters)}`, `数据导出:${customerScopeURL('history-query', { ...scopedFilters, tab: 'raw' })}`, `告警通知:${customerScopeURL('alert-events', scopedFilters)}` ]; diff --git a/vehicle-data-platform/apps/web/src/layout/AppShell.tsx b/vehicle-data-platform/apps/web/src/layout/AppShell.tsx index 499bc052..6ab967f4 100644 --- a/vehicle-data-platform/apps/web/src/layout/AppShell.tsx +++ b/vehicle-data-platform/apps/web/src/layout/AppShell.tsx @@ -48,12 +48,12 @@ const navGroups = [ ] }, { - title: '轨迹统计', + title: '轨迹里程', audience: '客户', - description: '回放轨迹、统计查询、导出数据', + description: '回放轨迹、里程统计、导出数据', items: [ { itemKey: 'history', text: '轨迹回放', icon: }, - { itemKey: 'mileage', text: '统计查询', icon: }, + { itemKey: 'mileage', text: '里程统计', icon: }, { itemKey: 'time-monitor', text: '时间窗监控', icon: }, { itemKey: 'history-query', text: '数据导出', icon: } ] @@ -82,7 +82,7 @@ const internalNavGroups = navGroups.filter((group) => group.audience === '内部 const customerPrimaryPath = [ { label: '车辆地图', page: 'map' as const }, { label: '轨迹回放', page: 'history' as const }, - { label: '统计查询', page: 'mileage' as const }, + { label: '里程统计', page: 'mileage' as const }, { label: '时间窗监控', page: 'time-monitor' as const }, { label: '数据导出', page: 'history-query' as const }, { label: '告警通知', page: 'alert-events' as const } @@ -91,7 +91,7 @@ const customerPrimaryPath = [ const customerTaskPath = [ { label: '地图看车', question: '车辆在哪里', page: 'map' as const }, { label: '轨迹回放', question: '这段时间怎么跑', page: 'history' as const }, - { label: '统计查询', question: '里程怎么算', page: 'mileage' as const }, + { label: '里程统计', question: '里程怎么算', page: 'mileage' as const }, { label: '时间窗监控', question: '这段时间发生什么', page: 'time-monitor' as const }, { label: '数据导出', question: '证据怎么给客户', page: 'history-query' as const }, { label: '告警通知', question: '异常谁处理', page: 'alert-events' as const } @@ -218,7 +218,7 @@ export function AppShell({ { label: '地图', ariaLabel: '顶部地图态势', page: 'map' as const }, { label: '监控', ariaLabel: '顶部实时监控', page: 'realtime' as const }, { label: '轨迹', ariaLabel: '顶部轨迹回放', page: 'history' as const }, - { label: '统计', ariaLabel: '顶部统计查询', page: 'mileage' as const }, + { label: '里程', ariaLabel: '顶部里程统计', page: 'mileage' as const }, { label: '时间窗', ariaLabel: '顶部时间窗监控', page: 'time-monitor' as const }, { label: '导出', ariaLabel: '顶部数据导出', page: 'history-query' as const }, { label: '告警', ariaLabel: '顶部告警事件', page: 'alert-events' as const } @@ -233,7 +233,7 @@ export function AppShell({ 车辆服务中台 - 实时地图 / 轨迹统计 / 告警通知 + 实时地图 / 轨迹里程 / 告警通知
@@ -257,7 +257,7 @@ export function AppShell({
客户任务分发台 - 输入 VIN / 车牌 / 手机号后,地图、轨迹、统计、导出和告警都围绕同一辆车服务。 + 输入 VIN / 车牌 / 手机号后,地图、轨迹、里程、导出和告警都围绕同一辆车服务。
{customerTaskPath.map((item) => ( @@ -395,7 +395,7 @@ export function AppShell({
客户时间窗 - 同步约束地图、轨迹、统计、导出和告警 + 同步约束地图、轨迹、里程、导出和告警
@@ -3845,7 +3845,7 @@ export function Dashboard({ 先看车在哪里,再处理轨迹、统计、告警和导出 - 客户主流程围绕车辆本身:地图看车、实时状态、时间窗复盘、统计查询、历史数据导出和告警通知。接入来源只作为追溯证据。 + 客户主流程围绕车辆本身:地图看车、实时状态、时间窗复盘、里程统计、历史数据导出和告警通知。接入来源只作为追溯证据。
{timeMonitorScope().keyword ? '单车' : '全域'} {timeMonitorSummary} - 同一时间窗会同步用于轨迹回放、统计查询、历史查询和告警复盘。 + 同一时间窗会同步用于轨迹回放、里程统计、历史查询和告警复盘。 - +
@@ -4022,7 +4022,7 @@ export function Dashboard({ 把车辆位置、时间窗、里程统计、历史证据和告警通知组织成客户可以直接使用的服务包。 - 客户打开首页后,先知道今天能交付什么,再选择地图、轨迹、统计、导出或通知。 + 客户打开首页后,先知道今天能交付什么,再选择地图、轨迹、里程、导出或通知。 @@ -4075,12 +4075,12 @@ export function Dashboard({
- +
- 同一时间窗会带入轨迹回放、统计查询和历史数据导出,避免跨页面重复输入。 + 同一时间窗会带入轨迹回放、里程统计和历史数据导出,避免跨页面重复输入。
@@ -4095,7 +4095,7 @@ export function Dashboard({ - + @@ -4261,7 +4261,7 @@ export function Dashboard({ {[ { title: '今天车辆轨迹', detail: '查看当天活跃车辆的轨迹、速度和里程断点。', action: '查今天', onClick: openTimeMonitorHistory }, { title: '历史时间窗', detail: '按任意起止时间查询位置历史、原始记录和字段明细。', action: '自定义查询', onClick: openTimeMonitorRaw }, - { title: '统计查询', detail: '按车辆和时间范围核对区间里程、日统计和异常点。', action: '统计查询', onClick: openTimeMonitorMileage }, + { title: '里程统计', detail: '按车辆和时间范围核对区间里程、日统计和异常点。', action: '里程统计', onClick: openTimeMonitorMileage }, { title: '告警复盘', detail: '按车辆或事件回放告警发生前后的轨迹和数据证据。', action: '告警事件', onClick: openTimeMonitorAlerts } ].map((item) => ( - +
diff --git a/vehicle-data-platform/apps/web/src/pages/History.tsx b/vehicle-data-platform/apps/web/src/pages/History.tsx index b80c1e42..e1b07a8f 100644 --- a/vehicle-data-platform/apps/web/src/pages/History.tsx +++ b/vehicle-data-platform/apps/web/src/pages/History.tsx @@ -361,7 +361,7 @@ function historyEvidencePackageText({ `历史位置:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'location' } }))}`, `明细证据:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, `字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'fields', includeFields: 'true', ...(filters.fields?.trim() ? { fields: filters.fields.trim() } : {}) } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: vehicle, protocol }))}` ].join('\n'); } @@ -398,7 +398,7 @@ function deliveryPackageText({ return [ '【客户查询导出包】', `交付状态:${deliveryState}`, - '交付物:轨迹报告 / 位置历史 / 统计查询 / 明细证据 / 字段裁剪 / 质量提示', + '交付物:轨迹报告 / 位置历史 / 里程统计 / 明细证据 / 字段裁剪 / 质量提示', `车辆范围:${vehicle || '全部车辆'}`, `数据通道:${protocol || '全部数据通道'}`, `时间范围:${filters.dateFrom?.trim() || '-'} 至 ${filters.dateTo?.trim() || '-'}`, @@ -411,7 +411,7 @@ function deliveryPackageText({ `明细证据:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, `字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'fields', includeFields: 'true', ...(filters.fields?.trim() ? { fields: filters.fields.trim() } : {}) } }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: vehicle, protocol, filters: evidenceFilters }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: vehicle, protocol }))}` ].join('\n'); } @@ -420,7 +420,7 @@ function deliveryCoverRecommendation(fieldCount: number, validPointCount: number if (fieldCount > 0 && validPointCount === 0) return '优先导出字段证据,并补查轨迹位置。'; if (validPointCount > 0) return '优先交付轨迹报告和位置历史,再附带字段证据。'; if (rawCount > 0) return '先交付明细证据,并补充客户需要的字段裁剪。'; - if (locationCount > 0) return '先交付位置历史,并补充统计查询说明。'; + if (locationCount > 0) return '先交付位置历史,并补充里程统计说明。'; return '先锁定车辆和时间窗,再查询位置或明细证据。'; } @@ -459,7 +459,7 @@ function deliveryCoverText({ '【客户数据交付封面包】', `交付主题:${vehicle} / ${protocol} / ${rangeFrom} 至 ${rangeTo}`, `交付结论:${deliveryState}`, - '交付物:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 统计查询链接 / 质量提示', + '交付物:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 里程统计链接 / 质量提示', `当前证据:位置 ${locationCount.toLocaleString()} 条 / 有效坐标 ${validPointCount.toLocaleString()} 点 / 明细 ${rawCount.toLocaleString()} 帧 / 字段 ${fieldCount.toLocaleString()} 个`, `质量提示:断点 ${anomalySummary.gapCount.toLocaleString()} / 里程回退 ${anomalySummary.mileageRollbackCount.toLocaleString()} / 超速 ${anomalySummary.overspeedCount.toLocaleString()}`, `建议动作:${deliveryCoverRecommendation(fieldCount, validPointCount, rawCount, locationCount)}`, @@ -467,7 +467,7 @@ function deliveryCoverText({ `位置历史:${appURL(buildAppHash({ page: 'history-query', keyword, protocol: protocolFilter, filters: { ...evidenceFilters, tab: 'location' } }))}`, `明细证据:${appURL(buildAppHash({ page: 'history-query', keyword, protocol: protocolFilter, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, `字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword, protocol: protocolFilter, filters: { ...evidenceFilters, tab: 'fields', includeFields: 'true', ...(filters.fields?.trim() ? { fields: filters.fields.trim() } : {}) } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword, protocol: protocolFilter, filters: evidenceFilters }))}` + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword, protocol: protocolFilter, filters: evidenceFilters }))}` ].join('\n'); } @@ -498,7 +498,7 @@ function scheduledHistoryReportPlanText({ `数据通道:${protocol || '全部数据通道'}`, `时间范围:${filters.dateFrom?.trim() || '-'} 至 ${filters.dateTo?.trim() || '-'}`, '推荐频率:日报用于客户复盘,周报用于客户对账,临时导出用于问题解释。', - '交付内容:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 统计查询链接 / 质量提示。', + '交付内容:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 里程统计链接 / 质量提示。', `当前数据量:位置 ${locationCount.toLocaleString()} 条,有效定位 ${validPointCount.toLocaleString()},明细证据 ${rawCount.toLocaleString()} 帧,字段裁剪 ${fieldCount.toLocaleString()} 个。`, `质量提示:断点 ${anomalySummary.gapCount.toLocaleString()} / 里程回退 ${anomalySummary.mileageRollbackCount.toLocaleString()} / 超速 ${anomalySummary.overspeedCount.toLocaleString()}`, '交付前检查:先锁定车辆和时间窗,再确认字段裁剪、分页覆盖和异常说明。', @@ -506,7 +506,7 @@ function scheduledHistoryReportPlanText({ `位置历史:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'location' } }))}`, `明细证据:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, `字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'fields', includeFields: 'true', ...(filters.fields?.trim() ? { fields: filters.fields.trim() } : {}) } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}` + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}` ].join('\n'); } @@ -592,7 +592,7 @@ function trajectoryReviewPackageText({ ...(filters.dateTo?.trim() ? { dateTo: filters.dateTo.trim() } : {}) }; const anomalyAction = anomalySummary.gapCount > 0 || anomalySummary.mileageRollbackCount > 0 || anomalySummary.overspeedCount > 0 - ? '建议核对明细证据、字段裁剪、当日统计查询,并确认平台是否存在断链或补发。' + ? '建议核对明细证据、字段裁剪、当日里程统计,并确认平台是否存在断链或补发。' : '当前页未发现明显断点、里程回退或速度异常,可作为轨迹复盘依据使用。'; return [ '【客户轨迹复盘包】', @@ -615,7 +615,7 @@ function trajectoryReviewPackageText({ `历史位置:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'location' } }))}`, `明细证据:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, `字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'fields', includeFields: 'true', ...(filters.fields?.trim() ? { fields: filters.fields.trim() } : {}) } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: vehicle, protocol }))}` ].join('\n'); } @@ -737,12 +737,12 @@ function trajectoryCustomerDecisionText({ '1. 先看轨迹覆盖:确认是否有足够有效坐标。', '2. 再看时间断点:断点会影响定位连续性和客户解释。', '3. 再看里程速度:区间里程、速度和轨迹方向需要能互相解释。', - '4. 最后回到依据:异常点必须打开明细证据、字段裁剪和统计查询复核。', + '4. 最后回到依据:异常点必须打开明细证据、字段裁剪和里程统计复核。', `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: vehicle, protocol, filters: evidenceFilters }))}`, `历史查询导出:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'location' } }))}`, `明细证据:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, `字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword: vehicle, protocol, filters: { ...evidenceFilters, tab: 'fields', includeFields: 'true', ...(filters.fields?.trim() ? { fields: filters.fields.trim() } : {}) } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: vehicle, protocol, filters: evidenceFilters }))}`, `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: vehicle, protocol }))}` ].join('\n'); } @@ -1027,9 +1027,9 @@ export function History({ { label: '里程速度', value: formatNumber(mileageDelta, ' km'), - detail: `最高速度 ${formatNumber(maxSpeed, ' km/h')},用于和统计查询互相解释。`, + detail: `最高速度 ${formatNumber(maxSpeed, ' km/h')},用于和里程统计互相解释。`, color: isFiniteNumber(mileageDelta) ? 'blue' as const : 'grey' as const, - action: '统计查询', + action: '里程统计', disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) }, @@ -1063,11 +1063,11 @@ export function History({ onClick: () => openQueryTab('location') }, { - title: '统计查询', + title: '里程统计', value: formatNumber(mileageDelta, ' km'), - detail: '进入统计查询核对区间里程和日统计闭合。', + detail: '进入里程统计核对区间里程和日统计闭合。', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, - action: '统计查询', + action: '里程统计', disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) }, @@ -1112,8 +1112,8 @@ export function History({ { title: '统计核对', value: formatNumber(mileageDelta, ' km'), - detail: '把同一时间窗带到统计查询,核对区间里程和日报闭合。', - action: '统计查询', + detail: '把同一时间窗带到里程统计,核对区间里程和日报闭合。', + action: '里程统计', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) @@ -1271,7 +1271,7 @@ export function History({ title: '里程对账', value: formatNumber(mileageDelta, ' km'), detail: '跳到同一车辆和时间窗的里程统计,核对区间差值和日报闭合。', - action: '统计查询', + action: '里程统计', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) @@ -1310,7 +1310,7 @@ export function History({ value: formatNumber(mileageDelta, ' km'), detail: '带着车辆和时间窗进入统计页,核对区间里程。', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, - action: '统计查询', + action: '里程统计', disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) }, @@ -1469,7 +1469,7 @@ export function History({ { title: '周报对账包', value: '客户对账', - detail: '按固定车辆范围沉淀周报计划,交付轨迹、统计查询链接和异常说明。', + detail: '按固定车辆范围沉淀周报计划,交付轨迹、里程统计链接和异常说明。', action: '复制周报计划', color: 'blue' as const, disabled: false, @@ -1584,7 +1584,7 @@ export function History({ question: '这段时间跑了多少公里?', answer: formatNumber(mileageDelta, ' km'), evidence: `最高速度 ${formatNumber(maxSpeed, ' km/h')}`, - action: '统计查询', + action: '里程统计', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) @@ -1728,7 +1728,7 @@ export function History({ `明细证据:${appURL(buildAppHash({ page: 'history-query', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, `字段裁剪:${appURL(buildAppHash({ page: 'history-query', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: fieldFilters }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: evidenceFilters }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: evidenceFilters }))}` + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: currentVehicleKeyword, protocol: currentProtocol, filters: evidenceFilters }))}` ]; copyText(lines.join('\n'), '客户导出向导包'); }; @@ -1994,7 +1994,7 @@ export function History({ title: '里程核对', value: formatNumber(mileageDelta, ' km'), detail: '把同一车辆和时间窗带到统计页,核对区间差值与日报闭合。', - action: '统计查询', + action: '里程统计', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, disabled: !onOpenMileage || !currentVehicleKeyword, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) @@ -2060,7 +2060,7 @@ export function History({ title: '核对里程', value: formatNumber(mileageDelta, ' km'), detail: '跳到同一车辆和时间窗的里程统计,检查区间差值。', - action: '统计查询', + action: '里程统计', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, disabled: !onOpenMileage || !currentVehicleKeyword, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) @@ -2308,7 +2308,7 @@ export function History({ }, { label: '统计核对', - action: '统计查询', + action: '里程统计', detail: `区间里程 ${formatNumber(mileageDelta, ' km')}`, color: isFiniteNumber(mileageDelta) ? 'blue' as const : 'grey' as const, disabled: !onOpenMileage || !currentVehicleKeyword, @@ -2827,7 +2827,7 @@ export function History({ 先锁定车辆和时间窗,再选择交付物并导出 - 面向客户的数据导出以车辆服务为中心:同一个筛选范围可以交付轨迹报告、位置历史、明细证据、字段裁剪、CSV 文件和统计查询。 + 面向客户的数据导出以车辆服务为中心:同一个筛选范围可以交付轨迹报告、位置历史、明细证据、字段裁剪、CSV 文件和里程统计。 @@ -3203,7 +3203,7 @@ export function History({ {[ { title: '轨迹复盘', value: validLocations.length > 0 ? '可播放' : '待查询', detail: '回放路线、速度和里程断点。', action: '播放轨迹', color: validLocations.length > 0 ? 'green' as const : 'orange' as const, disabled: validLocations.length === 0, onClick: () => openQueryTab('location') }, { title: '明细证据', value: `${(rawFrames.total ?? 0).toLocaleString()} 帧`, detail: '查看轨迹背后的接入证据。', action: '查看证据', color: (rawFrames.total ?? 0) > 0 ? 'blue' as const : 'grey' as const, disabled: false, onClick: () => openQueryTab('raw') }, - { title: '统计查询', value: formatNumber(mileageDelta, ' km'), detail: '进入同一时间窗的统计查询。', action: '统计复核', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) }, + { title: '里程统计', value: formatNumber(mileageDelta, ' km'), detail: '进入同一时间窗的里程统计。', action: '里程复核', color: isFiniteNumber(mileageDelta) ? 'green' as const : 'grey' as const, disabled: !onOpenMileage, onClick: () => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) }) }, { title: '客户导出', value: deliveryState, detail: '复制交付说明或导出 CSV 证据。', action: '复制交付', color: deliveryStateColor, disabled: false, onClick: copyDeliveryPackage } ].map((item) => ( - +
@@ -3347,7 +3347,7 @@ export function History({ 车辆服务
@@ -3562,12 +3562,12 @@ export function History({
{currentVehicleKeyword || '全部车辆'} - 轨迹、历史查询导出、明细证据和统计查询按同一车辆范围联动,用于客户复盘、客户问询和断链说明。 + 轨迹、历史查询导出、明细证据和里程统计按同一车辆范围联动,用于客户复盘、客户问询和断链说明。 - +
@@ -3801,9 +3801,9 @@ export function History({ ))}
- {hasTrajectoryAnomaly ? '建议核对明细证据和当日统计查询' : '轨迹质量可用'} + {hasTrajectoryAnomaly ? '建议核对明细证据和当日里程统计' : '轨迹质量可用'} - {hasTrajectoryAnomaly ? '异常点会影响轨迹回放、定位复盘和区间里程判断,请结合字段裁剪与统计查询交叉确认。' : '当前页轨迹未发现明显断点、里程回退或速度异常。'} + {hasTrajectoryAnomaly ? '异常点会影响轨迹回放、定位复盘和区间里程判断,请结合字段裁剪与里程统计交叉确认。' : '当前页轨迹未发现明显断点、里程回退或速度异常。'}
@@ -3849,7 +3849,7 @@ export function History({ render: (_: unknown, row: HistoryLocationRow) => ( - + ) @@ -3894,7 +3894,7 @@ export function History({ render: (_: unknown, row: RawFrameRow) => ( - + ) diff --git a/vehicle-data-platform/apps/web/src/pages/Mileage.tsx b/vehicle-data-platform/apps/web/src/pages/Mileage.tsx index 84a818ba..d46b1710 100644 --- a/vehicle-data-platform/apps/web/src/pages/Mileage.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Mileage.tsx @@ -188,8 +188,8 @@ function mileageSummaryText({ `当前页里程:${formatKm(pageMileageTotal)} km`, `异常记录:${anomalyCount.toLocaleString()}`, `最大单日:${peak}`, - '统计口径:区间总值等于各日里程之和', - `统计查询:${statisticsURL}`, + '里程口径:区间总值等于各日里程之和', + `里程统计:${statisticsURL}`, ...(vehicleURL ? [`车辆服务:${vehicleURL}`] : []) ].join('\n'); } @@ -249,7 +249,7 @@ function mileageDeliveryPackageText({ `在线影响:${onlineSummary.onlineVehicleCount.toLocaleString()} 在线 / ${onlineSummary.offlineVehicleCount.toLocaleString()} 离线 / 在线率 ${formatPercent(onlineSummary.onlineRatePercent)}`, `发布判断:${publishAuditConclusion}`, `可信度:${confidenceStatus}`, - '统计口径:日里程按首末总里程差值计算,区间总值应等于每日里程之和', + '里程口径:日里程按首末总里程差值计算,区间总值应等于每日里程之和', `里程统计:${statisticsURL}`, `轨迹复核:${appURL(buildAppHash({ page: 'history', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}) } }))}`, `历史明细:${appURL(buildAppHash({ page: 'history-query', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}), tab: 'raw', includeFields: 'true' } }))}`, @@ -368,7 +368,7 @@ function mileageReconciliationControlText({ `覆盖率:${formatPercent(pageCoverageRate)}`, `在线影响:${onlineSummary.onlineVehicleCount.toLocaleString()} 在线 / ${onlineSummary.offlineVehicleCount.toLocaleString()} 离线 / 在线率 ${formatPercent(onlineSummary.onlineRatePercent)}`, `轨迹证明:${peak}`, - `统计查询:${statisticsURL}`, + `里程统计:${statisticsURL}`, `报表导出:${statisticsURL}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}) } }))}`, `历史明细:${appURL(buildAppHash({ page: 'history-query', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}), tab: 'raw', includeFields: 'true' } }))}`, @@ -413,7 +413,7 @@ function mileageBIPublishText({ `车辆范围:${keyword}`, `数据通道:${protocol}`, `日期范围:${dateRange}`, - `统计口径:日里程按首末总里程差值计算,区间总值等于每日里程之和`, + `里程口径:日里程按首末总里程差值计算,区间总值等于每日里程之和`, `累计里程:${formatKm(summary.totalMileageKm)} km`, `明细合计:${formatKm(pageMileageTotal)} km`, `闭合状态:${closureStatus}${closureDeltaKm == null ? '' : `,差值 ${formatKm(Math.abs(closureDeltaKm))} km`}`, @@ -422,7 +422,7 @@ function mileageBIPublishText({ `通道一致性:${sourceConsistencyText}`, `统计车辆:${summary.vehicleCount.toLocaleString()},记录:${summary.recordCount.toLocaleString()},来源:${summary.sourceCount.toLocaleString()}`, `发布风险:${publishable ? '当前筛选范围闭合且无异常记录' : '存在分页未全量、异常记录或闭合差值,需要先复核轨迹和历史明细'}`, - `统计查询:${statisticsURL}`, + `里程统计:${statisticsURL}`, ...(vehicleURL ? [`车辆服务:${vehicleURL}`] : []) ].join('\n'); } @@ -470,7 +470,7 @@ function statisticsImpactText({ `异常记录:${anomalyCount.toLocaleString()}`, `当前页覆盖:${formatPercent(pageCoverageRate)}`, `业务影响:${publishAuditConclusion === '可发布' ? '当前统计范围可进入运营和BI口径' : '当前统计范围需要先复核轨迹、历史明细和离线车辆影响'}`, - `统计查询:${statisticsURL}`, + `里程统计:${statisticsURL}`, ...(vehicleURL ? [`车辆服务:${vehicleURL}`] : []) ].join('\n'); } @@ -528,7 +528,7 @@ function mileagePublishAuditReport({ ` 动作:${item.action}` ].join('\n')), '', - `统计查询:${statisticsURL}`, + `里程统计:${statisticsURL}`, ...(vehicleURL ? [`车辆服务:${vehicleURL}`] : []) ].join('\n'); } @@ -554,7 +554,7 @@ function mileageEvidencePackageText(row: DailyMileageRow) { `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol: row.source }))}`, `轨迹证据:${appURL(buildAppHash({ page: 'history', keyword: row.vin, protocol: row.source, filters: evidenceFilters }))}`, `历史明细:${appURL(buildAppHash({ page: 'history-query', keyword: row.vin, protocol: row.source, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: row.vin, protocol: row.source, filters: evidenceFilters }))}` + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: row.vin, protocol: row.source, filters: evidenceFilters }))}` ].join('\n'); } @@ -642,7 +642,7 @@ function onlineOperationsReportText({ '1. 在线率下降时先检查实时在线状态、数据接入和最后上报时间', '2. 离线车辆优先打开车辆服务,核对实时、轨迹、历史明细和告警记录', '3. 统计发布前确认离线车辆是否影响当日里程和区间闭合', - `统计查询:${statisticsURL}`, + `里程统计:${statisticsURL}`, ...(vehicleURL ? [`车辆服务:${vehicleURL}`] : []) ].join('\n'); } @@ -1074,7 +1074,7 @@ export function Mileage({ step: '05', title: '明细导出', value: `${rows.length.toLocaleString()} 当前页`, - detail: '导出明细并附带统计口径,支撑 BI 核对、客户复盘和报表交付。', + detail: '导出明细并附带里程口径,支撑 BI 核对、客户复盘和报表交付。', action: '导出明细', color: rows.length > 0 ? 'blue' as const : 'grey' as const, disabled: rows.length === 0, @@ -1133,7 +1133,7 @@ export function Mileage({ ]; const mileageDeliveryNavigation = [ { - title: '确认统计口径', + title: '确认里程口径', value: `${formatKm(summary.totalMileageKm)} km`, detail: `范围 ${mileageRangeText},闭合状态 ${closureStatus},发布判断 ${publishAuditConclusion}。`, action: '复制统计摘要', @@ -1914,7 +1914,7 @@ export function Mileage({ return (
onOpenVehicle(currentVehicleKeyword, currentProtocol)}> @@ -2206,18 +2206,18 @@ export function Mileage({
当前车辆:{currentVehicleKeyword || '-'} 数据通道:{currentProtocol || '全部数据通道'} - 统计查询以车辆为对象,当前先覆盖里程、在线影响、闭合审计和异常复核。 + 里程统计以车辆为对象,当前先覆盖里程、在线影响、闭合审计和异常复核。
- 客户统计查询 + 客户里程统计 {mileageDeliveryState} {closureStatus} 先定车辆和时间范围,再判断里程能否交付 - 统计查询从车辆服务出发:选择车辆或车队、设定时间窗、判断区间里程和发布状态,再进入轨迹、历史明细和导出明细。 + 里程统计从车辆服务出发:选择车辆或车队、设定时间窗、判断区间里程和发布状态,再进入轨迹、历史明细和导出明细。 @@ -2234,7 +2234,7 @@ export function Mileage({ className="vp-mileage-customer-query-step" disabled={item.disabled} onClick={item.onClick} - aria-label={`客户统计查询 ${item.title} ${item.action}`} + aria-label={`客户里程统计 ${item.title} ${item.action}`} > {item.step} {item.title} @@ -2543,7 +2543,7 @@ export function Mileage({ {statisticsImpactLevel}
{summary.vehicleCount.toLocaleString()} 辆车
- 当前筛选会影响 {summary.recordCount.toLocaleString()} 条里程记录、{formatKm(summary.totalMileageKm)} km 统计口径和 {offlineVehicleCount.toLocaleString()} 辆离线车辆判断。 + 当前筛选会影响 {summary.recordCount.toLocaleString()} 条里程记录、{formatKm(summary.totalMileageKm)} km 里程口径和 {offlineVehicleCount.toLocaleString()} 辆离线车辆判断。 {confidenceStatus} @@ -2711,7 +2711,7 @@ export function Mileage({ )}
-
统计口径
+
里程口径
区间里程以每日首末总里程差值汇总,目标是区间总值等于每日里程之和。 @@ -2813,7 +2813,7 @@ export function Mileage({
{closureStatus} - {closurePassed && anomalyRows.length === 0 ? '当前统计口径可直接用于 BI 里程口径;若存在跨通道差异,再进入车辆服务查看统计依据。' : '统计进入 BI 前需要结合异常记录、轨迹回放和历史明细完成复核。'} + {closurePassed && anomalyRows.length === 0 ? '当前里程口径可直接用于 BI 里程口径;若存在跨通道差异,再进入车辆服务查看统计依据。' : '统计进入 BI 前需要结合异常记录、轨迹回放和历史明细完成复核。'} @@ -3003,7 +3003,7 @@ export function Mileage({ ]} /> - +
可复制日报口径 diff --git a/vehicle-data-platform/apps/web/src/pages/Realtime.tsx b/vehicle-data-platform/apps/web/src/pages/Realtime.tsx index 804c4a67..d9fa5598 100644 --- a/vehicle-data-platform/apps/web/src/pages/Realtime.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Realtime.tsx @@ -422,7 +422,7 @@ function realtimeDutyHandoffText({ ` 车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol }))}`, ` 实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: row.vin, protocol }))}`, ` 轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: row.vin, protocol }))}`, - ` 统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: row.vin, protocol }))}`, + ` 里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: row.vin, protocol }))}`, ` 历史查询:${protocol ? rawFrameAPIURL(row, protocol) : '-'}` ); }); @@ -507,7 +507,7 @@ function mapCustomerPackageText({ `实时地图:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters }))}`, selectedVIN ? `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', - selectedVIN ? `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', + selectedVIN ? `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `历史数据:${appURL(buildAppHash({ page: 'history-query', keyword: selectedVIN, protocol: selectedProtocol, filters: { tab: 'raw', includeFields: 'true' } }))}` : '', selectedVIN ? `告警通知:${appURL(buildAppHash({ page: 'alert-events', keyword: selectedVIN, protocol: selectedProtocol }))}` : '' ].filter(Boolean).join('\n'); @@ -547,7 +547,7 @@ function mapExecutiveControlPackageText({ `实时地图:${appURL(buildAppHash({ page: 'map', protocol: filters.protocol, filters: { ...filters, online: filters.online || 'online' } }))}`, selectedVIN ? `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', `围栏告警:${appURL(buildAppHash({ page: 'alert-events', filters: { serviceStatus: 'degraded', ...(filters.protocol ? { protocol: filters.protocol } : {}) } }))}`, - selectedVIN ? `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', + selectedVIN ? `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: selectedVIN, protocol: selectedProtocol }))}` : '', selectedVIN ? `历史导出:${appURL(buildAppHash({ page: 'history-query', keyword: selectedVIN, protocol: selectedProtocol, filters: { tab: 'raw', includeFields: 'true' } }))}` : '' ].filter(Boolean).join('\n'); } @@ -569,7 +569,7 @@ function selectedMapVehicleHandoffText(row: VehicleRealtimeRow, protocol: string `车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: vin, protocol }))}`, `实时地图:${appURL(buildAppHash({ page: 'map', keyword: vin, protocol }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: vin, protocol }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: vin, protocol }))}`, + `里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: vin, protocol }))}`, `历史数据:${appURL(buildAppHash({ page: 'history-query', keyword: vin, protocol, filters: { tab: 'raw', includeFields: 'true' } }))}`, `告警通知:${appURL(buildAppHash({ page: 'alert-events', keyword: vin, protocol }))}` ].join('\n'); @@ -871,7 +871,7 @@ export function Realtime({ `实时状态:${timeWindowRow ? `${vehicleServiceStatus(timeWindowRow).label} / ${dataFreshness(timeWindowRow).detail}` : '未选车辆'}`, `轨迹回放:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'history', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }) : '-'}`, `历史数据:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'history-query', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters({ tab: 'raw', includeFields: 'true' }) }) : '-'}`, - `统计查询:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'mileage', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }) : '-'}`, + `里程统计:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'mileage', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }) : '-'}`, `告警通知:${timeWindowReady ? window.location.origin + window.location.pathname + buildAppHash({ page: 'alert-events', keyword: timeWindowKeyword, protocol: timeWindowProtocol, filters: timeWindowFilters() }) : '-'}` ].join('\n'), '客户时间窗复盘包'); const timeWindowWorkItems = [ @@ -894,7 +894,7 @@ export function Realtime({ onClick: openTimeWindowRaw }, { - title: '统计查询', + title: '里程统计', value: timeWindowRow?.totalMileageKm != null ? `${timeWindowRow.totalMileageKm} km` : '待核对', detail: '核对区间里程、日里程和总里程差值。', action: '查看统计', @@ -942,7 +942,7 @@ export function Realtime({ title: '里程核对', value: timeWindowRow?.totalMileageKm != null ? `${timeWindowRow.totalMileageKm} km` : '待核对', detail: '用同一时间窗进入里程统计,核对区间差值和日统计闭合。', - action: '统计查询', + action: '里程统计', color: timeWindowRow?.totalMileageKm != null ? 'blue' as const : 'orange' as const, disabled: !timeWindowReady, onClick: openTimeWindowMileage @@ -1192,10 +1192,10 @@ export function Realtime({ onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { - title: '统计查询', + title: '里程统计', value: selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '无里程', - detail: '进入单车统计查询,核对日里程和区间差值。', - action: '统计查询', + detail: '进入单车里程统计,核对日里程和区间差值。', + action: '里程统计', color: selectedMapRow?.totalMileageKm != null ? 'blue' as const : 'orange' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => { @@ -1299,10 +1299,10 @@ export function Realtime({ onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { - title: '统计查询', + title: '里程统计', value: selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '待选车', - detail: '按选中车辆进入统计查询,核对区间里程和日报闭合。', - action: '统计查询', + detail: '按选中车辆进入里程统计,核对区间里程和日报闭合。', + action: '里程统计', color: selectedMapRow?.totalMileageKm != null ? 'blue' as const : 'grey' as const, disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), onClick: () => { @@ -1612,7 +1612,7 @@ export function Realtime({ { label: '选车复盘', value: selectedVehicleLabel, - detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或车辆列表选择一辆车后进入轨迹、统计查询和历史查询。', + detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或车辆列表选择一辆车后进入轨迹、里程统计和历史查询。', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'grey' as const, action: '轨迹回放', disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin), @@ -1982,7 +1982,7 @@ export function Realtime({ step: '04', title: '单车复盘', value: selectedMapRow?.plate || selectedMapRow?.vin || '未选车', - detail: selectedMapRow ? '围绕选中车辆回放轨迹、统计查询和告警。' : '先在地图或表格中选择一辆可查询车辆。', + detail: selectedMapRow ? '围绕选中车辆回放轨迹、里程统计和告警。' : '先在地图或表格中选择一辆可查询车辆。', action: '轨迹回放', color: selectedMapRow ? 'blue' as const : 'grey' as const, onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol), @@ -2145,7 +2145,7 @@ export function Realtime({ onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol) }, { - label: '统计查询', + label: '里程统计', value: selectedMapRow?.totalMileageKm != null ? `${selectedMapRow.totalMileageKm} km` : '无里程', detail: '核对单车总里程、日里程和区间闭合。', color: selectedMapRow?.totalMileageKm != null ? 'blue' as const : 'grey' as const, @@ -2191,7 +2191,7 @@ export function Realtime({ level: selectedMapRow ? '单车' : '选车', title: selectedMapRow ? '复盘选中车辆' : '先选择一辆车', value: selectedMapRow?.plate || selectedMapRow?.vin || '等待选车', - detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或实时列表选择车辆后,进入轨迹、统计查询、历史和告警。', + detail: selectedMapRow ? `${vehicleServiceStatus(selectedMapRow).label},${dataFreshness(selectedMapRow).detail}` : '从地图或实时列表选择车辆后,进入轨迹、里程统计、历史和告警。', action: selectedMapRow ? '轨迹回放' : '查看车辆', color: selectedMapRow ? vehicleServiceStatus(selectedMapRow).color : 'blue' as const, disabled: selectedMapRow ? !canOpenVehicle(selectedMapRow.vin) : false, @@ -2301,7 +2301,7 @@ export function Realtime({ 按车辆和时间窗复盘发生了什么 - 客户问某辆车、某段时间发生了什么时,直接串起轨迹回放、历史数据、统计查询和告警通知。 + 客户问某辆车、某段时间发生了什么时,直接串起轨迹回放、历史数据、里程统计和告警通知。 @@ -2462,7 +2462,7 @@ export function Realtime({
车辆服务闭环 - 客户从这里完成看车、选车、查轨迹、查历史、查统计、收告警和导出。 + 客户从这里完成看车、选车、查轨迹、查历史、查里程、收告警和导出。
@@ -2713,7 +2713,7 @@ export function Realtime({ {amapConfigured ? 'Live Map 可用' : '坐标预览'} 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注
- 把 Live Map 当作客户服务入口:先看在线车辆和关注车辆,再进入路线回放、统计查询和证据导出。 + 把 Live Map 当作客户服务入口:先看在线车辆和关注车辆,再进入路线回放、里程统计和证据导出。 地图页的第一动作要围绕车辆服务,而不是围绕协议来源;客户从地图进入监控、复盘、统计和交付。 @@ -2963,7 +2963,7 @@ export function Realtime({ {selectedVehicleLabel} - 客户在地图上选中车辆后,直接进入车辆档案、轨迹回放、统计查询、数据导出和告警处置。 + 客户在地图上选中车辆后,直接进入车辆档案、轨迹回放、里程统计、数据导出和告警处置。
@@ -3051,7 +3051,7 @@ export function Realtime({ {selectedVehicleLabel} - 面向客户看图时,先确认车辆范围、在线态势、定位态势和选中车辆,再进入轨迹、统计查询、历史数据或告警通知。 + 面向客户看图时,先确认车辆范围、在线态势、定位态势和选中车辆,再进入轨迹、里程统计、历史数据或告警通知。 @@ -3340,7 +3340,7 @@ export function Realtime({ 从实时列表直接完成车辆监控闭环 - 先筛在线车辆,再看地图位置,异常车辆优先处置,最后进入单车轨迹、统计查询、告警或导出当前页。 + 先筛在线车辆,再看地图位置,异常车辆优先处置,最后进入单车轨迹、里程统计、告警或导出当前页。 diff --git a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx index 9e943562..58525bd0 100644 --- a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx +++ b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx @@ -85,7 +85,7 @@ function sourceFusionRow(source: VehicleSourceStatus, realtime: RealtimeLocation hasLocation ? '定位数据' : '', source.hasHistory ? '轨迹回放' : '', source.hasRaw ? '历史数据' : '', - hasMileage ? '统计口径' : '' + hasMileage ? '里程口径' : '' ].filter(Boolean); return { source, @@ -462,10 +462,10 @@ export function VehicleDetail({ `最新上报:${lastSeen}`, `轨迹证据:${overview?.historyCount ?? detail.history.total ?? 0} 条`, `历史数据:${overview?.rawCount ?? detail.raw.total ?? 0} 条`, - `统计查询:${overview?.mileageCount ?? detail.mileage.total ?? 0} 条`, + `里程统计:${overview?.mileageCount ?? detail.mileage.total ?? 0} 条`, `告警事件:${qualityCount.toLocaleString()} 项`, `轨迹回放:${vehicleServiceURL(buildAppHash({ page: 'history', keyword: filters.keyword, protocol: filters.protocol, filters }))}`, - `统计查询:${vehicleServiceURL(buildAppHash({ page: 'mileage', keyword: filters.keyword, protocol: filters.protocol, filters }))}`, + `里程统计:${vehicleServiceURL(buildAppHash({ page: 'mileage', keyword: filters.keyword, protocol: filters.protocol, filters }))}`, `历史导出:${vehicleServiceURL(buildAppHash({ page: 'history-query', keyword: rawFilters.keyword, protocol: rawFilters.protocol, filters: rawFilters }))}`, `告警通知:${vehicleServiceURL(buildAppHash({ page: 'alert-events', keyword: filters.keyword, protocol: filters.protocol, filters }))}` ]; @@ -500,7 +500,7 @@ export function VehicleDetail({ `实时:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹:${vehicleServiceURL(vehicleServiceHash('history'))}`, `历史数据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '诊断摘要'); }; @@ -532,7 +532,7 @@ export function VehicleDetail({ `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, `历史数据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '数据通道归并矩阵'); }; @@ -681,7 +681,7 @@ export function VehicleDetail({ `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, `历史数据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '统一车辆服务摘要'); }; @@ -708,7 +708,7 @@ export function VehicleDetail({ `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, `历史数据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '车辆服务档案'); }; @@ -736,7 +736,7 @@ export function VehicleDetail({ `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, `历史数据:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '车辆服务摘要'); }; @@ -786,11 +786,11 @@ export function VehicleDetail({ ] }, { - title: '统计复核', + title: '里程复核', value: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条统计`, meta: formatCompactNumber(evidenceMileageDelta, ' km 差异'), color: isFiniteNumber(evidenceMileageDelta) && Math.abs(evidenceMileageDelta) > 1 ? 'orange' as const : 'green' as const, - detail: '核对统计口径,确认区间总值、每日里程与数据通道是否闭合。', + detail: '核对里程口径,确认区间总值、每日里程与数据通道是否闭合。', disabled: !hasResolvedVIN, actions: [ { label: '查看统计', onClick: () => onOpenMileage(resolvedVIN, activeProtocol) } @@ -819,8 +819,8 @@ export function VehicleDetail({ { title: '核对里程', value: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条`, - detail: '进入统计查询,核对区间里程、日里程和统计闭合。', - action: '统计查询', + detail: '进入里程统计,核对区间里程、日里程和统计闭合。', + action: '里程统计', color: (overview?.mileageCount ?? detail?.mileage?.total ?? 0) > 0 ? 'green' as const : 'grey' as const, disabled: !hasResolvedVIN, onClick: () => onOpenMileage(resolvedVIN, activeProtocol) @@ -878,10 +878,10 @@ export function VehicleDetail({ onClick: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()) }, { - title: '复核统计口径', + title: '复核里程口径', evidence: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条统计,证据里程差 ${formatCompactNumber(evidenceMileageDelta, ' km')}`, acceptance: '区间里程、每日里程和轨迹总里程可以互相解释。', - action: '统计查询', + action: '里程统计', disabled: !hasResolvedVIN, onClick: () => onOpenMileage(resolvedVIN, activeProtocol) } @@ -907,7 +907,7 @@ export function VehicleDetail({ `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, `历史数据:${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'), '单车处理清单'); @@ -947,11 +947,11 @@ export function VehicleDetail({ onSecondary: () => exportVehicleReport() }, { - title: '复核统计查询', + title: '复核里程统计', value: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条统计`, detail: `证据里程差 ${formatCompactNumber(evidenceMileageDelta, ' km')},确认区间和日统计能闭合。`, color: isFiniteNumber(evidenceMileageDelta) && Math.abs(evidenceMileageDelta) > 1 ? 'orange' as const : 'green' as const, - primaryAction: '统计查询', + primaryAction: '里程统计', secondaryAction: '诊断摘要', disabled: !hasResolvedVIN, onPrimary: () => onOpenMileage(resolvedVIN, activeProtocol), @@ -1007,11 +1007,11 @@ export function VehicleDetail({ onClick: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()) }, { - title: '统计查询', + title: '里程统计', value: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条`, detail: `里程差 ${formatCompactNumber(evidenceMileageDelta, ' km')}`, color: isFiniteNumber(evidenceMileageDelta) && Math.abs(evidenceMileageDelta) > 1 ? 'orange' as const : 'green' as const, - action: '统计复核', + action: '里程复核', disabled: !hasResolvedVIN, onClick: () => onOpenMileage(resolvedVIN, activeProtocol) } @@ -1039,7 +1039,7 @@ export function VehicleDetail({ title: '里程与能源', value: `${formatCompactNumber(latest?.totalMileageKm, ' km')}`, detail: `SOC ${formatCompactNumber(latest?.socPercent, '%')} / 速度 ${formatCompactNumber(latest?.speedKmh, ' km/h')}`, - action: '统计查询', + action: '里程统计', color: isFiniteNumber(latest?.totalMileageKm) ? 'green' as const : 'orange' as const, disabled: !hasResolvedVIN, onClick: () => onOpenMileage(resolvedVIN, activeProtocol) @@ -1101,10 +1101,10 @@ export function VehicleDetail({ onClick: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()) }, { - title: '统计口径', + title: '里程口径', value: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条`, detail: `证据里程差 ${formatCompactNumber(evidenceMileageDelta, ' km')}`, - action: '统计查询', + action: '里程统计', color: isFiniteNumber(evidenceMileageDelta) && Math.abs(evidenceMileageDelta) > 1 ? 'orange' as const : 'green' as const, disabled: !hasResolvedVIN, onClick: () => onOpenMileage(resolvedVIN, activeProtocol) @@ -1138,7 +1138,7 @@ export function VehicleDetail({ { question: '这辆车跑了多少?', answer: `${formatCompactNumber(latest?.totalMileageKm, ' km')} / ${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条统计`, - action: '统计查询', + action: '里程统计', color: isFiniteNumber(latest?.totalMileageKm) ? 'green' as const : 'orange' as const, disabled: !hasResolvedVIN, onClick: () => onOpenMileage(resolvedVIN, activeProtocol) @@ -1170,21 +1170,21 @@ export function VehicleDetail({ '【单车客户服务交付包】', `车辆:${vehicleName}`, `当前范围:${scopeText}`, - `平台能力:实时监控 / 轨迹回放 / 历史数据查询 / 告警通知 / 统计查询`, + `平台能力:实时监控 / 轨迹回放 / 历史数据查询 / 告警通知 / 里程统计`, `服务状态:${customerStatusTitle(serviceStatus?.title) || serviceConclusion.status}`, `服务说明:${serviceStatus?.detail ?? serviceConclusion.risk}`, `在线数据通道:${evidenceSourceCount > 0 ? `${evidenceOnlineSourceCount}/${evidenceSourceCount}` : '-'}`, `最新上报:${lastSeen}`, `轨迹证据:${overview?.historyCount ?? detail.history.total ?? 0} 条`, `历史数据:${overview?.rawCount ?? detail.raw.total ?? 0} 条`, - `统计查询:${overview?.mileageCount ?? detail.mileage.total ?? 0} 条,证据差异 ${formatCompactNumber(evidenceMileageDelta, ' km')}`, + `里程统计:${overview?.mileageCount ?? detail.mileage.total ?? 0} 条,证据差异 ${formatCompactNumber(evidenceMileageDelta, ' km')}`, `告警事件:${qualityCount.toLocaleString()} 项`, `车辆服务:${vehicleServiceURL(vehicleServiceHash('detail'))}`, `实时监控:${vehicleServiceURL(vehicleServiceHash('realtime'))}`, `轨迹回放:${vehicleServiceURL(vehicleServiceHash('history'))}`, `历史数据查询:${vehicleServiceURL(vehicleServiceHash('history-query', { tab: 'raw', includeFields: 'true' }))}`, `告警通知:${vehicleServiceURL(buildAppHash({ page: 'alert-events', keyword: resolvedVIN, protocol: activeProtocol }))}`, - `统计查询:${vehicleServiceURL(vehicleServiceHash('mileage'))}` + `里程统计:${vehicleServiceURL(vehicleServiceHash('mileage'))}` ]; copyText(lines.join('\n'), '客户服务交付包'); }; @@ -1243,7 +1243,7 @@ export function VehicleDetail({ return (
- +
{ const nextQuery = { keyword: String(values.keyword ?? ''), protocol: String(values.protocol ?? '') }; @@ -1267,7 +1267,7 @@ export function VehicleDetail({ - +
@@ -1302,7 +1302,7 @@ export function VehicleDetail({ {[archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey} - 客户打开一辆车时,先看当前位置、最后上报、速度、SOC、总里程和告警,再进入轨迹回放、统计查询、数据导出和告警闭环。 + 客户打开一辆车时,先看当前位置、最后上报、速度、SOC、总里程和告警,再进入轨迹回放、里程统计、数据导出和告警闭环。
@@ -1413,7 +1413,7 @@ export function VehicleDetail({
{[ { title: '轨迹回放', value: vehicleTimeWindowText, detail: '按同一时间窗回放位置、速度和里程断点。', action: '轨迹回放', color: 'blue' as const, onClick: openVehicleWindowHistory }, - { title: '里程统计', value: vehicleTimeWindowText, detail: '核对区间里程、日统计和总里程差值。', action: '统计查询', color: 'green' as const, onClick: openVehicleWindowMileage }, + { title: '里程统计', value: vehicleTimeWindowText, detail: '核对区间里程、日统计和总里程差值。', action: '里程统计', color: 'green' as const, onClick: openVehicleWindowMileage }, { title: '历史数据导出', value: vehicleTimeWindowText, detail: '导出 RAW 与解析字段证据,缩小复盘范围。', action: '历史导出', color: 'blue' as const, onClick: openVehicleWindowRaw }, { title: '告警通知', value: vehicleTimeWindowText, detail: '查看这辆车在同一范围内的风险事件。', action: '告警通知', color: qualityCount > 0 ? 'orange' as const : 'green' as const, onClick: openVehicleWindowAlerts } ].map((item) => ( @@ -1510,7 +1510,7 @@ export function VehicleDetail({ - +
@@ -1591,14 +1591,14 @@ export function VehicleDetail({ {[archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey} - 面向客户交付时,以车辆为主对象提供实时监控、轨迹回放、历史数据查询、告警通知和统计查询,协议来源只作为可追溯证据。 + 面向客户交付时,以车辆为主对象提供实时监控、轨迹回放、历史数据查询、告警通知和里程统计,协议来源只作为可追溯证据。
- +
diff --git a/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx b/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx index 7979b700..4aa99386 100644 --- a/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx @@ -298,13 +298,13 @@ function vehicleCustomerLookupText({ `在线车辆:${(summary?.onlineVehicles ?? 0).toLocaleString()};待绑定:${(summary?.unboundVehicles ?? 0).toLocaleString()};暂无来源:${(summary?.noDataVehicles ?? 0).toLocaleString()};档案不完整:${(summary?.archiveIncompleteVehicles ?? 0).toLocaleString()}`, '', serviceMode === '单车服务' - ? '推荐路径:先看车辆档案和实时监控,再按需要进入轨迹回放、统计查询、历史数据导出。' + ? '推荐路径:先看车辆档案和实时监控,再按需要进入轨迹回放、里程统计、历史数据导出。' : '推荐路径:先筛在线/离线/无来源/待绑定车辆,再进入地图态势或导出处置清单。', `车辆服务:${appURL(scopeHash)}`, `实时监控:${appURL(buildAppHash({ page: 'realtime', ...singleVehicleFilters }))}`, `车辆地图:${appURL(buildAppHash({ page: 'map', keyword: filters.keyword, protocol: filters.protocol, filters: mapFilters }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', ...singleVehicleFilters, filters: { tab: 'location' } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', ...singleVehicleFilters }))}`, + `里程统计:${appURL(buildAppHash({ page: 'mileage', ...singleVehicleFilters }))}`, `历史数据:${appURL(buildAppHash({ page: 'history', ...singleVehicleFilters, filters: { tab: 'raw', includeFields: 'true' } }))}` ]; return lines.join('\n'); @@ -347,13 +347,13 @@ function vehicleCustomerServicePackageText({ `车辆地图:${appURL(buildAppHash({ page: 'map', keyword: filters.keyword, protocol: filters.protocol, filters: mapFilters }))}`, `实时监控:${appURL(buildAppHash({ page: 'realtime', ...singleVehicleFilters, filters: filters.keyword?.trim() ? undefined : { ...filters, online: filters.online || 'online' } }))}`, `轨迹回放:${appURL(buildAppHash({ page: 'history', ...singleVehicleFilters, filters: { tab: 'location' } }))}`, - `统计查询:${appURL(buildAppHash({ page: 'mileage', ...singleVehicleFilters }))}`, + `里程统计:${appURL(buildAppHash({ page: 'mileage', ...singleVehicleFilters }))}`, `告警通知:${appURL(buildAppHash({ page: 'alert-events', ...singleVehicleFilters, filters }))}`, `历史数据导出:${appURL(buildAppHash({ page: 'history', ...singleVehicleFilters, filters: { tab: 'raw', includeFields: 'true' } }))}`, '', '交付口径:', '1. 客户先看地图与实时状态,判断车辆是否在线和位置是否可信', - '2. 单车问题进入轨迹回放和统计查询,确认时间窗内发生了什么', + '2. 单车问题进入轨迹回放和里程统计,确认时间窗内发生了什么', '3. 异常车辆进入告警通知,带上原始记录和历史数据作为证据', '4. 对外交付时优先使用车辆口径,协议来源只作为证据说明' ].join('\n'); @@ -697,7 +697,7 @@ export function Vehicles({ onClick: () => onOpenHistory?.({ ...serviceScopeFilters, tab: 'location' }) }, { - label: '统计查询', + label: '里程统计', value: filters.keyword?.trim() ? '区间核对' : '车辆口径', detail: filters.keyword?.trim() ? '按当前车辆核对区间里程、日里程和统计结果。' : '输入车辆后查看时间窗统计结果。', color: filters.keyword?.trim() ? 'green' as const : 'grey' as const, @@ -819,7 +819,7 @@ export function Vehicles({ { title: '报表交付', value: `${rows.length.toLocaleString()} 当前页`, - detail: '导出当前车辆池清单,作为客户报表和后续轨迹统计入口。', + detail: '导出当前车辆池清单,作为客户报表和后续轨迹里程入口。', action: '导出清单', color: rows.length > 0 ? 'blue' as const : 'grey' as const, onClick: exportVehicles @@ -891,11 +891,11 @@ export function Vehicles({ onClick: () => onOpenHistory?.({ ...serviceScopeFilters, tab: 'location' }) }, { - label: '统计查询', + label: '里程统计', value: filters.keyword?.trim() ? '区间复核' : '单车后可用', detail: '核对时间窗里程、日里程和累计口径,支撑 BI 与客户问询。', color: filters.keyword?.trim() ? 'orange' as const : 'grey' as const, - action: '统计查询', + action: '里程统计', disabled: !onOpenMileage || !filters.keyword?.trim(), onClick: () => onOpenMileage?.(serviceScopeFilters) }, @@ -985,10 +985,10 @@ export function Vehicles({ onClick: () => onOpenHistory?.({ ...serviceScopeFilters, tab: 'location' }) }, { - title: '统计查询', + title: '里程统计', value: filters.keyword?.trim() ? '区间统计' : '单车后可用', - detail: '按车辆和时间窗核对里程、位置和业务统计口径。', - action: '查询统计', + detail: '按车辆和时间窗核对里程、位置和业务里程口径。', + action: '查询里程', color: filters.keyword?.trim() ? 'orange' as const : 'grey' as const, disabled: !onOpenMileage || !filters.keyword?.trim(), onClick: () => onOpenMileage?.(serviceScopeFilters) @@ -1199,7 +1199,7 @@ export function Vehicles({ return (
- +
@@ -1236,7 +1236,7 @@ export function Vehicles({ 高德地图车辆服务底座 {filters.keyword?.trim() ? '单车地图' : '车辆池地图'} - 用地图把车辆监控、轨迹回放、围栏告警、统计查询和历史导出串成客户能理解的一条服务路径。 + 用地图把车辆监控、轨迹回放、围栏告警、里程统计和历史导出串成客户能理解的一条服务路径。 车辆列表只负责锁定服务对象;地图能力负责解释位置、路线、区域、时间窗和异常通知。
@@ -1506,7 +1506,7 @@ export function Vehicles({ {filters.keyword?.trim() || `${(summary?.totalVehicles ?? pagination.total).toLocaleString()} 辆车`} - 把车辆地图、实时监控、轨迹回放、统计查询、告警通知和历史导出放在同一份服务包里,客户不用理解 GB32960、808 或 MQTT 的差异。 + 把车辆地图、实时监控、轨迹回放、里程统计、告警通知和历史导出放在同一份服务包里,客户不用理解 GB32960、808 或 MQTT 的差异。 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 051c68d0..950b63bf 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -37,27 +37,27 @@ test('renders vehicle platform shell', () => { render(); 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('输入 VIN / 车牌 / 手机号后,地图、轨迹、统计、导出和告警都围绕同一辆车服务。')).toBeInTheDocument(); + expect(screen.getByText('输入 VIN / 车牌 / 手机号后,地图、轨迹、里程、导出和告警都围绕同一辆车服务。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户任务 地图看车 车辆在哪里' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户任务 轨迹回放 这段时间怎么跑' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户任务 统计查询 里程怎么算' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户任务 里程统计 里程怎么算' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户任务 数据导出 证据怎么给客户' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户任务 告警通知 异常谁处理' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主线 车辆地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主线 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户主线 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户主线 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主线 数据导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主线 告警通知' })).toBeInTheDocument(); expect(screen.getByText('车辆监控')).toBeInTheDocument(); expect(screen.getByText('地图看车、实时状态、异常优先')).toBeInTheDocument(); expect(screen.getAllByText('车辆服务').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('按 VIN、车牌、手机号管理车辆')).toBeInTheDocument(); - expect(screen.getAllByText('轨迹统计').length).toBeGreaterThanOrEqual(1); - expect(screen.getByText('回放轨迹、统计查询、导出数据')).toBeInTheDocument(); + expect(screen.getAllByText('轨迹里程').length).toBeGreaterThanOrEqual(1); + expect(screen.getByText('回放轨迹、里程统计、导出数据')).toBeInTheDocument(); expect(screen.getAllByText('告警通知').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('接入运维')).toBeInTheDocument(); expect(screen.getAllByText('客户').length).toBeGreaterThanOrEqual(3); @@ -498,10 +498,10 @@ test('dashboard presents customer vehicle service modules before operations deta const servicePath = await screen.findByLabelText('客户车辆服务路径'); const serviceOverview = within(servicePath).getByLabelText('客户服务总览'); expect(within(serviceOverview).getByText('客户服务总览')).toBeInTheDocument(); - expect(within(serviceOverview).getByText('地图、轨迹、统计、导出是客户能直接使用的车辆服务;协议来源只进入证据和追溯。')).toBeInTheDocument(); + expect(within(serviceOverview).getByText('地图、轨迹、里程、导出是客户能直接使用的车辆服务;协议来源只进入证据和追溯。')).toBeInTheDocument(); expect(within(serviceOverview).getByRole('button', { name: '客户服务总览 车辆地图 进入地图' })).toBeInTheDocument(); expect(within(serviceOverview).getByRole('button', { name: '客户服务总览 轨迹回放 回放轨迹' })).toBeInTheDocument(); - expect(within(serviceOverview).getByRole('button', { name: '客户服务总览 统计查询 查看统计' })).toBeInTheDocument(); + expect(within(serviceOverview).getByRole('button', { name: '客户服务总览 里程统计 查看统计' })).toBeInTheDocument(); expect(within(serviceOverview).getByRole('button', { name: '客户服务总览 历史数据 查询导出' })).toBeInTheDocument(); }); @@ -525,7 +525,7 @@ test('topbar frames customer work as a vehicle service delivery strip', () => { expect(screen.getByText('服务动作')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务交付条 地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务交付条 轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '车辆服务交付条 统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆服务交付条 里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务交付条 导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务交付条 告警' })).toBeInTheDocument(); }); @@ -545,7 +545,7 @@ test('topbar exposes a mobile vehicle service shortcut dock', () => { expect(screen.getByRole('navigation', { name: '移动端车辆服务快捷入口' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '移动端车辆服务快捷入口 地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '移动端车辆服务快捷入口 轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '移动端车辆服务快捷入口 统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '移动端车辆服务快捷入口 里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '移动端车辆服务快捷入口 导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '移动端车辆服务快捷入口 告警' })).toBeInTheDocument(); }); @@ -725,7 +725,7 @@ test('exposes AMap operations shortcuts when map key is configured', async () => expect(await screen.findByRole('heading', { name: '历史查询导出' })).toBeInTheDocument(); expect(screen.getByText('默认查询最近一天,不预置任何车辆;输入 VIN、车牌或手机号后进入单车查询导出。')).toBeInTheDocument(); expect(screen.queryByDisplayValue('LB9A32A24R0LS1426')).not.toBeInTheDocument(); - fireEvent.click(screen.getByRole('button', { name: '顶部统计查询' })); + fireEvent.click(screen.getByRole('button', { name: '顶部里程统计' })); expect(window.location.hash.startsWith('#/mileage')).toBe(true); fireEvent.click(await screen.findByRole('button', { name: '顶部告警事件正常' })); expect(window.location.hash).toBe('#/alert-events'); @@ -1208,7 +1208,7 @@ test('dashboard prioritizes customer vehicle service command over data sources', expect((await screen.findAllByText('车辆服务指挥台')).length).toBeGreaterThan(0); expect(screen.getByText('10 秒内回答客户最关心的事:车辆在哪里、哪辆车异常、这段时间怎么跑、数据能不能导出。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务指挥台 看车在哪 实时地图' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '车辆服务指挥台 查这段时间 轨迹统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆服务指挥台 查这段时间 轨迹里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务指挥台 导出数据 历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务指挥台 处理告警 告警事件' })).toBeInTheDocument(); expect(screen.getAllByText('客户今日运营台').length).toBeGreaterThanOrEqual(1); @@ -1248,7 +1248,7 @@ test('dashboard prioritizes customer vehicle service command over data sources', expect(screen.getByRole('button', { name: '车辆服务驾驶舱 车辆总览 1,033 辆 车辆中心' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务驾驶舱 实时可见 208 在线 地图看车' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务驾驶舱 轨迹复盘 4 今日活跃 回放轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '车辆服务驾驶舱 里程统计 1 天窗口 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆服务驾驶舱 里程统计 1 天窗口 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务驾驶舱 数据交付 1,286,320 今日数据 导出证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务驾驶舱 告警通知 7 告警 闭环处理' })).toBeInTheDocument(); expect(await screen.findByText('车辆服务闭环')).toBeInTheDocument(); @@ -1256,7 +1256,7 @@ test('dashboard prioritizes customer vehicle service command over data sources', expect(screen.getByRole('button', { name: '车辆服务闭环 1 选车 1,033 车辆中心' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务闭环 2 实时看车 208 在线 实时地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务闭环 3 锁定时间窗 1 天窗口 自定义时间' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '车辆服务闭环 4 复盘统计 4 活跃 轨迹统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆服务闭环 4 复盘里程 4 活跃 轨迹里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆服务闭环 5 交付闭环 7 告警 导出通知' })).toBeInTheDocument(); expect(screen.getByText('车辆地图态势')).toBeInTheDocument(); expect(screen.getByText('先看在线车辆在哪里,再决定是否回放轨迹、核对里程、导出数据或通知处理。')).toBeInTheDocument(); @@ -1272,7 +1272,7 @@ test('dashboard prioritizes customer vehicle service command over data sources', expect(screen.getByText('三个接入来源统一沉到证据层,首页只回答客户怎么监控车辆、回放轨迹、核对里程、导出数据和处理告警。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务总控台 实时地图 208 在线 进入地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务总控台 轨迹回放 4 活跃 回放轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户车辆服务总控台 统计查询 1,033 车辆 查统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务总控台 里程统计 1,033 车辆 查里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务总控台 时间窗监控 1 天窗口 自定义时间' })).toBeInTheDocument(); expect(screen.getByText('同一时间窗贯穿轨迹、统计、历史导出和告警复盘。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务总控台 数据导出 1,286,320 今日数据 查询导出' })).toBeInTheDocument(); @@ -1295,7 +1295,7 @@ test('dashboard prioritizes customer vehicle service command over data sources', expect(screen.getByRole('button', { name: '车辆健康与能耗工作台 实时工况 208 在线 实时监控' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆健康与能耗工作台 SOC/氢能字段 1,286,320 今日数据 字段证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆健康与能耗工作台 异常维护 7 告警 告警事件' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '车辆健康与能耗工作台 里程能耗 1 天窗口 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆健康与能耗工作台 里程能耗 1 天窗口 里程统计' })).toBeInTheDocument(); expect(screen.getByText('地图服务能力清单')).toBeInTheDocument(); expect(screen.getByText('把高德 Web JS 和服务端 API 翻译成客户能使用的车辆服务能力。')).toBeInTheDocument(); expect(screen.getByText('实时底图')).toBeInTheDocument(); @@ -1399,7 +1399,7 @@ test('dashboard presents a customer dispatch operations home', async () => { expect(screen.getByRole('button', { name: '客户调度运营首页 今日重点 7 告警 处理告警' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '调度运营任务 看全域位置 208 在线 实时地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '调度运营任务 回放重点轨迹 4 活跃 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '调度运营任务 核对时间窗里程 1,033 车辆 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '调度运营任务 核对时间窗里程 1,033 车辆 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '调度运营任务 导出客户证据 1,286,320 帧 历史导出' })).toBeInTheDocument(); }); @@ -1495,7 +1495,7 @@ test('dashboard frames history query and export as a customer delivery workbench expect(screen.getByRole('button', { name: '客户常用时间范围 本周 2026-06-29 至 2026-07-05 应用' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户常用时间范围 自定义复盘 当前范围 应用' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户查询导出交付台 轨迹回放 4 活跃 回放轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户查询导出交付台 里程统计 1,033 车辆 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户查询导出交付台 里程统计 1,033 车辆 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户查询导出交付台 历史明细 1,286,320 帧 历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户查询导出交付台 告警说明 7 告警 告警通知' })).toBeInTheDocument(); }); @@ -1585,7 +1585,7 @@ test('dashboard separates customer vehicle service from operations evidence', as expect(screen.getByText('默认展示车辆地图、时间窗、里程、导出和告警;三类数据源只作为二级证据。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主流程 实时地图 208 在线 打开地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主流程 时间窗复盘 1 天窗口 查询导出' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户主流程 里程统计 1,033 车辆 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户主流程 里程统计 1,033 车辆 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主流程 告警通知 7 告警 通知处理' })).toBeInTheDocument(); expect(screen.getByText('运维证据层')).toBeInTheDocument(); expect(screen.getByText('用于解释车辆服务不可用的链路、队列、缓存、存储和来源证据,不作为客户默认入口。')).toBeInTheDocument(); @@ -1679,7 +1679,7 @@ test('dashboard guides customer custom time window service path', async () => { expect(screen.getByText('锁定同一辆车和同一时间范围后,按轨迹、里程、历史证据和告警说明形成客户可复盘的交付路径。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗服务路径 1 锁定范围 1 天窗口 应用时间窗' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗服务路径 2 回放轨迹 4 活跃 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '时间窗服务路径 3 核对里程 1,033 车辆 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '时间窗服务路径 3 核对里程 1,033 车辆 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗服务路径 4 导出证据 1,286,320 帧 数据导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗服务路径 5 告警说明 7 告警 告警通知' })).toBeInTheDocument(); expect(screen.getByText('时间窗下一步行动条')).toBeInTheDocument(); @@ -1690,7 +1690,7 @@ test('dashboard guides customer custom time window service path', async () => { expect(screen.getByRole('button', { name: '时间窗下一步 服务范围 全域巡检' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗下一步动作 处理告警 告警复盘' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗下一步动作 导出证据 历史导出' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '时间窗下一步动作 核对里程 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '时间窗下一步动作 核对里程 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗下一步动作 复制复盘 交付包' })).toBeInTheDocument(); }); @@ -1779,7 +1779,7 @@ test('time monitor route exposes a dedicated customer time window workspace', as expect(screen.getAllByText('时间窗监控').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('当前监控范围:粤A时间窗 / JT808 / 2026-07-01 至 2026-07-03')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗监控入口 轨迹回放 3 天窗口' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '时间窗监控入口 统计查询 3 天窗口' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '时间窗监控入口 里程统计 3 天窗口' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗监控入口 历史导出 9,988 帧' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗监控入口 告警复盘 2 告警' })).toBeInTheDocument(); expect(screen.getByText('时间窗复盘 SLA 作业台')).toBeInTheDocument(); @@ -1795,7 +1795,7 @@ test('time monitor route exposes a dedicated customer time window workspace', as }); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('作业范围:粤A时间窗 / JT808 / 2026-07-01 至 2026-07-03')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付SLA:3 天窗口内完成轨迹复盘、统计核对、历史导出和告警说明')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付物:轨迹回放链接 / 统计查询链接 / 历史导出链接 / 告警复盘链接')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付物:轨迹回放链接 / 里程统计链接 / 历史导出链接 / 告警复盘链接')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('升级条件:2 告警车辆需要先进入告警复盘')); }); @@ -1997,7 +1997,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => { expect(screen.getByText('把实时地图、轨迹回放、里程统计、历史导出和告警通知收敛成一个可交付的车辆服务入口。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务驾驶舱 车辆在哪里 0 有定位 打开地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务驾驶舱 轨迹能否回放 4 活跃 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户车辆服务驾驶舱 里程怎么算 1,033 车辆 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务驾驶舱 里程怎么算 1,033 车辆 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务驾驶舱 数据怎么导出 1,286,320 今日数据 历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务驾驶舱 异常谁处理 7 告警 告警通知' })).toBeInTheDocument(); expect(screen.getByText('客户车辆服务中台蓝图')).toBeInTheDocument(); @@ -2009,10 +2009,10 @@ test('dashboard exposes vehicle data center capability matrix', async () => { expect(screen.getByRole('button', { name: '客户车辆服务中台蓝图 车辆健康 1,033 车辆 车辆中心' })).toBeInTheDocument(); expect(screen.getByRole('region', { name: '客户常用视图库' })).toBeInTheDocument(); expect(screen.getByText('一个车辆服务入口,而不是三个数据源入口。')).toBeInTheDocument(); - expect(screen.getByText('把车队范围、时间窗、地图态势、轨迹回放、统计查询、导出模板和告警订阅保存成客户可复用的车辆服务入口。')).toBeInTheDocument(); + expect(screen.getByText('把车队范围、时间窗、地图态势、轨迹回放、里程统计、导出模板和告警订阅保存成客户可复用的车辆服务入口。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户常用视图库 在线车队视图 208 在线 打开地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户常用视图库 轨迹日报模板 4 活跃 历史导出' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户常用视图库 里程周报模板 1,033 车辆 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户常用视图库 里程周报模板 1,033 车辆 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户常用视图库 告警订阅视图 7 告警 通知闭环' })).toBeInTheDocument(); expect(screen.getByRole('region', { name: '十秒车辆处置台' })).toBeInTheDocument(); expect(screen.getByText('登录后先知道哪三类车辆最需要处理,再进入地图、车辆中心或告警通知。')).toBeInTheDocument(); @@ -2023,7 +2023,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => { expect(screen.getByText('一屏完成车辆地图、轨迹回放、里程统计、数据导出和告警闭环。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '现代车队运营台 Live Map 208 在线 打开地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '现代车队运营台 Route Replay 4 活跃 回放轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '现代车队运营台 Mileage 1,033 车辆 查统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '现代车队运营台 Mileage 1,033 车辆 查里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '现代车队运营台 Export 1,286,320 今日数据 导出数据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '现代车队运营台 Alerts 7 告警 通知闭环' })).toBeInTheDocument(); expect(screen.getByText('高德地图车辆服务底座')).toBeInTheDocument(); @@ -2034,19 +2034,19 @@ test('dashboard exposes vehicle data center capability matrix', async () => { expect(screen.getByRole('button', { name: '高德地图车辆服务底座 时间窗导出 1,286,320 今日数据 历史导出' })).toBeInTheDocument(); expect(screen.getByText('车辆监控中心')).toBeInTheDocument(); expect(screen.getByText('先看车在哪里,再处理轨迹、统计、告警和导出')).toBeInTheDocument(); - expect(screen.getByText('客户主流程围绕车辆本身:地图看车、实时状态、时间窗复盘、统计查询、历史数据导出和告警通知。接入来源只作为追溯证据。')).toBeInTheDocument(); + expect(screen.getByText('客户主流程围绕车辆本身:地图看车、实时状态、时间窗复盘、里程统计、历史数据导出和告警通知。接入来源只作为追溯证据。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆监控指标 车辆总数 1,033' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆监控指标 在线车辆 208' })).toBeInTheDocument(); expect(screen.getByText('客户任务导航')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户任务导航 看车在哪 实时地图' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户任务导航 查这段时间 轨迹统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户任务导航 查这段时间 轨迹里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户任务导航 导出数据 历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户任务导航 处理告警 告警事件' })).toBeInTheDocument(); expect(screen.getByText('客户问题处理台')).toBeInTheDocument(); expect(screen.getByText('先回答客户问题,再下钻到车辆、轨迹、统计和证据。')).toBeInTheDocument(); expect(screen.getByText('客户首先关心的是车辆、位置、时间、里程、告警和导出;GB32960、JT808、MQTT 只放在证据层。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户问题处理台 现在车辆在哪里 打开实时地图' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户问题处理台 这段时间跑了多少 查统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户问题处理台 这段时间跑了多少 查里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户问题处理台 轨迹能不能回放 打开轨迹回放' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户问题处理台 需要导出哪些证据 查询历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户问题处理台 哪些车需要通知处理 查看告警事件' })).toBeInTheDocument(); @@ -2062,7 +2062,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => { expect(screen.getByRole('button', { name: '车辆服务建议 按同一范围交付数据 复制复盘包' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆工作流 实时看车 实时地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆工作流 轨迹复盘 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户车辆工作流 统计查询 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆工作流 里程统计 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆工作流 数据交付 历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆工作流 告警通知 告警事件' })).toBeInTheDocument(); expect(screen.getByText('客户常问')).toBeInTheDocument(); @@ -2072,10 +2072,10 @@ test('dashboard exposes vehicle data center capability matrix', async () => { expect(screen.getByRole('button', { name: '客户常问 数据能导出给客户吗? 查询导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户常问 哪些车需要马上处理? 告警事件' })).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('客户打开首页后,先知道今天能交付什么,再选择地图、轨迹、里程、导出或通知。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付驾驶舱 在线车辆交付 实时地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付驾驶舱 时间窗复盘 轨迹回放' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付驾驶舱 数据证据交付 历史导出' })).toBeInTheDocument(); @@ -2135,17 +2135,17 @@ test('dashboard exposes vehicle data center capability matrix', async () => { expect(screen.getByRole('button', { name: '复制复盘包' })).toBeInTheDocument(); expect(screen.getByText('这个范围会同步带入轨迹、统计、历史证据和告警复盘,适合客户问询、BI 核对和异常解释。')).toBeInTheDocument(); expect(screen.getByText('查看轨迹')).toBeInTheDocument(); - 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('统计查询').length).toBeGreaterThanOrEqual(1); + expect(screen.getAllByText('里程统计').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('历史证据').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('告警复盘').length).toBeGreaterThanOrEqual(1); expect(screen.getByRole('button', { name: '时间窗作业 轨迹回放 打开轨迹' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗作业 历史证据 导出证据' })).toBeInTheDocument(); expect(screen.getByText('今天车辆轨迹')).toBeInTheDocument(); expect(screen.getByText('历史时间窗')).toBeInTheDocument(); - 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(); @@ -2165,7 +2165,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(); @@ -2197,7 +2197,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); expect(new URLSearchParams(window.location.hash.split('?')[1] ?? '').get('dateFrom')).toBeTruthy(); cleanup(); @@ -2234,7 +2234,7 @@ test('dashboard exposes vehicle data center capability matrix', async () => { cleanup(); await renderDashboard(); - fireEvent.click(screen.getAllByRole('button', { name: '统计查询' })[0]); + fireEvent.click(screen.getAllByRole('button', { name: '里程统计' })[0]); expect(window.location.hash.startsWith('#/mileage')).toBe(true); expect(new URLSearchParams(window.location.hash.split('?')[1] ?? '').get('dateFrom')).toBeTruthy(); expect(new URLSearchParams(window.location.hash.split('?')[1] ?? '').get('dateTo')).toBeTruthy(); @@ -2270,7 +2270,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); cleanup(); @@ -2318,7 +2318,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); }, 10000); @@ -2742,7 +2742,7 @@ test('dashboard exposes end-to-end operations workflow entries', async () => { expect(await screen.findByText('自定义时间窗复盘')).toBeInTheDocument(); expect(screen.getByText('今天车辆轨迹')).toBeInTheDocument(); expect(screen.getByText('历史时间窗')).toBeInTheDocument(); - expect(screen.getAllByText('统计查询').length).toBeGreaterThanOrEqual(1); + expect(screen.getAllByText('里程统计').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('告警复盘').length).toBeGreaterThanOrEqual(1); fireEvent.click(screen.getByRole('button', { name: '时间监控 今天车辆轨迹' })); @@ -3333,7 +3333,7 @@ test('shows vehicle service result summary on vehicle list filters', async () => expect(screen.getByRole('button', { name: '客户车队指挥台 当前交付 2 辆 数据导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车队指挥台 轨迹复盘 先选车辆 轨迹回放' })).toBeInTheDocument(); expect(screen.getByText('高德地图车辆服务底座')).toBeInTheDocument(); - expect(screen.getByText('用地图把车辆监控、轨迹回放、围栏告警、统计查询和历史导出串成客户能理解的一条服务路径。')).toBeInTheDocument(); + expect(screen.getByText('用地图把车辆监控、轨迹回放、围栏告警、里程统计和历史导出串成客户能理解的一条服务路径。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '高德地图车辆服务底座 实时看车 73 在线 打开地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '高德地图车辆服务底座 轨迹复盘 先选车辆 回放轨迹' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '高德地图车辆服务底座 围栏告警 13 待处理 告警通知' })).toBeInTheDocument(); @@ -3343,7 +3343,7 @@ test('shows vehicle service result summary on vehicle list filters', async () => expect(screen.getByRole('button', { name: '客户车辆服务台 车辆池 181 车辆 找车' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务台 实时地图 73 在线 打开地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务台 轨迹回放 先选车辆 回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户车辆服务台 统计查询 单车后可用 查询统计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务台 里程统计 单车后可用 查询里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务台 告警通知 13 待处理 查看告警' })).toBeInTheDocument(); expect(screen.getByText('车辆资产运营台')).toBeInTheDocument(); expect(screen.getByText('像车队资产系统一样,先判断车辆能不能服务,再进入地图、实时、轨迹、统计、导出和告警。')).toBeInTheDocument(); @@ -3392,14 +3392,14 @@ test('shows vehicle service result summary on vehicle list filters', async () => expect(screen.getByText('客户车辆服务交付包')).toBeInTheDocument(); expect(screen.getByText('客户交付')).toBeInTheDocument(); expect(screen.getByText('车辆池包')).toBeInTheDocument(); - expect(screen.getByText('把车辆地图、实时监控、轨迹回放、统计查询、告警通知和历史导出放在同一份服务包里,客户不用理解 GB32960、808 或 MQTT 的差异。')).toBeInTheDocument(); + expect(screen.getByText('把车辆地图、实时监控、轨迹回放、里程统计、告警通知和历史导出放在同一份服务包里,客户不用理解 GB32960、808 或 MQTT 的差异。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务交付 车辆地图 打开地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务交付 轨迹回放 回放轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户车辆服务交付 统计查询 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务交付 里程统计 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务交付 告警通知 查看告警' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户车辆服务交付 历史导出 导出清单' })).toBeInTheDocument(); 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(); @@ -3446,7 +3446,7 @@ test('shows vehicle service result summary on vehicle list filters', async () => expect(writeText).toHaveBeenCalledWith(expect.stringContaining('服务范围:当前车辆池')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆地图:http://localhost:3000/#/map?')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹回放:http://localhost:3000/#/history?tab=location')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计查询:http://localhost:3000/#/mileage')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程统计:http://localhost:3000/#/mileage')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('告警通知:http://localhost:3000/#/alert-events?coverage=multi')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('历史数据导出:http://localhost:3000/#/history?tab=raw&includeFields=true')); }); @@ -4198,7 +4198,7 @@ test('shows resolved vehicle service status after topbar search', async () => { fireEvent.click(screen.getByRole('button', { name: '客户任务 轨迹回放 这段时间怎么跑' })); expect(window.location.hash).toBe('#/history?keyword=LB9A32A24R0LS1426&protocol=JT808'); - fireEvent.click(screen.getByRole('button', { name: '客户任务 统计查询 里程怎么算' })); + fireEvent.click(screen.getByRole('button', { name: '客户任务 里程统计 里程怎么算' })); expect(window.location.hash).toBe('#/mileage?keyword=LB9A32A24R0LS1426&protocol=JT808'); fireEvent.click(screen.getByRole('button', { name: '客户任务 数据导出 证据怎么给客户' })); expect(window.location.hash).toBe('#/history-query?keyword=LB9A32A24R0LS1426&protocol=JT808&tab=raw'); @@ -6888,12 +6888,12 @@ test('copies trajectory playback summary from history page', async () => { expect(screen.getByText('像 Trips History 一样,先锁定车辆和时间,再回放路线、核对里程、导出证据。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户复盘导航 选车和时间 调整筛选' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户复盘导航 回放路线 播放轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户复盘导航 核对里程 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户复盘导航 核对里程 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户复盘导航 导出证据 复制交付' })).toBeInTheDocument(); expect(screen.getByText('客户时间窗证据链')).toBeInTheDocument(); expect(screen.getByText('同一辆车和同一时间窗,串起实时轨迹、里程核对、历史导出、字段裁剪和告警复盘。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户时间窗证据链 轨迹复盘 查看轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户时间窗证据链 里程核对 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户时间窗证据链 里程核对 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户时间窗证据链 历史导出 明细证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户时间窗证据链 字段裁剪 字段导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户时间窗证据链 告警复盘 告警事件' })).toBeInTheDocument(); @@ -6905,7 +6905,7 @@ test('copies trajectory playback summary from history page', async () => { expect(screen.getByRole('button', { name: '行程复盘摘要 最高速度 58.8 km/h' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '行程复盘摘要 异常提示 1 项' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '行程复盘动作 轨迹回放 播放轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '行程复盘动作 统计核对 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '行程复盘动作 统计核对 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '行程复盘动作 导出证据 复制交付' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '行程复盘动作 告警复盘 告警事件' })).toBeInTheDocument(); expect(screen.getByText('按车辆和时间窗复盘每一段行程')).toBeInTheDocument(); @@ -6914,17 +6914,17 @@ test('copies trajectory playback summary from history page', async () => { expect(screen.getByRole('button', { name: '轨迹回放工作台 轨迹复盘 播放轨迹' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '轨迹回放工作台 客户导出 复制交付' })).toBeInTheDocument(); expect(screen.getByText('客户轨迹决策台')).toBeInTheDocument(); - expect(screen.getByText('先判断轨迹能否复盘,再进入证据、字段和统计查询')).toBeInTheDocument(); + expect(screen.getByText('先判断轨迹能否复盘,再进入证据、字段和里程统计')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户轨迹决策 复盘结论 复制决策' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户轨迹决策 定位覆盖 播放轨迹' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户轨迹决策 时间断点 复盘包' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户轨迹决策 里程速度 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户轨迹决策 里程速度 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户轨迹决策 明细复核 明细证据' })).toBeInTheDocument(); fireEvent.click(screen.getAllByRole('button', { name: /复制决策说明/ })[0]); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【客户轨迹决策说明】')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('决策结论:可复盘,需附异常说明')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('客户复盘路径:')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('4. 最后回到依据:异常点必须打开明细证据、字段裁剪和统计查询复核。')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('4. 最后回到依据:异常点必须打开明细证据、字段裁剪和里程统计复核。')); fireEvent.click(screen.getByRole('button', { name: /复制轨迹摘要/ })); @@ -6949,7 +6949,7 @@ test('copies trajectory playback summary from history page', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('历史位置:http://localhost:3000/#/history-query?keyword=VIN-HISTORY-SUMMARY&protocol=JT808&tab=location&dateFrom=2026-07-03&dateTo=2026-07-04')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('明细证据:http://localhost:3000/#/history-query?keyword=VIN-HISTORY-SUMMARY&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=VIN-HISTORY-SUMMARY&protocol=JT808&tab=fields&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计查询:http://localhost:3000/#/mileage?keyword=VIN-HISTORY-SUMMARY&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程统计:http://localhost:3000/#/mileage?keyword=VIN-HISTORY-SUMMARY&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务:http://localhost:3000/#/detail?keyword=VIN-HISTORY-SUMMARY&protocol=JT808')); fireEvent.click(screen.getByRole('button', { name: /复制客户影响/ })); @@ -6975,7 +6975,7 @@ test('copies trajectory playback summary from history page', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程速度:区间里程 22.6 km / 最高速度 58.8 km/h')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('当前回放点:点 1/2,2026-07-03 10:00:00,12.5 km/h,1,000 km')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常判读:断点 1 / 里程回退 0 / 超速 0')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('下一步:建议核对明细证据、字段裁剪、当日统计查询,并确认平台是否存在断链或补发。')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('下一步:建议核对明细证据、字段裁剪、当日里程统计,并确认平台是否存在断链或补发。')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('明细证据:http://localhost:3000/#/history-query?keyword=VIN-HISTORY-SUMMARY&protocol=JT808&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true')); }); @@ -7822,7 +7822,7 @@ test('applies protocol from shareable history hash to API requests', async () => expect(screen.getByText('当前车辆:粤AG18312')).toBeInTheDocument(); expect(screen.getAllByText('来源证据:JT808').length).toBeGreaterThan(0); - fireEvent.click(screen.getByRole('button', { name: '顶部统计查询' })); + fireEvent.click(screen.getByRole('button', { name: '顶部里程统计' })); expect(window.location.hash).toBe('#/mileage?keyword=%E7%B2%A4AG18312&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03'); fireEvent.click(screen.getByRole('button', { name: '顶部数据导出' })); expect(window.location.hash).toBe('#/history-query?keyword=%E7%B2%A4AG18312&protocol=JT808&tab=raw&dateFrom=2026-07-01&dateTo=2026-07-03'); @@ -7880,7 +7880,7 @@ test('topbar customer time window scopes vehicle service tasks', async () => { render(); expect(screen.getByText('客户时间窗')).toBeInTheDocument(); - expect(screen.getByText('同步约束地图、轨迹、统计、导出和告警')).toBeInTheDocument(); + expect(screen.getByText('同步约束地图、轨迹、里程、导出和告警')).toBeInTheDocument(); expect(screen.getByLabelText('客户时间窗开始日期')).toHaveAttribute('placeholder', 'YYYY-MM-DD'); expect(screen.getByLabelText('客户时间窗结束日期')).toHaveAttribute('placeholder', 'YYYY-MM-DD'); @@ -7890,7 +7890,7 @@ test('topbar customer time window scopes vehicle service tasks', async () => { fireEvent.click(screen.getByRole('button', { name: '查询车辆' })); expect(await screen.findByText('粤A时间窗 / VIN-TOPBAR-WINDOW')).toBeInTheDocument(); - fireEvent.click(screen.getByRole('button', { name: '顶部统计查询' })); + fireEvent.click(screen.getByRole('button', { name: '顶部里程统计' })); expect(window.location.hash).toBe('#/mileage?keyword=VIN-TOPBAR-WINDOW&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03'); fireEvent.click(screen.getByRole('button', { name: '顶部数据导出' })); @@ -7970,7 +7970,7 @@ test('topbar customer time window presets support common monitoring ranges', asy expect(screen.getByLabelText('顶部时间窗开始')).toHaveValue(''); expect(screen.getByLabelText('顶部时间窗结束')).toHaveValue(''); - fireEvent.click(screen.getByRole('button', { name: '顶部统计查询' })); + fireEvent.click(screen.getByRole('button', { name: '顶部里程统计' })); expect(window.location.hash).toBe('#/mileage?keyword=VIN-TOPBAR-PRESET&protocol=GB32960'); }); @@ -8038,7 +8038,7 @@ test('topbar copies customer vehicle service scope links', async () => { expect(copied).toContain('时间窗:2026-06-29 至 2026-07-05'); expect(copied).toContain('实时地图:http://localhost:3000/#/map?keyword=VIN-SHARE-SCOPE&protocol=JT808'); expect(copied).toContain('轨迹回放:http://localhost:3000/#/history?keyword=VIN-SHARE-SCOPE&protocol=JT808&dateFrom=2026-06-29&dateTo=2026-07-05'); - expect(copied).toContain('统计查询:http://localhost:3000/#/mileage?keyword=VIN-SHARE-SCOPE&protocol=JT808&dateFrom=2026-06-29&dateTo=2026-07-05'); + expect(copied).toContain('里程统计:http://localhost:3000/#/mileage?keyword=VIN-SHARE-SCOPE&protocol=JT808&dateFrom=2026-06-29&dateTo=2026-07-05'); expect(copied).toContain('数据导出:http://localhost:3000/#/history-query?keyword=VIN-SHARE-SCOPE&protocol=JT808&tab=raw&dateFrom=2026-06-29&dateTo=2026-07-05'); expect(copied).toContain('告警通知:http://localhost:3000/#/alert-events?keyword=VIN-SHARE-SCOPE&protocol=JT808&dateFrom=2026-06-29&dateTo=2026-07-05'); }); @@ -8109,7 +8109,7 @@ test('topbar saves and restores reusable customer vehicle views', async () => { expect(screen.getByLabelText('顶部时间窗开始')).toHaveValue('2026-06-29'); expect(screen.getByLabelText('顶部时间窗结束')).toHaveValue('2026-07-05'); - fireEvent.click(screen.getByRole('button', { name: '顶部统计查询' })); + fireEvent.click(screen.getByRole('button', { name: '顶部里程统计' })); expect(window.location.hash).toBe('#/mileage?keyword=VIN-SAVED-SCOPE&protocol=GB32960&dateFrom=2026-06-29&dateTo=2026-07-05'); }); @@ -8306,20 +8306,20 @@ test('shows parsed field history as a flattened evidence table', async () => { expect(screen.getAllByText('来源证据:GB32960').length).toBeGreaterThan(0); expect(screen.getByText('当前服务范围:VIN-FIELDS-001 / GB32960')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆历史服务台 路线复盘 0 点 查询位置' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '车辆历史服务台 里程核对 - 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆历史服务台 里程核对 - 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆历史服务台 明细证据 1 帧 查看证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆历史服务台 字段裁剪 2 字段 字段配置' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆历史服务台 客户导出 可交付 复制交付' })).toBeInTheDocument(); expect(screen.getByText('客户导出中心')).toBeInTheDocument(); expect(screen.getByText('按客户用途选择报表:行程历史、里程对账、字段证据和告警说明。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户导出中心 行程历史 0 点 导出轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户导出中心 里程对账 - 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户导出中心 里程对账 - 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户导出中心 字段证据 2 字段 导出字段' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户导出中心 告警说明 无明显异常 复制说明' })).toBeInTheDocument(); expect(screen.getByText('自定义时间窗监控台')).toBeInTheDocument(); expect(screen.getByText('客户选定车辆和时间范围后,直接判断这个窗口能否用于轨迹复盘、统计核对、历史证据导出和告警说明。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '自定义时间窗监控 轨迹复盘 位置历史' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '自定义时间窗监控 统计核对 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '自定义时间窗监控 统计核对 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '自定义时间窗监控 历史证据 明细证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '自定义时间窗监控 告警复盘 告警说明' })).toBeInTheDocument(); expect(screen.getByText('客户数据交付台')).toBeInTheDocument(); @@ -8327,7 +8327,7 @@ test('shows parsed field history as a flattened evidence table', async () => { expect(screen.getByText('按车辆和时间窗复盘每一段行程')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '轨迹回放工作台 明细证据 查看证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '轨迹回放工作台 客户导出 复制交付' })).toBeInTheDocument(); - expect(screen.getByText('面向客户的数据导出以车辆服务为中心:同一个筛选范围可以交付轨迹报告、位置历史、明细证据、字段裁剪、CSV 文件和统计查询。')).toBeInTheDocument(); + expect(screen.getByText('面向客户的数据导出以车辆服务为中心:同一个筛选范围可以交付轨迹报告、位置历史、明细证据、字段裁剪、CSV 文件和里程统计。')).toBeInTheDocument(); expect(screen.getByText('先锁定车辆和时间窗,再选择交付物并导出')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户数据交付台 选择范围 调整筛选' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户数据交付台 位置历史 导出位置' })).toBeInTheDocument(); @@ -8340,7 +8340,7 @@ test('shows parsed field history as a flattened evidence table', async () => { expect(screen.getByText('客户历史问题')).toBeInTheDocument(); expect(screen.getByText('用客户语言回答路线、里程、异常和导出问题')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户历史问题 这辆车这段时间在哪里? 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户历史问题 这段时间跑了多少公里? 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户历史问题 这段时间跑了多少公里? 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户历史问题 为什么定位或里程不连续? 复核证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户历史问题 明细能导出给客户吗? 导出交付包' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '报表交付模板 轨迹报告 复制报告' })).toBeInTheDocument(); @@ -8382,7 +8382,7 @@ test('shows parsed field history as a flattened evidence table', async () => { expect(screen.getByText('客户交付物清单')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付清单 位置历史 导出位置' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付清单 轨迹回放 查看轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户交付清单 统计查询 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户交付清单 里程统计 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付清单 明细证据 导出证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付清单 字段裁剪 字段配置' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户交付清单 质量提示 复制清单' })).toBeInTheDocument(); @@ -8391,7 +8391,7 @@ test('shows parsed field history as a flattened evidence table', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【客户数据交付封面包】')); }); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付主题:VIN-FIELDS-001 / GB32960 / 2026-07-03 至 2026-07-04')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付物:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 统计查询链接 / 质量提示')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付物:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 里程统计链接 / 质量提示')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('当前证据:位置 0 条 / 有效坐标 0 点 / 明细 1 帧 / 字段 2 个')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('建议动作:优先导出字段证据,并补查轨迹位置。')); fireEvent.click(screen.getByRole('button', { name: /复制导出向导包/ })); @@ -8405,14 +8405,14 @@ test('shows parsed field history as a flattened evidence table', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('字段裁剪:http://localhost:3000/#/history-query?keyword=VIN-FIELDS-001&protocol=GB32960&tab=fields&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true&fields=gb32960.vehicle.speed_kmh')); fireEvent.click(screen.getByRole('button', { name: /复制交付清单/ })); await waitFor(() => { - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付物:轨迹报告 / 位置历史 / 统计查询 / 明细证据 / 字段裁剪 / 质量提示')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付物:轨迹报告 / 位置历史 / 里程统计 / 明细证据 / 字段裁剪 / 质量提示')); }); fireEvent.click(screen.getByRole('button', { name: '报表交付模板 周期交付计划 复制计划' })); await waitFor(() => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【历史数据周期交付计划】')); }); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('推荐频率:日报用于客户复盘,周报用于客户对账,临时导出用于问题解释。')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付内容:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 统计查询链接 / 质量提示。')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('交付内容:轨迹报告 / 位置历史 CSV / 明细证据 CSV / 字段裁剪 CSV / 里程统计链接 / 质量提示。')); fireEvent.click(screen.getByRole('button', { name: '保存报表视图 当前筛选 VIN-FIELDS-001 保存视图' })); await waitFor(() => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【保存报表视图】')); @@ -8691,7 +8691,7 @@ test('flags trajectory playback anomalies for gap mileage and speed review', asy expect(screen.getByText('2 km')).toBeInTheDocument(); expect(screen.getByText('速度异常')).toBeInTheDocument(); expect(screen.getAllByText('132 km/h').length).toBeGreaterThan(0); - expect(screen.getByText('建议核对明细证据和当日统计查询')).toBeInTheDocument(); + expect(screen.getByText('建议核对明细证据和当日里程统计')).toBeInTheDocument(); }); test('opens amap route from trajectory playback workspace', async () => { @@ -9337,7 +9337,7 @@ test('updates mileage hash when mileage filters are submitted', async () => { render(); - await screen.findByRole('heading', { name: '统计查询' }); + await screen.findByRole('heading', { name: '里程统计' }); fireEvent.change(screen.getByPlaceholderText('VIN / 车牌 / 手机号 / OEM'), { target: { value: '粤AG18312' } }); fireEvent.click(screen.getByText('全部数据通道')); fireEvent.click(await screen.findByText('JT808')); @@ -9738,7 +9738,7 @@ test('shows mileage anomaly action guidance', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务:http://localhost:3000/#/detail?keyword=VIN-MILEAGE-ANOMALY&protocol=GB32960')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('轨迹证据:http://localhost:3000/#/history?keyword=VIN-MILEAGE-ANOMALY&protocol=GB32960&dateFrom=2026-07-03&dateTo=2026-07-04')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('历史明细:http://localhost:3000/#/history-query?keyword=VIN-MILEAGE-ANOMALY&protocol=GB32960&tab=raw&dateFrom=2026-07-03&dateTo=2026-07-04&includeFields=true')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计查询:http://localhost:3000/#/mileage?keyword=VIN-MILEAGE-ANOMALY&protocol=GB32960&dateFrom=2026-07-03&dateTo=2026-07-04')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程统计:http://localhost:3000/#/mileage?keyword=VIN-MILEAGE-ANOMALY&protocol=GB32960&dateFrom=2026-07-03&dateTo=2026-07-04')); }); test('shows mileage statistics workspace with trend source and definition', async () => { @@ -9841,7 +9841,7 @@ test('shows mileage statistics workspace with trend source and definition', asyn expect(screen.getAllByText('100%').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('闭合校验').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('0 km').length).toBeGreaterThanOrEqual(1); - expect(screen.getAllByText('统计口径').length).toBeGreaterThanOrEqual(1); + expect(screen.getAllByText('里程口径').length).toBeGreaterThanOrEqual(1); expect(screen.getByText((content) => content.includes('区间总值应等于各日里程之和'))).toBeInTheDocument(); }); @@ -9958,7 +9958,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async () render(); - expect(await screen.findByText('客户统计查询')).toBeInTheDocument(); + expect(await screen.findByText('客户里程统计')).toBeInTheDocument(); expect(screen.getByText('客户里程对账总控')).toBeInTheDocument(); expect(screen.getByText('把区间里程、每日闭合、轨迹证明、异常通知和报表导出收敛成客户可验收的对账链路。')).toBeInTheDocument(); expect(screen.getByText('里程报表交付旅程')).toBeInTheDocument(); @@ -10002,11 +10002,11 @@ test('shows vehicle-first statistics domains for one vehicle service', async () expect(screen.getByRole('button', { name: '客户里程统计工作台 历史导出 3 条 导出明细' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户里程统计工作台 告警通知 1 离线 在线态势' })).toBeInTheDocument(); expect(screen.getByText('先定车辆和时间范围,再判断里程能否交付')).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户统计查询 选择范围 调整筛选' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户统计查询 区间里程 复制摘要' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户统计查询 发布判断 发布审计' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户统计查询 复核证据 轨迹复核' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户统计查询 明细导出 导出明细' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户里程统计 选择范围 调整筛选' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户里程统计 区间里程 复制摘要' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户里程统计 发布判断 发布审计' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户里程统计 复核证据 轨迹复核' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户里程统计 明细导出 导出明细' })).toBeInTheDocument(); expect(screen.getByText('客户里程对账台')).toBeInTheDocument(); expect(screen.getByText('用同一辆车和同一时间窗完成区间里程、日报闭合、轨迹证据、告警通知和报表导出。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户里程对账台 区间里程 210 km 复制摘要' })).toBeInTheDocument(); @@ -10016,7 +10016,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async () expect(screen.getByRole('button', { name: '客户里程对账台 报表导出 3 条 导出CSV' })).toBeInTheDocument(); expect(screen.getByText('客户里程交付导航')).toBeInTheDocument(); expect(screen.getByText('把里程统计变成客户能看懂的交付路径:先确认口径,再回放轨迹,最后导出明细和结论。')).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户里程交付导航 确认统计口径 复制统计摘要' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户里程交付导航 确认里程口径 复制统计摘要' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户里程交付导航 回放里程轨迹 轨迹复核' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户里程交付导航 导出明细证据 导出CSV' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户里程交付导航 发送交付结论 复制交付包' })).toBeInTheDocument(); @@ -10063,7 +10063,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async () expect(screen.getByRole('button', { name: '复制影响范围' })).toBeInTheDocument(); expect(screen.getByText('影响待复核')).toBeInTheDocument(); expect(screen.getByText('3 辆车')).toBeInTheDocument(); - expect(screen.getByText('当前筛选会影响 6 条里程记录、210 km 统计口径和 1 辆离线车辆判断。')).toBeInTheDocument(); + expect(screen.getByText('当前筛选会影响 6 条里程记录、210 km 里程口径和 1 辆离线车辆判断。')).toBeInTheDocument(); expect(screen.getByText('里程服务任务板')).toBeInTheDocument(); expect(screen.getAllByText('发布判断').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('区间复核')).toBeInTheDocument(); @@ -10133,7 +10133,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async () expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆范围:VIN-STATS-SERVICE')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('累计里程:210 km')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('发布判断:复核后发布')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计口径:日里程按首末总里程差值计算,区间总值应等于每日里程之和')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程口径:日里程按首末总里程差值计算,区间总值应等于每日里程之和')); expect(await screen.findByText('在线状态明细')).toBeInTheDocument(); expect(await screen.findByText('VIN-STATS-SERVICE-OFFLINE')).toBeInTheDocument(); expect(screen.getByText('粤A离线1')).toBeInTheDocument(); @@ -10220,13 +10220,13 @@ test('copies mileage statistics summary for operations reporting', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('当前页里程:140 km')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常记录:1')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('最大单日:粤A统计2 / 2026-07-02 / 100 km')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计口径:区间总值等于各日里程之和')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计查询:http://localhost:3000/#/mileage?keyword=VIN-MILEAGE-COPY&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程口径:区间总值等于各日里程之和')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程统计:http://localhost:3000/#/mileage?keyword=VIN-MILEAGE-COPY&protocol=JT808&dateFrom=2026-07-01&dateTo=2026-07-03')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务:http://localhost:3000/#/detail?keyword=VIN-MILEAGE-COPY&protocol=JT808')); fireEvent.click(screen.getByRole('button', { name: '复制BI发布口径' })); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【BI里程发布口径】')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('发布结论:需复核后发布')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计口径:日里程按首末总里程差值计算,区间总值等于每日里程之和')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程口径:日里程按首末总里程差值计算,区间总值等于每日里程之和')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('闭合状态:分页抽样')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('记录覆盖率:50%')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常记录:1')); @@ -10474,7 +10474,7 @@ test('opens same-day mileage statistics from history location row', async () => expect((await screen.findAllByText('VIN-HISTORY-MILEAGE')).length).toBeGreaterThan(0); const locationRow = screen.getByRole('row', { name: /VIN-HISTORY-MILEAGE/ }); - fireEvent.click(within(locationRow).getByRole('button', { name: '统计查询' })); + fireEvent.click(within(locationRow).getByRole('button', { name: '里程统计' })); await waitFor(() => { expect(window.location.hash).toBe('#/mileage?keyword=VIN-HISTORY-MILEAGE&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04'); @@ -10765,12 +10765,12 @@ test('opens same-day mileage statistics from raw history row', async () => { expect((await screen.findAllByText('raw-jt808-mileage-001')).length).toBeGreaterThanOrEqual(1); const rawRow = screen.getByRole('row', { name: /raw-jt808-mileage-001/ }); - fireEvent.click(within(rawRow).getByRole('button', { name: '统计查询' })); + fireEvent.click(within(rawRow).getByRole('button', { name: '里程统计' })); await waitFor(() => { expect(window.location.hash).toBe('#/mileage?keyword=VIN-RAW-MILEAGE&protocol=JT808&dateFrom=2026-07-03&dateTo=2026-07-04'); }); - expect(await screen.findByRole('heading', { name: '统计查询' })).toBeInTheDocument(); + expect(await screen.findByRole('heading', { name: '里程统计' })).toBeInTheDocument(); }); test('opens current vehicle service from history header with current source evidence', async () => { @@ -11354,7 +11354,7 @@ test('frames realtime page as one vehicle service with source evidence', async ( expect(screen.getByText('客户打开实时监控时,直接围绕选中车辆查看在线、位置、里程、新鲜度,并进入轨迹、统计、历史导出和告警通知。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '实时单车服务快照 车辆服务 粤ART002 车辆档案' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '实时单车服务快照 轨迹回放 更新超时 打开轨迹' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '实时单车服务快照 统计查询 119925 km 查里程' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '实时单车服务快照 里程统计 119925 km 查里程' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '实时单车服务快照 历史导出 GB32960 导出证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '实时单车服务快照 告警通知 服务正常 查看告警' })).toBeInTheDocument(); expect(screen.getAllByText('定位有效').length).toBeGreaterThan(0); @@ -11388,7 +11388,7 @@ test('frames realtime page as one vehicle service with source evidence', async ( expect(screen.getByText('把同一辆车、同一时间窗贯穿到轨迹、里程、历史导出和告警说明,避免客户跨页面重复筛选。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗监控任务台 1 锁定车辆 粤ART002 已锁定' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗监控任务台 2 轨迹复盘 1 天窗口 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '时间窗监控任务台 3 里程核对 119925 km 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '时间窗监控任务台 3 里程核对 119925 km 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗监控任务台 4 历史导出 GB32960 导出证据' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗监控任务台 5 告警闭环 服务正常 告警复盘' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '时间窗复盘 轨迹回放 打开轨迹' })).toBeInTheDocument(); @@ -11601,7 +11601,7 @@ test('shows realtime freshness status for recently updated and stale vehicles', expect(screen.getAllByText('数据新鲜').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('把客户常用的四件事固定成一条路径:实时找车、轨迹复盘、里程核对、导出通知。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车队服务旅程条 1 实时找车 1 在线' })).toBeInTheDocument(); @@ -11939,7 +11939,7 @@ test('copies realtime operations summary from realtime page', async () => { expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆覆盖:GB32960:在线 1/1,实时 1/1;JT808:在线 1/2,实时 2/2;YUTONG_MQTT:在线 0/1,实时 1/1')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('实时入口:http://localhost:3000/#/realtime?protocol=JT808&online=online')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆服务:http://localhost:3000/#/detail?keyword=VIN-RT-SUMMARY-003&protocol=JT808')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('统计查询:http://localhost:3000/#/mileage?keyword=VIN-RT-SUMMARY-003&protocol=JT808')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('里程统计:http://localhost:3000/#/mileage?keyword=VIN-RT-SUMMARY-003&protocol=JT808')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('历史查询:http://localhost:3000/api/history/raw-frames?protocol=JT808&vin=VIN-RT-SUMMARY-003&limit=20&includeFields=true')); fireEvent.click(screen.getByRole('button', { name: '实时筛选 需要关注 2' })); expect(window.location.hash).toBe('#/realtime?protocol=JT808&serviceStatus=degraded&online=online'); @@ -13510,13 +13510,13 @@ test('switches vehicle detail to a source from the source matrix', async () => { expect(screen.getByText('数据通道归并矩阵')).toBeInTheDocument(); expect(screen.getByText('主实时通道')).toBeInTheDocument(); 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(); fireEvent.click(screen.getByRole('button', { name: '复制归并矩阵' })); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【单车数据通道归并矩阵】')); expect(writeText).toHaveBeenCalledWith(expect.stringContaining('1. GB32960 / 主数据通道')); - expect(writeText).toHaveBeenCalledWith(expect.stringContaining('贡献:主实时通道、在线心跳、实时字段、定位数据、轨迹回放、历史数据、统计口径')); + expect(writeText).toHaveBeenCalledWith(expect.stringContaining('贡献:主实时通道、在线心跳、实时字段、定位数据、轨迹回放、历史数据、里程口径')); expect(screen.getByText('车辆服务角色')).toBeInTheDocument(); expect(screen.getAllByText('主数据通道').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('在线数据通道').length).toBeGreaterThanOrEqual(1); @@ -13606,7 +13606,7 @@ test('shows unified service overview on vehicle detail', async () => { expect(screen.getByText('看实时位置')).toBeInTheDocument(); expect(screen.getByText('回放轨迹证据')).toBeInTheDocument(); expect(screen.getAllByText('查询历史数据').length).toBeGreaterThanOrEqual(1); - expect(screen.getByText('复核统计查询')).toBeInTheDocument(); + expect(screen.getByText('复核里程统计')).toBeInTheDocument(); expect(screen.getByText('闭环告警事件')).toBeInTheDocument(); expect(screen.getByText('单车服务任务台')).toBeInTheDocument(); expect(screen.getByText('单车服务处理清单')).toBeInTheDocument(); @@ -13620,12 +13620,12 @@ test('shows unified service overview on vehicle detail', async () => { expect(screen.getAllByText('轨迹回放').length).toBeGreaterThanOrEqual(1); expect(screen.getAllByText('历史数据').length).toBeGreaterThan(0); expect(screen.getByText('告警处置')).toBeInTheDocument(); - expect(screen.getAllByText('统计复核').length).toBeGreaterThan(0); + expect(screen.getAllByText('里程复核').length).toBeGreaterThan(0); expect(screen.getByText('确认实时状态')).toBeInTheDocument(); expect(screen.getByText('回放轨迹断点')).toBeInTheDocument(); expect(screen.getAllByText('查询历史数据').length).toBeGreaterThanOrEqual(1); expect(screen.getByText('处理告警闭环')).toBeInTheDocument(); - expect(screen.getByText('复核统计口径')).toBeInTheDocument(); + expect(screen.getByText('复核里程口径')).toBeInTheDocument(); expect(screen.getByText('车辆在线状态、最新时间、有效坐标均可解释。')).toBeInTheDocument(); expect(screen.getByText('2026-07-03 20:12:10')).toBeInTheDocument(); expect(screen.getAllByText('12 条历史').length).toBeGreaterThanOrEqual(1); @@ -13637,7 +13637,7 @@ test('shows unified service overview on vehicle detail', async () => { expect(screen.getByRole('button', { name: '单车任务 看实时位置 实时监控' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车任务 回放轨迹证据 轨迹回放' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车任务 查询历史数据 历史数据' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '单车任务 复核统计查询 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '单车任务 复核里程统计 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车任务 闭环告警事件 告警事件' })).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: '单车服务任务台 历史数据 查看历史数据' })); expect(window.location.hash).toBe('#/history-query?keyword=VIN001&tab=raw'); @@ -14130,12 +14130,12 @@ test('copies vehicle service diagnostic summary', async () => { expect(screen.getByText('业务可用性')).toBeInTheDocument(); expect(await screen.findByText('车辆服务结论')).toBeInTheDocument(); expect(screen.getByText('单车 Live View')).toBeInTheDocument(); - expect(screen.getByText('客户打开一辆车时,先看当前位置、最后上报、速度、SOC、总里程和告警,再进入轨迹回放、统计查询、数据导出和告警闭环。')).toBeInTheDocument(); + expect(screen.getByText('客户打开一辆车时,先看当前位置、最后上报、速度、SOC、总里程和告警,再进入轨迹回放、里程统计、数据导出和告警闭环。')).toBeInTheDocument(); expect(screen.getByText('客户单车操作台')).toBeInTheDocument(); expect(screen.getByText('围绕这辆车直接完成看车、回放、统计、导出和告警通知。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户单车操作台 看当前位置 113.2, 23.1 实时地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户单车操作台 回放轨迹 12 条 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户单车操作台 核对里程 3 条 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户单车操作台 核对里程 3 条 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户单车操作台 导出证据 34 条 历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户单车操作台 告警通知 1 项 告警闭环' })).toBeInTheDocument(); expect(screen.getByText('当前位置')).toBeInTheDocument(); @@ -14147,22 +14147,22 @@ test('copies vehicle service diagnostic summary', async () => { expect(screen.getByRole('button', { name: '车辆档案摘要 轨迹证据 轨迹回放' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆档案摘要 历史证据 历史查询' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆档案摘要 告警通知 告警闭环' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '车辆档案摘要 统计口径 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆档案摘要 里程口径 里程统计' })).toBeInTheDocument(); expect(screen.getByText('客户常问')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车客户常问 这辆车现在在哪里? 实时监控' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车客户常问 最近是否还在线? 查看实时' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车客户常问 能不能回放轨迹? 轨迹回放' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '单车客户常问 这辆车跑了多少? 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '单车客户常问 这辆车跑了多少? 里程统计' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车客户常问 数据能导出吗? 历史导出' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车客户常问 是否需要通知处理? 告警通知' })).toBeInTheDocument(); expect(screen.getByText('车辆服务档案总览')).toBeInTheDocument(); expect(screen.getByText('单车客户服务交付包')).toBeInTheDocument(); - expect(screen.getByText('面向客户交付时,以车辆为主对象提供实时监控、轨迹回放、历史数据查询、告警通知和统计查询,协议来源只作为可追溯证据。')).toBeInTheDocument(); + expect(screen.getByText('面向客户交付时,以车辆为主对象提供实时监控、轨迹回放、历史数据查询、告警通知和里程统计,协议来源只作为可追溯证据。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户服务交付 实时监控 打开监控' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户服务交付 轨迹回放 回放轨迹' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户服务交付 历史数据查询 查询历史' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户服务交付 告警通知 告警闭环' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: '客户服务交付 统计查询 统计复核' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户服务交付 里程统计 里程复核' })).toBeInTheDocument(); expect(screen.getAllByText('单车时间窗交付').length).toBeGreaterThan(0); expect(screen.getByText('把同一辆车和同一段时间带入轨迹回放、里程统计、历史导出和告警通知,客户复盘时不需要跨页面重复输入。')).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: /复制归一摘要/ })); @@ -14200,12 +14200,12 @@ test('copies vehicle service diagnostic summary', async () => { const customerPackageCopied = String(writeText.mock.lastCall?.[0] ?? ''); expect(customerPackageCopied).toContain('【单车客户服务交付包】'); expect(customerPackageCopied).toContain('车辆:粤A诊断1 / VIN-SUMMARY-001'); - expect(customerPackageCopied).toContain('平台能力:实时监控 / 轨迹回放 / 历史数据查询 / 告警通知 / 统计查询'); + expect(customerPackageCopied).toContain('平台能力:实时监控 / 轨迹回放 / 历史数据查询 / 告警通知 / 里程统计'); expect(customerPackageCopied).toContain('实时监控:http://localhost:3000/#/realtime?keyword=VIN-SUMMARY-001&protocol=JT808'); expect(customerPackageCopied).toContain('轨迹回放:http://localhost:3000/#/history?keyword=VIN-SUMMARY-001&protocol=JT808'); expect(customerPackageCopied).toContain('历史数据查询:http://localhost:3000/#/history-query?keyword=VIN-SUMMARY-001&protocol=JT808&tab=raw&includeFields=true'); expect(customerPackageCopied).toContain('告警通知:http://localhost:3000/#/alert-events?keyword=VIN-SUMMARY-001&protocol=JT808'); - expect(customerPackageCopied).toContain('统计查询:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); + expect(customerPackageCopied).toContain('里程统计:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); fireEvent.click(screen.getByRole('button', { name: /复制诊断摘要/ })); await waitFor(() => { @@ -14228,7 +14228,7 @@ test('copies vehicle service diagnostic summary', async () => { 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('历史数据: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'); + expect(copied).toContain('里程统计:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); fireEvent.click(screen.getByRole('button', { name: /复制服务摘要/ })); await waitFor(() => { @@ -14250,7 +14250,7 @@ test('copies vehicle service diagnostic summary', async () => { 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('历史数据: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'); + expect(operationsCopied).toContain('里程统计:http://localhost:3000/#/mileage?keyword=VIN-SUMMARY-001&protocol=JT808'); fireEvent.click(screen.getByRole('button', { name: '复制处理清单' })); await waitFor(() => { @@ -14264,10 +14264,10 @@ test('copies vehicle service diagnostic summary', async () => { expect(runbookCopied).toContain('2. 回放轨迹断点'); expect(runbookCopied).toContain('3. 查询历史数据'); expect(runbookCopied).toContain('4. 处理告警闭环'); - expect(runbookCopied).toContain('5. 复核统计口径'); + 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'); fireEvent.change(screen.getByPlaceholderText('单车开始日期'), { target: { value: '2026-07-01' } }); fireEvent.change(screen.getByPlaceholderText('单车结束日期'), { target: { value: '2026-07-03' } });