feat(platform): align customer mileage service wording
This commit is contained in:
@@ -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)}`
|
||||
];
|
||||
|
||||
@@ -48,12 +48,12 @@ const navGroups = [
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '轨迹统计',
|
||||
title: '轨迹里程',
|
||||
audience: '客户',
|
||||
description: '回放轨迹、统计查询、导出数据',
|
||||
description: '回放轨迹、里程统计、导出数据',
|
||||
items: [
|
||||
{ itemKey: 'history', text: '轨迹回放', icon: <IconMapPin /> },
|
||||
{ itemKey: 'mileage', text: '统计查询', icon: <IconBarChartHStroked /> },
|
||||
{ itemKey: 'mileage', text: '里程统计', icon: <IconBarChartHStroked /> },
|
||||
{ itemKey: 'time-monitor', text: '时间窗监控', icon: <IconPulse /> },
|
||||
{ itemKey: 'history-query', text: '数据导出', icon: <IconHistogram /> }
|
||||
]
|
||||
@@ -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({
|
||||
<span className="vp-brand-mark" />
|
||||
<span className="vp-brand-copy">
|
||||
<span>车辆服务中台</span>
|
||||
<span>实时地图 / 轨迹统计 / 告警通知</span>
|
||||
<span>实时地图 / 轨迹里程 / 告警通知</span>
|
||||
</span>
|
||||
</div>
|
||||
<div className="vp-customer-primary-path" aria-label="客户主线">
|
||||
@@ -257,7 +257,7 @@ export function AppShell({
|
||||
<div className="vp-customer-task-dispatch" aria-label="客户任务分发台">
|
||||
<div className="vp-customer-task-dispatch-head">
|
||||
<strong>客户任务分发台</strong>
|
||||
<span>输入 VIN / 车牌 / 手机号后,地图、轨迹、统计、导出和告警都围绕同一辆车服务。</span>
|
||||
<span>输入 VIN / 车牌 / 手机号后,地图、轨迹、里程、导出和告警都围绕同一辆车服务。</span>
|
||||
</div>
|
||||
<div className="vp-customer-task-dispatch-actions">
|
||||
{customerTaskPath.map((item) => (
|
||||
@@ -395,7 +395,7 @@ export function AppShell({
|
||||
<div className="vp-topbar-time-window" aria-label="客户时间窗">
|
||||
<div className="vp-topbar-time-window-copy">
|
||||
<strong>客户时间窗</strong>
|
||||
<span>同步约束地图、轨迹、统计、导出和告警</span>
|
||||
<span>同步约束地图、轨迹、里程、导出和告警</span>
|
||||
</div>
|
||||
<label htmlFor="vp-customer-time-window-start">
|
||||
<span>开始日期</span>
|
||||
|
||||
@@ -227,7 +227,7 @@ function focusVehicleFromIssue(row: QualityIssueRow): FocusVehicleService {
|
||||
realtimeEvidence: `来源 ${qualityProtocolLabel(row.protocol)} / 最后 ${row.lastSeen || '-'}`,
|
||||
historyEvidence: filters.dateFrom ? `${filters.dateFrom} 至 ${filters.dateTo}` : '待确认时间窗',
|
||||
alertEvidence: row.detail || qualityIssueLabel(row.issueType),
|
||||
statisticEvidence: '统计查询需回溯车辆口径',
|
||||
statisticEvidence: '里程统计需回溯车辆口径',
|
||||
issueType: row.issueType
|
||||
};
|
||||
}
|
||||
@@ -475,7 +475,7 @@ export function Dashboard({
|
||||
onClick: () => onOpenHistory()
|
||||
},
|
||||
{
|
||||
title: '统计查询',
|
||||
title: '里程统计',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 辆可统计`,
|
||||
detail: '按自定义时间查询区间里程、日里程和异常记录。',
|
||||
action: '查看统计',
|
||||
@@ -513,9 +513,9 @@ export function Dashboard({
|
||||
},
|
||||
{
|
||||
step: '04',
|
||||
title: '统计查询',
|
||||
title: '里程统计',
|
||||
detail: '用同一时间窗核对区间里程和每日统计。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
onClick: () => onOpenMileage({})
|
||||
},
|
||||
{
|
||||
@@ -592,7 +592,7 @@ export function Dashboard({
|
||||
detail: '同一时间窗贯穿轨迹、统计、原始记录和告警,不需要跨页面重复输入。',
|
||||
color: 'blue' as const,
|
||||
primaryAction: '轨迹回放',
|
||||
secondaryAction: '统计查询',
|
||||
secondaryAction: '里程统计',
|
||||
onPrimary: () => openTimeMonitorHistory(),
|
||||
onSecondary: () => openTimeMonitorMileage()
|
||||
},
|
||||
@@ -659,10 +659,10 @@ export function Dashboard({
|
||||
onClick: () => onOpenQuality()
|
||||
},
|
||||
{
|
||||
title: '统计查询',
|
||||
title: '里程统计',
|
||||
status: `统计车辆 ${formatCount(serviceSummary?.totalVehicles)}`,
|
||||
color: 'green' as const,
|
||||
description: '提供里程等运营统计查询,保证区间总值与每日统计口径闭合。',
|
||||
description: '提供里程等运营里程统计,保证区间总值与每日里程口径闭合。',
|
||||
action: '查看统计',
|
||||
onClick: () => onOpenMileage()
|
||||
}
|
||||
@@ -731,11 +731,11 @@ export function Dashboard({
|
||||
onClick: () => onOpenQuality()
|
||||
},
|
||||
{
|
||||
title: '统计复核',
|
||||
title: '里程复核',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
color: 'green' as const,
|
||||
detail: '核对统计查询口径,保证区间统计和每日统计闭合。',
|
||||
action: '统计查询',
|
||||
detail: '核对里程口径,保证区间统计和每日统计闭合。',
|
||||
action: '里程统计',
|
||||
onClick: () => onOpenMileage()
|
||||
}
|
||||
];
|
||||
@@ -841,13 +841,13 @@ export function Dashboard({
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '统计查询',
|
||||
title: '里程统计',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆口径`,
|
||||
meta: '区间闭合复核',
|
||||
color: 'green' as const,
|
||||
detail: '统计指标先按车辆口径闭合,再回溯轨迹和原始记录。',
|
||||
actions: [
|
||||
{ label: '打开统计查询', onClick: () => onOpenMileage() },
|
||||
{ label: '打开里程统计', onClick: () => onOpenMileage() },
|
||||
{ label: '查看车辆中心', onClick: () => onOpenVehicles({}) }
|
||||
]
|
||||
}
|
||||
@@ -998,7 +998,7 @@ export function Dashboard({
|
||||
`范围:${timeMonitorSummary}`,
|
||||
`交付结论:${timeMonitorDeliveryStatus.label};${timeMonitorDeliveryStatus.detail}`,
|
||||
`时间窗判定:${dayRangeText(scope.dateFrom, scope.dateTo)}`,
|
||||
'平台能力:实时地图 / 轨迹回放 / 统计查询 / 历史数据查询 / 告警通知',
|
||||
'平台能力:实时地图 / 轨迹回放 / 里程统计 / 历史数据查询 / 告警通知',
|
||||
`车辆范围:${scope.keyword || '全部车辆'}`,
|
||||
`数据通道:${scope.protocol || '全部数据通道'}`,
|
||||
`时间范围:${scope.dateFrom || '-'} 至 ${scope.dateTo || '-'}`,
|
||||
@@ -1011,7 +1011,7 @@ export function Dashboard({
|
||||
'下一步动作:',
|
||||
...timeMonitorDeliveryActions.map((item, index) => `${index + 1}. ${item.label}:${item.value};${item.detail}`),
|
||||
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`历史数据查询:${appURL(buildAppHash({ page: 'history-query', keyword: scope.keyword, protocol: scope.protocol, filters: rawFilters }))}`,
|
||||
`告警通知:${appURL(buildAppHash({ page: 'alert-events', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`实时地图:${appURL(buildAppHash({ page: 'map', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`
|
||||
@@ -1028,7 +1028,7 @@ export function Dashboard({
|
||||
onClick: openTimeMonitorHistory
|
||||
},
|
||||
{
|
||||
label: '统计查询',
|
||||
label: '里程统计',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '用同一范围核对区间里程和日统计闭合。',
|
||||
action: '查看统计',
|
||||
@@ -1076,7 +1076,7 @@ export function Dashboard({
|
||||
label: '核对里程',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '用同一范围核对区间里程、日统计和 BI 口径。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
color: 'green' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -1174,7 +1174,7 @@ export function Dashboard({
|
||||
},
|
||||
{
|
||||
label: '核对里程',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
color: 'green' as const,
|
||||
disabled: false,
|
||||
onClick: openTimeMonitorMileage
|
||||
@@ -1195,11 +1195,11 @@ export function Dashboard({
|
||||
`作业范围:${timeMonitorSummary}`,
|
||||
`交付SLA:${timeMonitorWindowLabel}内完成轨迹复盘、统计核对、历史导出和告警说明`,
|
||||
`交付状态:${timeMonitorDeliveryStatus.label};${timeMonitorDeliveryStatus.detail}`,
|
||||
'交付物:轨迹回放链接 / 统计查询链接 / 历史导出链接 / 告警复盘链接',
|
||||
'交付物:轨迹回放链接 / 里程统计链接 / 历史导出链接 / 告警复盘链接',
|
||||
`升级条件:${formatCount(summary?.issueVehicles)} 告警车辆需要先进入告警复盘`,
|
||||
`责任动作:${timeMonitorHasAlerts ? '先处理告警,再交付证据' : '先完成客户复盘,再按需导出证据'}`,
|
||||
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`历史导出:${appURL(buildAppHash({ page: 'history-query', keyword: scope.keyword, protocol: scope.protocol, filters: rawFilters }))}`,
|
||||
`告警复盘:${appURL(buildAppHash({ page: 'alert-events', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`
|
||||
];
|
||||
@@ -1225,7 +1225,7 @@ export function Dashboard({
|
||||
{
|
||||
label: '交付物',
|
||||
value: '轨迹/统计/导出/告警',
|
||||
detail: '交付轨迹回放、统计查询、历史导出和告警复盘四个入口。',
|
||||
detail: '交付轨迹回放、里程统计、历史导出和告警复盘四个入口。',
|
||||
action: '导出证据',
|
||||
color: timeMonitorHasHistory ? 'blue' as const : 'orange' as const,
|
||||
onClick: openTimeMonitorRaw
|
||||
@@ -1248,7 +1248,7 @@ export function Dashboard({
|
||||
onClick: openTimeMonitorHistory
|
||||
},
|
||||
{
|
||||
label: '统计查询',
|
||||
label: '里程统计',
|
||||
value: timeMonitorWindowLabel,
|
||||
detail: '用同一时间窗核对区间里程、日报闭合和异常点。',
|
||||
color: 'green' as const,
|
||||
@@ -1321,7 +1321,7 @@ export function Dashboard({
|
||||
owner: '告警 / 统计',
|
||||
evidence: `告警 ${formatCount(summary?.issueVehicles)},统计车辆 ${formatCount(serviceSummary?.totalVehicles)}`,
|
||||
detail: '断链、缺字段、里程异常和离线时长进入通知、统计和复核工作流。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
onClick: () => onOpenMileage()
|
||||
}
|
||||
];
|
||||
@@ -1367,11 +1367,11 @@ export function Dashboard({
|
||||
onSecondary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {})
|
||||
},
|
||||
{
|
||||
title: '统计查询',
|
||||
title: '里程统计',
|
||||
objective: '按车辆口径查询里程等指标,保证区间统计和日统计可闭合。',
|
||||
evidence: `车辆口径 ${formatCount(serviceSummary?.totalVehicles)} / 区间统计可追溯轨迹证据`,
|
||||
sla: '统计值必须能追溯轨迹和原始记录',
|
||||
primaryAction: '统计查询',
|
||||
primaryAction: '里程统计',
|
||||
secondaryAction: '车辆中心',
|
||||
onPrimary: () => onOpenMileage(),
|
||||
onSecondary: () => onOpenVehicles({})
|
||||
@@ -1398,7 +1398,7 @@ export function Dashboard({
|
||||
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: highPriorityFilters?.keyword, protocol: highPriorityFilters?.protocol, filters: highPriorityFilters }))}`,
|
||||
`原始记录:${appURL(buildAppHash({ page: 'history-query', keyword: highPriorityFilters?.keyword, protocol: highPriorityFilters?.protocol, filters: { ...highPriorityFilters, tab: 'raw', includeFields: 'true' } }))}`,
|
||||
`告警事件:${appURL(buildAppHash({ page: 'alert-events', filters: highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {} }))}`,
|
||||
`统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}`,
|
||||
`里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}`,
|
||||
`车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: highPriorityLookupKey, protocol: highPriorityIssue?.protocol }))}`
|
||||
].filter(Boolean);
|
||||
copyText(lines.join('\n'), '客户交付摘要');
|
||||
@@ -1438,7 +1438,7 @@ export function Dashboard({
|
||||
`轨迹回放:${appURL(buildAppHash({ page: 'history' }))}`,
|
||||
`历史查询:${appURL(buildAppHash({ page: 'history-query', filters: { tab: 'raw', includeFields: 'true' } }))}`,
|
||||
`告警事件:${appURL(buildAppHash({ page: 'alert-events' }))}`,
|
||||
`统计查询:${appURL(buildAppHash({ page: 'mileage' }))}`,
|
||||
`里程统计:${appURL(buildAppHash({ page: 'mileage' }))}`,
|
||||
`运维质量:${appURL(buildAppHash({ page: 'ops-quality' }))}`
|
||||
];
|
||||
copyText(lines.join('\n'), '数据流转图');
|
||||
@@ -1462,7 +1462,7 @@ export function Dashboard({
|
||||
`实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
|
||||
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
|
||||
`原始记录:${appURL(buildAppHash({ page: 'history-query', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol, filters: { ...commonFilters, tab: 'raw', includeFields: 'true' } }))}`,
|
||||
`统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
|
||||
`里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol }))}`,
|
||||
`告警事件:${appURL(buildAppHash({ page: 'alert-events', keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol, filters: focusVehicle.issueType ? { issueType: focusVehicle.issueType } : {} }))}`
|
||||
];
|
||||
copyText(lines.join('\n'), '重点车辆服务处置卡');
|
||||
@@ -1563,10 +1563,10 @@ export function Dashboard({
|
||||
{
|
||||
title: '自定义时间复盘',
|
||||
value: taskTimeMonitorSummary,
|
||||
detail: '一个时间窗贯穿轨迹回放、统计查询、历史查询和告警复盘,适合客户问询与 BI 核对。',
|
||||
detail: '一个时间窗贯穿轨迹回放、里程统计、历史查询和告警复盘,适合客户问询与 BI 核对。',
|
||||
color: 'blue' as const,
|
||||
primaryAction: '轨迹复盘',
|
||||
secondaryAction: '统计查询',
|
||||
secondaryAction: '里程统计',
|
||||
onPrimary: () => openTimeMonitorHistory(),
|
||||
onSecondary: () => openTimeMonitorMileage()
|
||||
},
|
||||
@@ -1601,7 +1601,7 @@ export function Dashboard({
|
||||
{
|
||||
title: '复盘时间',
|
||||
value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo),
|
||||
detail: '同一个时间窗贯穿轨迹回放、统计查询、原始记录和告警复盘。',
|
||||
detail: '同一个时间窗贯穿轨迹回放、里程统计、原始记录和告警复盘。',
|
||||
action: '轨迹回放',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorHistory
|
||||
@@ -1653,10 +1653,10 @@ export function Dashboard({
|
||||
},
|
||||
{
|
||||
step: '4',
|
||||
title: '复盘统计',
|
||||
title: '复盘里程',
|
||||
value: `${formatCount(summary?.activeToday)} 活跃`,
|
||||
detail: '用轨迹、位置历史和里程统计回答这段时间发生了什么。',
|
||||
action: '轨迹统计',
|
||||
action: '轨迹里程',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -1689,7 +1689,7 @@ export function Dashboard({
|
||||
`车辆中心:${appURL(buildAppHash({ page: 'vehicles' }))}`,
|
||||
`实时地图:${appURL(buildAppHash({ page: 'map', filters: { online: 'online' } }))}`,
|
||||
`轨迹回放:${appURL(buildAppHash({ page: 'history', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`统计查询:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`里程统计:${appURL(buildAppHash({ page: 'mileage', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`,
|
||||
`历史数据:${appURL(buildAppHash({ page: 'history-query', keyword: scope.keyword, protocol: scope.protocol, filters: rawFilters }))}`,
|
||||
`告警事件:${appURL(buildAppHash({ page: 'alert-events', keyword: scope.keyword, protocol: scope.protocol, filters: scope }))}`
|
||||
];
|
||||
@@ -1753,8 +1753,8 @@ export function Dashboard({
|
||||
{
|
||||
label: '里程统计',
|
||||
value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo),
|
||||
detail: '核对区间里程、每日闭合、异常记录和 BI 统计口径。',
|
||||
action: '统计查询',
|
||||
detail: '核对区间里程、每日闭合、异常记录和 BI 里程口径。',
|
||||
action: '里程统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -1791,9 +1791,9 @@ export function Dashboard({
|
||||
onClick: openTimeMonitorHistory
|
||||
},
|
||||
{
|
||||
title: '统计查询',
|
||||
title: '里程统计',
|
||||
description: '按车辆口径核对区间里程、日统计和异常来源。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
evidence: `${formatCount(serviceSummary?.totalVehicles)} 辆可统计`,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -1833,7 +1833,7 @@ export function Dashboard({
|
||||
label: 'Mileage',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '按车辆口径查询区间里程、日统计和异常断点。',
|
||||
action: '查统计',
|
||||
action: '查里程',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -1917,7 +1917,7 @@ export function Dashboard({
|
||||
label: '里程周报模板',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '按车辆口径复用里程统计,支撑周报、对账和 BI 复核。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -2066,7 +2066,7 @@ export function Dashboard({
|
||||
question: '这段时间跑了多少',
|
||||
answer: `${dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo)},用同一时间窗核对区间里程和每日统计。`,
|
||||
metric: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
action: '查统计查询',
|
||||
action: '查里程统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -2189,7 +2189,7 @@ export function Dashboard({
|
||||
title: '查这段时间',
|
||||
value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo),
|
||||
detail: '同窗查看轨迹和里程统计',
|
||||
action: '轨迹统计',
|
||||
action: '轨迹里程',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorHistory
|
||||
},
|
||||
@@ -2304,10 +2304,10 @@ export function Dashboard({
|
||||
onClick: openTimeMonitorHistory
|
||||
},
|
||||
{
|
||||
label: '统计查询',
|
||||
label: '里程统计',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '按车辆口径核对区间里程、日统计和异常来源。',
|
||||
action: '查统计',
|
||||
action: '查里程',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -2432,8 +2432,8 @@ export function Dashboard({
|
||||
{
|
||||
label: '里程能耗',
|
||||
value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo),
|
||||
detail: '用同一时间窗核对里程、运行状态和能耗相关统计口径。',
|
||||
action: '统计查询',
|
||||
detail: '用同一时间窗核对里程、运行状态和能耗相关里程口径。',
|
||||
action: '里程统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
}
|
||||
@@ -2477,7 +2477,7 @@ export function Dashboard({
|
||||
title: '核对时间窗里程',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '按同一时间范围核对区间里程、每日统计和 BI 口径。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -2527,7 +2527,7 @@ export function Dashboard({
|
||||
label: '里程统计',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '核对区间里程、每日统计和 BI 展示口径。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
color: 'green' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -2569,7 +2569,7 @@ export function Dashboard({
|
||||
label: '里程统计',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '以车辆为对象核对区间里程、每日统计和 BI 口径。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -2602,7 +2602,7 @@ export function Dashboard({
|
||||
{
|
||||
label: '里程统计',
|
||||
value: dayRangeText(timeMonitorScopeValue.dateFrom, timeMonitorScopeValue.dateTo),
|
||||
detail: '核对区间里程、每日里程和客户 BI 统计口径。',
|
||||
detail: '核对区间里程、每日里程和客户 BI 里程口径。',
|
||||
action: '核对里程',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
@@ -2671,7 +2671,7 @@ export function Dashboard({
|
||||
question: '里程怎么算',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '查询区间里程、每日里程和统计闭合情况,支撑 BI 口径复核。',
|
||||
action: '统计查询',
|
||||
action: '里程统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
},
|
||||
@@ -2715,7 +2715,7 @@ export function Dashboard({
|
||||
label: '里程统计',
|
||||
question: '里程是否可信',
|
||||
value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`,
|
||||
detail: '面向客户核对区间里程、每日汇总和 BI 统计口径。',
|
||||
detail: '面向客户核对区间里程、每日汇总和 BI 里程口径。',
|
||||
action: '核对统计',
|
||||
color: 'blue' as const,
|
||||
onClick: openTimeMonitorMileage
|
||||
@@ -2874,7 +2874,7 @@ export function Dashboard({
|
||||
title={focusMode === 'time-window' ? '自定义时间监控' : '车辆服务工作台'}
|
||||
description={focusMode === 'time-window'
|
||||
? '把客户选择的一辆车和一个时间窗固定下来,同时进入实时地图、轨迹回放、里程统计、历史导出和告警复盘。'
|
||||
: '面向客户的车辆地图、实时监控、轨迹回放、统计查询、自定义时间窗复盘、历史查询、告警通知和数据导出'}
|
||||
: '面向客户的车辆地图、实时监控、轨迹回放、里程统计、自定义时间窗复盘、历史查询、告警通知和数据导出'}
|
||||
/>
|
||||
<Spin spinning={loading}>
|
||||
{focusMode === 'overview' ? (
|
||||
@@ -2919,7 +2919,7 @@ export function Dashboard({
|
||||
<div className="vp-customer-service-overview-copy">
|
||||
<Typography.Text strong>客户服务总览</Typography.Text>
|
||||
<Typography.Text type="secondary">
|
||||
地图、轨迹、统计、导出是客户能直接使用的车辆服务;协议来源只进入证据和追溯。
|
||||
地图、轨迹、里程、导出是客户能直接使用的车辆服务;协议来源只进入证据和追溯。
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div className="vp-customer-service-overview-grid">
|
||||
@@ -3242,7 +3242,7 @@ export function Dashboard({
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" aria-label="车辆地图态势 打开实时地图" onClick={() => onOpenMap({ online: 'online' })}>打开实时地图</Button>
|
||||
<Button size="small" theme="light" type="primary" aria-label="车辆地图态势 回放轨迹" onClick={openTimeMonitorHistory}>回放轨迹</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorMileage}>统计查询</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorMileage}>里程统计</Button>
|
||||
<Button size="small" theme="light" type="warning" onClick={() => onOpenQuality()}>告警通知</Button>
|
||||
</Space>
|
||||
</div>
|
||||
@@ -3372,7 +3372,7 @@ export function Dashboard({
|
||||
一个车辆服务入口,而不是三个数据源入口。
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
把车队范围、时间窗、地图态势、轨迹回放、统计查询、导出模板和告警订阅保存成客户可复用的车辆服务入口。
|
||||
把车队范围、时间窗、地图态势、轨迹回放、里程统计、导出模板和告警订阅保存成客户可复用的车辆服务入口。
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div className="vp-customer-saved-view-library-grid">
|
||||
@@ -3845,7 +3845,7 @@ export function Dashboard({
|
||||
</Space>
|
||||
<Typography.Title heading={3} style={{ margin: 0 }}>先看车在哪里,再处理轨迹、统计、告警和导出</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
客户主流程围绕车辆本身:地图看车、实时状态、时间窗复盘、统计查询、历史数据导出和告警通知。接入来源只作为追溯证据。
|
||||
客户主流程围绕车辆本身:地图看车、实时状态、时间窗复盘、里程统计、历史数据导出和告警通知。接入来源只作为追溯证据。
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<VehicleMap
|
||||
@@ -3995,10 +3995,10 @@ export function Dashboard({
|
||||
<Tag color={timeMonitorScope().keyword ? 'green' : 'grey'}>{timeMonitorScope().keyword ? '单车' : '全域'}</Tag>
|
||||
</Space>
|
||||
<strong>{timeMonitorSummary}</strong>
|
||||
<span>同一时间窗会同步用于轨迹回放、统计查询、历史查询和告警复盘。</span>
|
||||
<span>同一时间窗会同步用于轨迹回放、里程统计、历史查询和告警复盘。</span>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={openTimeMonitorHistory}>轨迹回放</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorMileage}>统计查询</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorMileage}>里程统计</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorRaw}>数据导出</Button>
|
||||
</Space>
|
||||
</div>
|
||||
@@ -4022,7 +4022,7 @@ export function Dashboard({
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>把车辆位置、时间窗、里程统计、历史证据和告警通知组织成客户可以直接使用的服务包。</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
客户打开首页后,先知道今天能交付什么,再选择地图、轨迹、统计、导出或通知。
|
||||
客户打开首页后,先知道今天能交付什么,再选择地图、轨迹、里程、导出或通知。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={copyCustomerServiceGuide}>复制客户服务说明</Button>
|
||||
@@ -4075,12 +4075,12 @@ export function Dashboard({
|
||||
</Form>
|
||||
<div className="vp-time-monitor-actions">
|
||||
<Button theme="solid" type="primary" onClick={openTimeMonitorHistory}>查看轨迹</Button>
|
||||
<Button theme="light" type="primary" onClick={openTimeMonitorMileage}>统计查询</Button>
|
||||
<Button theme="light" type="primary" onClick={openTimeMonitorMileage}>里程统计</Button>
|
||||
<Button theme="light" type="primary" onClick={openTimeMonitorRaw}>历史查询导出</Button>
|
||||
<Button theme="light" type="warning" onClick={openTimeMonitorAlerts}>查看告警</Button>
|
||||
</div>
|
||||
<Typography.Text type="secondary">
|
||||
同一时间窗会带入轨迹回放、统计查询和历史数据导出,避免跨页面重复输入。
|
||||
同一时间窗会带入轨迹回放、里程统计和历史数据导出,避免跨页面重复输入。
|
||||
</Typography.Text>
|
||||
<div className="vp-time-review-package">
|
||||
<div className="vp-time-review-summary">
|
||||
@@ -4095,7 +4095,7 @@ export function Dashboard({
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={copyTimeMonitorReviewPackage}>复制复盘包</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorHistory}>轨迹回放</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorMileage}>统计查询</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorMileage}>里程统计</Button>
|
||||
<Button size="small" theme="light" type="primary" onClick={openTimeMonitorRaw}>历史数据查询</Button>
|
||||
<Button size="small" theme="light" type="warning" onClick={openTimeMonitorAlerts}>告警通知</Button>
|
||||
</Space>
|
||||
@@ -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) => (
|
||||
<button key={item.title} type="button" className="vp-time-monitor-item" onClick={item.onClick} aria-label={`时间监控 ${item.title}`}>
|
||||
@@ -4472,7 +4472,7 @@ export function Dashboard({
|
||||
<Button size="small" theme="light" aria-label="重点车辆 实时监控" disabled={!focusVehicle.lookupKey} onClick={() => onOpenRealtime({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}>实时监控</Button>
|
||||
<Button size="small" theme="light" aria-label="重点车辆 轨迹回放" disabled={!focusVehicle.lookupKey} onClick={() => onOpenHistory({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}>轨迹回放</Button>
|
||||
<Button size="small" theme="light" aria-label="重点车辆 原始记录" disabled={!focusVehicle.lookupKey} onClick={() => onOpenHistory({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '', tab: 'raw', includeFields: 'true' })}>原始记录</Button>
|
||||
<Button size="small" theme="light" aria-label="重点车辆 统计查询" disabled={!focusVehicle.lookupKey} onClick={() => onOpenMileage({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}>统计查询</Button>
|
||||
<Button size="small" theme="light" aria-label="重点车辆 里程统计" disabled={!focusVehicle.lookupKey} onClick={() => onOpenMileage({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '' })}>里程统计</Button>
|
||||
<Button size="small" theme="light" type="warning" aria-label="重点车辆 告警事件" onClick={() => onOpenQuality({ keyword: focusVehicle.lookupKey, protocol: focusVehicle.protocol ?? '', ...(focusVehicle.issueType ? { issueType: focusVehicle.issueType } : {}) })}>告警事件</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
@@ -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({
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>先锁定车辆和时间窗,再选择交付物并导出</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
面向客户的数据导出以车辆服务为中心:同一个筛选范围可以交付轨迹报告、位置历史、明细证据、字段裁剪、CSV 文件和统计查询。
|
||||
面向客户的数据导出以车辆服务为中心:同一个筛选范围可以交付轨迹报告、位置历史、明细证据、字段裁剪、CSV 文件和里程统计。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={() => openQueryTab('location')}>查询位置</Button>
|
||||
@@ -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) => (
|
||||
<button key={item.title} type="button" className="vp-trip-action" disabled={item.disabled} onClick={item.onClick} aria-label={`轨迹回放工作台 ${item.title} ${item.action}`}>
|
||||
@@ -3228,7 +3228,7 @@ export function History({
|
||||
<Tag color={deliveryStateColor}>{deliveryState}</Tag>
|
||||
<Tag color={amapConfigured ? 'green' : 'orange'}>{amapConfigured ? '高德地图可用' : '坐标预览'}</Tag>
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>先判断轨迹能否复盘,再进入证据、字段和统计查询</Typography.Title>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>先判断轨迹能否复盘,再进入证据、字段和里程统计</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
客户问某辆车某段时间发生了什么时,先看定位覆盖、时间断点、里程速度和明细证据,避免把内部排查过程当成客户主流程。
|
||||
</Typography.Text>
|
||||
@@ -3236,7 +3236,7 @@ export function History({
|
||||
<Button size="small" theme="solid" type="primary" icon={<IconCopy />} onClick={copyTrajectoryDecision}>复制决策说明</Button>
|
||||
<Button size="small" disabled={validLocations.length === 0} onClick={() => openQueryTab('location')}>播放轨迹</Button>
|
||||
<Button size="small" disabled={(rawFrames.total ?? 0) === 0} onClick={() => openQueryTab('raw')}>明细证据</Button>
|
||||
<Button size="small" disabled={!onOpenMileage} onClick={() => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) })}>统计查询</Button>
|
||||
<Button size="small" disabled={!onOpenMileage} onClick={() => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) })}>里程统计</Button>
|
||||
</Space>
|
||||
</div>
|
||||
<div className="vp-trajectory-decision-grid">
|
||||
@@ -3347,7 +3347,7 @@ export function History({
|
||||
车辆服务
|
||||
</Button>
|
||||
<Button size="small" disabled={!onOpenMileage} onClick={() => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) })}>
|
||||
统计查询
|
||||
里程统计
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
@@ -3562,12 +3562,12 @@ export function History({
|
||||
</Space>
|
||||
<Typography.Text strong>{currentVehicleKeyword || '全部车辆'}</Typography.Text>
|
||||
<Typography.Text type="secondary">
|
||||
轨迹、历史查询导出、明细证据和统计查询按同一车辆范围联动,用于客户复盘、客户问询和断链说明。
|
||||
轨迹、历史查询导出、明细证据和里程统计按同一车辆范围联动,用于客户复盘、客户问询和断链说明。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" icon={<IconCopy />} onClick={copyTrajectoryImpactPackage}>复制客户影响</Button>
|
||||
<Button size="small" disabled={!currentVehicleKeyword} onClick={() => onOpenVehicle(currentVehicleKeyword, currentProtocol)}>轨迹车辆服务</Button>
|
||||
<Button size="small" disabled={!onOpenMileage} onClick={() => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) })}>统计查询</Button>
|
||||
<Button size="small" disabled={!onOpenMileage} onClick={() => onOpenMileage?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, ...(filters.dateFrom ? { dateFrom: filters.dateFrom } : {}), ...(filters.dateTo ? { dateTo: filters.dateTo } : {}) })}>里程统计</Button>
|
||||
</Space>
|
||||
</div>
|
||||
<div className="vp-trajectory-impact-grid">
|
||||
@@ -3801,9 +3801,9 @@ export function History({
|
||||
))}
|
||||
</div>
|
||||
<div className="vp-trajectory-anomaly-action">
|
||||
<Tag color={hasTrajectoryAnomaly ? 'orange' : 'green'}>{hasTrajectoryAnomaly ? '建议核对明细证据和当日统计查询' : '轨迹质量可用'}</Tag>
|
||||
<Tag color={hasTrajectoryAnomaly ? 'orange' : 'green'}>{hasTrajectoryAnomaly ? '建议核对明细证据和当日里程统计' : '轨迹质量可用'}</Tag>
|
||||
<Typography.Text type="secondary">
|
||||
{hasTrajectoryAnomaly ? '异常点会影响轨迹回放、定位复盘和区间里程判断,请结合字段裁剪与统计查询交叉确认。' : '当前页轨迹未发现明显断点、里程回退或速度异常。'}
|
||||
{hasTrajectoryAnomaly ? '异常点会影响轨迹回放、定位复盘和区间里程判断,请结合字段裁剪与里程统计交叉确认。' : '当前页轨迹未发现明显断点、里程回退或速度异常。'}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -3849,7 +3849,7 @@ export function History({
|
||||
render: (_: unknown, row: HistoryLocationRow) => (
|
||||
<Space wrap>
|
||||
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin, row.protocol)}>车辆服务</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenMileage} onClick={() => openLocationMileage(row)}>统计查询</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenMileage} onClick={() => openLocationMileage(row)}>里程统计</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenRaw} onClick={() => openLocationRaw(row)}>核对历史明细</Button>
|
||||
</Space>
|
||||
)
|
||||
@@ -3894,7 +3894,7 @@ export function History({
|
||||
render: (_: unknown, row: RawFrameRow) => (
|
||||
<Space wrap>
|
||||
<Button onClick={() => setSelectedRaw(row)}>字段</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenMileage} onClick={() => openRawMileage(row)}>统计查询</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenMileage} onClick={() => openRawMileage(row)}>里程统计</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin, row.protocol)}>车辆服务</Button>
|
||||
</Space>
|
||||
)
|
||||
|
||||
@@ -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 (
|
||||
<div className="vp-page">
|
||||
<PageHeader
|
||||
title="统计查询"
|
||||
title="里程统计"
|
||||
description="按车辆查询里程、在线影响、区间闭合、异常复核和数据交付"
|
||||
actions={(
|
||||
<Button disabled={!currentVehicleKeyword} onClick={() => onOpenVehicle(currentVehicleKeyword, currentProtocol)}>
|
||||
@@ -2206,18 +2206,18 @@ export function Mileage({
|
||||
<div className="vp-scope-bar">
|
||||
<span className="vp-scope-label">当前车辆:{currentVehicleKeyword || '-'}</span>
|
||||
<Tag color={currentProtocol ? 'blue' : 'green'}>数据通道:{currentProtocol || '全部数据通道'}</Tag>
|
||||
<Typography.Text type="tertiary">统计查询以车辆为对象,当前先覆盖里程、在线影响、闭合审计和异常复核。</Typography.Text>
|
||||
<Typography.Text type="tertiary">里程统计以车辆为对象,当前先覆盖里程、在线影响、闭合审计和异常复核。</Typography.Text>
|
||||
</div>
|
||||
<Card bordered className="vp-mileage-customer-query-board" bodyStyle={{ padding: 0 }}>
|
||||
<div className="vp-mileage-customer-query-summary">
|
||||
<Space wrap>
|
||||
<Tag color="blue">客户统计查询</Tag>
|
||||
<Tag color="blue">客户里程统计</Tag>
|
||||
<Tag color={mileageDeliveryColor}>{mileageDeliveryState}</Tag>
|
||||
<Tag color={closureStatusColor}>{closureStatus}</Tag>
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>先定车辆和时间范围,再判断里程能否交付</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
统计查询从车辆服务出发:选择车辆或车队、设定时间窗、判断区间里程和发布状态,再进入轨迹、历史明细和导出明细。
|
||||
里程统计从车辆服务出发:选择车辆或车队、设定时间窗、判断区间里程和发布状态,再进入轨迹、历史明细和导出明细。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={copyStatisticsSummary}>复制统计摘要</Button>
|
||||
@@ -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}`}
|
||||
>
|
||||
<span>{item.step}</span>
|
||||
<Tag color={item.color}>{item.title}</Tag>
|
||||
@@ -2543,7 +2543,7 @@ export function Mileage({
|
||||
<Tag color={statisticsImpactColor}>{statisticsImpactLevel}</Tag>
|
||||
<div className="vp-monitor-metric-value">{summary.vehicleCount.toLocaleString()} 辆车</div>
|
||||
<Typography.Text type="secondary">
|
||||
当前筛选会影响 {summary.recordCount.toLocaleString()} 条里程记录、{formatKm(summary.totalMileageKm)} km 统计口径和 {offlineVehicleCount.toLocaleString()} 辆离线车辆判断。
|
||||
当前筛选会影响 {summary.recordCount.toLocaleString()} 条里程记录、{formatKm(summary.totalMileageKm)} km 里程口径和 {offlineVehicleCount.toLocaleString()} 辆离线车辆判断。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Tag color={confidenceColor}>{confidenceStatus}</Tag>
|
||||
@@ -2711,7 +2711,7 @@ export function Mileage({
|
||||
)}
|
||||
</div>
|
||||
<div className="vp-mileage-side-card">
|
||||
<div className="vp-mileage-side-title">统计口径</div>
|
||||
<div className="vp-mileage-side-title">里程口径</div>
|
||||
<Typography.Text type="secondary">
|
||||
区间里程以每日首末总里程差值汇总,目标是区间总值等于每日里程之和。
|
||||
</Typography.Text>
|
||||
@@ -2813,7 +2813,7 @@ export function Mileage({
|
||||
<div className="vp-stat-closure-action">
|
||||
<Tag color={closureStatusColor}>{closureStatus}</Tag>
|
||||
<Typography.Text type="secondary">
|
||||
{closurePassed && anomalyRows.length === 0 ? '当前统计口径可直接用于 BI 里程口径;若存在跨通道差异,再进入车辆服务查看统计依据。' : '统计进入 BI 前需要结合异常记录、轨迹回放和历史明细完成复核。'}
|
||||
{closurePassed && anomalyRows.length === 0 ? '当前里程口径可直接用于 BI 里程口径;若存在跨通道差异,再进入车辆服务查看统计依据。' : '统计进入 BI 前需要结合异常记录、轨迹回放和历史明细完成复核。'}
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" onClick={copyStatisticsSummary}>复制闭合摘要</Button>
|
||||
@@ -3003,7 +3003,7 @@ export function Mileage({
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
<Card bordered title="统计口径" style={{ marginTop: 16 }}>
|
||||
<Card bordered title="里程口径" style={{ marginTop: 16 }}>
|
||||
<div className="vp-table-toolbar">
|
||||
<Space wrap>
|
||||
<Tag color="blue">可复制日报口径</Tag>
|
||||
|
||||
@@ -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({
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>按车辆和时间窗复盘发生了什么</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
客户问某辆车、某段时间发生了什么时,直接串起轨迹回放、历史数据、统计查询和告警通知。
|
||||
客户问某辆车、某段时间发生了什么时,直接串起轨迹回放、历史数据、里程统计和告警通知。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" disabled={!timeWindowReady} onClick={openTimeWindowHistory}>轨迹回放</Button>
|
||||
@@ -2462,7 +2462,7 @@ export function Realtime({
|
||||
<div className="vp-map-command-side-card">
|
||||
<Typography.Text strong>车辆服务闭环</Typography.Text>
|
||||
<Typography.Text type="secondary">
|
||||
客户从这里完成看车、选车、查轨迹、查历史、查统计、收告警和导出。
|
||||
客户从这里完成看车、选车、查轨迹、查历史、查里程、收告警和导出。
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</aside>
|
||||
@@ -2713,7 +2713,7 @@ export function Realtime({
|
||||
<Tag color={amapConfigured ? 'green' : 'orange'}>{amapConfigured ? 'Live Map 可用' : '坐标预览'}</Tag>
|
||||
<Tag color={mapAttentionRows.length > 0 ? 'orange' : 'green'}>{mapAttentionRows.length.toLocaleString()} 辆关注</Tag>
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>把 Live Map 当作客户服务入口:先看在线车辆和关注车辆,再进入路线回放、统计查询和证据导出。</Typography.Title>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>把 Live Map 当作客户服务入口:先看在线车辆和关注车辆,再进入路线回放、里程统计和证据导出。</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
地图页的第一动作要围绕车辆服务,而不是围绕协议来源;客户从地图进入监控、复盘、统计和交付。
|
||||
</Typography.Text>
|
||||
@@ -2963,7 +2963,7 @@ export function Realtime({
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>{selectedVehicleLabel}</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
客户在地图上选中车辆后,直接进入车辆档案、轨迹回放、统计查询、数据导出和告警处置。
|
||||
客户在地图上选中车辆后,直接进入车辆档案、轨迹回放、里程统计、数据导出和告警处置。
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div className="vp-map-selected-service-actions">
|
||||
@@ -3051,7 +3051,7 @@ export function Realtime({
|
||||
</Space>
|
||||
<Typography.Text strong>{selectedVehicleLabel}</Typography.Text>
|
||||
<Typography.Text type="secondary">
|
||||
面向客户看图时,先确认车辆范围、在线态势、定位态势和选中车辆,再进入轨迹、统计查询、历史数据或告警通知。
|
||||
面向客户看图时,先确认车辆范围、在线态势、定位态势和选中车辆,再进入轨迹、里程统计、历史数据或告警通知。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" icon={<IconCopy />} onClick={copyMapCustomerPackage}>复制地图监控包</Button>
|
||||
@@ -3340,7 +3340,7 @@ export function Realtime({
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>从实时列表直接完成车辆监控闭环</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
先筛在线车辆,再看地图位置,异常车辆优先处置,最后进入单车轨迹、统计查询、告警或导出当前页。
|
||||
先筛在线车辆,再看地图位置,异常车辆优先处置,最后进入单车轨迹、里程统计、告警或导出当前页。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={() => applyFilters({ ...filters, online: 'online' })}>只看在线</Button>
|
||||
|
||||
@@ -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 (
|
||||
<div className="vp-page">
|
||||
<PageHeader title="车辆服务" description="以车辆为主对象查看实时位置、轨迹回放、统计查询、告警通知和历史数据" />
|
||||
<PageHeader title="车辆服务" description="以车辆为主对象查看实时位置、轨迹回放、里程统计、告警通知和历史数据" />
|
||||
<Card bordered>
|
||||
<Form key={formKey} initValues={query} layout="horizontal" onSubmit={(values) => {
|
||||
const nextQuery = { keyword: String(values.keyword ?? ''), protocol: String(values.protocol ?? '') };
|
||||
@@ -1267,7 +1267,7 @@ export function VehicleDetail({
|
||||
<Button disabled={!hasResolvedVIN} onClick={() => onOpenRealtime(resolvedVIN, activeProtocol)}>查看实时</Button>
|
||||
<Button disabled={!hasResolvedVIN} onClick={() => onOpenHistory(resolvedVIN, activeProtocol)}>轨迹回放</Button>
|
||||
<Button disabled={!hasResolvedVIN} onClick={() => onOpenRaw(resolvedVIN, activeProtocol)}>历史数据</Button>
|
||||
<Button disabled={!hasResolvedVIN} onClick={() => onOpenMileage(resolvedVIN, activeProtocol)}>统计查询</Button>
|
||||
<Button disabled={!hasResolvedVIN} onClick={() => onOpenMileage(resolvedVIN, activeProtocol)}>里程统计</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
@@ -1302,7 +1302,7 @@ export function VehicleDetail({
|
||||
{[archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey}
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
客户打开一辆车时,先看当前位置、最后上报、速度、SOC、总里程和告警,再进入轨迹回放、统计查询、数据导出和告警闭环。
|
||||
客户打开一辆车时,先看当前位置、最后上报、速度、SOC、总里程和告警,再进入轨迹回放、里程统计、数据导出和告警闭环。
|
||||
</Typography.Text>
|
||||
<div className="vp-single-vehicle-action-bar" aria-label="客户单车操作台">
|
||||
<div className="vp-single-vehicle-action-head">
|
||||
@@ -1413,7 +1413,7 @@ export function VehicleDetail({
|
||||
<div className="vp-single-vehicle-time-window-actions">
|
||||
{[
|
||||
{ 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({
|
||||
<Button size="small" theme="solid" type="primary" disabled={!hasResolvedVIN} onClick={() => onOpenRealtime(resolvedVIN, activeProtocol)}>实时监控</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenHistory(resolvedVIN, activeProtocol)}>轨迹回放</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenRaw(resolvedVIN, activeProtocol)}>历史数据</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenMileage(resolvedVIN, activeProtocol)}>统计查询</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenMileage(resolvedVIN, activeProtocol)}>里程统计</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="vp-unified-service-grid">
|
||||
@@ -1591,14 +1591,14 @@ export function VehicleDetail({
|
||||
{[archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey}
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
面向客户交付时,以车辆为主对象提供实时监控、轨迹回放、历史数据查询、告警通知和统计查询,协议来源只作为可追溯证据。
|
||||
面向客户交付时,以车辆为主对象提供实时监控、轨迹回放、历史数据查询、告警通知和里程统计,协议来源只作为可追溯证据。
|
||||
</Typography.Text>
|
||||
<div className="vp-customer-service-links">
|
||||
<Button size="small" theme="solid" type="primary" disabled={!hasResolvedVIN} onClick={() => onOpenRealtime(resolvedVIN, activeProtocol)}>实时监控</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenHistory(resolvedVIN, activeProtocol)}>轨迹回放</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenRaw(resolvedVIN, activeProtocol)}>历史数据查询</Button>
|
||||
<Button size="small" theme="light" disabled={!onOpenQuality || (!hasResolvedVIN && qualityCount <= 0)} onClick={() => onOpenQuality?.(qualityFiltersForCurrentVehicle())}>告警通知</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenMileage(resolvedVIN, activeProtocol)}>统计查询</Button>
|
||||
<Button size="small" theme="light" disabled={!hasResolvedVIN} onClick={() => onOpenMileage(resolvedVIN, activeProtocol)}>里程统计</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="vp-customer-service-grid">
|
||||
|
||||
@@ -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 (
|
||||
<div className="vp-page">
|
||||
<PageHeader title="车辆服务" description="围绕车辆完成实时监控、地图查看、轨迹回放、统计查询和数据导出,协议来源只作为证据过滤条件" />
|
||||
<PageHeader title="车辆服务" description="围绕车辆完成实时监控、地图查看、轨迹回放、里程统计和数据导出,协议来源只作为证据过滤条件" />
|
||||
<section className="vp-fleet-command-center" aria-label="客户车队指挥台">
|
||||
<div className="vp-fleet-command-copy">
|
||||
<Space wrap>
|
||||
@@ -1236,7 +1236,7 @@ export function Vehicles({
|
||||
<Tag color="blue">高德地图车辆服务底座</Tag>
|
||||
<Tag color={filters.keyword?.trim() ? 'green' : 'grey'}>{filters.keyword?.trim() ? '单车地图' : '车辆池地图'}</Tag>
|
||||
</Space>
|
||||
<strong>用地图把车辆监控、轨迹回放、围栏告警、统计查询和历史导出串成客户能理解的一条服务路径。</strong>
|
||||
<strong>用地图把车辆监控、轨迹回放、围栏告警、里程统计和历史导出串成客户能理解的一条服务路径。</strong>
|
||||
<span>车辆列表只负责锁定服务对象;地图能力负责解释位置、路线、区域、时间窗和异常通知。</span>
|
||||
</div>
|
||||
<div className="vp-vehicle-amap-foundation-grid">
|
||||
@@ -1506,7 +1506,7 @@ export function Vehicles({
|
||||
</Space>
|
||||
<strong>{filters.keyword?.trim() || `${(summary?.totalVehicles ?? pagination.total).toLocaleString()} 辆车`}</strong>
|
||||
<span>
|
||||
把车辆地图、实时监控、轨迹回放、统计查询、告警通知和历史导出放在同一份服务包里,客户不用理解 GB32960、808 或 MQTT 的差异。
|
||||
把车辆地图、实时监控、轨迹回放、里程统计、告警通知和历史导出放在同一份服务包里,客户不用理解 GB32960、808 或 MQTT 的差异。
|
||||
</span>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" icon={<IconCopy />} onClick={copyCustomerServicePackage}>复制交付包</Button>
|
||||
|
||||
@@ -37,27 +37,27 @@ test('renders vehicle platform shell', () => {
|
||||
|
||||
render(<App />);
|
||||
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(<App />);
|
||||
|
||||
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(<App />);
|
||||
|
||||
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(<App />);
|
||||
|
||||
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' } });
|
||||
|
||||
Reference in New Issue
Block a user