diff --git a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx index c00820ed..5f381cf9 100644 --- a/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx +++ b/vehicle-data-platform/apps/web/src/pages/VehicleDetail.tsx @@ -947,6 +947,53 @@ export function VehicleDetail({ onClick: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()) } ]; + const vehicleArchiveSummaryItems = [ + { + title: '服务状态', + value: online ? '在线可服务' : hasResolvedVIN ? '离线待核' : '待绑定', + detail: lastSeen === '-' ? '暂无最后上报' : `最后上报 ${lastSeen}`, + action: '查看实时', + color: online ? 'green' as const : 'orange' as const, + disabled: !hasResolvedVIN, + onClick: () => onOpenRealtime(resolvedVIN, activeProtocol) + }, + { + title: '轨迹证据', + value: `${formatCompactNumber(overview?.historyCount ?? detail?.history?.total ?? 0)} 条`, + detail: evidenceLocatedSourceCount > 0 ? `${evidenceLocatedSourceCount} 个定位证据可回放` : '暂无有效定位证据', + action: '轨迹回放', + color: evidenceLocatedSourceCount > 0 ? 'blue' as const : 'grey' as const, + disabled: !hasResolvedVIN, + onClick: () => onOpenHistory(resolvedVIN, activeProtocol) + }, + { + title: '历史证据', + value: `${formatCompactNumber(overview?.rawCount ?? detail?.raw?.total ?? 0)} 帧`, + detail: latestRaw?.frameType ? `最新 ${latestRaw.frameType}` : '历史明细与解析字段', + action: '历史查询', + color: (overview?.rawCount ?? detail?.raw?.total ?? 0) > 0 ? 'blue' as const : 'grey' as const, + disabled: !hasResolvedVIN, + onClick: () => onOpenRaw(resolvedVIN, activeProtocol) + }, + { + title: '告警通知', + value: `${qualityCount.toLocaleString()} 项`, + detail: priorityQualityIssue ? `${qualityIssueLabel(priorityQualityIssue.issueType)} / ${priorityQualityIssue.lastSeen || '-'}` : '暂无待通知告警', + action: '告警闭环', + color: qualityCount > 0 ? 'orange' as const : 'green' as const, + disabled: !onOpenQuality || (!hasResolvedVIN && qualityCount <= 0), + onClick: () => onOpenQuality?.(qualityFiltersForCurrentVehicle()) + }, + { + title: '统计口径', + value: `${formatCompactNumber(overview?.mileageCount ?? detail?.mileage?.total ?? 0)} 条`, + detail: `证据里程差 ${formatCompactNumber(evidenceMileageDelta, ' km')}`, + action: '统计查询', + color: isFiniteNumber(evidenceMileageDelta) && Math.abs(evidenceMileageDelta) > 1 ? 'orange' as const : 'green' as const, + disabled: !hasResolvedVIN, + onClick: () => onOpenMileage(resolvedVIN, activeProtocol) + } + ]; const customerQuestionActions = [ { question: '这辆车现在在哪里?', @@ -1188,6 +1235,41 @@ export function VehicleDetail({ + +
+
+ + {hasResolvedVIN ? '已解析车辆' : '待绑定车辆'} + {scopeText} + {customerStatusTitle(serviceStatus?.title) || serviceConclusion.status} + + + {[archivePlate, displayVIN].filter((item) => item && item !== '-').join(' / ') || displayLookupKey} + + + 把 VIN、车牌、在线状态、实时位置、轨迹、历史数据、告警和统计放在同一个单车入口,协议来源只作为可追溯证据。 + +
+
+ {vehicleArchiveSummaryItems.map((item) => ( + + ))} +
+
+
+
{customerQuestionActions.map((item) => ( diff --git a/vehicle-data-platform/apps/web/src/styles/global.css b/vehicle-data-platform/apps/web/src/styles/global.css index bc8334c2..9c5f1328 100644 --- a/vehicle-data-platform/apps/web/src/styles/global.css +++ b/vehicle-data-platform/apps/web/src/styles/global.css @@ -6468,6 +6468,89 @@ button.vp-realtime-command-item:focus-visible { line-height: 18px; } +.vp-vehicle-archive-summary { + margin-top: 16px; + border-color: rgba(17, 24, 39, 0.1); +} + +.vp-vehicle-archive-summary-main { + display: grid; + grid-template-columns: minmax(260px, 0.72fr) minmax(0, 1.28fr); + gap: 16px; +} + +.vp-vehicle-archive-summary-copy { + min-width: 0; + padding: 14px; + border: 1px solid var(--vp-border); + border-radius: var(--vp-radius); + background: #fbfcff; + display: grid; + gap: 12px; + align-content: start; +} + +.vp-vehicle-archive-summary-copy .semi-typography { + font-size: 14px; + line-height: 22px; +} + +.vp-vehicle-archive-summary-grid { + min-width: 0; + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 10px; +} + +.vp-vehicle-archive-summary-item { + min-height: 128px; + padding: 12px; + border: 1px solid var(--vp-border); + border-radius: var(--vp-radius); + background: #fff; + color: inherit; + cursor: pointer; + font: inherit; + text-align: left; + display: grid; + gap: 7px; + align-content: start; +} + +.vp-vehicle-archive-summary-item:disabled { + cursor: not-allowed; + opacity: 0.58; +} + +.vp-vehicle-archive-summary-item:not(:disabled):hover, +.vp-vehicle-archive-summary-item:not(:disabled):focus-visible { + border-color: rgba(22, 100, 255, 0.42); + background: #f5f9ff; + outline: none; +} + +.vp-vehicle-archive-summary-item strong { + color: var(--vp-text); + font-size: 16px; + line-height: 22px; + font-weight: 700; + word-break: break-word; +} + +.vp-vehicle-archive-summary-item span { + color: var(--vp-text-muted); + font-size: 12px; + line-height: 18px; +} + +.vp-vehicle-archive-summary-item em { + color: var(--vp-primary); + font-size: 12px; + font-style: normal; + font-weight: 700; + line-height: 18px; +} + .vp-vehicle-question-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); @@ -7424,6 +7507,8 @@ button.vp-realtime-command-item:focus-visible { .vp-vehicle-live-view .semi-card-body, .vp-vehicle-live-main, .vp-vehicle-live-facts, + .vp-vehicle-archive-summary-main, + .vp-vehicle-archive-summary-grid, .vp-vehicle-question-grid, .vp-unified-service-board, .vp-unified-service-grid, diff --git a/vehicle-data-platform/apps/web/src/test/App.test.tsx b/vehicle-data-platform/apps/web/src/test/App.test.tsx index 5666c905..bf34c7a5 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -11966,6 +11966,13 @@ test('copies vehicle service diagnostic summary', async () => { expect(screen.getByText('当前位置')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车实时视图 实时位置 查看实时' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车实时视图 数据导出 历史导出' })).toBeInTheDocument(); + expect(screen.getByText('客户车辆档案摘要')).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.getByText('客户常问')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车客户常问 这辆车现在在哪里? 实时监控' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '单车客户常问 最近是否还在线? 查看实时' })).toBeInTheDocument();