diff --git a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx index 35e67aea..ed3386f8 100644 --- a/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Dashboard.tsx @@ -1673,6 +1673,40 @@ export function Dashboard({ onClick: () => onOpenVehicles({}) } ]; + const customerSavedViewItems = [ + { + label: '在线车队视图', + value: `${formatCount(serviceSummary?.onlineVehicles ?? summary?.onlineVehicles)} 在线`, + detail: '默认进入车辆地图,按在线车辆、最新位置和定位有效性巡检。', + action: '打开地图', + color: 'green' as const, + onClick: () => onOpenMap({ online: 'online' }) + }, + { + label: '轨迹日报模板', + value: `${formatCount(summary?.activeToday)} 活跃`, + detail: '按当前时间窗复用轨迹回放和历史位置查询,处理每日客户问询。', + action: '历史导出', + color: 'blue' as const, + onClick: openTimeMonitorHistory + }, + { + label: '里程周报模板', + value: `${formatCount(serviceSummary?.totalVehicles)} 车辆`, + detail: '按车辆口径复用里程统计,支撑周报、对账和 BI 复核。', + action: '统计查询', + color: 'blue' as const, + onClick: openTimeMonitorMileage + }, + { + label: '告警订阅视图', + value: `${formatCount(summary?.issueVehicles)} 告警`, + detail: '围绕断链、离线、定位异常和字段缺失形成通知闭环。', + action: '通知闭环', + color: (summary?.issueVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, + onClick: () => onOpenQuality(highPriorityIssue?.issueType ? { issueType: highPriorityIssue.issueType } : {}) + } + ]; const amapVehicleServiceItems = [ { label: '实时看车', @@ -2392,6 +2426,36 @@ export function Dashboard({ ))} +
+
+ + 客户常用视图库 + 一个车辆服务入口 + + + 一个车辆服务入口,而不是三个数据源入口。 + + + 把车队范围、时间窗、地图态势、轨迹回放、统计查询、导出模板和告警订阅保存成客户可复用的车辆服务入口。 + +
+
+ {customerSavedViewItems.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 7e1fc503..92888f0a 100644 --- a/vehicle-data-platform/apps/web/src/styles/global.css +++ b/vehicle-data-platform/apps/web/src/styles/global.css @@ -1999,6 +1999,88 @@ body { line-height: 18px; } +.vp-customer-saved-view-library { + margin-bottom: 16px; + padding: 14px; + border: 1px solid rgba(37, 119, 246, 0.16); + border-radius: 8px; + background: #ffffff; + display: grid; + grid-template-columns: minmax(300px, 0.46fr) minmax(0, 1.54fr); + gap: 14px; + align-items: stretch; +} + +.vp-customer-saved-view-library-copy { + padding: 16px; + border: 1px solid rgba(37, 119, 246, 0.12); + border-radius: 8px; + background: #f7fbff; + display: grid; + gap: 10px; + align-content: center; +} + +.vp-customer-saved-view-library-copy .semi-typography { + line-height: 25px; +} + +.vp-customer-saved-view-library-grid { + min-width: 0; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 10px; +} + +.vp-customer-saved-view-library-item { + min-width: 0; + min-height: 132px; + padding: 12px; + border: 1px solid rgba(37, 119, 246, 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-saved-view-library-item:hover, +.vp-customer-saved-view-library-item:focus-visible { + border-color: rgba(37, 119, 246, 0.42); + background: #f5f9ff; + box-shadow: 0 0 0 3px rgba(37, 119, 246, 0.08); + outline: none; +} + +.vp-customer-saved-view-library-item strong { + color: var(--vp-text); + font-size: 18px; + line-height: 24px; + font-weight: 800; + word-break: break-word; +} + +.vp-customer-saved-view-library-item span { + color: var(--vp-text-muted); + font-size: 12px; + line-height: 18px; + word-break: break-word; +} + +.vp-customer-saved-view-library-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; @@ -12279,6 +12361,8 @@ button.vp-realtime-command-item:focus-visible { .vp-vehicle-service-cockpit-grid, .vp-customer-platform-blueprint, .vp-customer-platform-blueprint-grid, + .vp-customer-saved-view-library, + .vp-customer-saved-view-library-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 aa254b92..f5452729 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -1362,6 +1362,13 @@ test('dashboard exposes vehicle data center capability matrix', async () => { 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.getByRole('region', { name: '客户常用视图库' })).toBeInTheDocument(); + expect(screen.getByText('一个车辆服务入口,而不是三个数据源入口。')).toBeInTheDocument(); + expect(screen.getByText('把车队范围、时间窗、地图态势、轨迹回放、统计查询、导出模板和告警订阅保存成客户可复用的车辆服务入口。')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户常用视图库 在线车队视图 208 在线 打开地图' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户常用视图库 轨迹日报模板 4 活跃 历史导出' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户常用视图库 里程周报模板 1,033 车辆 统计查询' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '客户常用视图库 告警订阅视图 7 告警 通知闭环' })).toBeInTheDocument(); expect(screen.getByText('现代车队运营台')).toBeInTheDocument(); expect(screen.getByText('一屏完成车辆地图、轨迹回放、里程统计、数据导出和告警闭环。')).toBeInTheDocument(); expect(screen.getByRole('button', { name: '现代车队运营台 Live Map 208 在线 打开地图' })).toBeInTheDocument();