From e48ea7d22ad90ae2f20c0b4d1c8336d3aff8e5c8 Mon Sep 17 00:00:00 2001 From: lingniu Date: Sun, 5 Jul 2026 19:03:12 +0800 Subject: [PATCH] feat(platform): add customer task dispatch --- .../apps/web/src/layout/AppShell.tsx | 28 ++++++++ .../apps/web/src/styles/global.css | 68 +++++++++++++++++++ .../apps/web/src/test/App.test.tsx | 7 ++ 3 files changed, 103 insertions(+) diff --git a/vehicle-data-platform/apps/web/src/layout/AppShell.tsx b/vehicle-data-platform/apps/web/src/layout/AppShell.tsx index 179f9ca2..be92ceb2 100644 --- a/vehicle-data-platform/apps/web/src/layout/AppShell.tsx +++ b/vehicle-data-platform/apps/web/src/layout/AppShell.tsx @@ -75,6 +75,14 @@ const customerPrimaryPath = [ { label: '告警通知', page: 'alert-events' as const } ]; +const customerTaskPath = [ + { label: '地图看车', question: '车辆在哪里', page: 'map' as const }, + { label: '轨迹回放', question: '这段时间怎么跑', page: 'history' as const }, + { label: '统计查询', question: '里程怎么算', page: 'mileage' as const }, + { label: '数据导出', question: '证据怎么给客户', page: 'history-query' as const }, + { label: '告警通知', question: '异常谁处理', page: 'alert-events' as const } +]; + function linkHealthClassName(count: number | null) { if (count == null) { return ''; @@ -193,6 +201,26 @@ export function AppShell({ ))} +
+
+ 客户任务分发台 + 输入 VIN / 车牌 / 手机号后,地图、轨迹、统计、导出和告警都围绕同一辆车服务。 +
+
+ {customerTaskPath.map((item) => ( + + ))} +
+
{navGroups.map((group) => ( diff --git a/vehicle-data-platform/apps/web/src/styles/global.css b/vehicle-data-platform/apps/web/src/styles/global.css index 993dc348..7d356fcd 100644 --- a/vehicle-data-platform/apps/web/src/styles/global.css +++ b/vehicle-data-platform/apps/web/src/styles/global.css @@ -126,6 +126,74 @@ body { outline: none; } +.vp-customer-task-dispatch { + padding-top: 10px; + border-top: 1px solid rgba(22, 100, 255, 0.12); + display: grid; + gap: 8px; +} + +.vp-customer-task-dispatch-head { + display: grid; + gap: 3px; +} + +.vp-customer-task-dispatch-head strong { + color: var(--vp-text); + font-size: 13px; + line-height: 18px; +} + +.vp-customer-task-dispatch-head span { + color: var(--vp-text-muted); + font-size: 11px; + line-height: 16px; +} + +.vp-customer-task-dispatch-actions { + display: grid; + gap: 6px; +} + +.vp-customer-task-dispatch-action { + min-height: 42px; + padding: 7px 8px; + border: 1px solid var(--vp-border); + border-radius: 7px; + background: #fff; + color: var(--vp-text); + cursor: pointer; + font: inherit; + text-align: left; + display: grid; + gap: 1px; +} + +.vp-customer-task-dispatch-action strong { + font-size: 12px; + line-height: 17px; +} + +.vp-customer-task-dispatch-action span { + color: var(--vp-text-muted); + font-size: 11px; + line-height: 15px; +} + +.vp-customer-task-dispatch-action:hover, +.vp-customer-task-dispatch-action:focus-visible, +.vp-customer-task-dispatch-action-active { + border-color: rgba(22, 100, 255, 0.38); + background: #ffffff; + outline: none; +} + +.vp-customer-task-dispatch-action-active strong, +.vp-customer-task-dispatch-action:hover strong, +.vp-customer-task-dispatch-action:focus-visible strong { + color: var(--vp-primary); +} + .vp-nav-groups { display: grid; gap: 12px; 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 c5caf8af..812c2a1f 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -24,6 +24,13 @@ test('renders vehicle platform shell', () => { expect(screen.getByText('实时地图 / 轨迹统计 / 告警通知')).toBeInTheDocument(); expect(screen.getByText('客户主线')).toBeInTheDocument(); expect(screen.getByText('先看车,再查时间窗,最后导出和通知。')).toBeInTheDocument(); + expect(screen.getByText('客户任务分发台')).toBeInTheDocument(); + expect(screen.getByText('输入 VIN / 车牌 / 手机号后,地图、轨迹、统计、导出和告警都围绕同一辆车服务。')).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.getByRole('button', { name: '客户任务 告警通知 异常谁处理' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主线 车辆地图' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主线 轨迹回放' })).toBeInTheDocument(); expect(screen.getByRole('button', { name: '客户主线 统计查询' })).toBeInTheDocument();