四端上传
This commit is contained in:
1 parent
25bbb5f9c8
commit
c6e2cb4d5b
276 files changed
+17812
-3
No files matched your search
@@ -0,0 +1,81 @@
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { usePathname, useRouter } from 'next/navigation';
|
||||
import { clearToken, isLoggedIn } from '@/lib/auth';
|
||||
import { RESOURCE_CONFIGS } from '@/lib/resources';
|
||||
|
||||
const FIXED_NAV = [
|
||||
{ href: '/', label: '数据看板' },
|
||||
{ href: '/users', label: '用户' },
|
||||
{ href: '/orders', label: '订单' },
|
||||
{ href: '/settings', label: '系统配置' },
|
||||
];
|
||||
|
||||
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
||||
const router = useRouter();
|
||||
const pathname = usePathname();
|
||||
const [ready, setReady] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoggedIn()) {
|
||||
router.replace('/login');
|
||||
return;
|
||||
}
|
||||
setReady(true);
|
||||
}, [router]);
|
||||
|
||||
if (!ready) {
|
||||
return <div className="flex min-h-screen items-center justify-center text-sm text-gray-400">加载中…</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen">
|
||||
<aside className="w-56 shrink-0 border-r border-gray-200 bg-white">
|
||||
<div className="border-b border-gray-200 px-4 py-4">
|
||||
<div className="text-sm font-semibold text-gray-900">叶雷讲数学</div>
|
||||
<div className="text-xs text-gray-400">管理后台</div>
|
||||
</div>
|
||||
<nav className="p-2">
|
||||
{FIXED_NAV.map((item) => (
|
||||
<NavItem key={item.href} href={item.href} label={item.label} active={pathname === item.href} />
|
||||
))}
|
||||
|
||||
<div className="px-3 pt-4 pb-1 text-xs text-gray-400">内容管理</div>
|
||||
{RESOURCE_CONFIGS.map((r) => (
|
||||
<NavItem key={r.key} href={`/${r.key}`} label={r.title} active={pathname === `/${r.key}`} />
|
||||
))}
|
||||
</nav>
|
||||
|
||||
<div className="border-t border-gray-200 p-2">
|
||||
<button
|
||||
onClick={() => {
|
||||
clearToken();
|
||||
router.replace('/login');
|
||||
}}
|
||||
className="w-full rounded-md px-3 py-2 text-left text-sm text-gray-600 hover:bg-gray-100"
|
||||
>
|
||||
退出登录
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<main className="flex-1 p-6">{children}</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NavItem({ href, label, active }: { href: string; label: string; active: boolean }) {
|
||||
return (
|
||||
<Link
|
||||
href={href}
|
||||
className={`block rounded-md px-3 py-2 text-sm transition ${
|
||||
active ? 'bg-blue-50 font-medium text-blue-700' : 'text-gray-600 hover:bg-gray-100'
|
||||
}`}
|
||||
>
|
||||
{label}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user