| import React, { useState } from 'react'; |
| import { useApi } from '@/hooks/request'; |
| import request from '@/utils/request'; |
| import { postUserLogin } from '@/api/auth'; |
| import { useAppDispatch } from '@/hooks/store'; |
| import style from './login.module.css'; |
| import { useNavigate } from 'react-router'; |
| import logo from '&/assets/logo.png'; |
| import { getUserInfo } from '@/api/user'; |
| import debounce from 'lodash/debounce'; |
| import { message } from 'antd'; |
| |
| const Login: React.FC = () => { |
| const [email, setEmail] = useState(''); |
| const [password, setPassword] = useState(''); |
| const [showRegister, setShowRegister] = useState(false); |
| const [inviteCode, setInviteCode] = useState(''); |
| const [registerEmail, setRegisterEmail] = useState(''); |
| const [registerPassword, setRegisterPassword] = useState(''); |
| const [emailCode, setEmailCode] = useState(''); |
| const [codeBtnDisabled, setCodeBtnDisabled] = useState(false); |
| const [codeBtnText, setCodeBtnText] = useState('发送验证码'); |
| const [codeTimer, setCodeTimer] = useState<NodeJS.Timeout | null>(null); |
| const [userName, setUserName] = useState(''); |
| |
| const dispatch = useAppDispatch(); |
| const [messageApi, contextHolder] = message.useMessage(); |
| const { refresh: postUserLoginRefresh } = useApi( |
| () => request.post(postUserLogin, { email, password}), false); |
| const { refresh: getUserInfoRefresh } = useApi( |
| () => request.get(getUserInfo), false); |
| const nav = useNavigate(); |
| const showErrorMessage = async (msg: string) => { |
| messageApi.error(msg); |
| }; |
| |
| // 登录逻辑 |
| const handleLogin = debounce(async () => { |
| try { |
| const res =await postUserLoginRefresh({email, password}); |
| console.log("res", res); |
| if (res==null ||(res as any).error) { |
| alert('Login failed. Please check your credentials.'); |
| return; |
| } |
| dispatch({ type: "user/login", payload: res }); |
| |
| const userInfo = await getUserInfoRefresh(); |
| if (userInfo == null || (userInfo as any).error) { |
| throw new Error('获取用户信息失败'); |
| } |
| |
| dispatch({ type: "user/getUserInfo", payload: userInfo.userInfo }); |
| |
| //设置宠物初始化参数 |
| localStorage.setItem('petState', JSON.stringify({ |
| mood: 30, |
| hunger: 50, |
| timestamp: Date.now() |
| })); |
| |
| nav('/'); |
| } catch (error) { |
| showErrorMessage('登录失败,请检查您的用户名和密码'); |
| } |
| }, 1000) as () => void; |
| |
| // 发送验证码逻辑 |
| const handleSendCode = async () => { |
| if (!registerEmail) { |
| showErrorMessage('请填写邮箱'); |
| return; |
| } |
| setCodeBtnDisabled(true); |
| let seconds = 60; |
| setCodeBtnText(`已发送(${seconds}s)`); |
| const timer = setInterval(() => { |
| seconds -= 1; |
| setCodeBtnText(`已发送(${seconds}s)`); |
| if (seconds <= 0) { |
| clearInterval(timer); |
| setCodeBtnDisabled(false); |
| setCodeBtnText('发送验证码'); |
| } |
| }, 1000); |
| setCodeTimer(timer); |
| // TODO: 调用发送验证码接口 |
| message.success('验证码已发送'); |
| }; |
| |
| // 切换回登录 |
| const handleBackToLogin = () => { |
| setShowRegister(false); |
| setInviteCode(''); |
| setRegisterEmail(''); |
| setRegisterPassword(''); |
| setEmailCode(''); |
| if (codeTimer) clearInterval(codeTimer); |
| setCodeBtnDisabled(false); |
| setCodeBtnText('发送验证码'); |
| }; |
| |
| // 注册逻辑(仅前端校验,实际应调用注册接口) |
| const handleRegister = async () => { |
| if (!inviteCode || !registerEmail || !registerPassword || !emailCode) { |
| showErrorMessage('请填写完整信息'); |
| return; |
| } |
| // TODO: 调用注册接口 |
| message.success('注册成功,请登录'); |
| handleBackToLogin(); |
| }; |
| |
| const handleLogoClick = () => { |
| nav('/'); |
| }; |
| |
| return ( |
| <div className={style.form}> |
| {contextHolder} |
| <img className={style.logo} src={logo} alt="logo" onClick={handleLogoClick} /> |
| {!showRegister ? ( |
| <> |
| <input |
| type="email" |
| value={email} |
| onChange={(e) => setEmail(e.target.value)} |
| className={style.email} |
| placeholder="Enter your email" |
| /> |
| <input |
| type="password" |
| value={password} |
| onChange={(e) => setPassword(e.target.value)} |
| className={style.password} |
| placeholder="Enter your password" |
| /> |
| <button className={style.submit} onClick={() => handleLogin()}>登录</button> |
| <button className={style.register} onClick={() => setShowRegister(true)}>注册</button> |
| <button className={style.forget}>忘记密码</button> |
| </> |
| ) : ( |
| <> |
| <input |
| type='text' |
| value={userName} |
| onChange={(e)=>setUserName(e.target.value)} |
| className={style.invite} |
| placeholder="用户名" |
| /> |
| <input |
| type="text" |
| value={inviteCode} |
| onChange={(e) => setInviteCode(e.target.value)} |
| className={style.invite} |
| placeholder="邀请码" |
| /> |
| <input |
| type="email" |
| value={registerEmail} |
| onChange={(e) => setRegisterEmail(e.target.value)} |
| className={style.email} |
| placeholder="邮箱" |
| /> |
| <input |
| type="password" |
| value={registerPassword} |
| onChange={(e) => setRegisterPassword(e.target.value)} |
| className={style.password} |
| placeholder="密码" |
| /> |
| <div style={{ display: 'flex',width:'80%', alignItems: 'center', gap: 8, padding:'10px' }}> |
| <input |
| type="text" |
| value={emailCode} |
| onChange={(e) => setEmailCode(e.target.value)} |
| className={style.code} |
| placeholder="邮箱验证码" |
| style={{ flex: 1 }} |
| /> |
| <button |
| className={style.sendCode} |
| onClick={handleSendCode} |
| disabled={codeBtnDisabled} |
| style={{ |
| background: codeBtnDisabled ? '#ccc' : undefined, |
| color: codeBtnDisabled ? '#888' : undefined, |
| cursor: codeBtnDisabled ? 'not-allowed' : 'pointer' |
| }} |
| > |
| {codeBtnText} |
| </button> |
| </div> |
| <button className={style.submit} onClick={handleRegister}>注册</button> |
| <button className={style.back} onClick={handleBackToLogin}>返回登录</button> |
| </> |
| )} |
| </div> |
| ); |
| }; |
| |
| export default Login; |