blob: 9170652c3b3ef83859cb9ee758df447619ad719d [file] [log] [blame]
2230100977253112025-04-15 21:30:39 +08001import React, { useEffect, useState } from 'react';
2import axios from 'axios';
3import './UserProfile.css';
22301009df48f962025-06-05 13:40:44 +08004import { useUser } from '../../context/UserContext';
22301009df48f962025-06-05 13:40:44 +08005const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
2230100977253112025-04-15 21:30:39 +08006
223010097ff51f22025-04-15 21:35:28 +08007const UserProfile = () => {
22301009df48f962025-06-05 13:40:44 +08008 const { user, loading } = useUser();
2230100977253112025-04-15 21:30:39 +08009 const [userProfile, setUserProfile] = useState(null);
2230100977253112025-04-15 21:30:39 +080010 const [error, setError] = useState(null);
11
2230100977253112025-04-15 21:30:39 +080012 useEffect(() => {
22301009df48f962025-06-05 13:40:44 +080013 if (loading) return;
2230100937ebec12025-06-03 21:17:04 +080014 if (!user || !user.userId) {
15 setError('未登录或用户信息缺失');
16 setUserProfile(null);
17 return;
18 }
19
2230100977253112025-04-15 21:30:39 +080020 const fetchUserProfile = async () => {
21 try {
2230100937ebec12025-06-03 21:17:04 +080022 setError(null);
22301009df48f962025-06-05 13:40:44 +080023 const { data: raw } = await axios.get(`/echo/user/${user.userId}/getProfile`);
2230100937ebec12025-06-03 21:17:04 +080024
25 if (!raw) {
26 setError('用户数据为空');
27 setUserProfile(null);
28 return;
2230100977253112025-04-15 21:30:39 +080029 }
2230100937ebec12025-06-03 21:17:04 +080030
31 const profile = {
2230100999cf3162025-06-06 00:19:25 +080032 avatarUrl: raw.avatarUrl
33 ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
34 : DEFAULT_AVATAR_URL,
2230100937ebec12025-06-03 21:17:04 +080035 nickname: raw.username || '未知用户',
36 email: raw.email || '未填写',
37 gender: raw.gender || '保密',
38 bio: raw.description || '无',
39 interests: raw.hobbies ? raw.hobbies.split(',') : [],
40 level: raw.level || '未知',
41 experience: raw.experience ?? 0,
22301009df48f962025-06-05 13:40:44 +080042 uploadAmount: raw.uploadCount ?? 0,
43 downloadAmount: raw.downloadCount ?? 0,
44 shareRate: raw.shareRate ?? 0,
45 joinedDate: raw.registrationTime,
2230100937ebec12025-06-03 21:17:04 +080046 };
47
48 setUserProfile(profile);
2230100977253112025-04-15 21:30:39 +080049 } catch (err) {
22301009df48f962025-06-05 13:40:44 +080050 setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
2230100937ebec12025-06-03 21:17:04 +080051 setUserProfile(null);
2230100977253112025-04-15 21:30:39 +080052 }
53 };
54
55 fetchUserProfile();
2230100937ebec12025-06-03 21:17:04 +080056 }, [user, loading]);
2230100977253112025-04-15 21:30:39 +080057
22301009df48f962025-06-05 13:40:44 +080058 const handleAvatarUpload = async (e) => {
59 const file = e.target.files[0];
60 if (!file) return;
61
62 const formData = new FormData();
63 formData.append('file', file);
64
65 try {
2230100999cf3162025-06-06 00:19:25 +080066 const { data } = await axios.post(
67 `/echo/user/${user.userId}/uploadAvatar`,
68 formData,
69 { headers: { 'Content-Type': 'multipart/form-data' } }
70 );
22301009df48f962025-06-05 13:40:44 +080071
72 if (data?.avatarUrl) {
73 setUserProfile((prev) => ({
74 ...prev,
75 avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
76 }));
77 alert('头像上传成功');
78 } else {
79 alert('头像上传成功,但未返回新头像地址');
80 }
81 } catch (err) {
82 console.error('上传失败:', err);
83 alert('头像上传失败,请重试');
84 }
85 };
86
2230100937ebec12025-06-03 21:17:04 +080087 if (loading) return <p>正在加载用户信息...</p>;
88 if (error) return <p className="error">{error}</p>;
89 if (!userProfile) return null;
2230100977253112025-04-15 21:30:39 +080090
22301009df48f962025-06-05 13:40:44 +080091 const {
92 avatarUrl,
93 nickname,
94 email,
95 gender,
96 bio,
97 interests,
98 level,
99 experience,
100 uploadAmount,
101 downloadAmount,
102 shareRate,
103 joinedDate,
104 } = userProfile;
105
2230100977253112025-04-15 21:30:39 +0800106 return (
Krishyac6b24832025-06-05 20:13:20 +0800107 <div className="common-card">
108 <div className="right-content">
109 <div className="profile-header">
110 <div className="avatar-wrapper">
111 <img src={avatarUrl} alt={nickname} className="avatar" />
112 <label htmlFor="avatar-upload" className="avatar-upload-label">
113 上传头像
114 </label>
115 <input
116 type="file"
117 id="avatar-upload"
118 accept="image/*"
119 style={{ display: 'none' }}
120 onChange={handleAvatarUpload}
121 />
2230100937ebec12025-06-03 21:17:04 +0800122 </div>
Krishyac6b24832025-06-05 20:13:20 +0800123 <h1>{nickname}</h1>
124 </div>
125
126 <div className="profile-details">
127 <p><strong>邮箱:</strong>{email}</p>
128 <p><strong>性别:</strong>{gender}</p>
129 <p><strong>个人简介:</strong>{bio}</p>
130 <p><strong>兴趣:</strong>{interests.length > 0 ? interests.join(', ') : '无'}</p>
131 <p><strong>等级:</strong>{level}</p>
132 <p><strong>经验:</strong>{experience}</p>
133 <p><strong>上传量:</strong>{uploadAmount}</p>
134 <p><strong>下载量:</strong>{downloadAmount}</p>
135 <p><strong>分享率:</strong>{(shareRate * 100).toFixed(2)}%</p>
136 <p><strong>加入时间:</strong>{new Date(joinedDate).toLocaleDateString()}</p>
Krishyac0f7e9b2025-04-22 15:28:28 +0800137 </div>
138 </div>
2230100977253112025-04-15 21:30:39 +0800139 </div>
140 );
141};
142
2230100999cf3162025-06-06 00:19:25 +0800143export default UserProfile;