From fbd99824275c797170dc7522a27c9d83b0b01af7 Mon Sep 17 00:00:00 2001 From: lingniu Date: Sun, 5 Jul 2026 23:41:32 +0800 Subject: [PATCH] feat(platform): add vehicle pool quick views --- .../apps/web/src/pages/Vehicles.tsx | 69 +++++++++++++++ .../apps/web/src/styles/global.css | 88 +++++++++++++++++++ .../apps/web/src/test/App.test.tsx | 7 ++ 3 files changed, 164 insertions(+) diff --git a/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx b/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx index b44cfa2d..7979b700 100644 --- a/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx +++ b/vehicle-data-platform/apps/web/src/pages/Vehicles.tsx @@ -782,6 +782,49 @@ export function Vehicles({ onClick: copyCustomerServicePackage } ]; + const offlineVehicleCount = Math.max((summary?.totalVehicles ?? pagination.total) - (summary?.onlineVehicles ?? 0), 0); + const vehiclePoolQuickViews = [ + { + title: '在线运营', + value: `${(summary?.onlineVehicles ?? 0).toLocaleString()} 在线`, + detail: '进入地图查看在线车辆分布、最近位置和运营范围。', + action: '打开地图', + color: (summary?.onlineVehicles ?? 0) > 0 ? 'green' as const : 'orange' as const, + onClick: () => onOpenMap?.({ ...serviceScopeFilters, online: 'online' }) + }, + { + title: '离线断链', + value: `${offlineVehicleCount.toLocaleString()} 离线`, + detail: '筛出离线车辆,结合最后上报时间判断断链影响。', + action: '排查离线', + color: offlineVehicleCount > 0 ? 'orange' as const : 'green' as const, + onClick: () => applyFilters({ ...filters, online: 'offline' }) + }, + { + title: '无来源车辆', + value: `${(summary?.noDataVehicles ?? 0).toLocaleString()} 无来源`, + detail: '优先确认平台转发、订阅和车辆身份是否可归并。', + action: '平台转发', + color: (summary?.noDataVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, + onClick: () => applyFilters({ ...filters, serviceStatus: 'no_data' }) + }, + { + title: '身份维护', + value: `${(summary?.unboundVehicles ?? 0).toLocaleString()} 未绑定`, + detail: '补齐车牌、手机号与 VIN 关系,保证客户能按车辆查数据。', + action: '维护绑定', + color: (summary?.unboundVehicles ?? 0) > 0 ? 'orange' as const : 'green' as const, + onClick: () => applyFilters({ ...filters, bindingStatus: 'unbound' }) + }, + { + title: '报表交付', + value: `${rows.length.toLocaleString()} 当前页`, + detail: '导出当前车辆池清单,作为客户报表和后续轨迹统计入口。', + action: '导出清单', + color: rows.length > 0 ? 'blue' as const : 'grey' as const, + onClick: exportVehicles + } + ]; const vehicleDecisionItems = [ { title: '在线车辆', @@ -1270,6 +1313,32 @@ export function Vehicles({ ))} +
+
+ + 车辆池快捷视图 + {filters.keyword?.trim() ? '单车范围' : '车辆池'} + + 按客户服务场景一键切换车辆池:在线运营、离线断链、无来源、身份维护和报表交付。 + 业务人员先按问题选择车辆池,再进入地图、实时、轨迹、统计或导出;协议来源继续沉到证据层。 +
+
+ {vehiclePoolQuickViews.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 27f317bb..10dd905f 100644 --- a/vehicle-data-platform/apps/web/src/styles/global.css +++ b/vehicle-data-platform/apps/web/src/styles/global.css @@ -4877,6 +4877,92 @@ button.vp-realtime-command-item:focus-visible { line-height: 20px; } +.vp-vehicle-pool-quick-views { + margin-bottom: 16px; + border: 1px solid rgba(255, 136, 0, 0.18); + border-radius: var(--vp-radius); + background: #ffffff; + display: grid; + grid-template-columns: minmax(280px, 0.55fr) minmax(0, 1.45fr); + overflow: hidden; +} + +.vp-vehicle-pool-quick-copy { + padding: 18px; + border-right: 1px solid var(--vp-border); + background: #fffaf3; + display: grid; + gap: 12px; + align-content: center; +} + +.vp-vehicle-pool-quick-copy strong { + color: var(--vp-text); + font-size: 20px; + font-weight: 700; + line-height: 28px; + word-break: break-word; +} + +.vp-vehicle-pool-quick-copy span { + color: var(--vp-text-muted); + font-size: 13px; + line-height: 20px; +} + +.vp-vehicle-pool-quick-grid { + padding: 14px; + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 10px; +} + +.vp-vehicle-pool-quick-item { + min-height: 142px; + padding: 12px; + border: 1px solid var(--vp-border); + border-radius: var(--vp-radius); + background: #fffefd; + 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-vehicle-pool-quick-item:hover, +.vp-vehicle-pool-quick-item:focus-visible { + border-color: rgba(255, 136, 0, 0.42); + background: #fffaf3; + box-shadow: 0 0 0 3px rgba(255, 136, 0, 0.08); + outline: none; +} + +.vp-vehicle-pool-quick-item strong { + color: var(--vp-text); + font-size: 20px; + font-weight: 700; + line-height: 26px; + word-break: break-word; +} + +.vp-vehicle-pool-quick-item span { + color: var(--vp-text-muted); + font-size: 12px; + line-height: 18px; +} + +.vp-vehicle-pool-quick-item em { + color: var(--vp-primary); + font-size: 13px; + font-style: normal; + font-weight: 700; + line-height: 20px; +} + .vp-vehicle-lookup-strip { display: grid; gap: 14px; @@ -11828,6 +11914,8 @@ button.vp-realtime-command-item:focus-visible { .vp-alert-closure-steps, .vp-vehicle-asset-console, .vp-vehicle-asset-console-grid, + .vp-vehicle-pool-quick-views, + .vp-vehicle-pool-quick-grid, .vp-vehicle-service-desk, .vp-vehicle-service-grid, .vp-vehicle-lookup-head, 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 71d85565..08374dc6 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -2682,6 +2682,13 @@ test('shows vehicle service result summary on vehicle list filters', async () => expect(screen.getByRole('button', { name: '车辆资产运营台 在线车辆 73 在线 打开实时' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆资产运营台 待处理 13 待处理 异常优先' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '车辆资产运营台 服务交付 2 当前页 复制交付包' })).toBeInTheDocument(); + expect(screen.getByText('车辆池快捷视图')).toBeInTheDocument(); + expect(screen.getByText('按客户服务场景一键切换车辆池:在线运营、离线断链、无来源、身份维护和报表交付。')).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆池快捷视图 在线运营 73 在线 打开地图' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆池快捷视图 离线断链 108 离线 排查离线' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆池快捷视图 无来源车辆 4 无来源 平台转发' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆池快捷视图 身份维护 9 未绑定 维护绑定' })).toBeInTheDocument(); + expect(screen.getByRole('button', { name: '车辆池快捷视图 报表交付 2 当前页 导出清单' })).toBeInTheDocument(); expect(screen.getByText('车辆服务台')).toBeInTheDocument(); expect(screen.getByText('客户视角')).toBeInTheDocument(); expect(screen.getByText('客户查车路径')).toBeInTheDocument();