From 843690cc7185cc1f218e3b21d89b644cd326b132 Mon Sep 17 00:00:00 2001 From: lingniu Date: Mon, 20 Jul 2026 05:26:08 +0800 Subject: [PATCH] feat(web): unify vehicle source navigation --- .../web/src/v2/pages/VehiclePage.test.tsx | 18 +++++++++------- .../apps/web/src/v2/pages/VehiclePage.tsx | 11 +++++----- .../src/v2/pages/VehicleSearchWorkspace.tsx | 5 +++-- .../web/src/v2/shared/MobileFilterToggle.tsx | 6 ++++-- .../v2/shared/VehicleSourceEvidencePanel.tsx | 10 +++++++-- .../apps/web/src/v2/styles/workspace.css | 21 +++++++++++++++++++ 6 files changed, 52 insertions(+), 19 deletions(-) diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx index 66682ad4..0ad2aed0 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.test.tsx @@ -100,6 +100,8 @@ test('polls lightweight single-vehicle realtime data and passes its report inter expect(screen.getByRole('heading', { name: '实时遥测', level: 5 })).toBeInTheDocument(); expect(screen.getByRole('heading', { name: '车辆主档', level: 5 })).toBeInTheDocument(); expect(screen.getByRole('navigation', { name: '单车详情导航' })).toBeInTheDocument(); + expect(view.container.querySelector('.v2-vehicle-record-page > .v2-source-evidence')).not.toBeInTheDocument(); + expect(screen.getByRole('button', { name: '来源证据' })).toBeInTheDocument(); const telemetryPanel = view.container.querySelector('#vehicle-telemetry-panel')!; const scrollIntoView = vi.fn(); Object.defineProperty(telemetryPanel, 'scrollIntoView', { configurable: true, value: scrollIntoView }); @@ -116,7 +118,7 @@ test('polls lightweight single-vehicle realtime data and passes its report inter expect(totalMileageSource).toHaveClass('semi-button', 'v2-workspace-metric-action'); expect(totalMileageSource.closest('.semi-card')).toHaveClass('v2-vehicle-live-metric-rail'); expect(totalMileageSource.closest('.v2-live-overview')).toBe(commandCard); - fireEvent.click(locationSource); + fireEvent.click(screen.getByRole('button', { name: '来源证据' })); await waitFor(() => expect(sourceEvidence).toHaveBeenCalledTimes(1)); }); @@ -278,7 +280,7 @@ test('keeps the mobile vehicle directory primary and applies search from a Semi expect(view.container.querySelector('.v2-vehicle-directory-table')).not.toBeInTheDocument(); expect(view.container.querySelector('.v2-vehicle-query-panel')).not.toBeInTheDocument(); expect(screen.queryByLabelText('查车操作')).not.toBeInTheDocument(); - const toggle = screen.getByRole('button', { name: '修改车辆范围:10 辆授权车辆' }); + const toggle = screen.getByRole('button', { name: '打开车辆搜索:10 辆授权车辆' }); expect(toggle).toHaveAttribute('aria-expanded', 'false'); fireEvent.click(toggle); const input = screen.getByRole('textbox', { name: '搜索车辆' }); @@ -291,20 +293,20 @@ test('keeps the mobile vehicle directory primary and applies search from a Semi expect(screen.getByRole('list', { name: '车辆搜索摘要' })).toHaveTextContent(`当前条件${items[0].plate}车牌 / VIN / 终端`); expect(screen.getAllByRole('button', { name: /打开 .* 车辆档案/ })).toHaveLength(8); fireEvent.click(screen.getByRole('button', { name: '应用搜索' })); - await waitFor(() => expect(screen.getByRole('button', { name: `修改车辆范围:${items[0].plate} · 10 辆匹配` })).toHaveAttribute('aria-expanded', 'false')); + await waitFor(() => expect(screen.getByRole('button', { name: `打开车辆搜索:${items[0].plate} · 10 辆匹配` })).toHaveAttribute('aria-expanded', 'false')); expect(screen.getByRole('heading', { name: '匹配车辆', level: 5 })).toBeInTheDocument(); - fireEvent.click(screen.getByRole('button', { name: `修改车辆范围:${items[0].plate} · 10 辆匹配` })); + fireEvent.click(screen.getByRole('button', { name: `打开车辆搜索:${items[0].plate} · 10 辆匹配` })); fireEvent.change(screen.getByRole('textbox', { name: '搜索车辆' }), { target: { value: items[1].plate } }); fireEvent.click(screen.getByRole('button', { name: '关闭车辆搜索' })); - await waitFor(() => expect(screen.getByRole('button', { name: `修改车辆范围:${items[0].plate} · 10 辆匹配` })).toBeInTheDocument()); + await waitFor(() => expect(screen.getByRole('button', { name: `打开车辆搜索:${items[0].plate} · 10 辆匹配` })).toBeInTheDocument()); - fireEvent.click(screen.getByRole('button', { name: `修改车辆范围:${items[0].plate} · 10 辆匹配` })); + fireEvent.click(screen.getByRole('button', { name: `打开车辆搜索:${items[0].plate} · 10 辆匹配` })); fireEvent.click(screen.getByRole('button', { name: '重置范围' })); expect(screen.getByRole('dialog', { name: '车辆搜索' })).toBeInTheDocument(); - expect(screen.getByRole('button', { name: `关闭车辆范围:${items[0].plate} · 10 辆匹配` })).toHaveAttribute('aria-expanded', 'true'); + expect(screen.getByRole('button', { name: `关闭车辆搜索:${items[0].plate} · 10 辆匹配` })).toHaveAttribute('aria-expanded', 'true'); fireEvent.click(screen.getByRole('button', { name: '应用搜索' })); - await waitFor(() => expect(screen.getByRole('button', { name: '修改车辆范围:10 辆授权车辆' })).toBeInTheDocument()); + await waitFor(() => expect(screen.getByRole('button', { name: '打开车辆搜索:10 辆授权车辆' })).toBeInTheDocument()); expect(screen.getByRole('heading', { name: '授权车辆', level: 5 })).toBeInTheDocument(); }); diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx index f8b08134..f32661ec 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx @@ -21,7 +21,7 @@ import { MonitorReturnBar } from '../shared/MonitorReturnBar'; import { PlatformTime } from '../shared/PlatformTime'; import { ProtocolTag } from '../shared/ProtocolTag'; import { SegmentedTabs } from '../shared/SegmentedTabs'; -import { VehicleSourceEvidencePanel } from '../shared/VehicleSourceEvidencePanel'; +import { VehicleSourceEvidenceButton, VehicleSourceEvidencePanel } from '../shared/VehicleSourceEvidencePanel'; import { WorkspaceCommandBar } from '../shared/WorkspaceCommandBar'; import { WorkspaceMetricRail, type WorkspaceQueueMetricRailItem } from '../shared/WorkspaceMetricRail'; import { WorkspacePanelHeader } from '../shared/WorkspacePanelHeader'; @@ -425,7 +425,7 @@ const vehicleSectionIDs = { type VehicleSection = keyof typeof vehicleSectionIDs; -function VehicleRecordNavigation() { +function VehicleRecordNavigation({ onOpenSources }: { onOpenSources: () => void }) { const jumpToSection = (section: VehicleSection) => { const target = document.getElementById(vehicleSectionIDs[section]); if (!target) return; @@ -442,8 +442,9 @@ function VehicleRecordNavigation() { + {navigationItems.map(([key, label, icon]) => )} } /> @@ -587,8 +588,8 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele - - + + setSourceEvidenceOpen(true)} />
diff --git a/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx b/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx index 02ba91e5..c7ca6e99 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehicleSearchWorkspace.tsx @@ -193,12 +193,13 @@ export default function VehicleSearchWorkspace() { /> : null} {mobileLayout ?
diff --git a/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx b/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx index 6e5b8954..4271abb3 100644 --- a/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx +++ b/vehicle-data-platform/apps/web/src/v2/shared/VehicleSourceEvidencePanel.tsx @@ -79,14 +79,20 @@ function MileageSourceCard({ source }: { source: VehicleMileageSourceEvidence }) ; } +export function VehicleSourceEvidenceButton({ onClick }: { onClick: () => void }) { + return ; +} + export function VehicleSourceEvidencePanel({ vin, compact = false, + hideTrigger = false, open, onOpenChange }: { vin: string; compact?: boolean; + hideTrigger?: boolean; open?: boolean; onOpenChange?: (open: boolean) => void; }) { @@ -133,12 +139,12 @@ export function VehicleSourceEvidencePanel({
; return <> - + {!hideTrigger ?
位置与里程来源{description}
-
+
: null} .semi-button:first-child { + min-width: 82px; + min-height: 34px; + border-radius: 8px; + padding-inline: 9px; + font-size: 9px; + font-weight: 700; +} + .v2-vehicle-recent-card > .semi-card-body > .v2-vehicle-directory-pagination { background: #fbfcfe; box-shadow: 0 -8px 22px rgba(43, 62, 86, .025); @@ -25701,6 +25710,18 @@ .v2-vehicle-directory-v3 .v2-vehicle-recent-item-shell.is-offline { box-shadow: inset 2px 0 #c9d2de; } + + .v2-vehicle-record-v3.is-mobile-layout .v2-vehicle-section-nav { + grid-template-columns: repeat(5, minmax(0, 1fr)); + } + + .v2-vehicle-record-v3.is-mobile-layout .v2-vehicle-section-nav > .semi-button:first-child { + width: 100%; + min-width: 0; + min-height: 36px; + padding-inline: 2px; + font-size: 8px; + } } /*