diff --git a/apps/web/src/layouts/MainLayout.tsx b/apps/web/src/layouts/MainLayout.tsx index 8a6374c..972b5d8 100644 --- a/apps/web/src/layouts/MainLayout.tsx +++ b/apps/web/src/layouts/MainLayout.tsx @@ -132,6 +132,73 @@ const SidebarMenuItem = memo(function SidebarMenuItem({ ); }); +// 可折叠子分组(3 级菜单) +const CollapsibleSubGroup = memo(function CollapsibleSubGroup({ + directory, + collapsed, + currentPath, + onNavigate, +}: { + directory: MenuInfo; + collapsed: boolean; + currentPath: string; + onNavigate: (key: string) => void; +}) { + const [expanded, setExpanded] = useState(false); + const visibleChildren = directory.children?.filter((c) => c.visible !== false) || []; + const hasActive = visibleChildren.some((c) => currentPath === (c.path || c.id)); + + useEffect(() => { + if (hasActive) setExpanded(true); + }, [hasActive]); + + if (collapsed) { + return ( + +
{ + const first = visibleChildren[0]; + if (first) onNavigate(first.path || first.id); + }} + className={`erp-sidebar-item ${hasActive ? 'erp-sidebar-item-active' : ''}`} + > + {getIcon(directory.icon)} +
+
+ ); + } + + return ( +
+
setExpanded((e) => !e)} + > + + + + {directory.title} +
+ {expanded && visibleChildren.map((child) => ( + onNavigate(child.path || child.id)} + indented + /> + ))} +
+ ); +}); + // 插件子菜单组 const SidebarSubMenu = memo(function SidebarSubMenu({ group, @@ -195,7 +262,12 @@ const SidebarSubMenu = memo(function SidebarSubMenu({ ); }); -// 动态菜单渲染 +// 判断是否为可点击的叶子菜单类型 +function isLeafType(menuType: string): boolean { + return menuType === 'menu' || menuType === 'page'; +} + +// 动态菜单渲染(支持多级嵌套) const DynamicMenuSection = memo(function DynamicMenuSection({ menus, collapsed, @@ -211,30 +283,45 @@ const DynamicMenuSection = memo(function DynamicMenuSection({ <> {menus.map((menu) => { if (menu.menu_type === 'directory') { + const visibleChildren = menu.children?.filter((c) => c.visible !== false) || []; return (
{!collapsed &&
{menu.title}
}
- {menu.children - ?.filter((child) => child.visible !== false) - .map((child) => ( - onNavigate(child.path || child.id)} - /> - ))} + {visibleChildren.map((child) => { + if (child.menu_type === 'directory') { + return ( + + ); + } + if (isLeafType(child.menu_type)) { + return ( + onNavigate(child.path || child.id)} + /> + ); + } + return null; + })}
); } - if (menu.menu_type === 'menu' && menu.visible !== false) { + if (isLeafType(menu.menu_type) && menu.visible !== false) { return (