Files
PolyWeather/frontend/components/ops/layout/AdminSidebar.tsx
2026-05-31 03:21:58 +08:00

108 lines
3.5 KiB
TypeScript

"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import {
LayoutDashboard,
Cpu,
Database,
CreditCard,
Users,
UserCheck,
BarChart3,
Settings,
FileText,
ScrollText,
Activity,
ShieldAlert,
} from "lucide-react";
const navGroups = [
{
label: "监控",
items: [
{ href: "/ops/overview", icon: LayoutDashboard, label: "总览" },
{ href: "/ops/health", icon: Activity, label: "API 状态" },
{ href: "/ops/system", icon: Cpu, label: "系统状态" },
{ href: "/ops/training", icon: Database, label: "训练数据" },
{ href: "/ops/analytics", icon: BarChart3, label: "转化分析" },
],
},
{
label: "运营",
items: [
{ href: "/ops/payments", icon: CreditCard, label: "支付管理" },
{ href: "/ops/memberships", icon: UserCheck, label: "会员订阅" },
{ href: "/ops/telegram-audit", icon: ShieldAlert, label: "电报清理" },
{ href: "/ops/users", icon: Users, label: "用户积分" },
],
},
{
label: "管理",
items: [
{ href: "/ops/config", icon: Settings, label: "系统配置" },
{ href: "/ops/subscriptions", icon: ScrollText, label: "订阅操作" },
{ href: "/ops/view-logs", icon: FileText, label: "日志查看" },
],
},
{
label: "历史",
items: [
{ href: "/ops/truth-history", icon: Activity, label: "真值历史" },
],
},
];
export function AdminSidebar() {
const pathname = usePathname();
return (
<aside className="fixed left-0 top-0 z-40 flex h-screen w-56 flex-col border-r border-slate-200 bg-white shadow-[1px_0_2px_rgba(15,23,42,0.04)]">
<div className="flex h-14 items-center gap-2 border-b border-slate-200 px-4">
<LayoutDashboard className="h-5 w-5 text-blue-600" />
<Link href="/ops/system" className="text-sm font-extrabold text-slate-950">
PolyWeather Ops
</Link>
</div>
<nav className="flex-1 space-y-6 overflow-y-auto py-4">
{navGroups.map((group) => (
<div key={group.label} className="px-3">
<h4 className="mb-2 px-2 text-[11px] font-bold uppercase tracking-wider text-slate-500">
{group.label}
</h4>
<ul className="space-y-0.5">
{group.items.map((item) => {
const isActive = pathname === item.href || pathname.startsWith(item.href + "/");
return (
<li key={item.href}>
<Link
href={item.href}
className={
"flex items-center gap-2.5 rounded-md border border-transparent px-2 py-2 text-sm transition-colors " +
(isActive
? "border-blue-200 bg-blue-50 text-blue-700 font-semibold shadow-[inset_3px_0_0_#2563eb]"
: "text-slate-600 hover:border-slate-200 hover:bg-slate-50 hover:text-slate-950")
}
>
<item.icon className="h-4 w-4 shrink-0" />
<span>{item.label}</span>
</Link>
</li>
);
})}
</ul>
</div>
))}
</nav>
<div className="border-t border-slate-200 px-4 py-3">
<Link
href="/"
className="flex items-center gap-2 text-xs font-semibold text-slate-500 transition-colors hover:text-blue-700"
>
返回前台
</Link>
</div>
</aside>
);
}