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 {