From 13ef1779ac30aafd864e7e38f8c1cc0045ad722c Mon Sep 17 00:00:00 2001 From: lingniu Date: Sun, 5 Jul 2026 02:10:10 +0800 Subject: [PATCH] feat(platform): add vehicle monitoring command center --- .../apps/web/src/pages/Dashboard.tsx | 75 +++++++++++++++++++ .../apps/web/src/styles/global.css | 36 +++++++++ .../apps/web/src/test/App.test.tsx | 9 +++ 3 files changed, 120 insertions(+) diff --git a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx index 85d61e9b..7f11fe06 100644 --- a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx @@ -1044,6 +1044,48 @@ export function Dashboard({ downloadCsv('dashboard-snapshot.csv', buildCsv(dashboardSnapshotColumns, rows)); Toast.success(`已导出 ${rows.length.toLocaleString()} 条驾驶舱摘要`); }; + const commandCenterItems = [ + { + title: '全域车辆监控', + value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, + detail: `有效定位 ${commandLocatedCount.toLocaleString()} 辆,先从地图确认车辆分布、在线状态和最新位置。`, + color: 'green' as const, + primaryAction: '打开车辆地图', + secondaryAction: '在线车辆', + onPrimary: () => onOpenMap({ online: 'online' }), + onSecondary: () => onOpenVehicles({ online: 'online' }) + }, + { + title: '异常车辆闭环', + value: `${formatCount(summary?.issueVehicles)} 告警`, + detail: highPriorityIssue ? `最高优先级:${qualityIssueLabel(highPriorityIssue.issueType)} / ${priorityIssueVehicleLabel(highPriorityIssue)}` : '当前没有高优先级告警,保持实时巡检。', + color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, + primaryAction: '告警事件', + secondaryAction: '通知规则', + onPrimary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}), + onSecondary: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) + }, + { + title: '自定义时间复盘', + value: taskTimeMonitorSummary, + detail: '一个时间窗贯穿轨迹回放、里程统计、历史查询和告警复盘,适合客户问询与 BI 核对。', + color: 'blue' as const, + primaryAction: '轨迹复盘', + secondaryAction: '里程统计', + onPrimary: () => openTimeMonitorHistory(), + onSecondary: () => openTimeMonitorMileage() + }, + { + title: '数据交付与导出', + value: `${formatCount(summary?.frameToday)} 今日数据`, + detail: '按车辆、时间、字段裁剪导出位置、原始记录和字段证据,交付给业务或客户复盘。', + color: 'blue' as const, + primaryAction: '历史导出', + secondaryAction: '导出概览', + onPrimary: () => openTimeMonitorRaw(), + onSecondary: () => exportDashboardSnapshot() + } + ]; return (
@@ -1086,6 +1128,39 @@ export function Dashboard({
+ +
+ {commandCenterItems.map((item) => ( +
+
+ {item.title} + {item.value} +
+ {item.detail} + + + + +
+ ))} +
+
{customerHeroActions.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 7729acce..1181c4fd 100644 --- a/vehicle-data-platform/apps/web/src/styles/global.css +++ b/vehicle-data-platform/apps/web/src/styles/global.css @@ -410,6 +410,41 @@ body { line-height: 26px; } +.vp-command-center-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 12px; +} + +.vp-command-center-item { + min-height: 166px; + padding: 16px; + border: 1px solid var(--vp-border); + border-radius: 8px; + background: #ffffff; + display: grid; + align-content: space-between; + gap: 12px; +} + +.vp-command-center-head { + min-width: 0; + display: grid; + gap: 8px; +} + +.vp-command-center-head strong { + color: var(--vp-text); + font-size: 20px; + line-height: 26px; + word-break: break-word; +} + +.vp-command-center-item .semi-typography { + font-size: 13px; + line-height: 20px; +} + .vp-customer-task-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); @@ -3176,6 +3211,7 @@ button.vp-realtime-command-item:focus-visible { .vp-map-ops-readiness, .vp-map-ops-work, .vp-time-monitor-grid, + .vp-command-center-grid, .vp-customer-task-grid, .vp-current-service-board, .vp-current-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 b1d47e73..b730f0c6 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -788,6 +788,15 @@ test('dashboard exposes vehicle data center capability matrix', async () => { await renderDashboard(); 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(); + expect(screen.getByRole('button', { name: '车辆监控指挥台 数据交付与导出 历史导出' })).toBeInTheDocument(); expect(screen.getByText('客户常用工作流')).toBeInTheDocument(); expect(screen.getByText('实时车辆地图')).toBeInTheDocument(); expect(screen.getByText('历史数据导出')).toBeInTheDocument();