blob: e135e970639609f726f9abe496e63f0a4a8640f9 [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';
阳菜,放晴!f1325762025-06-09 22:44:30 +080012import { postUserRegister } from '@/api/auth'
13import { sendVerificationCode } from '@/api/auth'
San3yuan6f2ed692025-04-16 20:24:49 +080014
15const Login: React.FC = () => {
16 const [email, setEmail] = useState('');
17 const [password, setPassword] = useState('');
San3yuan8166d1b2025-06-05 23:15:53 +080018 const [showRegister, setShowRegister] = useState(false);
19 const [inviteCode, setInviteCode] = useState('');
20 const [registerEmail, setRegisterEmail] = useState('');
21 const [registerPassword, setRegisterPassword] = useState('');
22 const [emailCode, setEmailCode] = useState('');
23 const [codeBtnDisabled, setCodeBtnDisabled] = useState(false);
24 const [codeBtnText, setCodeBtnText] = useState('发送验证码');
25 const [codeTimer, setCodeTimer] = useState<NodeJS.Timeout | null>(null);
San3yuan292794c2025-06-08 20:02:46 +080026 const [userName, setUserName] = useState('');
San3yuan6f2ed692025-04-16 20:24:49 +080027
San3yuan8166d1b2025-06-05 23:15:53 +080028 const dispatch = useAppDispatch();
29 const [messageApi, contextHolder] = message.useMessage();
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080030 const { refresh: postUserLoginRefresh } = useApi(
31 () => request.post(postUserLogin, { email, password}), false);
32 const { refresh: getUserInfoRefresh } = useApi(
33 () => request.get(getUserInfo), false);
San3yuan6f2ed692025-04-16 20:24:49 +080034 const nav = useNavigate();
San3yuan8166d1b2025-06-05 23:15:53 +080035 const showErrorMessage = async (msg: string) => {
36 messageApi.error(msg);
San3yuana2ee30b2025-06-05 21:20:17 +080037 };
San3yuan8166d1b2025-06-05 23:15:53 +080038
39 // 登录逻辑
San3yuan03ab0642025-04-29 18:00:25 +080040 const handleLogin = debounce(async () => {
San3yuan6f2ed692025-04-16 20:24:49 +080041 try {
阳菜,放晴!7e1e3a52025-06-05 23:00:51 +080042 const res =await postUserLoginRefresh({email, password});
43 console.log("res", res);
San3yuan6f2ed692025-04-16 20:24:49 +080044 if (res==null ||(res as any).error) {
45 alert('Login failed. Please check your credentials.');
46 return;
47 }
48 dispatch({ type: "user/login", payload: res });
San3yuana2ee30b2025-06-05 21:20:17 +080049
San3yuan6f2ed692025-04-16 20:24:49 +080050 const userInfo = await getUserInfoRefresh();
San3yuana2ee30b2025-06-05 21:20:17 +080051 if (userInfo == null || (userInfo as any).error) {
52 throw new Error('获取用户信息失败');
San3yuan6f2ed692025-04-16 20:24:49 +080053 }
阳菜,放晴!2f987042025-06-08 14:54:50 +080054
55 dispatch({ type: "user/getUserInfo", payload: userInfo.userInfo });
56
57 //设置宠物初始化参数
58 localStorage.setItem('petState', JSON.stringify({
59 mood: 30,
60 hunger: 50,
61 timestamp: Date.now()
62 }));
63
San3yuan6f2ed692025-04-16 20:24:49 +080064 nav('/');
65 } catch (error) {
San3yuana2ee30b2025-06-05 21:20:17 +080066 showErrorMessage('登录失败,请检查您的用户名和密码');
San3yuan6f2ed692025-04-16 20:24:49 +080067 }
San3yuan03ab0642025-04-29 18:00:25 +080068 }, 1000) as () => void;
San3yuan6f2ed692025-04-16 20:24:49 +080069
San3yuan8166d1b2025-06-05 23:15:53 +080070 // 发送验证码逻辑
71 const handleSendCode = async () => {
72 if (!registerEmail) {
73 showErrorMessage('请填写邮箱');
74 return;
75 }
76 setCodeBtnDisabled(true);
77 let seconds = 60;
78 setCodeBtnText(`已发送(${seconds}s)`);
79 const timer = setInterval(() => {
80 seconds -= 1;
81 setCodeBtnText(`已发送(${seconds}s)`);
82 if (seconds <= 0) {
83 clearInterval(timer);
84 setCodeBtnDisabled(false);
85 setCodeBtnText('发送验证码');
86 }
87 }, 1000);
88 setCodeTimer(timer);
阳菜,放晴!f1325762025-06-09 22:44:30 +080089
San3yuan8166d1b2025-06-05 23:15:53 +080090 // TODO: 调用发送验证码接口
阳菜,放晴!f1325762025-06-09 22:44:30 +080091 const bodyData = {
92 email:registerEmail,
93 }
94
95 const res = await request.post(sendVerificationCode, bodyData);
96 console.log("res", res);
San3yuan8166d1b2025-06-05 23:15:53 +080097 message.success('验证码已发送');
98 };
99
100 // 切换回登录
101 const handleBackToLogin = () => {
102 setShowRegister(false);
103 setInviteCode('');
104 setRegisterEmail('');
105 setRegisterPassword('');
106 setEmailCode('');
107 if (codeTimer) clearInterval(codeTimer);
108 setCodeBtnDisabled(false);
109 setCodeBtnText('发送验证码');
110 };
111
112 // 注册逻辑(仅前端校验,实际应调用注册接口)
113 const handleRegister = async () => {
114 if (!inviteCode || !registerEmail || !registerPassword || !emailCode) {
115 showErrorMessage('请填写完整信息');
116 return;
117 }
118 // TODO: 调用注册接口
阳菜,放晴!f1325762025-06-09 22:44:30 +0800119
120 const sendData = {
121 userName,
122 password:registerPassword,
123 email:registerEmail,
124 verificationCode: emailCode,
125 invitationCode:inviteCode,
126 }
127
128 const res = await request.post(postUserRegister, sendData);
129 console.log("res", res);
130
San3yuan8166d1b2025-06-05 23:15:53 +0800131 message.success('注册成功,请登录');
132 handleBackToLogin();
133 };
134
San3yuan03ab0642025-04-29 18:00:25 +0800135 const handleLogoClick = () => {
136 nav('/');
San3yuan8166d1b2025-06-05 23:15:53 +0800137 };
138
San3yuan6f2ed692025-04-16 20:24:49 +0800139 return (
140 <div className={style.form}>
San3yuana2ee30b2025-06-05 21:20:17 +0800141 {contextHolder}
San3yuan8166d1b2025-06-05 23:15:53 +0800142 <img className={style.logo} src={logo} alt="logo" onClick={handleLogoClick} />
143 {!showRegister ? (
144 <>
145 <input
146 type="email"
147 value={email}
148 onChange={(e) => setEmail(e.target.value)}
149 className={style.email}
150 placeholder="Enter your email"
151 />
152 <input
153 type="password"
154 value={password}
155 onChange={(e) => setPassword(e.target.value)}
156 className={style.password}
157 placeholder="Enter your password"
158 />
159 <button className={style.submit} onClick={() => handleLogin()}>登录</button>
160 <button className={style.register} onClick={() => setShowRegister(true)}>注册</button>
161 <button className={style.forget}>忘记密码</button>
162 </>
163 ) : (
164 <>
165 <input
San3yuan292794c2025-06-08 20:02:46 +0800166 type='text'
167 value={userName}
168 onChange={(e)=>setUserName(e.target.value)}
169 className={style.invite}
170 placeholder="用户名"
171 />
172 <input
San3yuan8166d1b2025-06-05 23:15:53 +0800173 type="text"
174 value={inviteCode}
175 onChange={(e) => setInviteCode(e.target.value)}
176 className={style.invite}
177 placeholder="邀请码"
178 />
179 <input
180 type="email"
181 value={registerEmail}
182 onChange={(e) => setRegisterEmail(e.target.value)}
183 className={style.email}
184 placeholder="邮箱"
185 />
186 <input
187 type="password"
188 value={registerPassword}
189 onChange={(e) => setRegisterPassword(e.target.value)}
190 className={style.password}
191 placeholder="密码"
192 />
193 <div style={{ display: 'flex',width:'80%', alignItems: 'center', gap: 8, padding:'10px' }}>
194 <input
195 type="text"
196 value={emailCode}
197 onChange={(e) => setEmailCode(e.target.value)}
198 className={style.code}
199 placeholder="邮箱验证码"
200 style={{ flex: 1 }}
201 />
202 <button
203 className={style.sendCode}
204 onClick={handleSendCode}
205 disabled={codeBtnDisabled}
206 style={{
207 background: codeBtnDisabled ? '#ccc' : undefined,
208 color: codeBtnDisabled ? '#888' : undefined,
209 cursor: codeBtnDisabled ? 'not-allowed' : 'pointer'
210 }}
211 >
212 {codeBtnText}
213 </button>
214 </div>
215 <button className={style.submit} onClick={handleRegister}>注册</button>
216 <button className={style.back} onClick={handleBackToLogin}>返回登录</button>
217 </>
218 )}
San3yuan6f2ed692025-04-16 20:24:49 +0800219 </div>
220 );
221};
222
223export default Login;