Spaces:
Running
Running
| 'use client'; | |
| /** | |
| * 用户菜单组件 | |
| * - 已登录:显示用户名、VIP 徽章、退出按钮 | |
| * - 未登录:显示登录/注册按钮 | |
| */ | |
| import { useState, useEffect, useRef } from 'react'; | |
| import { User, LogOut, Crown, LogIn, Smartphone, Shield } from 'lucide-react'; | |
| import { useAuthStore } from '@/store/authStore'; | |
| import AuthModal from './AuthModal'; | |
| import PaymentModal from './PaymentModal'; | |
| import UserInfoModal from './UserInfoModal'; | |
| import AdminPanel from './AdminPanel'; | |
| interface UserMenuProps { | |
| compact?: boolean; // 紧凑模式(游戏进行中) | |
| } | |
| export default function UserMenu({ compact = false }: UserMenuProps) { | |
| const { username, isVip, vipExpireAt, isInitialized, logout, initialize } = useAuthStore(); | |
| const [showAuthModal, setShowAuthModal] = useState(false); | |
| const [showPayment, setShowPayment] = useState(false); | |
| const [showUserInfo, setShowUserInfo] = useState(false); | |
| const [showAdminPanel, setShowAdminPanel] = useState(false); | |
| const [showDropdown, setShowDropdown] = useState(false); | |
| const dropdownRef = useRef<HTMLDivElement>(null); | |
| // 初始化认证状态 | |
| useEffect(() => { | |
| if (!isInitialized) { | |
| initialize(); | |
| } | |
| }, [isInitialized, initialize]); | |
| // 点击外部关闭下拉 | |
| useEffect(() => { | |
| const handleClickOutside = (event: MouseEvent) => { | |
| if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { | |
| setShowDropdown(false); | |
| } | |
| }; | |
| document.addEventListener('mousedown', handleClickOutside); | |
| return () => document.removeEventListener('mousedown', handleClickOutside); | |
| }, []); | |
| const handleLogout = async () => { | |
| setShowDropdown(false); | |
| await logout(); | |
| }; | |
| // 格式化 VIP 到期时间 | |
| const formatExpireDate = (dateStr: string | null) => { | |
| if (!dateStr) return ''; | |
| const date = new Date(dateStr); | |
| const now = new Date(); | |
| const diffDays = Math.ceil((date.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); | |
| if (diffDays <= 0) return '已过期'; | |
| if (diffDays <= 7) return `${diffDays}天后到期`; | |
| return dateStr.split(' ')[0]; // 只显示日期部分 | |
| }; | |
| if (!isInitialized) return null; | |
| // 未登录状态 | |
| if (!username) { | |
| return ( | |
| <> | |
| <button | |
| onClick={() => setShowAuthModal(true)} | |
| className={`flex items-center gap-1.5 bg-blue-600/20 hover:bg-blue-600/30 text-blue-400 hover:text-blue-300 rounded-lg transition-colors ${compact ? 'px-2 py-1 text-xs' : 'px-3 py-2 text-sm' | |
| }`} | |
| > | |
| <LogIn size={compact ? 12 : 14} /> | |
| <span>登录</span> | |
| </button> | |
| {showAuthModal && <AuthModal onClose={() => setShowAuthModal(false)} />} | |
| </> | |
| ); | |
| } | |
| // 已登录状态 | |
| return ( | |
| <> | |
| <div className="relative" ref={dropdownRef}> | |
| <button | |
| onClick={() => setShowDropdown(!showDropdown)} | |
| className={`flex items-center gap-1.5 bg-[#2A2D3C] hover:bg-[#35394B] rounded-lg transition-colors ${compact ? 'px-2 py-1 text-xs' : 'px-3 py-2 text-sm' | |
| }`} | |
| > | |
| <div className="w-5 h-5 bg-blue-600/30 rounded-full flex items-center justify-center"> | |
| <User size={12} className="text-blue-400" /> | |
| </div> | |
| <span className="text-gray-200 font-medium max-w-[80px] truncate">{username}</span> | |
| {isVip && ( | |
| <Crown size={compact ? 10 : 12} className="text-yellow-500" /> | |
| )} | |
| </button> | |
| {/* 下拉菜单 */} | |
| {showDropdown && ( | |
| <div className="absolute right-0 top-full mt-1 w-48 bg-[#2A2D3C] rounded-xl shadow-2xl border border-gray-700/50 z-50 overflow-hidden"> | |
| {/* 用户信息 */} | |
| <div | |
| className="px-4 py-3 border-b border-gray-700/30 hover:bg-gray-700/20 cursor-pointer transition-colors" | |
| onClick={() => { setShowDropdown(false); setShowUserInfo(true); }} | |
| > | |
| <div className="text-white text-sm font-medium hover:text-blue-400 flex items-center justify-between"> | |
| {username} | |
| <User size={12} className="text-gray-500" /> | |
| </div> | |
| {isVip ? ( | |
| <div className="flex items-center gap-1 mt-1"> | |
| <Crown size={11} className="text-yellow-500" /> | |
| <span className="text-yellow-500 text-xs">VIP 会员</span> | |
| <span className="text-gray-500 text-xs ml-1"> | |
| {formatExpireDate(vipExpireAt)} | |
| </span> | |
| </div> | |
| ) : ( | |
| <div className="text-gray-500 text-xs mt-1">普通用户</div> | |
| )} | |
| </div> | |
| {/* 操作 */} | |
| <div className="p-1 space-y-1"> | |
| {!isVip && ( | |
| <button | |
| onClick={() => { setShowDropdown(false); setShowPayment(true); }} | |
| className="w-full flex items-center gap-2 px-3 py-2 text-yellow-500 hover:bg-yellow-500/10 rounded-lg text-sm transition-colors font-medium border border-yellow-500/20" | |
| > | |
| <Crown size={14} /> | |
| 开通会员 | |
| </button> | |
| )} | |
| <button | |
| onClick={handleLogout} | |
| className="w-full flex items-center gap-2 px-3 py-2 text-gray-400 hover:text-white hover:bg-gray-700/50 rounded-lg text-sm transition-colors" | |
| > | |
| <LogOut size={14} /> | |
| 退出登录 | |
| </button> | |
| {/* 超级管理员额外功能 */} | |
| {username === '583079759' && ( | |
| <button | |
| onClick={() => { setShowDropdown(false); setShowAdminPanel(true); }} | |
| className="w-full flex items-center gap-2 px-3 py-2 text-indigo-400 hover:text-white hover:bg-indigo-600/20 rounded-lg text-[11px] transition-colors mt-2 border-t border-gray-700/30 pt-2 font-bold" | |
| > | |
| <Shield size={12} /> | |
| 管理后台 (Super Admin) | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| {showAuthModal && <AuthModal onClose={() => setShowAuthModal(false)} />} | |
| <PaymentModal isOpen={showPayment} onClose={() => setShowPayment(false)} /> | |
| <UserInfoModal | |
| isOpen={showUserInfo} | |
| onClose={() => setShowUserInfo(false)} | |
| username={username || ''} | |
| isVip={isVip} | |
| vipExpireAt={vipExpireAt} | |
| onRenewVip={() => { | |
| setShowUserInfo(false); | |
| setShowPayment(true); | |
| }} | |
| /> | |
| <AdminPanel | |
| isOpen={showAdminPanel} | |
| onClose={() => setShowAdminPanel(false)} | |
| /> | |
| </> | |
| ); | |
| } | |