diff --git a/vehicle-data-platform/apps/web/src/pages/Realtime.tsx b/vehicle-data-platform/apps/web/src/pages/Realtime.tsx index 7677eeed..781019cd 100644 --- a/vehicle-data-platform/apps/web/src/pages/Realtime.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Realtime.tsx @@ -1018,6 +1018,60 @@ export function Realtime({ selectedProtocol: selectedVehicleProtocol, amapConfigured }), '地图客户决策说明'); + const realtimeCustomerJourneyItems = [ + { + step: '01', + title: '只看在线', + value: `${onlineCount.toLocaleString()} 在线`, + detail: '先确认客户当前能看到哪些车辆仍在上报。', + action: '在线车辆', + color: onlineCount > 0 ? 'green' as const : 'orange' as const, + onClick: () => applyFilters({ ...filters, online: 'online' }), + disabled: false + }, + { + step: '02', + title: '地图态势', + value: `${locatedCount.toLocaleString()} 有定位`, + detail: '在地图上确认车辆位置、定位有效性和分布情况。', + action: '查看地图', + color: locatedCount > 0 ? 'blue' as const : 'orange' as const, + onClick: () => { + window.location.hash = buildAppHash({ page: 'map', protocol: filters.protocol, filters }); + }, + disabled: false + }, + { + step: '03', + title: '异常优先', + value: `${Math.max(degradedCount, sourceIssueRows.length).toLocaleString()} 关注`, + detail: '优先处理离线、更新超时、坐标无效或服务降级车辆。', + action: '关注车辆', + color: degradedCount > 0 || sourceIssueRows.length > 0 ? 'orange' as const : 'green' as const, + onClick: () => applyFilters({ ...filters, serviceStatus: 'degraded' }), + disabled: false + }, + { + step: '04', + title: '单车复盘', + value: selectedMapRow?.plate || selectedMapRow?.vin || '未选车', + detail: selectedMapRow ? '围绕选中车辆回放轨迹、核对里程和告警。' : '先在地图或表格中选择一辆可查询车辆。', + action: '轨迹回放', + color: selectedMapRow ? 'blue' as const : 'grey' as const, + onClick: () => selectedMapRow && onOpenHistory?.(selectedMapRow.vin, selectedVehicleProtocol), + disabled: !selectedMapRow || !canOpenVehicle(selectedMapRow.vin) + }, + { + step: '05', + title: '数据交付', + value: `${rows.length.toLocaleString()} 当前页`, + detail: '导出当前实时车辆清单,用于客户问询和运营交接。', + action: '导出 CSV', + color: rows.length > 0 ? 'blue' as const : 'grey' as const, + onClick: exportRealtime, + disabled: rows.length === 0 + } + ]; if (mode === 'map') { return ( @@ -1303,6 +1357,43 @@ export function Realtime({ return (