blob: de523bd9d2a01c534f0a4bdc727cfecd5c44a611 [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';
5
6const DEFAULT_AVATAR_URL = `${process.env.PUBLIC_URL}/default-avatar.png`;
2230100977253112025-04-15 21:30:39 +08007
223010097ff51f22025-04-15 21:35:28 +08008const UserProfile = () => {
22301009df48f962025-06-05 13:40:44 +08009 const { user, loading } = useUser();
2230100977253112025-04-15 21:30:39 +080010 const [userProfile, setUserProfile] = useState(null);
2230100977253112025-04-15 21:30:39 +080011 const [error, setError] = useState(null);
12
2230100977253112025-04-15 21:30:39 +080013 useEffect(() => {
22301009df48f962025-06-05 13:40:44 +080014 if (loading) return;
2230100937ebec12025-06-03 21:17:04 +080015 if (!user || !user.userId) {
16 setError('未登录或用户信息缺失');
17 setUserProfile(null);
18 return;
19 }
20
2230100977253112025-04-15 21:30:39 +080021 const fetchUserProfile = async () => {
22 try {
2230100937ebec12025-06-03 21:17:04 +080023 setError(null);
22301009df48f962025-06-05 13:40:44 +080024 const { data: raw } = await axios.get(`/echo/user/${user.userId}/getProfile`);
2230100937ebec12025-06-03 21:17:04 +080025
26 if (!raw) {
27 setError('用户数据为空');
28 setUserProfile(null);
29 return;
2230100977253112025-04-15 21:30:39 +080030 }
2230100937ebec12025-06-03 21:17:04 +080031
32 const profile = {
22301009df48f962025-06-05 13:40:44 +080033 avatarUrl: raw.avatarUrl
34 ? `${process.env.REACT_APP_AVATAR_BASE_URL}${raw.avatarUrl}`
35 : DEFAULT_AVATAR_URL,
2230100937ebec12025-06-03 21:17:04 +080036 nickname: raw.username || '未知用户',
37 email: raw.email || '未填写',
38 gender: raw.gender || '保密',
39 bio: raw.description || '无',
40 interests: raw.hobbies ? raw.hobbies.split(',') : [],
41 level: raw.level || '未知',
42 experience: raw.experience ?? 0,
22301009df48f962025-06-05 13:40:44 +080043 uploadAmount: raw.uploadCount ?? 0,
44 downloadAmount: raw.downloadCount ?? 0,
45 shareRate: raw.shareRate ?? 0,
46 joinedDate: raw.registrationTime,
2230100937ebec12025-06-03 21:17:04 +080047 };
48
49 setUserProfile(profile);
2230100977253112025-04-15 21:30:39 +080050 } catch (err) {
22301009df48f962025-06-05 13:40:44 +080051 setError(err.response?.status === 404 ? '用户不存在' : '请求失败,请稍后再试');
2230100937ebec12025-06-03 21:17:04 +080052 setUserProfile(null);
2230100977253112025-04-15 21:30:39 +080053 }
54 };
55
56 fetchUserProfile();
2230100937ebec12025-06-03 21:17:04 +080057 }, [user, loading]);
2230100977253112025-04-15 21:30:39 +080058
22301009df48f962025-06-05 13:40:44 +080059 const handleAvatarUpload = async (e) => {
60 const file = e.target.files[0];
61 if (!file) return;
62
63 const formData = new FormData();
64 formData.append('file', file);
65
66 try {
67 const { data } = await axios.post(
68 `/echo/user/${user.userId}/uploadAvatar`,
69 formData,
70 { headers: { 'Content-Type': 'multipart/form-data' } }
71 );
72
73 if (data?.avatarUrl) {
74 setUserProfile((prev) => ({
75 ...prev,
76 avatarUrl: `${process.env.REACT_APP_AVATAR_BASE_URL}${data.avatarUrl}`,
77 }));
78 alert('头像上传成功');
79 } else {
80 alert('头像上传成功,但未返回新头像地址');
81 }
82 } catch (err) {
83 console.error('上传失败:', err);
84 alert('头像上传失败,请重试');
85 }
86 };
87
2230100937ebec12025-06-03 21:17:04 +080088 if (loading) return <p>正在加载用户信息...</p>;
89 if (error) return <p className="error">{error}</p>;
90 if (!userProfile) return null;
2230100977253112025-04-15 21:30:39 +080091
22301009df48f962025-06-05 13:40:44 +080092 const {
93 avatarUrl,
94 nickname,
95 email,
96 gender,
97 bio,
98 interests,
99 level,
100 experience,
101 uploadAmount,
102 downloadAmount,
103 shareRate,
104 joinedDate,
105 } = userProfile;
106
2230100977253112025-04-15 21:30:39 +0800107 return (
Krishyac6b24832025-06-05 20:13:20 +0800108 <div className="common-card">
109 <div className="right-content">
110 <div className="profile-header">
111 <div className="avatar-wrapper">
112 <img src={avatarUrl} alt={nickname} className="avatar" />
113 <label htmlFor="avatar-upload" className="avatar-upload-label">
114 上传头像
115 </label>
116 <input
117 type="file"
118 id="avatar-upload"
119 accept="image/*"
120 style={{ display: 'none' }}
121 onChange={handleAvatarUpload}
122 />
2230100937ebec12025-06-03 21:17:04 +0800123 </div>
Krishyac6b24832025-06-05 20:13:20 +0800124 <h1>{nickname}</h1>
125 </div>
126
127 <div className="profile-details">
128 <p><strong>邮箱:</strong>{email}</p>
129 <p><strong>性别:</strong>{gender}</p>
130 <p><strong>个人简介:</strong>{bio}</p>
131 <p><strong>兴趣:</strong>{interests.length > 0 ? interests.join(', ') : '无'}</p>
132 <p><strong>等级:</strong>{level}</p>
133 <p><strong>经验:</strong>{experience}</p>
134 <p><strong>上传量:</strong>{uploadAmount}</p>
135 <p><strong>下载量:</strong>{downloadAmount}</p>
136 <p><strong>分享率:</strong>{(shareRate * 100).toFixed(2)}%</p>
137 <p><strong>加入时间:</strong>{new Date(joinedDate).toLocaleDateString()}</p>
Krishyac0f7e9b2025-04-22 15:28:28 +0800138 </div>
139 </div>
2230100977253112025-04-15 21:30:39 +0800140 </div>
141 );
142};
143
2230100937ebec12025-06-03 21:17:04 +0800144export default UserProfile;
Krishyac6b24832025-06-05 20:13:20 +0800145