'use client'; import React, { useState } from 'react'; import { usePathname, useRouter } from 'next/navigation'; import Link from 'next/link'; import { t } from '@/i18n/locales'; import { useAuth } from '@/lib/auth-context'; /** * D. Web管理前端 - 主布局 * * 左侧Sidebar导航 + 顶部Header + 主内容区 * 覆盖 D1-D8 所有管理模块的路由结构 */ interface NavItem { key: string; icon: string; label: string; children?: NavItem[]; badge?: number; } const navItems: NavItem[] = [ { key: 'dashboard', icon: '📊', label: t('nav_dashboard') }, { key: 'issuers', icon: '🏢', label: t('nav_issuers'), children: [ { key: 'issuers/review', icon: '', label: t('nav_issuers_review') }, { key: 'issuers/list', icon: '', label: t('nav_issuers_list') }, { key: 'issuers/coupons', icon: '', label: t('nav_issuers_coupons') }, ], }, { key: 'users', icon: '👤', label: t('nav_users'), children: [ { key: 'users/list', icon: '', label: t('nav_users_list') }, { key: 'users/kyc', icon: '', label: t('nav_users_kyc'), badge: 5 }, { key: 'users/sms-logs', icon: '', label: t('nav_users_sms_logs') }, ], }, { key: 'trading', icon: '💱', label: t('nav_trading'), children: [ { key: 'trading/realtime', icon: '', label: t('nav_trading_realtime') }, { key: 'trading/stats', icon: '', label: t('nav_trading_stats') }, { key: 'trading/orders', icon: '', label: t('nav_trading_orders') }, ], }, { key: 'risk', icon: '🛡️', label: t('nav_risk'), children: [ { key: 'risk/dashboard', icon: '', label: t('nav_risk_dashboard'), badge: 3 }, { key: 'risk/suspicious', icon: '', label: t('nav_risk_suspicious') }, { key: 'risk/blacklist', icon: '', label: t('nav_risk_blacklist') }, { key: 'risk/ofac', icon: '', label: t('nav_risk_ofac') }, ], }, { key: 'compliance', icon: '📋', label: t('nav_compliance'), children: [ { key: 'compliance/sar', icon: '', label: t('nav_compliance_sar') }, { key: 'compliance/ctr', icon: '', label: t('nav_compliance_ctr') }, { key: 'compliance/audit', icon: '', label: t('nav_compliance_audit') }, { key: 'compliance/reports', icon: '', label: t('nav_compliance_reports') }, ], }, { key: 'app-versions', icon: '📱', label: t('nav_app_versions') }, { key: 'system', icon: '⚙️', label: t('nav_system'), children: [ { key: 'system/admins', icon: '', label: t('nav_system_admins') }, { key: 'system/config', icon: '', label: t('nav_system_config') }, { key: 'system/contracts', icon: '', label: t('nav_system_contracts') }, { key: 'system/monitor', icon: '', label: t('nav_system_monitor') }, ], }, { key: 'disputes', icon: '⚖️', label: t('nav_disputes'), badge: 8 }, { key: 'coupons', icon: '🎫', label: t('nav_coupons_mgmt') }, { key: 'finance', icon: '💰', label: t('nav_finance') }, { key: 'chain', icon: '⛓️', label: t('nav_chain') }, { key: 'reports', icon: '📈', label: t('nav_reports') }, { key: 'merchant', icon: '🏪', label: t('nav_merchant') }, { key: 'agent', icon: '🤖', label: t('nav_agent') }, { key: 'insurance', icon: '🛡️', label: t('nav_insurance') }, { key: 'analytics', icon: '📊', label: t('nav_analytics'), children: [ { key: 'analytics/users', icon: '', label: t('nav_analytics_users') }, { key: 'analytics/coupons', icon: '', label: t('nav_analytics_coupons') }, { key: 'analytics/market-maker', icon: '', label: t('nav_analytics_market_maker') }, { key: 'analytics/consumer-protection', icon: '', label: t('nav_analytics_consumer_protection') }, ], }, ]; export const AdminLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => { const pathname = usePathname(); const router = useRouter(); const { isAuthenticated, isLoading, user, logout } = useAuth(); const [collapsed, setCollapsed] = useState(false); // 未登录 → /login if (!isLoading && !isAuthenticated) { router.replace('/login'); return null; } // 加载中显示空白 if (isLoading) return null; // Derive activeKey from current pathname const activeKey = pathname.replace(/^\//, '') || 'dashboard'; // Auto-expand parent nav items based on current path const getInitialExpanded = () => { const expanded: string[] = []; navItems.forEach(item => { if (item.children && item.children.some(c => activeKey.startsWith(c.key) || activeKey === item.key)) { expanded.push(item.key); } }); return expanded; }; const [expandedKeys, setExpandedKeys] = useState(getInitialExpanded); const toggleExpand = (key: string) => { setExpandedKeys(prev => prev.includes(key) ? prev.filter(k => k !== key) : [...prev, key] ); }; return (
{/* Sidebar */} {/* Main Content */}
{/* Header */}
{/* AI Agent Button */} {/* Notifications */} {/* Admin avatar + logout */}
{user?.name?.charAt(0)?.toUpperCase() || 'A'}
{/* Page Content */}
{children}
); };