feat(platform): make mobile workflows task focused
This commit is contained in:
@@ -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 (
|
||||
<div className="v2-shell">
|
||||
<Sidebar />
|
||||
{mobileLayout ? <MobileNavigation /> : <Sidebar />}
|
||||
<div className="v2-main">
|
||||
<header className="v2-topbar">
|
||||
<h1>{pageNames[section] ?? '车辆数据中台'}</h1>
|
||||
@@ -93,6 +102,32 @@ export function AppShell() {
|
||||
);
|
||||
}
|
||||
|
||||
const mobilePrimaryNavigation = [navigation[0], navigation[1], navigation[2], navigation[4]];
|
||||
const mobileMoreNavigation = [navigation[3], navigation[5], navigation[6], { to: '/operations', label: '运维质量', icon: IconSetting }];
|
||||
|
||||
function MobileNavigation() {
|
||||
const location = useLocation();
|
||||
const [moreOpen, setMoreOpen] = useState(false);
|
||||
const moreActive = mobileMoreNavigation.some((item) => location.pathname.startsWith(item.to));
|
||||
const warmRoute = (path: string) => { if (shouldPreloadRouteOnIntent()) void preloadRoute(path); };
|
||||
useEffect(() => setMoreOpen(false), [location.pathname]);
|
||||
useEffect(() => {
|
||||
if (!moreOpen) return;
|
||||
const closeOnEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') setMoreOpen(false); };
|
||||
window.addEventListener('keydown', closeOnEscape);
|
||||
return () => window.removeEventListener('keydown', closeOnEscape);
|
||||
}, [moreOpen]);
|
||||
|
||||
const link = ({ to, label, icon: Icon }: (typeof navigation)[number]) => <NavLink key={to} to={to} aria-label={label} onPointerDown={() => warmRoute(to)} className={({ isActive }) => `v2-mobile-nav-item ${isActive ? 'is-active' : ''}`}><Icon size="large" /><span>{label}</span></NavLink>;
|
||||
return <>
|
||||
{moreOpen ? <div className="v2-mobile-more-backdrop" role="presentation" onMouseDown={(event) => { if (event.target === event.currentTarget) setMoreOpen(false); }}><section className="v2-mobile-more-sheet" role="dialog" aria-modal="true" aria-label="更多功能"><header><div><strong>更多功能</strong><span>数据分析与系统管理</span></div><button type="button" aria-label="关闭更多功能" onClick={() => setMoreOpen(false)}>×</button></header><nav>{mobileMoreNavigation.map(link)}</nav></section></div> : null}
|
||||
<nav className="v2-mobile-navigation" aria-label="主导航">
|
||||
{mobilePrimaryNavigation.map(link)}
|
||||
<button type="button" className={`v2-mobile-nav-item${moreActive ? ' is-active' : ''}`} aria-label="更多功能" aria-expanded={moreOpen} onClick={() => setMoreOpen((value) => !value)}><IconMore size="large" /><span>更多</span></button>
|
||||
</nav>
|
||||
</>;
|
||||
}
|
||||
|
||||
function Sidebar() {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const warmRoute = (path: string) => { if (shouldPreloadRouteOnIntent()) void preloadRoute(path); };
|
||||
|
||||
Reference in New Issue
Block a user