"use client" import { useState, useEffect } from "react" import { usePathname } from "next/navigation" import * as LucideIcons from "lucide-react" import { cn } from "@/lib/utils" import { useTabContext } from "@/app/dashboard/layout" import { getMenus } from "@/lib/menu-api" // 适配后端返回的菜单项格式 interface MenuItem { id: number parentId?: number | null parent_id?: number // 后端返回的字段 name?: string title?: string // 后端返回的字段 path: string icon?: string order?: number sort?: number // 后端返回的字段 status?: number children?: MenuItem[] } export function Sidebar() { const pathname = usePathname() const [menus, setMenus] = useState([]) const [loading, setLoading] = useState(true) const [expandedMenus, setExpandedMenus] = useState>(new Set()) const [collapsed, setCollapsed] = useState(false) // 添加折叠状态 const { addTab } = useTabContext() // 字段适配:将后端返回的菜单数据格式转换为前端需要的格式 const adaptMenuItem = (item: MenuItem): MenuItem => { return { id: item.id, parentId: item.parent_id || null, name: item.title || item.name, path: item.path, icon: item.icon, order: item.sort || item.order || 0, children: item.children ? item.children.map(adaptMenuItem) : [] }; }; // 切换折叠状态 const toggleCollapsed = () => { setCollapsed(prev => !prev); }; // 获取菜单数据 useEffect(() => { const fetchMenus = async () => { setLoading(true) try { // 从后端API获取菜单数据 const menuData = await getMenus(true); // 适配数据格式 const adaptedMenus = menuData.map(adaptMenuItem); // 构建菜单树 const menuTree = buildMenuTree(adaptedMenus); setMenus(menuTree); // 初始自动展开当前活动菜单的父菜单 autoExpandActiveMenuParent(adaptedMenus); } catch (error) { console.error("获取菜单数据失败:", error); // 获取失败时使用空菜单 setMenus([]); } finally { setLoading(false); } }; fetchMenus(); }, []); // 仅在组件挂载时执行一次,移除pathname依赖 // 监听路径变化以更新菜单展开状态 useEffect(() => { if (menus.length > 0) { // 只在菜单数据存在且路径变化时更新展开状态 // 获取当前路径所需展开的所有父菜单ID const pathMenuItems = menus.reduce((allItems, item) => { const flattenMenu = (menuItem: MenuItem, items: MenuItem[] = []) => { items.push(menuItem); if (menuItem.children && menuItem.children.length > 0) { menuItem.children.forEach(child => flattenMenu(child, items)); } return items; }; return [...allItems, ...flattenMenu(item)]; }, [] as MenuItem[]); // 保存当前展开状态 setExpandedMenus(prev => { // 创建新集合,保留所有已展开的菜单 const newExpanded = new Set(prev); // 将需要展开的菜单添加到集合中 const currentPath = pathname === "/" ? "/dashboard" : pathname; // 查找当前路径对应的菜单项和所有父菜单 const findActiveMenuParents = (items: MenuItem[], parentIds: number[] = []): number[] => { for (const item of items) { // 如果是"#"路径的菜单,检查其子菜单 if (item.path === "#" && item.children && item.children.length > 0) { const found = findActiveMenuParents(item.children, [...parentIds, item.id]); if (found.length > 0) { return [...found, item.id]; } } // 检查菜单路径是否匹配当前路径 else if (currentPath === item.path || currentPath.startsWith(item.path + "/")) { return [...parentIds]; } // 递归检查子菜单 if (item.children && item.children.length > 0) { const found = findActiveMenuParents(item.children, [...parentIds, item.id]); if (found.length > 0) { return found; } } } return []; }; // 获取需要自动展开的菜单ID const parentsToExpand = findActiveMenuParents(menus); // 添加到展开集合中 parentsToExpand.forEach(id => newExpanded.add(id)); return newExpanded; }); } }, [pathname, menus]); // 构建菜单树结构 const buildMenuTree = (items: MenuItem[]) => { const map = new Map(); const roots: MenuItem[] = []; // 先创建所有菜单项的映射 items.forEach(item => { map.set(item.id, { ...item, children: item.children || [] }); }); // 构建树结构 items.forEach(item => { if (!item.parentId || item.parentId === 0) { // 根菜单 roots.push(map.get(item.id)!); } else { // 子菜单 const parent = map.get(item.parentId); if (parent && parent.children) { parent.children.push(map.get(item.id)!); } } }); // 排序 roots.sort((a, b) => (a.order || 0) - (b.order || 0)); roots.forEach(root => { if (root.children) { root.children.sort((a, b) => (a.order || 0) - (b.order || 0)); } }); return roots; }; // 自动展开当前活动菜单的父菜单 const autoExpandActiveMenuParent = (menuItems: MenuItem[]) => { const newExpandedMenus = new Set(); // 递归查找当前路径匹配的菜单项 const findActiveMenu = (items: MenuItem[], parentIds: number[] = []) => { for (const item of items) { // 如果是"#"路径的菜单,跳过路径检查 if (item.path === "#") { if (item.children && item.children.length > 0) { const found = findActiveMenu(item.children, [...parentIds, item.id]); if (found) { // 将所有父菜单ID添加到展开集合 parentIds.forEach(id => newExpandedMenus.add(id)); newExpandedMenus.add(item.id); // 确保当前菜单也被展开 return true; } } continue; } const currentPath = pathname === "/" ? "/dashboard" : pathname; if (currentPath === item.path || currentPath.startsWith(item.path + "/")) { // 将所有父菜单ID添加到展开集合 parentIds.forEach(id => newExpandedMenus.add(id)); return true; } if (item.children && item.children.length > 0) { const found = findActiveMenu(item.children, [...parentIds, item.id]); if (found) { return true; } } } return false; }; findActiveMenu(menuItems); // 将新的展开菜单集合设置到状态 setExpandedMenus(newExpandedMenus); }; // 切换菜单展开状态 const toggleMenu = (menuId: number, e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); setExpandedMenus(prev => { const newExpanded = new Set(prev); if (newExpanded.has(menuId)) { newExpanded.delete(menuId); } else { newExpanded.add(menuId); } return newExpanded; }); }; // 获取Lucide图标组件 const getLucideIcon = (iconName: string) => { if (!iconName) return null; const Icon = (LucideIcons as any)[iconName]; return Icon ? : null; }; // 渲染菜单项 const renderMenuItem = (item: MenuItem) => { // 修改子菜单项活动状态判断逻辑 const isMenuPathActive = (menuPath: string, currentPath: string) => { // 对于精确匹配的情况,直接返回true if (currentPath === menuPath) { return true; } // 特殊处理项目列表路径 if (menuPath === "/dashboard/projects" && currentPath !== "/dashboard/projects") { // 如果当前路径不是精确匹配项目列表,则项目列表不高亮 return false; } // 对于其他情况,保持原来的前缀匹配逻辑 // 但要确保父级路径后有斜杠再做前缀匹配 return currentPath.startsWith(menuPath + "/"); }; const currentPath = pathname === "/" ? "/dashboard" : pathname; const isActive = isMenuPathActive(item.path, currentPath); const hasChildren = item.children && item.children.length > 0; const isExpanded = expandedMenus.has(item.id); const name = item.name || item.title || ""; // 折叠状态下的菜单项 if (collapsed) { return (
  • { e.preventDefault(); e.stopPropagation(); if (!hasChildren) { const tabId = addTab({ label: name, path: item.path, closable: item.path !== "/dashboard" }); } }} > {getLucideIcon(item.icon || "")} {/* 悬浮提示 */} {hasChildren ? ( ) : (
    {name}
    )}
  • ); } // 展开状态下的菜单项 return (
  • {hasChildren ? ( <> {isExpanded && ( )} ) : ( { e.preventDefault(); e.stopPropagation(); // 使用addTab返回的标签ID,在TabContext中处理,确保标签被激活并导航 const tabId = addTab({ label: name, path: item.path, closable: item.path !== "/dashboard" // 仪表盘不可关闭 }); }} className={cn( "flex items-center py-2 px-3 rounded-md transition-colors", isActive ? "text-white font-medium" : "text-blue-100 hover:bg-blue-700/30" )} > {getLucideIcon(item.icon || "")} {name} )}
  • ); }; return (
    {!collapsed &&

    超级管理员

    }
    ); }