feat(frontend): P0 导航架构重构 — 6 业务域 + 角色化排序 + 新路由

- 投资人 Sidebar: 5 扁平分组 → 6 业务域(今日/组合/工作/增长/洞察/报告)
- 角色化导航: GP→组合优先, 投后负责人→今日优先, 投资经理→今日+组合
- 新增路由: /today /compare /threads /threads/[id] /workspace
- Admin: 单页标签 → 6 管理域 Sidebar(租户/用户/审计/数据源/安全/设置)
- 创始人: 3 底部导航 → 6 域(今日/经营/月报/Copilot/通知/我的)
- 新增 navConfig.ts 统一管理导航配置
This commit is contained in:
selfrelease
2026-07-19 18:51:38 +08:00
parent 947642919b
commit 956270d14d
9 changed files with 575 additions and 82 deletions
@@ -0,0 +1,48 @@
/** 多企业对比工作区 — 2-5 家企业并排对比。 */
import { GitCompareArrows } from "lucide-react";
/** 多企业对比页面。 */
export default function ComparePage() {
return (
<div className="space-y-6">
<div className="flex items-center gap-2">
<GitCompareArrows className="text-[var(--investor-primary)]" size={24} />
<h1 className="text-2xl font-bold"></h1>
</div>
<div className="rounded-lg border bg-white p-4 shadow-sm">
<p className="text-sm text-muted-foreground">
2-5
</p>
</div>
{/* 对比卡片占位 */}
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
{["智链科技", "云栈数据", "深瞳智能"].map((name) => (
<div key={name} className="rounded-lg border bg-white p-4 shadow-sm">
<h3 className="mb-3 font-medium">{name}</h3>
<div className="space-y-2 text-sm">
<div className="flex justify-between">
<span className="text-muted-foreground"></span>
<span className="font-medium">78.5</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground"></span>
<span className="font-medium">800</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground">Runway</span>
<span className="font-medium">12</span>
</div>
<div className="flex justify-between">
<span className="text-muted-foreground"></span>
<span className="font-medium">0</span>
</div>
</div>
</div>
))}
</div>
</div>
);
}
+53 -67
View File
@@ -1,90 +1,76 @@
/** 投资人端布局 — B 端专业风格:左 Sidebar + 灰色内容区 + AI Copilot。 */
import {
LayoutDashboard, Building2, FileText, AlertTriangle, Settings,
Receipt, ScrollText, Users, Lightbulb, Target, GitBranch,
TrendingUp, Network, ShieldCheck, Bot, BookOpen, BarChart3,
} from "lucide-react";
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { useMemo } from "react";
import { CopilotWidget } from "@/components/shared/CopilotWidget";
import { RiskToastNotifier } from "@/components/shared/RiskToastNotifier";
import { AuthGuard } from "@/components/shared/AuthGuard";
import { useAuth } from "@/lib/auth-context";
import { getNavDomains, NAV_FOOTER } from "@/lib/navConfig";
const navSections = [
{
title: "核心功能",
items: [
{ href: "/dashboard", label: "驾驶舱", icon: LayoutDashboard },
{ href: "/companies", label: "企业档案", icon: Building2 },
{ href: "/reports", label: "月报管理", icon: FileText },
{ href: "/risks", label: "风险工作台", icon: AlertTriangle },
],
},
{
title: "投后管理",
items: [
{ href: "/financial", label: "财务校验", icon: Receipt },
{ href: "/agreements", label: "协议监控", icon: ScrollText },
{ href: "/board", label: "董事会", icon: Users },
{ href: "/weak-signals", label: "弱信号", icon: Lightbulb },
{ href: "/sentinels", label: "决策前哨", icon: Target },
{ href: "/events", label: "重大事项", icon: AlertTriangle },
],
},
{
title: "增值服务",
items: [
{ href: "/synergies", label: "协同中心", icon: Network },
{ href: "/innovation", label: "组合创新", icon: Lightbulb },
{ href: "/talents", label: "人才引力场", icon: Users },
{ href: "/okrs", label: "OKR", icon: Target },
{ href: "/milestones", label: "里程碑", icon: GitBranch },
{ href: "/tasks", label: "任务看板", icon: BarChart3 },
],
},
{
title: "高级分析",
items: [
{ href: "/alpha", label: "Alpha 归因", icon: TrendingUp },
{ href: "/exit-signals", label: "退出信号", icon: TrendingUp },
{ href: "/portfolio", label: "组合管理", icon: BarChart3 },
{ href: "/digital-twins", label: "数字孪生", icon: Bot },
{ href: "/knowledge-graph", label: "知识图谱", icon: Network },
{ href: "/aars", label: "AAR 复盘", icon: BookOpen },
{ href: "/pre-mortems", label: "Pre-mortem", icon: ShieldCheck },
{ href: "/agents", label: "Agent 监控", icon: Bot },
],
},
{
title: "系统",
items: [
{ href: "/settings", label: "设置", icon: Settings },
],
},
];
/**
* 投资人端布局组件。
*
* 左侧 Sidebar 按 6 业务域分组,域顺序根据用户角色动态排序。
*/
export default function InvestorLayout({ children }: { children: React.ReactNode }) {
const { user } = useAuth();
const pathname = usePathname();
const domains = useMemo(() => getNavDomains(user?.role ?? "investor"), [user?.role]);
return (
<div className="flex min-h-screen">
{/* 左侧 Sidebar */}
<aside className="sticky top-0 hidden h-screen w-52 shrink-0 bg-[var(--investor-sidebar-bg)] text-white md:block">
<div className="flex h-14 items-center px-4 font-bold">AIPortPilot</div>
<nav className="flex flex-col gap-1 overflow-y-auto px-3 py-2">
{navSections.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) => (
<nav className="flex flex-col gap-1 overflow-y-auto px-3 py-2" style={{ maxHeight: "calc(100vh - 3.5rem)" }}>
{domains.map((domain) => (
<div key={domain.key} className="mb-2">
<div className="px-3 py-1 text-xs font-medium text-white/40">{domain.title}</div>
{domain.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-white/15 text-white"
: "text-white/70 hover:bg-white/10 hover:text-white"
}`}
>
<item.icon size={16} aria-hidden="true" />
{item.label}
</Link>
);
})}
</div>
))}
{/* 底部固定 */}
<div className="mt-auto border-t border-white/10 pt-2">
{NAV_FOOTER.map((item) => {
const isActive = pathname === item.href;
return (
<Link
key={item.href}
href={item.href}
className="flex items-center gap-2 rounded-md px-3 py-2 text-sm text-white/70 transition-colors hover:bg-white/10 hover:text-white"
className={`flex items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors ${
isActive
? "bg-white/15 text-white"
: "text-white/70 hover:bg-white/10 hover:text-white"
}`}
>
<item.icon size={16} aria-hidden="true" />
{item.label}
</Link>
))}
</div>
))}
);
})}
</div>
</nav>
</aside>
@@ -0,0 +1,52 @@
/** 决策线程详情页 — 状态机时间线 + 关联事件 + AAR 链接。 */
import { GitBranch, ArrowLeft } from "lucide-react";
import Link from "next/link";
/** 决策线程详情页面。 */
export default function ThreadDetailPage({ params }: { params: { id: string } }) {
return (
<div className="space-y-6">
<Link href="/threads" className="flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground">
<ArrowLeft size={16} />
线
</Link>
<div className="flex items-center gap-2">
<GitBranch className="text-[var(--investor-primary)]" size={24} />
<h1 className="text-2xl font-bold">线</h1>
</div>
<div className="rounded-lg border bg-white p-4 shadow-sm">
<div className="mb-4 flex items-center justify-between">
<h2 className="text-lg font-medium">线 #{params.id}</h2>
<span className="rounded-full bg-indigo-50 px-3 py-1 text-xs text-indigo-600"></span>
</div>
<p className="text-sm text-muted-foreground">
线 AAR P1 #17
</p>
</div>
{/* 时间线占位 */}
<div className="rounded-lg border bg-white p-4 shadow-sm">
<h3 className="mb-4 font-medium">线</h3>
<div className="space-y-4">
{[
{ label: "已识别", date: "2026-07-09", active: true },
{ label: "分析中", date: "2026-07-12", active: true },
{ label: "已行动", date: "—", active: false },
{ label: "已关闭", date: "—", active: false },
].map((step, i) => (
<div key={i} className="flex items-center gap-3">
<div className={`h-3 w-3 rounded-full ${step.active ? "bg-indigo-500" : "bg-gray-300"}`} />
<span className={`text-sm ${step.active ? "font-medium" : "text-muted-foreground"}`}>
{step.label}
</span>
<span className="text-xs text-muted-foreground">{step.date}</span>
</div>
))}
</div>
</div>
</div>
);
}
@@ -0,0 +1,42 @@
/** 决策线程列表页 — 按状态/企业筛选 + 线程卡片。 */
import { GitBranch } from "lucide-react";
/** 决策线程列表页面。 */
export default function ThreadsPage() {
return (
<div className="space-y-6">
<div className="flex items-center gap-2">
<GitBranch className="text-[var(--investor-primary)]" size={24} />
<h1 className="text-2xl font-bold">线</h1>
</div>
<div className="rounded-lg border bg-white p-4 shadow-sm">
<p className="text-sm text-muted-foreground">
线线
</p>
</div>
{/* 线程卡片占位 */}
<div className="space-y-3">
{[
{ title: "云栈数据 A+轮融资时机选择", status: "分析中", company: "云栈数据" },
{ title: "深瞳智能 CTO retention 策略", status: "已识别", company: "深瞳智能" },
{ title: "量子芯微 融资策略:天使+ vs Pre-A", status: "已行动", company: "量子芯微" },
].map((thread) => (
<div key={thread.title} className="rounded-lg border bg-white p-4 shadow-sm">
<div className="flex items-center justify-between">
<div>
<h3 className="font-medium">{thread.title}</h3>
<p className="mt-1 text-sm text-muted-foreground">{thread.company}</p>
</div>
<span className="rounded-full bg-indigo-50 px-3 py-1 text-xs text-indigo-600">
{thread.status}
</span>
</div>
</div>
))}
</div>
</div>
);
}
+110
View File
@@ -0,0 +1,110 @@
/** 今日行动中心 — 投后负责人/投资经理默认首页。 */
import { CalendarClock, AlertTriangle, FileText, ListTodo, TrendingUp } from "lucide-react";
/** 今日行动中心页面。 */
export default function TodayPage() {
return (
<div className="space-y-6">
<div className="flex items-center gap-2">
<CalendarClock className="text-[var(--investor-primary)]" size={24} />
<h1 className="text-2xl font-bold"></h1>
</div>
{/* AI 简报 */}
<div className="rounded-lg border bg-white p-4 shadow-sm">
<h2 className="mb-2 text-sm font-medium text-muted-foreground">AI </h2>
<p className="text-sm text-gray-700">
3 2 5 Runway 7
</p>
</div>
{/* 四象限概览 */}
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="rounded-lg border bg-white p-4 shadow-sm">
<div className="mb-3 flex items-center gap-2">
<AlertTriangle className="text-amber-500" size={18} />
<h3 className="font-medium"></h3>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between rounded bg-red-50 px-3 py-2 text-sm">
<span> Runway不足7月</span>
<span className="text-red-600"></span>
</div>
<div className="flex items-center justify-between rounded bg-amber-50 px-3 py-2 text-sm">
<span> </span>
<span className="text-amber-600"></span>
</div>
<div className="flex items-center justify-between rounded bg-blue-50 px-3 py-2 text-sm">
<span> </span>
<span className="text-blue-600"></span>
</div>
</div>
</div>
<div className="rounded-lg border bg-white p-4 shadow-sm">
<div className="mb-3 flex items-center gap-2">
<FileText className="text-blue-500" size={18} />
<h3 className="font-medium"></h3>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
<span> </span>
<span className="text-green-600">AI </span>
</div>
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
<span> </span>
<span className="text-green-600"></span>
</div>
<div className="flex items-center justify-between rounded bg-amber-50 px-3 py-2 text-sm">
<span> 稿</span>
<span className="text-amber-600"></span>
</div>
</div>
</div>
<div className="rounded-lg border bg-white p-4 shadow-sm">
<div className="mb-3 flex items-center gap-2">
<ListTodo className="text-indigo-500" size={18} />
<h3 className="font-medium"></h3>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between rounded bg-indigo-50 px-3 py-2 text-sm">
<span>访</span>
<span className="text-indigo-600"></span>
</div>
<div className="flex items-center justify-between rounded bg-gray-50 px-3 py-2 text-sm">
<span>使+ BP</span>
<span className="text-gray-600"></span>
</div>
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
<span></span>
<span className="text-green-600"></span>
</div>
</div>
</div>
<div className="rounded-lg border bg-white p-4 shadow-sm">
<div className="mb-3 flex items-center gap-2">
<TrendingUp className="text-emerald-500" size={18} />
<h3 className="font-medium"></h3>
</div>
<div className="space-y-2">
<div className="flex items-center justify-between rounded bg-green-50 px-3 py-2 text-sm">
<span> 78.5 </span>
<span className="text-green-600">+2.3</span>
</div>
<div className="flex items-center justify-between rounded bg-red-50 px-3 py-2 text-sm">
<span> 48.0 </span>
<span className="text-red-600">-5.0</span>
</div>
<div className="flex items-center justify-between rounded bg-gray-50 px-3 py-2 text-sm">
<span> 62.0 </span>
<span className="text-gray-600"></span>
</div>
</div>
</div>
</div>
</div>
);
}
@@ -0,0 +1,22 @@
/** 通用工作区 — URL 参数驱动,支持多 Tab 独立上下文。 */
import { Layers } from "lucide-react";
/** 通用工作区页面。 */
export default function WorkspacePage() {
return (
<div className="space-y-6">
<div className="flex items-center gap-2">
<Layers className="text-[var(--investor-primary)]" size={24} />
<h1 className="text-2xl font-bold"></h1>
</div>
<div className="rounded-lg border bg-white p-4 shadow-sm">
<p className="text-sm text-muted-foreground">
Tab 8 Tab URL
P1 #18 Multi-Workspace Tab
</p>
</div>
</div>
);
}
+103 -9
View File
@@ -1,15 +1,109 @@
/** Admin 端布局 — 警示风格:slate-950 Header + amber 主色。 */
/** 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="min-h-screen bg-slate-100">
<header className="sticky top-0 z-10 flex h-14 items-center bg-[var(--admin-header-bg)] px-4">
<span className="font-bold text-[var(--admin-primary)]">AIPortPilot</span>
<span className="ml-2 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>
<main className="container mx-auto max-w-7xl px-4 py-6">{children}</main>
<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>
);
}
+15 -6
View File
@@ -1,14 +1,23 @@
/** 创始人端布局 — C 端温暖风格:顶部 Header + indigo 主色。 */
/** 创始人端布局 — C 端温暖风格:顶部 Header + indigo 主色 + 6 域底部导航。 */
import { Home, FileText, Sparkle } from "lucide-react";
import { CalendarClock, Gauge, FileText, Sparkle, Bell, UserCircle } from "lucide-react";
import Link from "next/link";
/** 创始人端 6 域导航。 */
const navItems = [
{ href: "/founder", label: "概览", icon: Home },
{ href: "/founder", label: "今日", icon: CalendarClock },
{ href: "/founder/operations", label: "经营", icon: Gauge },
{ href: "/founder/reports", label: "月报", icon: FileText },
{ href: "/founder/copilot", label: "AI 副驾驶", icon: Sparkle },
{ href: "/founder/copilot", label: "Copilot", icon: Sparkle },
{ href: "/founder/notifications", label: "通知", icon: Bell },
{ href: "/founder/profile", label: "我的", icon: UserCircle },
];
/**
* 创始人端布局组件。
*
* 顶部 sticky Header + 底部 6 域导航栏,移动优先设计。
*/
export default function FounderLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen bg-gradient-to-b from-indigo-50 to-white">
@@ -21,8 +30,8 @@ export default function FounderLayout({ children }: { children: React.ReactNode
{/* 内容区 */}
<main className="container mx-auto max-w-7xl px-4 py-6 pb-20 md:pb-6">{children}</main>
{/* 移动端底部导航 */}
<nav className="fixed bottom-0 left-0 right-0 flex h-14 border-t bg-white md:hidden">
{/* 底部 6 域导航 */}
<nav className="fixed bottom-0 left-0 right-0 flex h-14 border-t bg-white">
{navItems.map((item) => (
<Link
key={item.href}
+130
View File
@@ -0,0 +1,130 @@
/** 投资人端导航配置 — 6 业务域分组 + 角色化排序。 */
import {
CalendarClock, LayoutDashboard, Building2, Scale, GitCompareArrows,
AlertTriangle, FileText, Receipt, ScrollText, Users, Flag, ListTodo,
Network, UserCircle, TrendingUp, Target, GitBranch, Lightbulb,
Radar, Crosshair, TrendingUp as TrendUp, LogOut, Bot, Cpu, Network as Net,
BookOpen, ShieldCheck, FileBarChart, Settings,
type LucideIcon,
} from "lucide-react";
/** 导航项定义。 */
export interface NavItem {
href: string;
label: string;
icon: LucideIcon;
}
/** 业务域定义。 */
export interface NavDomain {
key: string;
title: string;
items: NavItem[];
}
/** 角色默认首页。 */
export const ROLE_HOME: Record<string, string> = {
gp: "/dashboard",
partner: "/dashboard",
post_invest_lead: "/today",
investor: "/today",
};
/** 6 业务域完整定义(顺序为通用默认顺序)。 */
export const NAV_DOMAINS: Record<string, NavDomain> = {
today: {
key: "today",
title: "今日",
items: [
{ href: "/today", label: "今日行动中心", icon: CalendarClock },
],
},
portfolio: {
key: "portfolio",
title: "组合",
items: [
{ href: "/dashboard", label: "指挥塔", icon: LayoutDashboard },
{ href: "/companies", label: "企业列表", icon: Building2 },
{ href: "/portfolio", label: "组合再平衡", icon: Scale },
{ href: "/compare", label: "多企业对比", icon: GitCompareArrows },
],
},
work: {
key: "work",
title: "工作",
items: [
{ href: "/risks", label: "风险队列", icon: AlertTriangle },
{ href: "/reports", label: "月报审阅", icon: FileText },
{ href: "/financial", label: "财务校验", icon: Receipt },
{ href: "/agreements", label: "协议监控", icon: ScrollText },
{ href: "/board", label: "董事会", icon: Users },
{ href: "/events", label: "重大事项", icon: Flag },
{ href: "/tasks", label: "任务看板", icon: ListTodo },
],
},
growth: {
key: "growth",
title: "增长",
items: [
{ href: "/synergies", label: "协同机会", icon: Network },
{ href: "/talents", label: "人才", icon: UserCircle },
{ href: "/customer-growth", label: "客户增长", icon: TrendingUp },
{ href: "/okrs", label: "OKR", icon: Target },
{ href: "/milestones", label: "里程碑", icon: GitBranch },
{ href: "/innovation", label: "组合创新", icon: Lightbulb },
{ href: "/peer-circles", label: "Peer Learning", icon: Users },
{ href: "/product-diagnostics", label: "产品诊断", icon: Cpu },
],
},
insight: {
key: "insight",
title: "洞察",
items: [
{ href: "/weak-signals", label: "弱信号", icon: Radar },
{ href: "/sentinels", label: "决策前哨", icon: Crosshair },
{ href: "/threads", label: "决策线程", icon: GitBranch },
{ href: "/alpha", label: "Alpha 归因", icon: TrendUp },
{ href: "/exit-signals", label: "退出信号", icon: LogOut },
{ href: "/digital-twins", label: "数字孪生", icon: Bot },
{ href: "/knowledge-graph", label: "知识图谱", icon: Net },
{ href: "/agents", label: "Agent 监控", icon: Bot },
{ href: "/nudges", label: "行为助推", icon: Lightbulb },
],
},
report: {
key: "report",
title: "报告",
items: [
{ href: "/aars", label: "AAR 复盘", icon: BookOpen },
{ href: "/pre-mortems", label: "Pre-mortem", icon: ShieldCheck },
{ href: "/reports/templates", label: "投后报告", icon: FileBarChart },
],
},
};
/** 底部固定项。 */
export const NAV_FOOTER: NavItem[] = [
{ href: "/settings", label: "设置", icon: Settings },
];
/** 角色化域排序。 */
export const ROLE_DOMAIN_ORDER: Record<string, string[]> = {
gp: ["portfolio", "insight", "report", "growth", "work", "today"],
partner: ["portfolio", "insight", "report", "growth", "work", "today"],
post_invest_lead: ["today", "work", "portfolio", "growth", "insight", "report"],
investor: ["today", "portfolio", "work", "growth", "report", "insight"],
};
/** 默认域排序。 */
const DEFAULT_ORDER = ["today", "portfolio", "work", "growth", "insight", "report"];
/**
* 根据角色获取排序后的导航域列表。
* @param role 用户角色
* @returns 排序后的 NavDomain 数组
*/
export function getNavDomains(role: string): NavDomain[] {
const order = ROLE_DOMAIN_ORDER[role] ?? DEFAULT_ORDER;
return order.map((key) => NAV_DOMAINS[key]).filter(Boolean);
}