feat(auth): 添加登出功能并优化认证处理

- 添加了登出相关的API端点和常量定义
- 实现了登出功能及密码验证登出逻辑
- 添加了登出会话清理和浏览器存储清除
- 在用户信息模态框中集成了登出按钮
- 添加了登出相关的国际化翻译
- 优化了API客户端中的认证错误处理
- 实现了无效令牌的自动处理机制
- 更新了GitNexus索引统计数据
- 修改了构建输出目录配置
- 清理了不必要的注释和代码
- 调整了移动端头部组件结构
- 优化了游戏历史记录查询逻辑
- 添加了控制台日志用于调试
- 设置默认注册邀请码为D97DBC16
- 在.gitignore中添加构建产物忽略规则
This commit is contained in:
JiaJun
2026-05-29 16:26:35 +08:00
parent dbfe5701aa
commit 15c519a42c
26 changed files with 527 additions and 87 deletions

View File

@@ -0,0 +1,223 @@
import {
Info,
Mail,
UserKey,
UserRoundPlus,
Volume2,
VolumeX,
Wifi,
} from 'lucide-react'
import { useTranslation } from 'react-i18next'
import avatar from '@/assets/system/avatar.webp'
import diamond from '@/assets/system/diamond.webp'
import logo from '@/assets/system/logo.webp'
import { SmartImage } from '@/components/smart-image.tsx'
import { useHeaderVm } from '@/features/game/hooks/use-header-vm'
export function MobileHeader() {
const { t } = useTranslation()
const {
authStatus,
currentLanguageLabel,
currentLanguageOption,
currentUser,
isSoundEnabled,
onOpenLanguage,
onOpenLogin,
onOpenNotice,
onOpenProcedures,
onOpenRegister,
onOpenRules,
onOpenUserInfo,
signalPresentation,
systemTimeLabel,
toggleSoundEnabled,
} = useHeaderVm()
const actionButtonClassName =
'common-neon-inset flex h-design-19 shrink-0 cursor-pointer items-center justify-center gap-design-5 !rounded-[3px] !px-design-5 !py-0 text-design-7 leading-none transition-opacity hover:opacity-85'
const accountButtonClassName =
'common-neon-inset flex h-design-19 items-center justify-end !rounded-[3px] !py-0 text-design-7 leading-none transition-[opacity,transform] duration-150 group-hover:opacity-90 group-active:scale-[0.98]'
return (
<header className="sticky top-0 z-30 h-design-62">
<div className="border-b-2 border-[#787553] bg-[#020B14]] bg-[#020B14] flex h-design-33 w-full items-center">
<div className="flex h-design-23 w-design-130 shrink-0 items-center justify-center border-r border-[rgba(128,223,231,0.45)] px-design-10">
<SmartImage
src={logo}
alt="logo"
priority
className="h-full w-full"
imgClassName="object-contain"
/>
</div>
{authStatus === 'authenticated' ? (
<div className="flex h-full min-w-0 flex-1 items-center justify-end gap-design-7 px-design-9">
<button
type="button"
onClick={onOpenUserInfo}
className="group relative flex min-w-0 items-center justify-center transition-transform duration-150 hover:-translate-y-[1px] active:translate-y-[1px]"
>
<SmartImage
src={avatar}
alt="avatar"
priority
className="absolute left-0 z-20 h-design-25 w-design-25 rounded-full"
/>
<div
className={`${accountButtonClassName} w-design-92 pl-design-28 pr-design-6`}
>
<span className="truncate">
{currentUser?.username || '--'}
</span>
</div>
</button>
<button
type="button"
onClick={onOpenProcedures}
className="group relative flex min-w-0 items-center justify-center transition-transform duration-150 hover:-translate-y-[1px] active:translate-y-[1px]"
>
<SmartImage
src={diamond}
alt="diamond"
priority
className="absolute left-0 z-20 h-design-25 w-design-25"
/>
<div
className={`${accountButtonClassName} w-design-90 gap-design-4 pl-design-26 pr-design-4`}
>
<span className="min-w-0 truncate">
{currentUser?.coin || '--'}
</span>
{/*<div className="common-neon-inset flex h-design-15 w-design-15 shrink-0 items-center justify-center !rounded-[3px] !p-0">*/}
{/* <Plus*/}
{/* aria-hidden="true"*/}
{/* className="h-design-10 w-design-10 shrink-0"*/}
{/* color="#57B8BF"*/}
{/* strokeWidth={2.5}*/}
{/* />*/}
{/*</div>*/}
</div>
</button>
</div>
) : (
<div className="flex h-full min-w-0 flex-1 items-center justify-end gap-design-8 px-design-9">
<button
type="button"
className={`${actionButtonClassName} w-design-72`}
onClick={onOpenLogin}
>
<UserKey
className="h-design-8 w-design-8 shrink-0"
color="#57B8BF"
/>
<div className="min-w-0 truncate">
{t('gameDesktop.header.login')}
</div>
</button>
<button
type="button"
className={`${actionButtonClassName} w-design-78`}
onClick={onOpenRegister}
>
<UserRoundPlus
className="h-design-8 w-design-8 shrink-0"
color="#57B8BF"
/>
<div className="min-w-0 truncate">
{t('gameDesktop.header.register')}
</div>
</button>
</div>
)}
</div>
<div className={'w-full px-design-10 '}>
<div className="flex h-design-29 w-full items-center gap-design-5 my-design-5 rounded-sm border-[#0A353E] border-1">
<div className="flex h-design-19 w-design-43 shrink-0 items-center justify-center gap-design-5 !rounded-[3px] !px-design-6 !py-0">
<Wifi
aria-hidden="true"
color="currentColor"
strokeWidth={2.4}
className={`${signalPresentation.toneClassName} h-design-10 w-design-10 shrink-0`}
/>
<div
className={`${signalPresentation.toneClassName} whitespace-nowrap text-design-7 font-bold leading-none`}
>
{signalPresentation.latencyLabel}
<span className="pl-[1px] text-design-6">ms</span>
</div>
</div>
<div className="flex h-full w-design-66 shrink-0 flex-col items-start justify-center border-r border-[rgba(128,223,231,0.32)] pr-design-7 text-design-7 leading-none">
<div className="text-[#B4E4E9]">
{t('gameDesktop.header.systemTime')}
</div>
<div className="mt-design-3 whitespace-nowrap text-design-7 font-bold text-[#D2FCFF]">
{systemTimeLabel}
</div>
</div>
<button
type="button"
onClick={onOpenRules}
className={`${actionButtonClassName} !px-design-10`}
>
<Info className="h-design-8 w-design-8 shrink-0" color="#57B8BF" />
<div className="min-w-0 truncate">
{t('gameDesktop.header.rules')}
</div>
</button>
<button
type="button"
onClick={onOpenNotice}
className={`${actionButtonClassName} !px-design-10`}
>
<Mail className="h-design-8 w-design-8 shrink-0" color="#57B8BF" />
<div className="min-w-0 truncate">
{t('gameDesktop.header.message')}
</div>
</button>
<button
type="button"
onClick={toggleSoundEnabled}
className={`${actionButtonClassName} !px-design-10`}
>
{isSoundEnabled ? (
<Volume2
className="h-design-8 w-design-8 shrink-0"
color="#57B8BF"
/>
) : (
<VolumeX
className="h-design-8 w-design-8 shrink-0"
color="#57B8BF"
/>
)}
<div className="min-w-0 truncate">
{t('gameDesktop.header.bgm')}
</div>
</button>
<button
type="button"
onClick={onOpenLanguage}
className={`${actionButtonClassName} !px-design-10 justify-between`}
>
<SmartImage
src={currentLanguageOption.icon}
alt={currentLanguageLabel}
className="h-design-14 w-design-14 shrink-0 rounded-full"
imgClassName="object-cover"
/>
<div className="min-w-0 truncate">{currentLanguageLabel}</div>
</button>
</div>
</div>
</header>
)
}