'use client'; /** * 控制台外壳 - 侧边栏导航(4 标签)+ 配额提醒横幅 + 主区头部 + 面板切换 * 客户端组件:管理 activeTab 与 bannerOpen 状态,承载各面板 * 会话:读取 localStorage(dotouch_user / dotouch_token),未登录跳转登录弹窗 */ import { useEffect, useState } from 'react'; import { useRouter } from 'next/navigation'; import { useLocale, useTranslations } from 'next-intl'; import { BrandLogo } from '@/components/BrandLogo'; import { OverviewPanel } from './OverviewPanel'; import { KeysPanel } from './KeysPanel'; import { WalletPanel } from './WalletPanel'; import { UsagePanel } from './UsagePanel'; import { ReferralPanel } from './ReferralPanel'; import { cls } from './ui'; /** 演示环境 API 地址(生产替换为真实网关域名) */ const API_BASE = process.env['NEXT_PUBLIC_API_URL'] || 'http://localhost:8081/v1'; /** 侧边导航项(图标 + i18n 标签键) */ const tabs = [ { id: 'overview', icon: '📊', labelKey: 'c_overview' }, { id: 'keys', icon: '🔑', labelKey: 'c_keys' }, { id: 'wallet', icon: '💳', labelKey: 'c_wallet' }, { id: 'usage', icon: '📈', labelKey: 'c_usage' }, { id: 'referral', icon: '🤝', labelKey: 'c_referral' }, ] as const; type Tab = (typeof tabs)[number]['id']; export function ConsoleShell() { const t = useTranslations(); const locale = useLocale(); const router = useRouter(); const [activeTab, setActiveTab] = useState('overview'); // 配额提醒横幅默认隐藏,由总览面板的演示开关触发 const [bannerOpen, setBannerOpen] = useState(false); const [userEmail, setUserEmail] = useState(null); const [balanceCents, setBalanceCents] = useState(null); // 会话检查:读取本地登录态,未登录跳转官网登录弹窗 useEffect(() => { let email: string | null = null; let token: string | null = null; try { email = localStorage.getItem('dotouch_user'); token = localStorage.getItem('dotouch_token'); } catch { /* 忽略 */ } if (!email || !token) { router.replace(`/${locale}?auth=login`); return; } setUserEmail(email); // 拉取真实余额 fetch(`${API_BASE}/wallet`, { headers: { Authorization: `Bearer ${token}` }, }) .then((r) => r.json().catch(() => null)) .then((data) => { if (data && typeof data.balanceCents === 'number') { setBalanceCents(data.balanceCents); } }) .catch(() => { /* 余额获取失败不阻塞页面 */ }); }, [locale, router]); const logout = () => { try { localStorage.removeItem('dotouch_token'); localStorage.removeItem('dotouch_user'); } catch { /* 忽略 */ } router.push(`/${locale}`); }; const activeLabel = t(tabs.find((tab) => tab.id === activeTab)!.labelKey); return (
{/* ══ 侧边栏 ══ */} {/* ══ 主区 ══ */}
{/* 配额提醒横幅(默认隐藏,演示开关触发) */} {bannerOpen && (
⚠️ {t('q_banner_80')}
)} {/* 主区头部:当前标签标题 + 欢迎语 + 创建 Key 按钮 */}

{activeLabel}

{t('c_welcome')}
{/* 面板切换 */} {activeTab === 'overview' && ( setBannerOpen((v) => !v)} /> )} {activeTab === 'keys' && } {activeTab === 'wallet' && } {activeTab === 'usage' && } {activeTab === 'referral' && }
); }