blob: 70b5573ecb99ffe916f51cdb35c84b79a65535b3 [file] [log] [blame]
San3yuan8166d1b2025-06-05 23:15:53 +08001import React, { useState } from 'react';
San3yuan6f2ed692025-04-16 20:24:49 +08002import { useApi } from '@/hooks/request';
3import request from '@/utils/request';
San3yuan8166d1b2025-06-05 23:15:53 +08004import { postUserLogin } from '@/api/auth';
San3yuan6f2ed692025-04-16 20:24:49 +08005import { useAppDispatch } from '@/hooks/store';
San3yuan6f2ed692025-04-16 20:24:49 +08006import style from './login.module.css';
San3yuan6f2ed692025-04-16 20:24:49 +08007import { useNavigate } from 'react-router';
San3yuan03ab0642025-04-29 18:00:25 +08008import logo from '&/assets/logo.png';
San3yuan6f2ed692025-04-16 20:24:49 +08009import { getUserInfo } from '@/api/user';
San3yuan03ab0642025-04-29 18:00:25 +080010import debounce from 'lodash/debounce';
San3yuan8166d1b2025-06-05 23:15:53 +080011import { message } from 'antd';
San3yuan6f2ed692025-04-16 20:24:49 +080012
13const Login: React.FC = () => {
14 const [email, setEmail] = useState('');
15 const [password, setPassword] = useState('');
San3yuan8166d1b2025-06-05 23:15:53 +080016 const [showRegister, setShowRegister] = useState(false);
17 const [inviteCode, setInviteCode] = useState('');
18 const [registerEmail, setRegisterEmail] = useState('');
19 const [registerPassword, setRegisterPassword] = useState('');
20 const [emailCode, setEmailCode] = useState('');
21 const [codeBtnDisabled, setCodeBtnDisabled] = useState(false);
22 const [codeBtnText, setCodeBtnText] = useState('发送验证码');
23 const [codeTimer, setCodeTimer] = useState<NodeJS.Timeout | null>(null);
San3yuan6f2ed692025-04-16 20:24:49 +080024
San3yuan8166d1b2025-06-05 23:15:53 +080025 const dispatch = useAppDispatch();
26 const [messageApi, contextHolder] = message.useMessage();
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080027 const { refresh: postUserLoginRefresh } = useApi(
28 () => request.post(postUserLogin, { email, password}), false);
29 const { refresh: getUserInfoRefresh } = useApi(
30 () => request.get(getUserInfo), false);
San3yuan6f2ed692025-04-16 20:24:49 +080031 const nav = useNavigate();
San3yuan8166d1b2025-06-05 23:15:53 +080032 const showErrorMessage = async (msg: string) => {
33 messageApi.error(msg);
San3yuana2ee30b2025-06-05 21:20:17 +080034 };
San3yuan8166d1b2025-06-05 23:15:53 +080035
36 // 登录逻辑
San3yuan03ab0642025-04-29 18:00:25 +080037 const handleLogin = debounce(async () => {
San3yuan6f2ed692025-04-16 20:24:49 +080038 try {
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080039 const res =await postUserLoginRefresh({email, password});
40 console.log("res", res);
San3yuan6f2ed692025-04-16 20:24:49 +080041 if (res==null ||(res as any).error) {
42 alert('Login failed. Please check your credentials.');
43 return;
44 }
45 dispatch({ type: "user/login", payload: res });
San3yuana2ee30b2025-06-05 21:20:17 +080046
San3yuan6f2ed692025-04-16 20:24:49 +080047 const userInfo = await getUserInfoRefresh();
San3yuana2ee30b2025-06-05 21:20:17 +080048 if (userInfo == null || (userInfo as any).error) {
49 throw new Error('获取用户信息失败');
San3yuan6f2ed692025-04-16 20:24:49 +080050 }
阳菜,放晴!2f987042025-06-08 14:54:50 +080051
52 dispatch({ type: "user/getUserInfo", payload: userInfo.userInfo });
53
54 //设置宠物初始化参数
55 localStorage.setItem('petState', JSON.stringify({
56 mood: 30,
57 hunger: 50,
58 timestamp: Date.now()
59 }));
60
San3yuan6f2ed692025-04-16 20:24:49 +080061 nav('/');
62 } catch (error) {
San3yuana2ee30b2025-06-05 21:20:17 +080063 showErrorMessage('登录失败,请检查您的用户名和密码');
San3yuan6f2ed692025-04-16 20:24:49 +080064 }
San3yuan03ab0642025-04-29 18:00:25 +080065 }, 1000) as () => void;
San3yuan6f2ed692025-04-16 20:24:49 +080066
San3yuan8166d1b2025-06-05 23:15:53 +080067 // 发送验证码逻辑
68 const handleSendCode = async () => {
69 if (!registerEmail) {
70 showErrorMessage('请填写邮箱');
71 return;
72 }
73 setCodeBtnDisabled(true);
74 let seconds = 60;
75 setCodeBtnText(`已发送(${seconds}s)`);
76 const timer = setInterval(() => {
77 seconds -= 1;
78 setCodeBtnText(`已发送(${seconds}s)`);
79 if (seconds <= 0) {
80 clearInterval(timer);
81 setCodeBtnDisabled(false);
82 setCodeBtnText('发送验证码');
83 }
84 }, 1000);
85 setCodeTimer(timer);
86 // TODO: 调用发送验证码接口
87 message.success('验证码已发送');
88 };
89
90 // 切换回登录
91 const handleBackToLogin = () => {
92 setShowRegister(false);
93 setInviteCode('');
94 setRegisterEmail('');
95 setRegisterPassword('');
96 setEmailCode('');
97 if (codeTimer) clearInterval(codeTimer);
98 setCodeBtnDisabled(false);
99 setCodeBtnText('发送验证码');
100 };
101
102 // 注册逻辑(仅前端校验,实际应调用注册接口)
103 const handleRegister = async () => {
104 if (!inviteCode || !registerEmail || !registerPassword || !emailCode) {
105 showErrorMessage('请填写完整信息');
106 return;
107 }
108 // TODO: 调用注册接口
109 message.success('注册成功,请登录');
110 handleBackToLogin();
111 };
112
San3yuan03ab0642025-04-29 18:00:25 +0800113 const handleLogoClick = () => {
114 nav('/');
San3yuan8166d1b2025-06-05 23:15:53 +0800115 };
116
San3yuan6f2ed692025-04-16 20:24:49 +0800117 return (
118 <div className={style.form}>
San3yuana2ee30b2025-06-05 21:20:17 +0800119 {contextHolder}
San3yuan8166d1b2025-06-05 23:15:53 +0800120 <img className={style.logo} src={logo} alt="logo" onClick={handleLogoClick} />
121 {!showRegister ? (
122 <>
123 <input
124 type="email"
125 value={email}
126 onChange={(e) => setEmail(e.target.value)}
127 className={style.email}
128 placeholder="Enter your email"
129 />
130 <input
131 type="password"
132 value={password}
133 onChange={(e) => setPassword(e.target.value)}
134 className={style.password}
135 placeholder="Enter your password"
136 />
137 <button className={style.submit} onClick={() => handleLogin()}>登录</button>
138 <button className={style.register} onClick={() => setShowRegister(true)}>注册</button>
139 <button className={style.forget}>忘记密码</button>
140 </>
141 ) : (
142 <>
143 <input
144 type="text"
145 value={inviteCode}
146 onChange={(e) => setInviteCode(e.target.value)}
147 className={style.invite}
148 placeholder="邀请码"
149 />
150 <input
151 type="email"
152 value={registerEmail}
153 onChange={(e) => setRegisterEmail(e.target.value)}
154 className={style.email}
155 placeholder="邮箱"
156 />
157 <input
158 type="password"
159 value={registerPassword}
160 onChange={(e) => setRegisterPassword(e.target.value)}
161 className={style.password}
162 placeholder="密码"
163 />
164 <div style={{ display: 'flex',width:'80%', alignItems: 'center', gap: 8, padding:'10px' }}>
165 <input
166 type="text"
167 value={emailCode}
168 onChange={(e) => setEmailCode(e.target.value)}
169 className={style.code}
170 placeholder="邮箱验证码"
171 style={{ flex: 1 }}
172 />
173 <button
174 className={style.sendCode}
175 onClick={handleSendCode}
176 disabled={codeBtnDisabled}
177 style={{
178 background: codeBtnDisabled ? '#ccc' : undefined,
179 color: codeBtnDisabled ? '#888' : undefined,
180 cursor: codeBtnDisabled ? 'not-allowed' : 'pointer'
181 }}
182 >
183 {codeBtnText}
184 </button>
185 </div>
186 <button className={style.submit} onClick={handleRegister}>注册</button>
187 <button className={style.back} onClick={handleBackToLogin}>返回登录</button>
188 </>
189 )}
San3yuan6f2ed692025-04-16 20:24:49 +0800190 </div>
191 );
192};
193
194export default Login;