diff --git a/vehicle-data-platform/apps/web/src/v2/hooks/useMobileLayout.ts b/vehicle-data-platform/apps/web/src/v2/hooks/useMobileLayout.ts
new file mode 100644
index 00000000..562dce0d
--- /dev/null
+++ b/vehicle-data-platform/apps/web/src/v2/hooks/useMobileLayout.ts
@@ -0,0 +1,15 @@
+import { useEffect, useState } from 'react';
+
+export function useMobileLayout(maxWidth = 680) {
+ const query = `(max-width: ${maxWidth}px)`;
+ const [mobile, setMobile] = useState(() => typeof window !== 'undefined' && typeof window.matchMedia === 'function' && window.matchMedia(query).matches);
+ useEffect(() => {
+ if (typeof window.matchMedia !== 'function') return;
+ const media = window.matchMedia(query);
+ const update = () => setMobile(media.matches);
+ media.addEventListener('change', update);
+ update();
+ return () => media.removeEventListener('change', update);
+ }, [query]);
+ return mobile;
+}
diff --git a/vehicle-data-platform/apps/web/src/v2/layout/AppShell.tsx b/vehicle-data-platform/apps/web/src/v2/layout/AppShell.tsx
index 6f55cae5..c3f91e48 100644
--- a/vehicle-data-platform/apps/web/src/v2/layout/AppShell.tsx
+++ b/vehicle-data-platform/apps/web/src/v2/layout/AppShell.tsx
@@ -6,6 +6,7 @@ import {
IconHelpCircle,
IconHome,
IconMapPin,
+ IconMore,
IconSearch,
IconSetting,
IconUser,
@@ -71,12 +72,20 @@ export function AppShell() {
const activeRoutePath = `/${section}`;
const { session, logout } = usePlatformSession();
const [helpOpen, setHelpOpen] = useState(false);
+ const [mobileLayout, setMobileLayout] = useState(() => typeof window !== 'undefined' && window.matchMedia('(max-width: 680px)').matches);
const roleLabel = { viewer: '只读', operator: '处置员', admin: '管理员' }[session.role];
useEffect(() => scheduleIdleRoutePreloads({ activePathname: activeRoutePath }), [activeRoutePath]);
+ useEffect(() => {
+ const media = window.matchMedia('(max-width: 680px)');
+ const update = () => setMobileLayout(media.matches);
+ media.addEventListener('change', update);
+ update();
+ return () => media.removeEventListener('change', update);
+ }, []);
return (