'use client' import { useEffect, useState } from 'react' import Link from 'next/link' import { useRouter } from 'next/navigation' import { signOut } from 'next-auth/react' import type { Session } from 'next-auth' import type { ReactNode } from 'react' import BrandLogo from '@/components/BrandLogo' import { DEFAULT_LOGIN_LOGO_URL } from '@/lib/brand-assets' /* * BoardShell —— 品牌中心看板顶层骨架(云采石场 · seed 32cb33b5 世界内扩展) * 顶栏=白色石材地面上的切割导航:当前板块以切割蓝垫层高亮,规划中板块保持"未开采"不可点状态; * 供看板骨架首页(/)与组织管理(/organization)共用,后续各板块入住时沿用同一顶栏。 */ export type BoardSection = 'dashboard' | 'organization' | 'assets' | 'business' | 'governance' interface BoardShellProps { session?: Session | null active: BoardSection children: ReactNode } const ADMIN_ROLES = ['ADMIN', 'SYSTEM_ADMIN', 'DEPT_ADMIN'] const NAV_ITEMS: Array<{ key: BoardSection label: string href?: string planned?: boolean plannedLabel?: string adminOnly?: boolean }> = [ { key: 'dashboard', label: '中心仪表盘', href: '/' }, { key: 'assets', label: '创意资产库', href: '/materials' }, { key: 'organization', label: '组织管理', href: '/organization', adminOnly: true }, { key: 'business', label: '业务经营', planned: true }, { key: 'governance', label: '治理与设置', planned: true }, ] export default function BoardShell({ session, active, children }: BoardShellProps) { const router = useRouter() // 本壳顶栏为浅色,用浅底适配版 logo(loginLogoUrl);深底版仅用于素材库黑色顶栏 const [brandLogoUrl, setBrandLogoUrl] = useState(DEFAULT_LOGIN_LOGO_URL) useEffect(() => { const loadSettings = async () => { try { const response = await fetch('/api/system-settings') if (response.ok) { const settings = await response.json() setBrandLogoUrl(settings.loginLogoUrl || DEFAULT_LOGIN_LOGO_URL) } } catch { // 设置加载失败时保留默认 logo } } void loadSettings() }, []) const sessionUser = session?.user as | { role?: string name?: string | null realName?: string | null username?: string | null } | undefined const isAdmin = ADMIN_ROLES.includes(sessionUser?.role || '') const displayName = sessionUser?.realName || sessionUser?.name || sessionUser?.username || '成员' const handleSignOut = async () => { try { await signOut({ redirect: false }) await new Promise((resolve) => setTimeout(resolve, 100)) } finally { router.push('/login') router.refresh() } } const visibleItems = NAV_ITEMS.filter((item) => !item.adminOnly || isAdmin) const renderNavItem = (item: (typeof visibleItems)[number], compact = false) => { if (item.planned) { return ( {item.label} {item.plannedLabel ?? '规划中'} ) } const isActive = active === item.key return ( {item.label} ) } return (
由壹点·品牌中心 {/* 桌面端板块导航 */}
{displayName}
{/* 移动端板块导航:横向滚动 */}
{children}
) }