blob: fef6e321fb017a8ef657ca0a0168ffcab5df2615 [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 }
51 dispatch({ type: "user/getUserInfo", payload: userInfo });
52 nav('/');
53 } catch (error) {
San3yuana2ee30b2025-06-05 21:20:17 +080054 showErrorMessage('登录失败,请检查您的用户名和密码');
San3yuan6f2ed692025-04-16 20:24:49 +080055 }
San3yuan03ab0642025-04-29 18:00:25 +080056 }, 1000) as () => void;
San3yuan6f2ed692025-04-16 20:24:49 +080057
San3yuan8166d1b2025-06-05 23:15:53 +080058 // 发送验证码逻辑
59 const handleSendCode = async () => {
60 if (!registerEmail) {
61 showErrorMessage('请填写邮箱');
62 return;
63 }
64 setCodeBtnDisabled(true);
65 let seconds = 60;
66 setCodeBtnText(`已发送(${seconds}s)`);
67 const timer = setInterval(() => {
68 seconds -= 1;
69 setCodeBtnText(`已发送(${seconds}s)`);
70 if (seconds <= 0) {
71 clearInterval(timer);
72 setCodeBtnDisabled(false);
73 setCodeBtnText('发送验证码');
74 }
75 }, 1000);
76 setCodeTimer(timer);
77 // TODO: 调用发送验证码接口
78 message.success('验证码已发送');
79 };
80
81 // 切换回登录
82 const handleBackToLogin = () => {
83 setShowRegister(false);
84 setInviteCode('');
85 setRegisterEmail('');
86 setRegisterPassword('');
87 setEmailCode('');
88 if (codeTimer) clearInterval(codeTimer);
89 setCodeBtnDisabled(false);
90 setCodeBtnText('发送验证码');
91 };
92
93 // 注册逻辑(仅前端校验,实际应调用注册接口)
94 const handleRegister = async () => {
95 if (!inviteCode || !registerEmail || !registerPassword || !emailCode) {
96 showErrorMessage('请填写完整信息');
97 return;
98 }
99 // TODO: 调用注册接口
100 message.success('注册成功,请登录');
101 handleBackToLogin();
102 };
103
San3yuan03ab0642025-04-29 18:00:25 +0800104 const handleLogoClick = () => {
105 nav('/');
San3yuan8166d1b2025-06-05 23:15:53 +0800106 };
107
San3yuan6f2ed692025-04-16 20:24:49 +0800108 return (
109 <div className={style.form}>
San3yuana2ee30b2025-06-05 21:20:17 +0800110 {contextHolder}
San3yuan8166d1b2025-06-05 23:15:53 +0800111 <img className={style.logo} src={logo} alt="logo" onClick={handleLogoClick} />
112 {!showRegister ? (
113 <>
114 <input
115 type="email"
116 value={email}
117 onChange={(e) => setEmail(e.target.value)}
118 className={style.email}
119 placeholder="Enter your email"
120 />
121 <input
122 type="password"
123 value={password}
124 onChange={(e) => setPassword(e.target.value)}
125 className={style.password}
126 placeholder="Enter your password"
127 />
128 <button className={style.submit} onClick={() => handleLogin()}>登录</button>
129 <button className={style.register} onClick={() => setShowRegister(true)}>注册</button>
130 <button className={style.forget}>忘记密码</button>
131 </>
132 ) : (
133 <>
134 <input
135 type="text"
136 value={inviteCode}
137 onChange={(e) => setInviteCode(e.target.value)}
138 className={style.invite}
139 placeholder="邀请码"
140 />
141 <input
142 type="email"
143 value={registerEmail}
144 onChange={(e) => setRegisterEmail(e.target.value)}
145 className={style.email}
146 placeholder="邮箱"
147 />
148 <input
149 type="password"
150 value={registerPassword}
151 onChange={(e) => setRegisterPassword(e.target.value)}
152 className={style.password}
153 placeholder="密码"
154 />
155 <div style={{ display: 'flex',width:'80%', alignItems: 'center', gap: 8, padding:'10px' }}>
156 <input
157 type="text"
158 value={emailCode}
159 onChange={(e) => setEmailCode(e.target.value)}
160 className={style.code}
161 placeholder="邮箱验证码"
162 style={{ flex: 1 }}
163 />
164 <button
165 className={style.sendCode}
166 onClick={handleSendCode}
167 disabled={codeBtnDisabled}
168 style={{
169 background: codeBtnDisabled ? '#ccc' : undefined,
170 color: codeBtnDisabled ? '#888' : undefined,
171 cursor: codeBtnDisabled ? 'not-allowed' : 'pointer'
172 }}
173 >
174 {codeBtnText}
175 </button>
176 </div>
177 <button className={style.submit} onClick={handleRegister}>注册</button>
178 <button className={style.back} onClick={handleBackToLogin}>返回登录</button>
179 </>
180 )}
San3yuan6f2ed692025-04-16 20:24:49 +0800181 </div>
182 );
183};
184
185export default Login;