blob: fe1b42bd67efa1261c01b43942889e42cb754fb5 [file] [log] [blame]
Krishya57cc17b2025-05-26 16:43:34 +08001import { useState } from "react";
2import { Link } from "wouter";
3import "./AuthPage.css";
Krishya7096ab12025-06-05 17:15:46 +08004import logo from '../../assets/logo.png';
Krishya2283d882025-05-27 22:25:19 +08005
Krishya57cc17b2025-05-26 16:43:34 +08006function AuthPage() {
7 const [activeTab, setActiveTab] = useState("login");
8
9 // Login form state
10 const [loginData, setLoginData] = useState({
11 username: "",
12 password: "",
13 rememberMe: false,
14 });
15
16 // Register form state
17 const [registerData, setRegisterData] = useState({
18 username: "",
19 email: "",
20 password: "",
21 confirmPassword: "",
22 inviteCode: "",
Krishya57cc17b2025-05-26 16:43:34 +080023 });
24
25 // Form errors
26 const [errors, setErrors] = useState({
27 login: {},
28 register: {},
29 });
30
Krishya57cc17b2025-05-26 16:43:34 +080031 // Handle login form submission
32 const handleLogin = async (e) => {
Krishyaf66d9592025-06-03 17:41:05 +080033 e.preventDefault();
Krishya57cc17b2025-05-26 16:43:34 +080034
Krishyaf66d9592025-06-03 17:41:05 +080035 const newErrors = {};
36 if (!loginData.username) {
Krishya7096ab12025-06-05 17:15:46 +080037 newErrors.username = "请输入用户名";
Krishyaf66d9592025-06-03 17:41:05 +080038 }
39 if (!loginData.password) {
40 newErrors.password = "请输入密码";
41 }
42
43 if (Object.keys(newErrors).length > 0) {
44 setErrors((prev) => ({ ...prev, login: newErrors }));
45 return;
46 }
47
48 try {
49 const response = await fetch("/echo/user/login", {
50 method: 'POST',
51 headers: {
52 'Content-Type': 'application/json',
53 },
54 body: JSON.stringify({
55 username: loginData.username,
56 password: loginData.password,
57 }),
58 });
59
60 const data = await response.json();
61
62 if (data.msg === "登录成功" && data.user) {
63 // 保存用户信息到 localStorage
64 localStorage.setItem("user", JSON.stringify(data.user));
Krishya8f2fec82025-06-04 21:54:46 +080065 localStorage.setItem("userId", data.user.userId); // 如果有 id 字段
Krishya51f611d2025-06-04 22:25:58 +080066 window.location.href = '/forum';
Krishyaf66d9592025-06-03 17:41:05 +080067 } else {
68 throw new Error(data.msg || "登录失败");
Krishya57cc17b2025-05-26 16:43:34 +080069 }
Krishyaf66d9592025-06-03 17:41:05 +080070 } catch (error) {
71 console.error('登录错误:', error.message);
72 setErrors((prev) => ({
73 ...prev,
74 login: { message: error.message },
75 }));
76 }
77};
Krishya57cc17b2025-05-26 16:43:34 +080078
Krishya57cc17b2025-05-26 16:43:34 +080079
80 // Handle register form submission
81 const handleRegister = async (e) => {
Krishyaf66d9592025-06-03 17:41:05 +080082 e.preventDefault();
Krishya57cc17b2025-05-26 16:43:34 +080083
Krishyaf66d9592025-06-03 17:41:05 +080084 const newErrors = {};
85 if (!registerData.username) {
86 newErrors.username = "请输入用户名";
87 }
88 if (!registerData.email) {
89 newErrors.email = "请输入邮箱";
90 } else if (!/\S+@\S+\.\S+/.test(registerData.email)) {
91 newErrors.email = "邮箱格式不正确";
92 }
93 if (!registerData.password) {
94 newErrors.password = "请输入密码";
95 } else if (registerData.password.length < 6) {
96 newErrors.password = "密码长度至少为6位";
97 }
98 if (registerData.password !== registerData.confirmPassword) {
99 newErrors.confirmPassword = "两次输入的密码不一致";
100 }
Krishya57cc17b2025-05-26 16:43:34 +0800101
Krishyaf66d9592025-06-03 17:41:05 +0800102 if (Object.keys(newErrors).length > 0) {
103 setErrors((prev) => ({ ...prev, register: newErrors }));
104 return;
105 }
106
Krishyaf66d9592025-06-03 17:41:05 +0800107 try {
108 const response = await fetch("/echo/user/register", {
109 method: 'POST',
110 headers: {
111 'Content-Type': 'application/json',
112 },
113 body: JSON.stringify({
114 username: registerData.username,
115 email: registerData.email,
Krishya7096ab12025-06-05 17:15:46 +0800116 password: registerData.password, // 原始密码
117 role: "user",
Krishyaf66d9592025-06-03 17:41:05 +0800118 inviteCode: registerData.inviteCode,
119 }),
120 });
121
122 const data = await response.json();
123
124 if (data.msg === "注册成功") {
125 alert("注册成功,请登录!");
126 setActiveTab("login");
127 } else {
128 throw new Error(data.msg || "注册失败");
Krishya57cc17b2025-05-26 16:43:34 +0800129 }
Krishyaf66d9592025-06-03 17:41:05 +0800130 } catch (error) {
131 console.error("注册错误:", error.message);
132 setErrors((prev) => ({
133 ...prev,
134 register: { message: error.message },
135 }));
136 }
137};
Krishya57cc17b2025-05-26 16:43:34 +0800138
Krishya57cc17b2025-05-26 16:43:34 +0800139
Krishya7096ab12025-06-05 17:15:46 +0800140
Krishya57cc17b2025-05-26 16:43:34 +0800141 // Update login form data
142 const updateLoginData = (field, value) => {
143 setLoginData({
144 ...loginData,
145 [field]: value,
146 });
147 };
148
149 // Update register form data
150 const updateRegisterData = (field, value) => {
151 setRegisterData({
152 ...registerData,
153 [field]: value,
154 });
155 };
Krishya75e43c02025-04-05 21:16:30 +0800156
157 return (
Krishya57cc17b2025-05-26 16:43:34 +0800158 <div className="auth-container">
Krishya7096ab12025-06-05 17:15:46 +0800159 <div className="logo-container">
160 <img src={logo} alt="Logo" className="site-logo" />
161 </div>
162
Krishya57cc17b2025-05-26 16:43:34 +0800163 <div className="auth-card">
164 <div className="auth-header">
165 <div className={`auth-tab ${activeTab === "login" ? "active" : ""}`} onClick={() => setActiveTab("login")}>
166 登录
167 </div>
168 <div className={`auth-tab ${activeTab === "register" ? "active" : ""}`} onClick={() => setActiveTab("register")}>
169 注册
170 </div>
Krishyaf66d9592025-06-03 17:41:05 +0800171
Krishya57cc17b2025-05-26 16:43:34 +0800172 </div>
173
174 <div className="auth-content">
175 {activeTab === "login" ? (
176 <form className="auth-form" onSubmit={handleLogin}>
177 {errors.login.message && <div className="error-message">{errors.login.message}</div>}
178 <div className="form-group">
Krishya7096ab12025-06-05 17:15:46 +0800179 <label htmlFor="login-username">用户名</label>
Krishya57cc17b2025-05-26 16:43:34 +0800180 <input
181 type="text"
182 id="login-username"
183 value={loginData.username}
184 onChange={(e) => updateLoginData("username", e.target.value)}
Krishya7096ab12025-06-05 17:15:46 +0800185 placeholder="请输入用户名"
Krishya57cc17b2025-05-26 16:43:34 +0800186 required
187 />
188 {errors.login.username && <div className="error-message">{errors.login.username}</div>}
189 </div>
190
191 <div className="form-group">
192 <label htmlFor="login-password">密码</label>
193 <input
194 type="password"
195 id="login-password"
196 value={loginData.password}
197 onChange={(e) => updateLoginData("password", e.target.value)}
198 placeholder="请输入密码"
199 required
200 />
201 {errors.login.password && <div className="error-message">{errors.login.password}</div>}
202 </div>
203
204 <div className="form-group-inline">
205 <div className="checkbox-container">
Krishya7096ab12025-06-05 17:15:46 +0800206 {/* <input
Krishya57cc17b2025-05-26 16:43:34 +0800207 type="checkbox"
208 id="remember-me"
209 checked={loginData.rememberMe}
210 onChange={(e) => updateLoginData("rememberMe", e.target.checked)}
Krishya7096ab12025-06-05 17:15:46 +0800211 /> */}
212 {/* <label htmlFor="remember-me">记住我</label> */}
Krishya57cc17b2025-05-26 16:43:34 +0800213 </div>
214 <Link to="/forgot-password" className="forgot-password">
215 忘记密码?
216 </Link>
217 </div>
218
219 <button type="submit" className="auth-button">
220 登录
221 </button>
222 </form>
223 ) : (
224 <form className="auth-form" onSubmit={handleRegister}>
225 {errors.register.message && <div className="error-message">{errors.register.message}</div>}
226 <div className="form-group">
227 <label htmlFor="register-username">用户名</label>
228 <input
229 type="text"
230 id="register-username"
231 value={registerData.username}
232 onChange={(e) => updateRegisterData("username", e.target.value)}
233 placeholder="请输入用户名"
234 required
235 />
236 {errors.register.username && <div className="error-message">{errors.register.username}</div>}
237 </div>
238
239 <div className="form-group">
240 <label htmlFor="register-email">邮箱</label>
241 <input
242 type="email"
243 id="register-email"
244 value={registerData.email}
245 onChange={(e) => updateRegisterData("email", e.target.value)}
246 placeholder="请输入邮箱"
247 required
248 />
249 {errors.register.email && <div className="error-message">{errors.register.email}</div>}
250 </div>
251
252 <div className="form-group">
253 <label htmlFor="register-password">密码</label>
254 <input
255 type="password"
256 id="register-password"
257 value={registerData.password}
258 onChange={(e) => updateRegisterData("password", e.target.value)}
259 placeholder="请输入密码"
260 required
261 />
262 {errors.register.password && <div className="error-message">{errors.register.password}</div>}
263 </div>
264
265 <div className="form-group">
266 <label htmlFor="register-confirm-password">确认密码</label>
267 <input
268 type="password"
269 id="register-confirm-password"
270 value={registerData.confirmPassword}
271 onChange={(e) => updateRegisterData("confirmPassword", e.target.value)}
272 placeholder="请再次输入密码"
273 required
274 />
275 {errors.register.confirmPassword && (
276 <div className="error-message">{errors.register.confirmPassword}</div>
277 )}
278 </div>
279
280 <div className="form-group">
281 <label htmlFor="register-inviteCode">邀请码</label>
282 <input
283 type="text"
284 id="register-inviteCode"
285 value={registerData.inviteCode}
286 onChange={(e) => updateRegisterData("inviteCode", e.target.value)}
287 placeholder="请输入邀请码"
288 />
289 {errors.register.inviteCode && <div className="error-message">{errors.register.inviteCode}</div>}
290 </div>
291
292 <button type="submit" className="auth-button">
293 注册
294 </button>
295 </form>
296 )}
297 </div>
298 </div>
Krishya75e43c02025-04-05 21:16:30 +0800299 </div>
300 );
Krishya57cc17b2025-05-26 16:43:34 +0800301}
Krishya75e43c02025-04-05 21:16:30 +0800302
303export default AuthPage;