146 lines
5.3 KiB
TypeScript
146 lines
5.3 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import Button from '../components/ui/Button';
|
|
import Input from '../components/ui/Input';
|
|
import Card from '../components/ui/Card';
|
|
import { useAuth } from '../hooks/useAuth';
|
|
import { useAuthStore } from '../stores/authStore';
|
|
import { getVipStatus, activateVip } from '../services/auth.api';
|
|
|
|
function callElectron(method: string) {
|
|
try { (window as any).electronAPI?.[method](); } catch {}
|
|
}
|
|
|
|
export default function Login() {
|
|
const navigate = useNavigate();
|
|
const { login } = useAuth();
|
|
const isLoggedIn = useAuthStore(s => s.isLoggedIn);
|
|
|
|
const [tab, setTab] = useState<'login' | 'register' | 'vip'>('login');
|
|
const [username, setUsername] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [email, setEmail] = useState('');
|
|
const [cardKey, setCardKey] = useState('');
|
|
const [loading, setLoading] = useState(false);
|
|
const [error, setError] = useState('');
|
|
|
|
const handleLogin = async () => {
|
|
setLoading(true); setError('');
|
|
try {
|
|
await login({
|
|
username, password,
|
|
installId: 'maqt-desktop',
|
|
deviceHash: 'maqt-desktop',
|
|
platform: navigator.platform || 'win32',
|
|
osVersion: navigator.userAgent || '',
|
|
appVersion: '7.0.4',
|
|
});
|
|
navigate('/');
|
|
} catch (e: any) {
|
|
setError(e.message || '登录失败');
|
|
} finally { setLoading(false); }
|
|
};
|
|
|
|
const handleActivateVip = async () => {
|
|
setLoading(true); setError('');
|
|
try {
|
|
await activateVip(cardKey);
|
|
const status = await getVipStatus();
|
|
if (status) navigate('/');
|
|
} catch (e: any) {
|
|
setError(e.message || '激活失败');
|
|
} finally { setLoading(false); }
|
|
};
|
|
|
|
return (
|
|
<div className="h-screen bg-[#1a1a1a] flex flex-col items-center justify-center p-6">
|
|
{/* 关闭按钮 */}
|
|
<button
|
|
onClick={() => callElectron('closeWindow')}
|
|
className="absolute top-3 right-3 text-[#555] hover:text-[#cc3300] text-[14px] px-2 py-1 border border-[#333] hover:border-[#cc3300] transition-colors duration-75"
|
|
>
|
|
✕
|
|
</button>
|
|
|
|
<div className="text-center mb-6">
|
|
<h1 className="text-[14px] font-bold tracking-[0.2em] uppercase text-[#e0e0e0]">码枪堂 2.0</h1>
|
|
<p className="text-[12px] font-mono text-[#555] mt-1">用户认证系统</p>
|
|
</div>
|
|
|
|
<Card className="w-full max-w-xs" serial="AUTH-01">
|
|
<div className="flex border-b border-[#333]">
|
|
{(['login', 'register', 'vip'] as const).map(t => (
|
|
<button
|
|
key={t}
|
|
onClick={() => setTab(t)}
|
|
className={`flex-1 py-2 text-[12px] font-semibold tracking-[0.12em] uppercase transition-colors duration-75
|
|
border-r border-[#333] last:border-r-0
|
|
${tab === t ? 'bg-[#ff4500]/10 text-[#ff4500]' : 'text-[#555] hover:text-[#888]'}`}
|
|
>
|
|
{t === 'login' ? '登录' : t === 'register' ? '注册' : 'VIP'}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
<div className="p-3 space-y-2.5">
|
|
{tab === 'vip' ? (
|
|
<>
|
|
<Input
|
|
placeholder="VIP 卡密"
|
|
value={cardKey}
|
|
onChange={e => setCardKey(e.target.value)}
|
|
style={{ borderRadius: 0, borderColor: '#333', background: '#111', color: '#e0e0e0', fontSize: 10 }}
|
|
/>
|
|
<Button variant="primary" size="sm" className="w-full text-[12px]" onClick={handleActivateVip} loading={loading}>
|
|
激活 VIP
|
|
</Button>
|
|
</>
|
|
) : (
|
|
<>
|
|
<Input
|
|
placeholder="用户名"
|
|
value={username}
|
|
onChange={e => setUsername(e.target.value)}
|
|
style={{ borderRadius: 0, borderColor: '#333', background: '#111', color: '#e0e0e0', fontSize: 10 }}
|
|
/>
|
|
<Input
|
|
type="password"
|
|
placeholder="密码"
|
|
value={password}
|
|
onChange={e => setPassword(e.target.value)}
|
|
style={{ borderRadius: 0, borderColor: '#333', background: '#111', color: '#e0e0e0', fontSize: 10 }}
|
|
/>
|
|
{tab === 'register' && (
|
|
<Input
|
|
placeholder="邮箱(可选)"
|
|
value={email}
|
|
onChange={e => setEmail(e.target.value)}
|
|
style={{ borderRadius: 0, borderColor: '#333', background: '#111', color: '#e0e0e0', fontSize: 10 }}
|
|
/>
|
|
)}
|
|
<Button variant="primary" size="sm" className="w-full text-[12px]" onClick={handleLogin} loading={loading}>
|
|
{tab === 'login' ? '登录' : '注册'}
|
|
</Button>
|
|
</>
|
|
)}
|
|
|
|
{error && (
|
|
<p className="text-[12px] font-mono text-[#cc3300] border border-[#cc3300]/30 p-1.5 bg-[#cc3300]/5">
|
|
✕ {error}
|
|
</p>
|
|
)}
|
|
|
|
<p className="text-[12px] font-mono text-[#444] text-center">SYS-AUTH v1.0</p>
|
|
</div>
|
|
</Card>
|
|
|
|
<button
|
|
onClick={() => navigate('/')}
|
|
className="mt-4 text-[12px] font-mono text-[#555] hover:text-[#888] transition-colors duration-75"
|
|
>
|
|
← 返回桌面
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|