blob: 8199b4baba49d7b9483d51ccdcde627142004525 [file] [log] [blame]
Akane12173a7bb972025-06-01 01:05:27 +08001// Personal.jsx
2import React, { useState, useEffect } from 'react';
3import { useNavigate, useLocation, Outlet } from 'react-router-dom';
4import { getUserInfo, getDownloadQuota, getDownloadProgress } from '../../api/personal';
Akane121765b61a72025-05-17 13:52:25 +08005import './Personal.css';
6import ActionCard from './ActionCard';
7
8const Personal = () => {
9 const navigate = useNavigate();
Akane12173a7bb972025-06-01 01:05:27 +080010 const location = useLocation();
11 const [userData, setUserData] = useState(null);
12 const [loading, setLoading] = useState(true);
13 const [error, setError] = useState(null);
14 const [downloadProgress, setDownloadProgress] = useState({});
15
16 useEffect(() => {
17 const fetchData = async () => {
18 try {
19 // 并行获取用户信息和下载额度
20 const [userInfo, downloadQuota] = await Promise.all([
21 getUserInfo(),
22 getDownloadQuota()
23 ]);
24
25 setUserData({
26 username: userInfo.username,
27 avatar: 'https://via.placeholder.com/150',
28 joinDate: userInfo.registTime,
29 level: userInfo.level, // 可以根据userInfo.level设置不同等级
30 points: userInfo.magicPoints,
31 upload: userInfo.upload,
32 download: userInfo.download,
33 ratio: userInfo.shareRate,
34 downloadQuota: {
35 total: downloadQuota.total,
36 used: downloadQuota.used,
37 remaining: downloadQuota.remaining
38 }
39 });
40 } catch (err) {
41 setError(err.message);
42 } finally {
43 setLoading(false);
44 }
45 };
46
47 fetchData();
48 }, []);
49
50 // 获取下载进度数据
51 const fetchDownloadProgress = async () => {
52 try {
53 const progressData = await getDownloadProgress();
54 setDownloadProgress(progressData);
55 } catch (err) {
56 console.error('获取下载进度失败:', err);
Akane121765b61a72025-05-17 13:52:25 +080057 }
58 };
59
Akane12173a7bb972025-06-01 01:05:27 +080060 useEffect(() => {
61 // 初始获取下载进度
62 fetchDownloadProgress();
63
64 // 设置定时器,每10秒获取一次下载进度
65 const intervalId = setInterval(fetchDownloadProgress, 10000);
66
67 // 组件卸载时清除定时器
68 return () => clearInterval(intervalId);
69 }, []);
70
71
72 if (loading) {
73 return <div className="loading">加载中...</div>;
74 }
75
76 if (error) {
77 return <div className="error">错误: {error}</div>;
78 }
79
80 if (!userData) {
81 return <div className="error">未获取到用户数据</div>;
82 }
83
Akane121765b61a72025-05-17 13:52:25 +080084 const features = [
85 {
Akane12173a7bb972025-06-01 01:05:27 +080086 title: '兑换区',
87 description: '下载量/邀请码',
88 path: '/personal/Exchange' // 相对路径
Akane121765b61a72025-05-17 13:52:25 +080089 },
90 {
91 title: '上传记录',
92 description: '管理上传的资源',
93 path: '/personal/Upload'
94 },
95 {
96 title: '消息通知',
97 description: '查看系统消息',
98 path: '/personal/Notice'
99 },
100 {
101 title: '设置',
102 description: '修改个人资料',
103 path: '/personal/Setting'
104 }
105 ];
106
107 const handleCardClick = (path) => {
108 navigate(path); // 相对导航
109 };
110
111 const handleBack = () => {
112 if (location.state?.fromSubpage) {
113 // 如果是从子页面返回,则继续返回到Dashboard
114 navigate(`/dashboard/${location.state.dashboardTab || ''}`, {
115 replace: true
116 });
117 } else {
118 // 普通返回逻辑
119 navigate(-1);
120 }
121 };
122
Akane12173a7bb972025-06-01 01:05:27 +0800123 const formatSize = (bytes) => {
124 if (bytes < 1024) return `${bytes} B`;
125 const kb = bytes / 1024;
126 if (kb < 1024) return `${kb.toFixed(2)} KB`;
127 const mb = kb / 1024;
128 if (mb < 1024) return `${mb.toFixed(2)} MB`;
129 const gb = mb / 1024;
130 return `${gb.toFixed(2)} GB`;
131 };
132
133 // 添加进度条颜色函数
134 const getProgressColor = (percentage) => {
135 if (percentage < 0.3) return '#4CAF50'; // 绿色
136 if (percentage < 0.7) return '#FFC107'; // 黄色
137 return '#F44336'; // 红色
138 };
139
Akane121765b61a72025-05-17 13:52:25 +0800140 return (
141 <div className="personal-container">
142 {/* 返回按钮 */}
143 <button className="back-button" onClick={handleBack}>
DREW5b1883e2025-06-07 10:41:32 +0800144 返回
Akane121765b61a72025-05-17 13:52:25 +0800145 </button>
146
147 {/* 用户基本信息卡片 */}
148 <div className="profile-card">
149 <div className="profile-header">
150 <img
151 src={userData.avatar}
152 alt={userData.username}
153 className="profile-avatar"
154 />
155 <div className="profile-info">
156 <h2 className="username">{userData.username}</h2>
157 <div className="user-meta">
158 <span>加入时间: {userData.joinDate}</span>
Akane12173a7bb972025-06-01 01:05:27 +0800159 <span>会员等级: Lv.{userData.level}</span>
Akane121765b61a72025-05-17 13:52:25 +0800160 </div>
161 </div>
162 </div>
163
164 {/* 用户数据统计 */}
165 <div className="stats-grid">
166 <div className="stat-item">
Akane12173a7bb972025-06-01 01:05:27 +0800167 <div className="stat-label">保种积分</div>
Akane121765b61a72025-05-17 13:52:25 +0800168 <div className="stat-value">{userData.points}</div>
169 </div>
170 <div className="stat-item">
171 <div className="stat-label">上传量</div>
Akane12173a7bb972025-06-01 01:05:27 +0800172 <div className="stat-value">{formatSize(userData.upload)}</div>
Akane121765b61a72025-05-17 13:52:25 +0800173 </div>
174 <div className="stat-item">
175 <div className="stat-label">下载量</div>
Akane12173a7bb972025-06-01 01:05:27 +0800176 <div className="stat-value">{formatSize(userData.download)}</div>
Akane121765b61a72025-05-17 13:52:25 +0800177 </div>
178 <div className="stat-item">
179 <div className="stat-label">分享率</div>
180 <div className="stat-value">{userData.ratio}</div>
181 </div>
182 </div>
183 </div>
184
185 {/* 下载额度卡片 */}
186 <div className="quota-card">
187 <h3>下载额度</h3>
188 <div className="quota-info">
Akane12173a7bb972025-06-01 01:05:27 +0800189 <span className="quota-used">
190 {formatSize(userData.downloadQuota.used)} 已使用
191 </span>
192 <span className="quota-remaining">
193 {formatSize(userData.downloadQuota.remaining)} 剩余
194 </span>
Akane121765b61a72025-05-17 13:52:25 +0800195 </div>
196 <div className="progress-bar">
197 <div
198 className="progress-fill"
Akane12173a7bb972025-06-01 01:05:27 +0800199 style={{
200 width: `${(userData.downloadQuota.used / userData.downloadQuota.total) * 100}%`,
201 backgroundColor: getProgressColor(userData.downloadQuota.used / userData.downloadQuota.total)
202 }}
Akane121765b61a72025-05-17 13:52:25 +0800203 ></div>
204 </div>
Akane12173a7bb972025-06-01 01:05:27 +0800205 <div className="quota-total">
206 总额度: {formatSize(userData.downloadQuota.total)}
207 </div>
Akane121765b61a72025-05-17 13:52:25 +0800208 </div>
Akane12173a7bb972025-06-01 01:05:27 +0800209
210 {Object.keys(downloadProgress).length > 0 && (
211 <div className="progress-card">
212 <h3>当前下载进度</h3>
213 {Object.entries(downloadProgress).map(([taskId, progress]) => (
214 <div key={taskId} className="download-task">
215 <div className="task-info">
216 <span className="task-id">任务: {taskId.substring(0, 8)}...</span>
217 <span className="task-progress">{Math.round(progress * 100)}%</span>
218 </div>
219 <div className="progress-bar">
220 <div
221 className="progress-fill"
222 style={{ width: `${progress * 100}%` }}
223 ></div>
224 </div>
225 </div>
226 ))}
227 </div>
228 )}
Akane121765b61a72025-05-17 13:52:25 +0800229
230 {/* 功能卡片区 */}
231 <div className="action-cards">
232 {features.map((feature) => (
233 <div
234 key={feature.path}
235 className="action-card"
236 onClick={() => handleCardClick(feature.path)}
237 >
238 <h3>{feature.title}</h3>
239 <p>{feature.description}</p>
240 </div>
241 ))}
242 </div>
243
244 {/* 子路由出口 */}
245 <div className="subpage-container">
246 <Outlet />
247 </div>
248 </div>
249 );
250};
251
252export default Personal;