AdminLayout.tsx 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import {
  2. BookOpen,
  3. LayoutDashboard,
  4. LogOut,
  5. ShieldCheck,
  6. Users
  7. } from 'lucide-react'
  8. import { NavLink, Navigate, Outlet, useNavigate } from 'react-router-dom'
  9. import { Brand } from '../../components/Brand'
  10. import { Footer } from '../../components/Footer'
  11. import { useAuth } from '../../AuthContext'
  12. export function AdminLayout() {
  13. const { user, loading, logout } = useAuth()
  14. const navigate = useNavigate()
  15. if (loading) return <div className="center-loading">正在加载管理后台…</div>
  16. // 未登录或非管理员,统一拦截跳转至管理员专属登录页 /admin/login
  17. if (!user || user.role !== 'ADMIN') {
  18. return <Navigate to="/admin/login" replace />
  19. }
  20. const handleAdminLogout = async () => {
  21. await logout()
  22. navigate('/admin/login', { replace: true })
  23. }
  24. return (
  25. <div className="admin-shell">
  26. <header className="admin-topbar">
  27. <div className="admin-brand-wrap">
  28. <NavLink to="/admin" className="logo-link">
  29. <Brand />
  30. </NavLink>
  31. <div className="admin-badge">
  32. <ShieldCheck size={14} />
  33. <span>管理后台</span>
  34. </div>
  35. </div>
  36. <nav className="admin-nav">
  37. <NavLink to="/admin" end className={({ isActive }) => (isActive ? 'active' : '')}>
  38. <LayoutDashboard size={16} />
  39. <span>概览看板</span>
  40. </NavLink>
  41. <NavLink to="/admin/courses" className={({ isActive }) => (isActive ? 'active' : '')}>
  42. <BookOpen size={16} />
  43. <span>课程制作</span>
  44. </NavLink>
  45. <NavLink to="/admin/users" className={({ isActive }) => (isActive ? 'active' : '')}>
  46. <Users size={16} />
  47. <span>用户管理</span>
  48. </NavLink>
  49. </nav>
  50. <div className="admin-top-actions">
  51. <div className="admin-user-info">
  52. <strong>{user.contactName || '系统管理员'}</strong>
  53. <small>{user.phone}</small>
  54. </div>
  55. <button className="icon-button" title="退出管理员登录" onClick={handleAdminLogout}>
  56. <LogOut size={18} />
  57. </button>
  58. </div>
  59. </header>
  60. <main className="admin-main">
  61. <Outlet />
  62. </main>
  63. <Footer />
  64. </div>
  65. )
  66. }