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 c8285c09..bfc87bdf 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 @@ -404,7 +404,7 @@ test('keeps protocol telemetry independent and explains mileage semantics', asyn test('uses compact Semi telemetry evidence cards on mobile', async () => { layout.mobile = true; - vi.spyOn(api, 'vehicleDetail').mockResolvedValue(detail); + vi.spyOn(api, 'vehicleDetail').mockResolvedValue({ ...detail, sources: ['GB32960', 'JT808', 'YUTONG_MQTT'] }); vi.spyOn(api, 'vehicleRealtime').mockResolvedValue({ items: [initialRealtime], total: 1, limit: 1, offset: 0 }); vi.spyOn(api, 'latestTelemetry').mockResolvedValue({ vin: initialRealtime.vin, @@ -424,5 +424,10 @@ test('uses compact Semi telemetry evidence cards on mobile', async () => { expect(document.querySelector('.v2-telemetry-table')).not.toBeInTheDocument(); expect(document.querySelector('.v2-telemetry-mobile-list.semi-list')).toBeInTheDocument(); expect(document.querySelector('.v2-telemetry-mobile-item.semi-list-item')).toHaveTextContent('36km/h正常'); + expect(document.querySelector('.v2-vehicle-record-page')).toHaveClass('is-mobile-layout'); + expect(screen.getByRole('group', { name: '车辆快捷操作' }).querySelectorAll('.semi-button')).toHaveLength(5); + expect(screen.getByRole('group', { name: '车辆快捷操作' })).toHaveTextContent('切换车辆轨迹回放历史数据里程查询告警事件'); + expect(document.querySelectorAll('.v2-identity-sources .semi-tag')).toHaveLength(3); expect(document.querySelector('.v2-vehicle-command-card .v2-live-grid')).toHaveAttribute('aria-label', '车辆实时指标'); + expect(document.querySelectorAll('.v2-vehicle-command-card .v2-live-grid > [role="listitem"]')).toHaveLength(6); }); 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 57375304..2b48a69f 100644 --- a/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx +++ b/vehicle-data-platform/apps/web/src/v2/pages/VehiclePage.tsx @@ -393,6 +393,7 @@ function VehicleRecordNavigation() { function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, telemetryError, monitorReturn, onUpdated }: { detail: VehicleDetail; liveRealtime?: VehicleRealtimeRow; telemetry?: LatestTelemetryResponse; telemetryPending: boolean; telemetryError?: string; monitorReturn: string; onUpdated: () => void }) { const { session } = usePlatformSession(); const navigate = useNavigate(); + const mobileLayout = useMobileLayout(); const [sourceEvidenceOpen, setSourceEvidenceOpen] = useState(false); const realtime = liveRealtime ?? detail.realtimeSummary; const identity = detail.identity; @@ -405,7 +406,7 @@ function VehicleRecord({ detail, liveRealtime, telemetry, telemetryPending, tele ...(hasMenu(session, 'statistics') ? [{ key: 'statistics', label: '里程查询', icon: , to: withMonitorReturn(`/statistics?vins=${encodeURIComponent(detail.vin)}`, monitorReturn), type: 'tertiary' as const }] : []), ...(hasMenu(session, 'alerts') ? [{ key: 'alerts', label: '告警事件', icon: , to: `/alerts?vin=${encodeURIComponent(detail.vin)}`, type: 'tertiary' as const }] : []) ]; - return
+ return
diff --git a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css index d0dd1d5b..63785735 100644 --- a/vehicle-data-platform/apps/web/src/v2/styles/workspace.css +++ b/vehicle-data-platform/apps/web/src/v2/styles/workspace.css @@ -5830,18 +5830,21 @@ } .v2-vehicle-command-header .v2-identity-meta { - grid-template-columns: minmax(0, 1.15fr) minmax(120px, .85fr); + grid-template-columns: minmax(0, 1fr); border-top: 1px solid #e7edf4; border-left: 0; - padding: 8px 0; + padding: 0; } .v2-vehicle-command-header .v2-identity-meta > div { - padding-inline: 12px; + padding: 9px 12px; } .v2-vehicle-command-header .v2-identity-meta > div + div { - padding-inline: 12px; + margin: 0; + border-top: 1px solid #edf1f6; + border-left: 0; + padding: 8px 12px 9px; } .v2-vehicle-command-header .v2-identity-meta strong { @@ -5850,10 +5853,9 @@ } .v2-vehicle-command-header .v2-identity-sources { - flex-wrap: nowrap; - overflow-x: auto; + flex-wrap: wrap; + overflow: visible; margin-top: 5px; - scrollbar-width: none; } .v2-vehicle-command-header .v2-identity-meta .semi-tag { @@ -5861,23 +5863,39 @@ } .v2-vehicle-command-header .v2-identity-actions { - display: flex; - grid-template-columns: none; - gap: 6px; - padding: 6px 10px; - scrollbar-width: none; - } - - .v2-vehicle-command-header .v2-identity-actions::-webkit-scrollbar, - .v2-vehicle-command-header .v2-identity-sources::-webkit-scrollbar { - display: none; + display: grid; + grid-template-columns: repeat(auto-fit, minmax(56px, 1fr)); + gap: 4px; + overflow: visible; + padding: 6px 8px; } .v2-vehicle-command-header .v2-identity-actions > .semi-button { - width: auto; - min-width: 112px; - min-height: 38px; - flex: 0 0 auto; + width: 100%; + min-width: 0; + min-height: 52px; + padding: 4px 2px; + } + + .v2-vehicle-command-header .v2-identity-actions > .semi-button .semi-button-content { + min-width: 0; + flex-direction: column; + justify-content: center; + gap: 3px; + } + + .v2-vehicle-command-header .v2-identity-actions > .semi-button .semi-button-content-left { + margin-right: 0; + font-size: 15px; + } + + .v2-vehicle-command-header .v2-identity-actions > .semi-button .semi-button-content-right { + max-width: 100%; + overflow: hidden; + margin-left: 0; + font-size: 9px; + text-overflow: ellipsis; + white-space: nowrap; } .v2-vehicle-live-section > .v2-workspace-panel-header { @@ -5894,17 +5912,36 @@ font-size: 9px; } + .v2-vehicle-command-card .v2-live-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + overflow: visible; + scroll-snap-type: none; + } + .v2-vehicle-command-card .v2-live-grid > div { - min-width: 134px; - min-height: 88px; - flex-basis: 134px; + min-width: 0; + min-height: 82px; + flex: none; padding: 11px 12px 10px; } + .v2-vehicle-command-card .v2-live-grid > div:nth-child(3n + 1) { + border-left: 0; + } + + .v2-vehicle-command-card .v2-live-grid > div:nth-child(n + 4) { + border-top: 1px solid #e7edf4; + } + .v2-vehicle-command-card .v2-live-grid strong, .v2-vehicle-command-card .v2-live-source-link { margin-top: 7px; - font-size: 19px; + font-size: 17px; + } + + .v2-vehicle-command-card .v2-live-grid strong.is-text { + font-size: 13px; } .v2-vehicle-command-card .v2-current-location { @@ -5932,7 +5969,7 @@ } .v2-vehicle-section-nav > .semi-button { - min-height: 32px; + min-height: 44px; } .v2-vehicle-record-page .v2-record-grid {