blob: 902fbb728d0acbd1ba0daa6d6ee333531829f84c [file] [log] [blame]
Krishyac6b24832025-06-05 20:13:20 +08001// import React, { useEffect, useState } from 'react';
2// import axios from 'axios';
3// import './UserProfile.css';
4// import UserNav from './UserNav';
5// import Header from '../../components/Header';
6// import { useUser } from '../../context/UserContext';
7
8// const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
9
10// const UserProfile = () => {
11// const { user, loading } = useUser();
12// const [userProfile, setUserProfile] = useState(null);
13// const [error, setError] = useState(null);
14
15// useEffect(() => {
16// if (loading) return;
17// if (!user || !user.userId) {
18// setError('未登录或用户信息缺失');
19// setUserProfile(null);
20// return;
21// }
22
23// const fetchUserProfile = async () => {
24// try {
25// setError(null);
26// const { data: raw } = await axios.get(`/echo/user/${user.userId}/getProfile`);
27
28// if (!raw) {
29// setError('用户数据为空');
30// setUserProfile(null);
31// return;
32// }
33
34// const profile = {
35// avatarUrl: raw.avatarUrl
36// ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
37// : DEFAULT_AVATAR_URL,
38// nickname: raw.username || '未知用户',
39// email: raw.email || '未填写',
40// gender: raw.gender || '保密',
41// bio: raw.description || '无',
42// interests: raw.hobbies ? raw.hobbies.split(',') : [],
43// level: raw.level || '未知',
44// experience: raw.experience ?? 0,
45// uploadAmount: raw.uploadCount ?? 0,
46// downloadAmount: raw.downloadCount ?? 0,
47// shareRate: raw.shareRate ?? 0,
48// joinedDate: raw.registrationTime,
49// };
50
51// setUserProfile(profile);
52// } catch (err) {
53// setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
54// setUserProfile(null);
55// }
56// };
57
58// fetchUserProfile();
59// }, [user, loading]);
60
61// const handleAvatarUpload = async (e) => {
62// const file = e.target.files[0];
63// if (!file) return;
64
65// const formData = new FormData();
66// formData.append('file', file);
67
68// try {
69// const { data } = await axios.post(
70// `/echo/user/${user.userId}/uploadAvatar`,
71// formData,
72// { headers: { 'Content-Type': 'multipart/form-data' } }
73// );
74
75// if (data?.avatarUrl) {
76// setUserProfile((prev) => ({
77// ...prev,
78// avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
79// }));
80// alert('头像上传成功');
81// } else {
82// alert('头像上传成功,但未返回新头像地址');
83// }
84// } catch (err) {
85// console.error('上传失败:', err);
86// alert('头像上传失败,请重试');
87// }
88// };
89
90// if (loading) return <p>正在加载用户信息...</p>;
91// if (error) return <p className="error">{error}</p>;
92// if (!userProfile) return null;
93
94// const {
95// avatarUrl,
96// nickname,
97// email,
98// gender,
99// bio,
100// interests,
101// level,
102// experience,
103// uploadAmount,
104// downloadAmount,
105// shareRate,
106// joinedDate,
107// } = userProfile;
108
109// return (
110// <div className="user-profile-container">
111// <Header />
112// <div className="user-center">
113// <div className="user-nav-container">
114// <UserNav />
115// </div>
116// <div className="common-card">
117// <div className="right-content">
118// <div className="profile-header">
119// <div className="avatar-wrapper">
120// <img src={avatarUrl} alt={nickname} className="avatar" />
121// <label htmlFor="avatar-upload" className="avatar-upload-label">
122// 上传头像
123// </label>
124// <input
125// type="file"
126// id="avatar-upload"
127// accept="image/*"
128// style={{ display: 'none' }}
129// onChange={handleAvatarUpload}
130// />
131// </div>
132// <h1>{nickname}</h1>
133// </div>
134
135// <div className="profile-details">
136// <p><strong>邮箱:</strong>{email}</p>
137// <p><strong>性别:</strong>{gender}</p>
138// <p><strong>个人简介:</strong>{bio}</p>
139// <p><strong>兴趣:</strong>{interests.length > 0 ? interests.join(', ') : '无'}</p>
140// <p><strong>等级:</strong>{level}</p>
141// <p><strong>经验:</strong>{experience}</p>
142// <p><strong>上传量:</strong>{uploadAmount}</p>
143// <p><strong>下载量:</strong>{downloadAmount}</p>
144// <p><strong>分享率:</strong>{(shareRate * 100).toFixed(2)}%</p>
145// <p><strong>加入时间:</strong>{new Date(joinedDate).toLocaleDateString()}</p>
146// </div>
147// </div>
148// </div>
149// </div>
150// </div>
151// );
152// };
153
154// export default UserProfile;
155
2230100977253112025-04-15 21:30:39 +0800156import React, { useEffect, useState } from 'react';
157import axios from 'axios';
158import './UserProfile.css';
22301009df48f962025-06-05 13:40:44 +0800159import { useUser } from '../../context/UserContext';
160
161const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
2230100977253112025-04-15 21:30:39 +0800162
223010097ff51f22025-04-15 21:35:28 +0800163const UserProfile = () => {
22301009df48f962025-06-05 13:40:44 +0800164 const { user, loading } = useUser();
2230100977253112025-04-15 21:30:39 +0800165 const [userProfile, setUserProfile] = useState(null);
2230100977253112025-04-15 21:30:39 +0800166 const [error, setError] = useState(null);
167
2230100977253112025-04-15 21:30:39 +0800168 useEffect(() => {
22301009df48f962025-06-05 13:40:44 +0800169 if (loading) return;
2230100937ebec12025-06-03 21:17:04 +0800170 if (!user || !user.userId) {
171 setError('未登录或用户信息缺失');
172 setUserProfile(null);
173 return;
174 }
175
2230100977253112025-04-15 21:30:39 +0800176 const fetchUserProfile = async () => {
177 try {
2230100937ebec12025-06-03 21:17:04 +0800178 setError(null);
22301009df48f962025-06-05 13:40:44 +0800179 const { data: raw } = await axios.get(`/echo/user/${user.userId}/getProfile`);
2230100937ebec12025-06-03 21:17:04 +0800180
181 if (!raw) {
182 setError('用户数据为空');
183 setUserProfile(null);
184 return;
2230100977253112025-04-15 21:30:39 +0800185 }
2230100937ebec12025-06-03 21:17:04 +0800186
187 const profile = {
22301009df48f962025-06-05 13:40:44 +0800188 avatarUrl: raw.avatarUrl
189 ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
190 : DEFAULT_AVATAR_URL,
2230100937ebec12025-06-03 21:17:04 +0800191 nickname: raw.username || '未知用户',
192 email: raw.email || '未填写',
193 gender: raw.gender || '保密',
194 bio: raw.description || '无',
195 interests: raw.hobbies ? raw.hobbies.split(',') : [],
196 level: raw.level || '未知',
197 experience: raw.experience ?? 0,
22301009df48f962025-06-05 13:40:44 +0800198 uploadAmount: raw.uploadCount ?? 0,
199 downloadAmount: raw.downloadCount ?? 0,
200 shareRate: raw.shareRate ?? 0,
201 joinedDate: raw.registrationTime,
2230100937ebec12025-06-03 21:17:04 +0800202 };
203
204 setUserProfile(profile);
2230100977253112025-04-15 21:30:39 +0800205 } catch (err) {
22301009df48f962025-06-05 13:40:44 +0800206 setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
2230100937ebec12025-06-03 21:17:04 +0800207 setUserProfile(null);
2230100977253112025-04-15 21:30:39 +0800208 }
209 };
210
211 fetchUserProfile();
2230100937ebec12025-06-03 21:17:04 +0800212 }, [user, loading]);
2230100977253112025-04-15 21:30:39 +0800213
22301009df48f962025-06-05 13:40:44 +0800214 const handleAvatarUpload = async (e) => {
215 const file = e.target.files[0];
216 if (!file) return;
217
218 const formData = new FormData();
219 formData.append('file', file);
220
221 try {
222 const { data } = await axios.post(
223 `/echo/user/${user.userId}/uploadAvatar`,
224 formData,
225 { headers: { 'Content-Type': 'multipart/form-data' } }
226 );
227
228 if (data?.avatarUrl) {
229 setUserProfile((prev) => ({
230 ...prev,
231 avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
232 }));
233 alert('头像上传成功');
234 } else {
235 alert('头像上传成功,但未返回新头像地址');
236 }
237 } catch (err) {
238 console.error('上传失败:', err);
239 alert('头像上传失败,请重试');
240 }
241 };
242
2230100937ebec12025-06-03 21:17:04 +0800243 if (loading) return <p>正在加载用户信息...</p>;
244 if (error) return <p className="error">{error}</p>;
245 if (!userProfile) return null;
2230100977253112025-04-15 21:30:39 +0800246
22301009df48f962025-06-05 13:40:44 +0800247 const {
248 avatarUrl,
249 nickname,
250 email,
251 gender,
252 bio,
253 interests,
254 level,
255 experience,
256 uploadAmount,
257 downloadAmount,
258 shareRate,
259 joinedDate,
260 } = userProfile;
261
2230100977253112025-04-15 21:30:39 +0800262 return (
Krishyac6b24832025-06-05 20:13:20 +0800263 <div className="common-card">
264 <div className="right-content">
265 <div className="profile-header">
266 <div className="avatar-wrapper">
267 <img src={avatarUrl} alt={nickname} className="avatar" />
268 <label htmlFor="avatar-upload" className="avatar-upload-label">
269 上传头像
270 </label>
271 <input
272 type="file"
273 id="avatar-upload"
274 accept="image/*"
275 style={{ display: 'none' }}
276 onChange={handleAvatarUpload}
277 />
2230100937ebec12025-06-03 21:17:04 +0800278 </div>
Krishyac6b24832025-06-05 20:13:20 +0800279 <h1>{nickname}</h1>
280 </div>
281
282 <div className="profile-details">
283 <p><strong>邮箱:</strong>{email}</p>
284 <p><strong>性别:</strong>{gender}</p>
285 <p><strong>个人简介:</strong>{bio}</p>
286 <p><strong>兴趣:</strong>{interests.length > 0 ? interests.join(', ') : '无'}</p>
287 <p><strong>等级:</strong>{level}</p>
288 <p><strong>经验:</strong>{experience}</p>
289 <p><strong>上传量:</strong>{uploadAmount}</p>
290 <p><strong>下载量:</strong>{downloadAmount}</p>
291 <p><strong>分享率:</strong>{(shareRate * 100).toFixed(2)}%</p>
292 <p><strong>加入时间:</strong>{new Date(joinedDate).toLocaleDateString()}</p>
Krishyac0f7e9b2025-04-22 15:28:28 +0800293 </div>
294 </div>
2230100977253112025-04-15 21:30:39 +0800295 </div>
296 );
297};
298
2230100937ebec12025-06-03 21:17:04 +0800299export default UserProfile;
Krishyac6b24832025-06-05 20:13:20 +0800300