956270d14d
- 投资人 Sidebar: 5 扁平分组 → 6 业务域(今日/组合/工作/增长/洞察/报告) - 角色化导航: GP→组合优先, 投后负责人→今日优先, 投资经理→今日+组合 - 新增路由: /today /compare /threads /threads/[id] /workspace - Admin: 单页标签 → 6 管理域 Sidebar(租户/用户/审计/数据源/安全/设置) - 创始人: 3 底部导航 → 6 域(今日/经营/月报/Copilot/通知/我的) - 新增 navConfig.ts 统一管理导航配置
110 lines
3.7 KiB
TypeScript
110 lines
3.7 KiB
TypeScript
/** Admin 端布局 — 警示风格:slate-950 Header + amber 主色 + 6 管理域 Sidebar。 */
|
|
|
|
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import {
|
|
Building2, Users, ScrollText, Database, ShieldCheck, Settings,
|
|
} from "lucide-react";
|
|
|
|
/** Admin 6 管理域导航。 */
|
|
const adminNav = [
|
|
{
|
|
title: "租户管理",
|
|
items: [
|
|
{ href: "/admin", label: "系统概览", icon: Building2 },
|
|
{ href: "/admin/tenants", label: "租户列表", icon: Building2 },
|
|
],
|
|
},
|
|
{
|
|
title: "用户管理",
|
|
items: [
|
|
{ href: "/admin/users", label: "用户列表", icon: Users },
|
|
],
|
|
},
|
|
{
|
|
title: "审计日志",
|
|
items: [
|
|
{ href: "/admin/audit", label: "操作日志", icon: ScrollText },
|
|
],
|
|
},
|
|
{
|
|
title: "数据源",
|
|
items: [
|
|
{ href: "/admin/data-sources", label: "数据源管理", icon: Database },
|
|
],
|
|
},
|
|
{
|
|
title: "安全配置",
|
|
items: [
|
|
{ href: "/admin/security", label: "商业秘密保护", icon: ShieldCheck },
|
|
],
|
|
},
|
|
{
|
|
title: "系统设置",
|
|
items: [
|
|
{ href: "/admin/settings", label: "系统参数", icon: Settings },
|
|
],
|
|
},
|
|
];
|
|
|
|
/**
|
|
* Admin 端布局组件。
|
|
*
|
|
* 左侧 Sidebar 按 6 管理域分组,Header 使用 slate-950 + amber 警示色。
|
|
*/
|
|
export default function AdminLayout({ children }: { children: React.ReactNode }) {
|
|
const pathname = usePathname();
|
|
|
|
return (
|
|
<div className="flex min-h-screen bg-slate-100">
|
|
{/* 左侧 Sidebar */}
|
|
<aside className="sticky top-0 hidden h-screen w-52 shrink-0 bg-slate-950 text-white md:block">
|
|
<div className="flex h-14 items-center gap-2 px-4">
|
|
<span className="font-bold text-[var(--admin-primary)]">AIPortPilot</span>
|
|
<span className="inline-flex items-center rounded bg-[var(--admin-primary)]/20 px-1.5 py-0.5 text-xs font-medium text-[var(--admin-primary)]">
|
|
ADMIN
|
|
</span>
|
|
</div>
|
|
<nav className="flex flex-col gap-1 overflow-y-auto px-3 py-2" style={{ maxHeight: "calc(100vh - 3.5rem)" }}>
|
|
{adminNav.map((section) => (
|
|
<div key={section.title} className="mb-2">
|
|
<div className="px-3 py-1 text-xs font-medium text-white/40">{section.title}</div>
|
|
{section.items.map((item) => {
|
|
const isActive = pathname === item.href || pathname.startsWith(item.href + "/");
|
|
return (
|
|
<Link
|
|
key={item.href}
|
|
href={item.href}
|
|
className={`flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors ${
|
|
isActive
|
|
? "bg-[var(--admin-primary)]/20 text-[var(--admin-primary)]"
|
|
: "text-white/70 hover:bg-white/10 hover:text-white"
|
|
}`}
|
|
>
|
|
<item.icon size={16} aria-hidden="true" />
|
|
{item.label}
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
))}
|
|
</nav>
|
|
</aside>
|
|
|
|
{/* 内容区 */}
|
|
<main className="flex-1">
|
|
{/* 移动端顶部 Header */}
|
|
<header className="sticky top-0 z-10 flex h-14 items-center gap-2 bg-[var(--admin-header-bg)] px-4 md:hidden">
|
|
<span className="font-bold text-[var(--admin-primary)]">AIPortPilot</span>
|
|
<span className="inline-flex items-center rounded bg-[var(--admin-primary)]/20 px-1.5 py-0.5 text-xs font-medium text-[var(--admin-primary)]">
|
|
ADMIN
|
|
</span>
|
|
</header>
|
|
<div className="container mx-auto max-w-7xl px-4 py-6">{children}</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|