| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- 'use client';
- import { useState, useEffect } from 'react';
- import { usePathname, useRouter } from 'next/navigation';
- import Link from 'next/link';
- import {
- LayoutDashboard,
- ShoppingBag,
- LifeBuoy,
- Settings,
- LogOut,
- Activity,
- CreditCard,
- Users,
- ChevronLeft,
- ChevronRight,
- Plane,
- LucideIcon,
- CalendarClock,
- LayoutGrid
- } from 'lucide-react';
- interface MenuItem {
- name: string;
- href: string;
- icon: LucideIcon;
- }
- export default function AdminSidebar() {
- const pathname = usePathname();
- const router = useRouter();
-
- // 控制折叠状态
- const [isCollapsed, setIsCollapsed] = useState(false);
- const [mounted, setMounted] = useState(false); // 用于解决 Hydration 不匹配问题
- const menu: MenuItem[] = [
- { name: '概览', href: '/admin', icon: LayoutDashboard },
- { name: '用户管理', href: '/admin/users', icon: Users },
- { name: '工单处理', href: '/admin/tickets', icon: LifeBuoy },
- { name: '订单管理', href: '/admin/orders', icon: ShoppingBag },
- { name: '支付配置', href: '/admin/payments', icon: CreditCard },
- { name: '商品配置', href: '/admin/products', icon: Settings },
- { name: '系统任务', href: '/admin/tasks', icon: Activity },
- { name: 'TROOV Slot监控', href: '/admin/slots', icon: CalendarClock }, // 新增
- { name: '卡片管理', href: '/admin/cards', icon: LayoutGrid },
- ];
- // 初始化:从 localStorage 读取状态
- useEffect(() => {
- setMounted(true);
- const savedState = localStorage.getItem('sidebar_collapsed');
- if (savedState) {
- setIsCollapsed(JSON.parse(savedState));
- }
- }, []);
- // 切换并保存状态
- const toggleSidebar = () => {
- const newState = !isCollapsed;
- setIsCollapsed(newState);
- localStorage.setItem('sidebar_collapsed', JSON.stringify(newState));
- };
- const handleLogout = () => {
- if (confirm('确定要退出管理后台吗?')) {
- localStorage.removeItem('rsid');
- localStorage.removeItem('user_info');
- router.push('/login');
- }
- };
- // 防止服务端渲染和客户端渲染不一致导致的闪烁
- if (!mounted) return null;
- return (
- <aside
- className={`bg-slate-900 text-white flex-shrink-0 hidden md:flex flex-col h-screen sticky top-0 transition-all duration-300 ease-in-out
- ${isCollapsed ? 'w-20' : 'w-64'}
- `}
- >
- {/* Header / Logo Area */}
- <div className={`h-16 flex items-center border-b border-slate-800 transition-all duration-300 ${isCollapsed ? 'justify-center px-0' : 'px-6 gap-3'}`}>
- <Plane className="text-blue-500 flex-shrink-0" size={24} />
-
- {/* 文字部分:折叠时隐藏 */}
- <div className={`font-bold text-xl whitespace-nowrap overflow-hidden transition-all duration-300 ${isCollapsed ? 'w-0 opacity-0' : 'w-auto opacity-100'}`}>
- <span className="text-blue-400">Visafly</span> Admin
- </div>
- </div>
-
- {/* Navigation */}
- <nav className="flex-1 p-3 space-y-1 overflow-y-auto overflow-x-hidden">
- {menu.map((item) => {
- const Icon = item.icon;
- const isActive = pathname === item.href; // 精确匹配
- // 如果有子路由(比如 /admin/orders/new),可以使用 pathname.startsWith(item.href)
- return (
- <Link
- key={item.href}
- href={item.href}
- title={isCollapsed ? item.name : ''} // 折叠时显示 tooltip
- className={`flex items-center rounded-lg transition-all duration-200 group relative
- ${isCollapsed ? 'justify-center px-2 py-3' : 'px-4 py-3 gap-3'}
- ${isActive
- ? 'bg-blue-600 text-white shadow-lg shadow-blue-900/50'
- : 'text-slate-400 hover:bg-slate-800 hover:text-white'
- }
- `}
- >
- <Icon size={20} className={`flex-shrink-0 transition-transform duration-200 ${!isCollapsed && isActive ? 'scale-110' : ''}`} />
-
- {/* 菜单文字 */}
- <span className={`whitespace-nowrap overflow-hidden transition-all duration-300 ${isCollapsed ? 'w-0 opacity-0 hidden' : 'w-auto opacity-100 font-medium'}`}>
- {item.name}
- </span>
- {/* 折叠时的悬浮提示 (可选) */}
- {isCollapsed && (
- <div className="absolute left-full ml-2 px-2 py-1 bg-slate-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 pointer-events-none transition-opacity z-50 whitespace-nowrap">
- {item.name}
- </div>
- )}
- </Link>
- );
- })}
- </nav>
- {/* Footer Actions */}
- <div className="p-3 border-t border-slate-800 space-y-1">
-
- {/* 折叠切换按钮 */}
- <button
- onClick={toggleSidebar}
- className="flex items-center w-full rounded-lg text-slate-500 hover:bg-slate-800 hover:text-white transition-colors
- justify-center py-2
- "
- title={isCollapsed ? "展开侧边栏" : "折叠侧边栏"}
- >
- {isCollapsed ? <ChevronRight size={20} /> : <ChevronLeft size={20} />}
- </button>
- {/* 退出按钮 */}
- <button
- onClick={handleLogout}
- title={isCollapsed ? "退出登录" : ""}
- className={`flex items-center w-full rounded-lg text-slate-400 hover:text-red-400 hover:bg-slate-800 transition-colors
- ${isCollapsed ? 'justify-center py-3' : 'px-4 py-3 gap-3'}
- `}
- >
- <LogOut size={20} className="flex-shrink-0" />
- <span className={`whitespace-nowrap overflow-hidden transition-all duration-300 ${isCollapsed ? 'w-0 opacity-0 hidden' : 'w-auto opacity-100 font-medium'}`}>
- 退出登录
- </span>
- </button>
- </div>
- </aside>
- );
- }
|