feat(platform): refine customer mileage evidence copy
This commit is contained in:
@@ -235,7 +235,7 @@ function mileageDeliveryPackageText({
|
||||
'统计口径:日里程按首末总里程差值计算,区间总值应等于每日里程之和',
|
||||
`里程统计:${statisticsURL}`,
|
||||
`轨迹复核:${appURL(buildAppHash({ page: 'history', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}) } }))}`,
|
||||
`RAW证据:${appURL(buildAppHash({ page: 'history-query', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}), tab: 'raw', includeFields: 'true' } }))}`,
|
||||
`原始记录:${appURL(buildAppHash({ page: 'history-query', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}), tab: 'raw', includeFields: 'true' } }))}`,
|
||||
...(vehicleURL ? [`车辆服务:${vehicleURL}`] : [])
|
||||
].join('\n');
|
||||
}
|
||||
@@ -298,11 +298,11 @@ function mileageCustomerDecisionText({
|
||||
'客户判断路径:',
|
||||
'1. 先看区间闭合:区间总值必须等于每日里程之和。',
|
||||
'2. 再看记录覆盖:发布前需要覆盖全量明细或导出全量。',
|
||||
'3. 再看异常记录:异常日必须回看轨迹和 RAW。',
|
||||
'3. 再看异常记录:异常日必须回看轨迹和原始记录。',
|
||||
'4. 最后看在线影响:离线车辆会影响当天里程解释。',
|
||||
`里程统计:${statisticsURL}`,
|
||||
`轨迹复核:${appURL(buildAppHash({ page: 'history', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}) } }))}`,
|
||||
`RAW证据:${appURL(buildAppHash({ page: 'history-query', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}), tab: 'raw', includeFields: 'true' } }))}`,
|
||||
`原始记录:${appURL(buildAppHash({ page: 'history-query', keyword: filters.keyword?.trim() || '', protocol: filters.protocol?.trim() || '', filters: { ...(dateFrom ? { dateFrom } : {}), ...(dateTo ? { dateTo } : {}), tab: 'raw', includeFields: 'true' } }))}`,
|
||||
...(vehicleURL ? [`车辆服务:${vehicleURL}`] : [])
|
||||
].join('\n');
|
||||
}
|
||||
@@ -352,7 +352,7 @@ function mileageBIPublishText({
|
||||
`异常记录:${anomalyCount.toLocaleString()}`,
|
||||
`来源一致性:${sourceConsistencyText}`,
|
||||
`统计车辆:${summary.vehicleCount.toLocaleString()},记录:${summary.recordCount.toLocaleString()},来源:${summary.sourceCount.toLocaleString()}`,
|
||||
`发布风险:${publishable ? '当前筛选范围闭合且无异常记录' : '存在分页未全量、异常记录或闭合差值,需要先复核轨迹和 RAW 证据'}`,
|
||||
`发布风险:${publishable ? '当前筛选范围闭合且无异常记录' : '存在分页未全量、异常记录或闭合差值,需要先复核轨迹和原始记录'}`,
|
||||
`统计查询:${statisticsURL}`,
|
||||
...(vehicleURL ? [`车辆服务:${vehicleURL}`] : [])
|
||||
].join('\n');
|
||||
@@ -400,7 +400,7 @@ function statisticsImpactText({
|
||||
`可信度:${confidenceStatus}`,
|
||||
`异常记录:${anomalyCount.toLocaleString()}`,
|
||||
`当前页覆盖:${formatPercent(pageCoverageRate)}`,
|
||||
`业务影响:${publishAuditConclusion === '可发布' ? '当前统计范围可进入运营和BI口径' : '当前统计范围需要先复核轨迹、RAW和离线车辆影响'}`,
|
||||
`业务影响:${publishAuditConclusion === '可发布' ? '当前统计范围可进入运营和BI口径' : '当前统计范围需要先复核轨迹、原始记录和离线车辆影响'}`,
|
||||
`统计查询:${statisticsURL}`,
|
||||
...(vehicleURL ? [`车辆服务:${vehicleURL}`] : [])
|
||||
].join('\n');
|
||||
@@ -484,7 +484,7 @@ function mileageEvidencePackageText(row: DailyMileageRow) {
|
||||
`处置建议:${mileageActionRecommendation(row).detail}`,
|
||||
`车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol: row.source }))}`,
|
||||
`轨迹证据:${appURL(buildAppHash({ page: 'history', keyword: row.vin, protocol: row.source, filters: evidenceFilters }))}`,
|
||||
`RAW证据:${appURL(buildAppHash({ page: 'history-query', keyword: row.vin, protocol: row.source, filters: { ...evidenceFilters, tab: 'raw', includeFields: 'true' } }))}`,
|
||||
`原始记录:${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 }))}`
|
||||
].join('\n');
|
||||
}
|
||||
@@ -514,7 +514,7 @@ function onlineStatusHandoffText({
|
||||
`证据来源:${protocol}`,
|
||||
`在线概览:${summary.onlineVehicleCount.toLocaleString()} 在线 / ${summary.offlineVehicleCount.toLocaleString()} 离线 / 在线率 ${formatPercent(summary.onlineRatePercent)}`,
|
||||
`Redis 在线 Key:${summary.redisOnlineKeys == null ? '-' : summary.redisOnlineKeys.toLocaleString()}`,
|
||||
`协议在线:${protocolLines}`,
|
||||
`来源在线:${protocolLines}`,
|
||||
`统计证据:${summary.evidence || '-'}`,
|
||||
`当前页离线:${offlineRows.length.toLocaleString()} 辆 / 当前筛选 ${total.toLocaleString()} 辆`,
|
||||
'',
|
||||
@@ -522,7 +522,7 @@ function onlineStatusHandoffText({
|
||||
...(offlineRows.length > 0 ? offlineRows.map((row, index) => [
|
||||
`${index + 1}. ${row.plate || '-'} / ${row.vin || '-'} / ${row.oem || '-'}`,
|
||||
` 离线时长:${formatOfflineDuration(row.offlineDurationMinutes)};最后上报:${row.lastSeen || '-'}`,
|
||||
` 来源覆盖:${row.onlineSourceCount}/${row.sourceCount};协议:${(row.protocols ?? []).join('、') || '-'}`,
|
||||
` 来源覆盖:${row.onlineSourceCount}/${row.sourceCount};来源:${(row.protocols ?? []).join('、') || '-'}`,
|
||||
` 车辆服务:${appURL(buildAppHash({ page: 'detail', keyword: row.vin, protocol: filters.protocol?.trim() || row.protocols?.[0] || '' }))}`,
|
||||
` 实时监控:${appURL(buildAppHash({ page: 'realtime', keyword: row.vin, protocol: filters.protocol?.trim() || row.protocols?.[0] || '' }))}`
|
||||
].join('\n')) : ['当前页暂无离线车辆'])
|
||||
@@ -563,15 +563,15 @@ function onlineOperationsReportText({
|
||||
`当前页离线:${offlineRows.length.toLocaleString()}`,
|
||||
`最长离线:${longestOffline ? `${longestOffline.plate || longestOffline.vin} / ${formatOfflineDuration(longestOffline.offlineDurationMinutes)} / ${longestOffline.lastSeen || '-'}` : '-'}`,
|
||||
'',
|
||||
'协议在线:',
|
||||
'来源在线:',
|
||||
...(protocolStats.length > 0 ? protocolStats.map((item, index) => {
|
||||
const rate = item.total > 0 ? (item.online / item.total) * 100 : 0;
|
||||
return `${index + 1}. ${item.protocol}:${item.online.toLocaleString()}/${item.total.toLocaleString()},在线率 ${formatPercent(rate)}`;
|
||||
}) : ['暂无协议在线统计']),
|
||||
}) : ['暂无来源在线统计']),
|
||||
'',
|
||||
'处置建议:',
|
||||
'1. 在线率下降时先检查 Redis online key、协议接入和最后上报时间',
|
||||
'2. 离线车辆优先打开车辆服务,核对实时、轨迹、RAW 和告警证据',
|
||||
'1. 在线率下降时先检查实时在线状态、数据接入和最后上报时间',
|
||||
'2. 离线车辆优先打开车辆服务,核对实时、轨迹、原始记录和告警证据',
|
||||
'3. 统计发布前确认离线车辆是否影响当日里程和区间闭合',
|
||||
`统计查询:${statisticsURL}`,
|
||||
...(vehicleURL ? [`车辆服务:${vehicleURL}`] : [])
|
||||
@@ -681,14 +681,14 @@ export function Mileage({
|
||||
status: anomalyRows.length > 0 ? 'review' : 'pass',
|
||||
value: anomalyRows.length.toLocaleString(),
|
||||
detail: anomalyRows.length > 0 ? '存在日里程异常标记,需核对首末总里程、补传和断链。' : '当前筛选范围未发现异常里程记录。',
|
||||
action: anomalyRows.length > 0 ? '优先打开异常行的轨迹和 RAW 证据复核。' : '继续检查来源一致性和在线证据。'
|
||||
action: anomalyRows.length > 0 ? '优先打开异常行的轨迹和原始记录复核。' : '继续检查来源一致性和在线证据。'
|
||||
},
|
||||
{
|
||||
key: 'source',
|
||||
label: '来源一致性',
|
||||
status: summary.sourceCount > 1 ? 'pass' : summary.sourceCount === 1 ? 'review' : 'blocked',
|
||||
value: sourceConsistencyText,
|
||||
detail: summary.sourceCount > 1 ? '可使用多协议来源交叉验证车辆统计。' : summary.sourceCount === 1 ? '只有单一来源,统计可用但可信度低于多来源。' : '当前统计缺少来源证据。',
|
||||
detail: summary.sourceCount > 1 ? '可使用多来源交叉验证车辆统计。' : summary.sourceCount === 1 ? '只有单一来源,统计可用但可信度低于多来源。' : '当前统计缺少来源证据。',
|
||||
action: summary.sourceCount > 1 ? '保留来源贡献作为审计附件。' : '核对 32960、808、MQTT 是否有缺失来源。'
|
||||
},
|
||||
{
|
||||
@@ -880,8 +880,8 @@ export function Mileage({
|
||||
{
|
||||
step: '04',
|
||||
title: '复核证据',
|
||||
value: anomalyRows.length > 0 ? `${anomalyRows.length.toLocaleString()} 异常` : '轨迹/RAW',
|
||||
detail: anomalyRows.length > 0 ? '异常日优先回看轨迹和原始记录。' : '可从同一时间窗进入轨迹和RAW证据。',
|
||||
value: anomalyRows.length > 0 ? `${anomalyRows.length.toLocaleString()} 异常` : '轨迹/原始',
|
||||
detail: anomalyRows.length > 0 ? '异常日优先回看轨迹和原始记录。' : '可从同一时间窗进入轨迹和原始记录。',
|
||||
action: '轨迹复核',
|
||||
color: anomalyRows.length > 0 ? 'orange' as const : 'green' as const,
|
||||
disabled: !currentVehicleKeyword || !onOpenHistory,
|
||||
@@ -1144,7 +1144,7 @@ export function Mileage({
|
||||
detail: `范围 ${mileageRangeText},${closureActionText}`,
|
||||
color: closureStatusColor,
|
||||
primaryAction: '轨迹证据',
|
||||
secondaryAction: 'RAW证据',
|
||||
secondaryAction: '原始记录',
|
||||
disabled: !currentVehicleKeyword || !onOpenHistory,
|
||||
secondaryDisabled: !currentVehicleKeyword || !onOpenRaw,
|
||||
onPrimary: () => onOpenHistory?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, dateFrom: filters.dateFrom ?? '', dateTo: filters.dateTo ?? '' }),
|
||||
@@ -1209,7 +1209,7 @@ export function Mileage({
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>先定车辆和时间范围,再判断里程能否交付</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
统计查询从车辆服务出发:选择车辆或车队、设定时间窗、判断区间里程和发布状态,再进入轨迹、RAW 和导出明细。
|
||||
统计查询从车辆服务出发:选择车辆或车队、设定时间窗、判断区间里程和发布状态,再进入轨迹、原始记录和导出明细。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={copyStatisticsSummary}>复制统计摘要</Button>
|
||||
@@ -1292,14 +1292,14 @@ export function Mileage({
|
||||
<Tag color={publishAuditColor}>{publishAuditConclusion}</Tag>
|
||||
<Tag color={confidenceColor}>{confidenceStatus}</Tag>
|
||||
</Space>
|
||||
<Typography.Title heading={5} style={{ margin: 0 }}>先判断能不能交付,再进入轨迹、RAW 和导出复核</Typography.Title>
|
||||
<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={copyMileageDecision}>复制决策说明</Button>
|
||||
<Button size="small" disabled={!currentVehicleKeyword || !onOpenHistory} onClick={() => onOpenHistory?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, dateFrom: filters.dateFrom ?? '', dateTo: filters.dateTo ?? '' })}>轨迹复核</Button>
|
||||
<Button size="small" disabled={!currentVehicleKeyword || !onOpenRaw} onClick={() => onOpenRaw?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, dateFrom: filters.dateFrom ?? '', dateTo: filters.dateTo ?? '', includeFields: 'true' })}>RAW证据</Button>
|
||||
<Button size="small" disabled={!currentVehicleKeyword || !onOpenRaw} onClick={() => onOpenRaw?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, dateFrom: filters.dateFrom ?? '', dateTo: filters.dateTo ?? '', includeFields: 'true' })}>原始记录</Button>
|
||||
<Button size="small" disabled={rows.length === 0} onClick={exportMileage}>导出明细</Button>
|
||||
</Space>
|
||||
</div>
|
||||
@@ -1330,7 +1330,7 @@ export function Mileage({
|
||||
</Space>
|
||||
<div className="vp-monitor-metric-value">{formatKm(summary.totalMileageKm)} km</div>
|
||||
<Typography.Text type="secondary">
|
||||
面向客户交付里程时,先确认区间里程、闭合状态、异常记录和在线影响,再导出明细或进入轨迹与 RAW 证据复核。
|
||||
面向客户交付里程时,先确认区间里程、闭合状态、异常记录和在线影响,再导出明细或进入轨迹与原始记录复核。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" theme="solid" type="primary" onClick={copyMileageDeliveryPackage}>复制交付包</Button>
|
||||
@@ -1626,9 +1626,9 @@ export function Mileage({
|
||||
color: offlineVehicleCount > 0 ? 'orange' as const : 'green' as const
|
||||
},
|
||||
{
|
||||
label: '协议覆盖',
|
||||
label: '来源覆盖',
|
||||
value: onlineProtocolStats.length.toLocaleString(),
|
||||
detail: onlineProtocolStats.length > 0 ? onlineProtocolStats.map((item) => `${item.protocol} ${item.online}/${item.total}`).join(';') : '暂无协议在线统计。',
|
||||
detail: onlineProtocolStats.length > 0 ? onlineProtocolStats.map((item) => `${item.protocol} ${item.online}/${item.total}`).join(';') : '暂无来源在线统计。',
|
||||
color: onlineProtocolStats.length > 0 ? 'blue' as const : 'grey' as const
|
||||
},
|
||||
{
|
||||
@@ -1677,7 +1677,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 前需要结合异常记录、轨迹回放和 RAW 解析字段完成复核。'}
|
||||
{closurePassed && anomalyRows.length === 0 ? '当前统计口径可直接用于 BI 里程口径;若存在跨来源差异,再进入车辆服务查看来源证据。' : '统计进入 BI 前需要结合异常记录、轨迹回放和原始记录字段完成复核。'}
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" onClick={copyStatisticsSummary}>复制闭合摘要</Button>
|
||||
@@ -1693,7 +1693,7 @@ export function Mileage({
|
||||
disabled={!currentVehicleKeyword || !onOpenRaw}
|
||||
onClick={() => onOpenRaw?.({ keyword: currentVehicleKeyword, protocol: currentProtocol, dateFrom: filters.dateFrom ?? '', dateTo: filters.dateTo ?? '', includeFields: 'true' })}
|
||||
>
|
||||
闭合复核 RAW
|
||||
闭合复核原始
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
@@ -1729,7 +1729,7 @@ export function Mileage({
|
||||
通过 {publishAuditItems.length - publishReviewCount - publishBlockedCount} / 复核 {publishReviewCount} / 阻断 {publishBlockedCount}
|
||||
</div>
|
||||
<Typography.Text type="secondary">
|
||||
发布前统一审计闭合、覆盖、异常、来源和在线证据;不满足时先回到轨迹和 RAW 证据复核。
|
||||
发布前统一审计闭合、覆盖、异常、来源和在线证据;不满足时先回到轨迹和原始记录复核。
|
||||
</Typography.Text>
|
||||
<Space wrap>
|
||||
<Button size="small" onClick={copyPublishAudit}>复制统计发布审计</Button>
|
||||
@@ -1848,7 +1848,7 @@ export function Mileage({
|
||||
render: (_: unknown, row: OnlineVehicleStatusRow) => `${row.onlineSourceCount}/${row.sourceCount}`
|
||||
},
|
||||
{
|
||||
title: '协议',
|
||||
title: '来源明细',
|
||||
width: 240,
|
||||
render: (_: unknown, row: OnlineVehicleStatusRow) => (
|
||||
<Space spacing={4} wrap>
|
||||
@@ -1885,7 +1885,7 @@ export function Mileage({
|
||||
</div>
|
||||
<div>
|
||||
<Tag color="orange">异常复核</Tag>
|
||||
<p>异常优先检查补传、来源切换、总里程回退和跨协议差异,必要时回到车辆服务查看 RAW 证据。</p>
|
||||
<p>异常优先检查补传、来源切换、总里程回退和跨来源差异,必要时回到车辆服务查看原始记录。</p>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
@@ -1937,7 +1937,7 @@ export function Mileage({
|
||||
<Space spacing={4} wrap>
|
||||
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => copyMileageEvidence(row)}>复制证据</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenHistory} onClick={() => openMileageEvidence(row)}>核对轨迹</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenRaw} onClick={() => openMileageRawEvidence(row)}>核对 RAW</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin) || !onOpenRaw} onClick={() => openMileageRawEvidence(row)}>核对原始</Button>
|
||||
<Button disabled={!canOpenVehicle(row.vin)} onClick={() => onOpenVehicle(row.vin, row.source)}>车辆服务</Button>
|
||||
</Space>
|
||||
)
|
||||
|
||||
@@ -7682,7 +7682,7 @@ test('opens same-day raw frame evidence from mileage row', async () => {
|
||||
render(<App />);
|
||||
|
||||
expect(await screen.findByText('VIN-MILEAGE-RAW')).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: '核对 RAW' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '核对原始' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(window.location.hash.startsWith('#/history-query?')).toBe(true);
|
||||
@@ -7774,7 +7774,7 @@ test('shows mileage anomaly action guidance', async () => {
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常等级:warning'));
|
||||
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('RAW证据: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/#/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'));
|
||||
});
|
||||
|
||||
@@ -7851,7 +7851,7 @@ test('shows mileage statistics workspace with trend source and definition', asyn
|
||||
expect(screen.getAllByText('当前筛选范围汇总总里程与明细合计一致,可作为统计证据。').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getByRole('button', { name: '复制闭合摘要' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '闭合复核轨迹' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '闭合复核 RAW' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '闭合复核原始' })).toBeInTheDocument();
|
||||
expect(screen.getByText('统计发布审计')).toBeInTheDocument();
|
||||
expect(screen.getAllByText('复核后发布').length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getAllByText('区间闭合').length).toBeGreaterThanOrEqual(1);
|
||||
@@ -8004,7 +8004,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async ()
|
||||
expect(screen.getByText('当前统计证据')).toBeInTheDocument();
|
||||
expect(screen.getByText('3 车 / 2 来源 / 3 条明细')).toBeInTheDocument();
|
||||
expect(screen.getByText('客户里程决策台')).toBeInTheDocument();
|
||||
expect(screen.getByText('先判断能不能交付,再进入轨迹、RAW 和导出复核')).toBeInTheDocument();
|
||||
expect(screen.getByText('先判断能不能交付,再进入轨迹、原始记录和导出复核')).toBeInTheDocument();
|
||||
expect(screen.getAllByRole('button', { name: '复制决策说明' }).length).toBeGreaterThanOrEqual(1);
|
||||
expect(screen.getByRole('button', { name: '客户里程决策 交付结论 复制决策' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '客户里程决策 区间闭合 统计摘要' })).toBeInTheDocument();
|
||||
@@ -8012,7 +8012,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async ()
|
||||
expect(screen.getByRole('button', { name: '客户里程决策 异常复核 异常证据' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '客户里程决策 在线影响 在线态势' })).toBeInTheDocument();
|
||||
expect(screen.getByText('客户里程复核交付包')).toBeInTheDocument();
|
||||
expect(screen.getByText('面向客户交付里程时,先确认区间里程、闭合状态、异常记录和在线影响,再导出明细或进入轨迹与 RAW 证据复核。')).toBeInTheDocument();
|
||||
expect(screen.getByText('面向客户交付里程时,先确认区间里程、闭合状态、异常记录和在线影响,再导出明细或进入轨迹与原始记录复核。')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '里程交付 区间里程 复制交付' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '里程交付 闭合校验 闭合摘要' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '里程交付 异常记录 异常证据' })).toBeInTheDocument();
|
||||
@@ -8039,7 +8039,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async ()
|
||||
expect(screen.getByText('在线统计运营态势')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '复制在线态势' })).toBeInTheDocument();
|
||||
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();
|
||||
@@ -8056,7 +8056,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async ()
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('累计里程:210 km'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('在线状态:3 在线 / 1 离线 / 在线率 75%'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('发布判断:复核后发布'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('业务影响:当前统计范围需要先复核轨迹、RAW和离线车辆影响'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('业务影响:当前统计范围需要先复核轨迹、原始记录和离线车辆影响'));
|
||||
fireEvent.click(screen.getAllByRole('button', { name: '复制决策说明' })[0]);
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【客户里程决策说明】'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('决策结论:复核后交付'));
|
||||
@@ -8071,7 +8071,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async ()
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('当前页车辆:2 / 当前筛选 2'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('最长离线:粤A离线1 / 2 小时 / 2026-07-03 18:12:10'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('1. JT808:2/3,在线率 66.7%'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('2. 离线车辆优先打开车辆服务,核对实时、轨迹、RAW 和告警证据'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('2. 离线车辆优先打开车辆服务,核对实时、轨迹、原始记录和告警证据'));
|
||||
fireEvent.click(screen.getByRole('button', { name: '里程交付 区间里程 复制交付' }));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【客户里程复核交付包】'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆范围:VIN-STATS-SERVICE'));
|
||||
@@ -8086,7 +8086,7 @@ test('shows vehicle-first statistics domains for one vehicle service', async ()
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【车辆在线状态交接】'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('车辆范围:VIN-STATS-SERVICE'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('在线概览:3 在线 / 1 离线 / 在线率 75%'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('协议在线:JT808 2/3;GB32960 1/2'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('来源在线:JT808 2/3;GB32960 1/2'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('1. 粤A离线1 / VIN-STATS-SERVICE-OFFLINE / 广安车联'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('离线时长:2 小时;最后上报:2026-07-03 18:12:10'));
|
||||
});
|
||||
@@ -8175,7 +8175,7 @@ test('copies mileage statistics summary for operations reporting', async () => {
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('记录覆盖率:50%'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('异常记录:1'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('来源一致性:可做跨来源核对'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('发布风险:存在分页未全量、异常记录或闭合差值,需要先复核轨迹和 RAW 证据'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('发布风险:存在分页未全量、异常记录或闭合差值,需要先复核轨迹和原始记录'));
|
||||
fireEvent.click(screen.getByRole('button', { name: '复制统计发布审计' }));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('【统计发布审计】'));
|
||||
expect(writeText).toHaveBeenCalledWith(expect.stringContaining('发布结论:复核后发布'));
|
||||
|
||||
Reference in New Issue
Block a user