From 79207d50962d757b39aa44035cd955d9a7cb036a Mon Sep 17 00:00:00 2001 From: lingniu Date: Mon, 6 Jul 2026 00:12:09 +0800 Subject: [PATCH] feat(platform): add customer service blueprint --- .../apps/web/src/pages/Dashboard.tsx | 73 +++++++++++++++++ .../apps/web/src/styles/global.css | 82 +++++++++++++++++++ .../apps/web/src/test/App.test.tsx | 8 ++ 3 files changed, 163 insertions(+) diff --git a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx index c150de64..35e67aea 100644 --- a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx @@ -1631,6 +1631,48 @@ export function Dashboard({ onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) } ]; + const customerPlatformBlueprintItems = [ + { + label: '实时地图', + value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, + detail: `有效定位 ${commandLocatedCount.toLocaleString()} 辆,支撑客户看车、调度和在线巡检。`, + action: '打开地图', + color: commandLocatedCount > 0 ? 'green' as const : 'orange' as const, + onClick: () => onOpenMap({ online: 'online' }) + }, + { + label: '轨迹回放', + value: `${formatCount(summary?.activeToday)} 活跃`, + detail: '按车辆和时间窗回放路线、速度、停留与里程断点。', + action: '回放轨迹', + color: 'blue' as const, + onClick: openTimeMonitorHistory + }, + { + label: '围栏告警', + value: `${formatCount(summary?.issueVehicles)} 告警`, + detail: highPriorityIssue ? `${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '断链、定位异常、围栏事件进入告警通知闭环。', + action: '告警通知', + color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, + onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) + }, + { + label: '报表导出', + value: `${formatCount(summary?.frameToday)} 今日数据`, + detail: '按车辆、时间、字段裁剪轨迹、历史明细、统计和告警说明。', + action: '历史导出', + color: 'blue' as const, + onClick: openTimeMonitorRaw + }, + { + label: '车辆健康', + value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, + detail: '围绕车辆档案、在线状态、能耗字段和异常维护建立服务视图。', + action: '车辆中心', + color: 'blue' as const, + onClick: () => onOpenVehicles({}) + } + ]; const amapVehicleServiceItems = [ { label: '实时看车', @@ -2319,6 +2361,37 @@ export function Dashboard({ ))} +
+
+ + 客户车辆服务中台蓝图 + {amapConfigured ? '高德地图可用' : '坐标预览'} + 0 ? 'orange' : 'green'}>{formatCount(summary?.issueVehicles)} 告警 + + + 参考主流车联网平台的信息架构,把 Live Map、Route Replay、Geofence Alerts、Reports Export 和 Vehicle Health 收敛成客户可直接使用的车辆服务。 + + + 三个接入来源继续作为证据层,客户首页只围绕车辆监控、时间窗复盘、告警通知和报表交付组织路径。 + +
+
+ {customerPlatformBlueprintItems.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 307bb12c..d7b281ad 100644 --- a/vehicle-data-platform/apps/web/src/styles/global.css +++ b/vehicle-data-platform/apps/web/src/styles/global.css @@ -1811,6 +1811,86 @@ body { line-height: 24px; } +.vp-customer-platform-blueprint { + margin-bottom: 16px; + padding: 14px; + border: 1px solid rgba(22, 100, 255, 0.18); + border-radius: 8px; + background: #ffffff; + display: grid; + grid-template-columns: minmax(320px, 0.5fr) minmax(0, 1.5fr); + gap: 14px; + align-items: stretch; +} + +.vp-customer-platform-blueprint-copy { + padding: 16px; + border: 1px solid rgba(22, 100, 255, 0.12); + border-radius: 8px; + background: #f6f9ff; + display: grid; + gap: 10px; + align-content: center; +} + +.vp-customer-platform-blueprint-copy .semi-typography { + line-height: 25px; +} + +.vp-customer-platform-blueprint-grid { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 10px; +} + +.vp-customer-platform-blueprint-item { + min-height: 138px; + padding: 12px; + border: 1px solid rgba(22, 100, 255, 0.14); + border-radius: 8px; + background: #fbfcff; + color: inherit; + cursor: pointer; + font: inherit; + text-align: left; + display: grid; + gap: 8px; + align-content: start; + transition: border-color 0.16s ease, box-shadow 0.16s ease, background 0.16s ease; +} + +.vp-customer-platform-blueprint-item:hover, +.vp-customer-platform-blueprint-item:focus-visible { + border-color: rgba(22, 100, 255, 0.42); + background: #f5f9ff; + box-shadow: 0 0 0 3px rgba(22, 100, 255, 0.08); + outline: none; +} + +.vp-customer-platform-blueprint-item strong { + color: var(--vp-text); + font-size: 18px; + line-height: 24px; + font-weight: 800; + word-break: break-word; +} + +.vp-customer-platform-blueprint-item span { + color: var(--vp-text-muted); + font-size: 12px; + line-height: 18px; + word-break: break-word; +} + +.vp-customer-platform-blueprint-item em { + align-self: end; + color: var(--vp-primary); + font-size: 12px; + font-style: normal; + font-weight: 800; + line-height: 18px; +} + .vp-customer-service-journey { margin-bottom: 16px; padding: 14px; @@ -12089,6 +12169,8 @@ button.vp-realtime-command-item:focus-visible { .vp-customer-delivery-workbench-grid, .vp-vehicle-service-cockpit, .vp-vehicle-service-cockpit-grid, + .vp-customer-platform-blueprint, + .vp-customer-platform-blueprint-grid, .vp-customer-service-separation, .vp-customer-primary-flow-grid, .vp-source-readiness-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 f07faad7..ded8fa4b 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -879,6 +879,7 @@ test('dashboard presents a customer dispatch operations home', async () => { test('dashboard frames history query and export as a customer delivery workbench', async () => { window.history.replaceState(null, '', '/#/dashboard'); + vi.setSystemTime(new Date('2026-07-05T12:00:00+08:00')); vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => { const path = String(input); if (path.includes('/api/ops/health')) { @@ -1350,6 +1351,13 @@ test('dashboard exposes vehicle data center capability matrix', async () => { await renderDashboard(); expect(screen.getByText('车辆服务工作台')).toBeInTheDocument(); + expect(screen.getByText('客户车辆服务中台蓝图')).toBeInTheDocument(); + expect(screen.getByText('参考主流车联网平台的信息架构,把 Live Map、Route Replay、Geofence Alerts、Reports Export 和 Vehicle Health 收敛成客户可直接使用的车辆服务。')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务中台蓝图 实时地图 208 在线 打开地图' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务中台蓝图 轨迹回放 4 活跃 回放轨迹' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务中台蓝图 围栏告警 7 告警 告警通知' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务中台蓝图 报表导出 1,286,320 今日数据 历史导出' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户车辆服务中台蓝图 车辆健康 1,033 车辆 车辆中心' })).toBeInTheDocument(); expect(screen.getByText('现代车队运营台')).toBeInTheDocument(); expect(screen.getByText('一屏完成车辆地图、轨迹回放、里程统计、数据导出和告警闭环。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '现代车队运营台 Live Map 208 在线 打开地图' })).toBeInTheDocument();