From 6da5f772670cf3dcdceac677090814b9424555c3 Mon Sep 17 00:00:00 2001 From: lingniu Date: Mon, 6 Jul 2026 01:06:59 +0800 Subject: [PATCH] feat(platform): add mobile vehicle service dock --- .../apps/web/src/layout/AppShell.tsx | 12 +++ .../apps/web/src/styles/global.css | 77 +++++++++++++++++++ .../apps/web/src/test/App.test.tsx | 20 +++++ 3 files changed, 109 insertions(+) diff --git a/vehicle-data-platform/apps/web/src/layout/AppShell.tsx b/vehicle-data-platform/apps/web/src/layout/AppShell.tsx index 0bd97ef2..b47b9930 100644 --- a/vehicle-data-platform/apps/web/src/layout/AppShell.tsx +++ b/vehicle-data-platform/apps/web/src/layout/AppShell.tsx @@ -346,6 +346,18 @@ export function AppShell({ /> +
diff --git a/vehicle-data-platform/apps/web/src/styles/global.css b/vehicle-data-platform/apps/web/src/styles/global.css index 6b9ce4b2..33afb693 100644 --- a/vehicle-data-platform/apps/web/src/styles/global.css +++ b/vehicle-data-platform/apps/web/src/styles/global.css @@ -389,6 +389,10 @@ body { flex-wrap: wrap; } +.vp-mobile-service-dock { + display: none; +} + .vp-topbar-time-window { display: inline-flex; align-items: center; @@ -12528,9 +12532,82 @@ button.vp-realtime-command-item:focus-visible { .vp-topbar { position: relative; grid-template-columns: minmax(0, 1fr); + gap: 8px; padding: 12px; } + .vp-mobile-service-dock { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 6px; + padding: 8px; + border: 1px solid rgba(22, 100, 255, 0.16); + border-radius: 8px; + background: #ffffff; + box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06); + } + + .vp-mobile-service-dock button { + min-width: 0; + min-height: 34px; + border: 1px solid rgba(22, 100, 255, 0.14); + border-radius: 7px; + background: #f8fafc; + color: var(--vp-text); + font-size: 12px; + font-weight: 700; + line-height: 1; + cursor: pointer; + } + + .vp-mobile-service-dock button:focus-visible, + .vp-mobile-service-dock button:hover { + border-color: rgba(22, 100, 255, 0.42); + background: rgba(22, 100, 255, 0.08); + color: var(--vp-primary); + outline: none; + } + + .vp-topbar-context { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 8px; + overflow: visible; + } + + .vp-service-delivery-strip, + .vp-topbar-quick-actions { + display: none; + } + + .vp-topbar-time-window { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 6px; + } + + .vp-topbar-time-window-copy { + width: auto; + } + + .vp-topbar-time-window-copy span { + max-width: none; + } + + .vp-topbar-time-window-presets, + .vp-topbar-time-window label { + flex-wrap: wrap; + } + + .vp-topbar-time-window label { + height: auto; + min-height: 28px; + } + + .vp-topbar-time-window input { + width: min(100%, 132px); + } + .vp-evidence-grid, .vp-action-grid, .vp-fleet-monitor .semi-card-body, 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 2ed2a49c..a08af8a2 100644 --- a/vehicle-data-platform/apps/web/src/test/App.test.tsx +++ b/vehicle-data-platform/apps/web/src/test/App.test.tsx @@ -96,6 +96,26 @@ test('topbar frames customer work as a vehicle service delivery strip', () => { expect(screen.getByRole('button', { name: '车辆服务交付条 告警' })).toBeInTheDocument(); }); +test('topbar exposes a mobile vehicle service shortcut dock', () => { + vi.spyOn(globalThis, 'fetch').mockImplementation(async () => ({ + ok: true, + json: async () => ({ + data: { items: [], total: 0, limit: 20, offset: 0, linkHealth: [], runtime: { requestTimeoutMs: 5000 } }, + traceId: 'trace-test', + timestamp: 1783094400000 + }) + }) as Response); + + render(); + + expect(screen.getByRole('navigation', { 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(); +}); + test('exposes AMap operations shortcuts when map key is configured', async () => { window.__LINGNIU_APP_CONFIG__ = { amapWebJsKey: 'amap-web-key' }; vi.spyOn(globalThis, 'fetch').mockImplementation(async (input) => {