146 lines
4.1 KiB
React
146 lines
4.1 KiB
React
import { useState } from 'react';
|
||
import { useNavigate } from 'react-router-dom';
|
||
import { GlassCard, GlassInput, GlassButton } from '../components/ui';
|
||
import useStore from '../store/useStore';
|
||
import useCountdown from '../hooks/useCountdown';
|
||
|
||
/**
|
||
* LoginPage 组件
|
||
* 登录页面,包含手机号和验证码输入
|
||
*/
|
||
const LoginPage = () => {
|
||
const navigate = useNavigate();
|
||
const { login, getSmsCode, setLogin, loading } = useStore();
|
||
|
||
// 表单状态
|
||
const [phone, setPhone] = useState('');
|
||
const [code, setCode] = useState('');
|
||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||
|
||
// 倒计时
|
||
const { countdown, isActive, start } = useCountdown(60);
|
||
|
||
/**
|
||
* 处理获取验证码
|
||
*/
|
||
const handleGetCode = async () => {
|
||
if (phone.length !== 11) {
|
||
alert('请输入正确的手机号');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
start();
|
||
// 调用后端获取验证码
|
||
await getSmsCode(phone);
|
||
alert('验证码已发送');
|
||
} catch (error) {
|
||
// 后端不可用时,使用模拟验证码
|
||
alert('验证码已发送 (模拟验证码: 888888)');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 处理登录提交
|
||
*/
|
||
const handleSubmit = async () => {
|
||
if (phone.length !== 11) {
|
||
alert('请输入正确的手机号');
|
||
return;
|
||
}
|
||
if (code.length !== 6) {
|
||
alert('请输入6位验证码');
|
||
return;
|
||
}
|
||
|
||
setIsSubmitting(true);
|
||
|
||
try {
|
||
// 尝试调用后端登录
|
||
await login(phone, code);
|
||
navigate('/onboarding');
|
||
} catch (error) {
|
||
// 后端不可用时,使用本地验证
|
||
if (code === '888888') {
|
||
setLogin(true, phone);
|
||
navigate('/onboarding');
|
||
} else {
|
||
alert('验证失败,请检查手机号或验证码');
|
||
}
|
||
} finally {
|
||
setIsSubmitting(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="w-full h-full flex items-center justify-center p-6 animate-fade-in">
|
||
<GlassCard className="max-w-md w-full space-y-8 border-white/5 shadow-2xl" padding="lg">
|
||
{/* 标题区域 */}
|
||
<div className="text-center space-y-2">
|
||
<h2 className="text-3xl font-serif tracking-wider text-white/90">
|
||
欢迎回来
|
||
</h2>
|
||
<p className="text-sm text-white/40 italic">
|
||
开启你的数字生命档案
|
||
</p>
|
||
</div>
|
||
|
||
{/* 表单区域 */}
|
||
<div className="space-y-4">
|
||
{/* 手机号输入 */}
|
||
<GlassInput
|
||
label="手机号码"
|
||
type="tel"
|
||
placeholder="输入手机号"
|
||
value={phone}
|
||
onChange={setPhone}
|
||
maxLength={11}
|
||
className="text-center tracking-[0.1em]"
|
||
/>
|
||
|
||
{/* 验证码输入 */}
|
||
<div className="grid grid-cols-3 gap-3">
|
||
<div className="col-span-2">
|
||
<GlassInput
|
||
label="验证码"
|
||
type="text"
|
||
placeholder="六位验证码"
|
||
value={code}
|
||
onChange={setCode}
|
||
maxLength={6}
|
||
className="text-center"
|
||
/>
|
||
</div>
|
||
<div className="flex items-end">
|
||
<button
|
||
onClick={handleGetCode}
|
||
disabled={isActive || loading}
|
||
className="w-full h-[46px] rounded-2xl border border-white/5 bg-white/5 text-[10px] uppercase tracking-tighter hover:bg-white/10 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
|
||
>
|
||
{isActive ? `${countdown}S` : '获取'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 登录按钮 */}
|
||
<GlassButton
|
||
variant="primary"
|
||
onClick={handleSubmit}
|
||
loading={isSubmitting || loading}
|
||
className="w-full"
|
||
>
|
||
开启旅程
|
||
</GlassButton>
|
||
|
||
{/* 协议文字 */}
|
||
<p className="text-[10px] text-center text-white/20 px-4 leading-relaxed">
|
||
登录即代表同意《用户协议》与《隐私政策》,我们将妥善保管您的生命数据。
|
||
</p>
|
||
</GlassCard>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default LoginPage;
|