feat(auth): 添加登出功能并优化认证处理
- 添加了登出相关的API端点和常量定义 - 实现了登出功能及密码验证登出逻辑 - 添加了登出会话清理和浏览器存储清除 - 在用户信息模态框中集成了登出按钮 - 添加了登出相关的国际化翻译 - 优化了API客户端中的认证错误处理 - 实现了无效令牌的自动处理机制 - 更新了GitNexus索引统计数据 - 修改了构建输出目录配置 - 清理了不必要的注释和代码 - 调整了移动端头部组件结构 - 优化了游戏历史记录查询逻辑 - 添加了控制台日志用于调试 - 设置默认注册邀请码为D97DBC16 - 在.gitignore中添加构建产物忽略规则
This commit is contained in:
223
src/features/game/components/mobile/mobile-header.tsx
Normal file
223
src/features/game/components/mobile/mobile-header.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user