feat(torrents): 优化种子页面功能和交互
- 调整 torrents API 调用,增加更多接口支持
- 优化种子列表展示和操作,支持下载和查看详情
- 新增种子详情页面路由和组件
- 改进上传种子功能,增加表单验证和错误提示
- 优化用户信息展示
Change-Id: I9343f2f446639733ee5800a86bab85a4ac6d1a72
diff --git a/src/features/profile/pages/ProfilePage.jsx b/src/features/profile/pages/ProfilePage.jsx
index d39589b..4b25a98 100644
--- a/src/features/profile/pages/ProfilePage.jsx
+++ b/src/features/profile/pages/ProfilePage.jsx
@@ -1,4 +1,4 @@
-import React, { useState, useEffect } from 'react';
+import React, { useState, useEffect, useRef } from 'react';
import {
Typography,
Card,
@@ -33,15 +33,16 @@
CameraOutlined
} from '@ant-design/icons';
import { useAuth } from '@/features/auth/contexts/AuthContext';
-import { getUserStats, updateUserProfile, uploadAvatar } from '@/api/user';
+import { updateUserProfile, uploadAvatar } from '@/api/user';
const { Title, Text, Paragraph } = Typography;
const ProfilePage = () => {
- const { user } = useAuth();
+ const { user, updateUserInfo } = useAuth();
const [loading, setLoading] = useState(false);
const [editModalVisible, setEditModalVisible] = useState(false);
const [form] = Form.useForm();
+ const hasUpdatedRef = useRef(false); // 用来追踪是否已经更新过用户信息
// PT站统计数据
const [ptStats, setPtStats] = useState({
@@ -59,49 +60,83 @@
hitAndRuns: 0
});
- // 获取用户统计信息
+ // 页面加载时更新用户信息
useEffect(() => {
- if (user?.username) {
- fetchUserStats();
+ const handleUserInfoUpdate = async () => {
+ if (user?.username && updateUserInfo && !hasUpdatedRef.current) {
+ console.log('页面加载,正在更新用户信息...');
+ hasUpdatedRef.current = true; // 标记为已更新
+ try {
+ await updateUserInfo(user.username);
+ console.log('用户信息更新成功');
+ } catch (error) {
+ console.error('更新用户信息失败:', error);
+ hasUpdatedRef.current = false; // 如果失败,重置标记以便重试
+ }
+ }
+ };
+
+ handleUserInfoUpdate();
+ }, [user?.username, updateUserInfo]); // 依赖用户名和更新函数
+
+ // 用户信息更新后,从用户数据中提取统计信息
+ useEffect(() => {
+ if (user) {
+ console.log('用户数据变化,更新统计信息:', user);
+ updateStatsFromUser(user);
}
}, [user]);
- // 监听ptStats的变化
- useEffect(() => {
- console.log('ptStats updated:', ptStats);
- }, [ptStats]);
-
- const fetchUserStats = async () => {
- try {
- setLoading(true);
- const response = await getUserStats(user.username);
+ // 从用户数据中提取统计信息
+ const updateStatsFromUser = (userData) => {
+ if (userData) {
+ const uploaded = Number(userData.uploaded) || 0;
+ const downloaded = Number(userData.downloaded) || 0;
+ const shareRatio = Number(userData.shareRatio) || 0;
- if (response && response.data) {
- const newStats = {
- ...ptStats,
- ...response.data
- };
- setPtStats(newStats);
- } else {
- message.error('获取用户统计信息失败:数据格式错误');
- }
- } catch (error) {
- if (error.response) {
- message.error(error.response.data.message || '获取用户统计信息失败');
- } else {
- message.error('获取用户统计信息失败,请检查网络连接');
- }
- } finally {
- setLoading(false);
+
+ const newStats = {
+ uploadSize: uploaded, // 保存原始字节值
+ downloadSize: downloaded, // 保存原始字节值
+ ratio: shareRatio,
+ points: Number(userData.points) || 0,
+ userClass: `用户等级`,
+ level: Number(userData.level) || 1
+ };
+
+ console.log('原始数据:', { uploaded, downloaded, shareRatio });
+ console.log('更新后的统计数据:', newStats);
+ setPtStats(newStats);
}
};
+
// 格式化文件大小
- const formatSize = (sizeInGB) => {
- if (sizeInGB >= 1024) {
- return `${(sizeInGB / 1024).toFixed(2)} TB`;
+ const formatSize = (sizeInBytes) => {
+ if (sizeInBytes === 0) {
+ return '0 B';
}
- return `${sizeInGB.toFixed(2)} GB`;
+
+ const units = ['B', 'KB', 'MB', 'GB', 'TB'];
+ const k = 1024;
+ let bytes = Math.abs(sizeInBytes);
+ let unitIndex = 0;
+
+ // 找到合适的单位
+ while (bytes >= k && unitIndex < units.length - 1) {
+ bytes /= k;
+ unitIndex++;
+ }
+
+ // 根据大小决定小数位数
+ let decimals = 2;
+ if (bytes >= 100) {
+ decimals = 0; // 大于等于100时不显示小数
+ } else if (bytes >= 10) {
+ decimals = 1; // 10-99时显示1位小数
+ }
+
+ return `${bytes.toFixed(decimals)} ${units[unitIndex]}`;
};
// 获取分享率颜色
@@ -150,7 +185,13 @@
if (response && response.data) {
message.success('资料更新成功');
setEditModalVisible(false);
- // 可以触发AuthContext的用户信息更新
+ // 资料更新成功后刷新用户信息
+ try {
+ await updateUserInfo(user.username);
+ console.log('资料更新后用户信息已刷新');
+ } catch (error) {
+ console.error('资料更新后刷新用户信息失败:', error);
+ }
} else {
message.error('更新失败,请重试');
}
@@ -184,7 +225,13 @@
const response = await uploadAvatar(formData);
if (response && response.data) {
message.success('头像上传成功');
- // 可以触发AuthContext的用户信息更新或重新获取用户信息
+ // 头像上传成功后更新用户信息
+ try {
+ await updateUserInfo(user.username);
+ console.log('头像上传后用户信息已更新');
+ } catch (error) {
+ console.error('头像上传后更新用户信息失败:', error);
+ }
} else {
message.error('头像上传失败');
}
@@ -207,13 +254,48 @@
<div className="space-y-6">
<div className="flex justify-between items-center">
<Title level={2}>个人资料</Title>
- <Button
- type="primary"
- icon={<EditOutlined />}
- onClick={showEditModal}
- >
- 编辑资料
- </Button>
+ <Space>
+ <Button
+ icon={<SyncOutlined />}
+ onClick={async () => {
+ if (!user?.username) {
+ message.error('用户信息不完整,请重新登录');
+ return;
+ }
+
+ console.log('手动刷新用户信息...');
+ setLoading(true);
+
+ try {
+ // 重置标记,允许手动更新
+ hasUpdatedRef.current = false;
+
+ // 调用getUserInfo更新用户信息
+ await updateUserInfo(user.username);
+ console.log('用户信息更新成功');
+
+ // 统计信息会通过 useEffect 自动更新
+
+ message.success('用户信息已更新');
+ } catch (error) {
+ console.error('刷新用户信息失败:', error);
+ message.error('刷新失败: ' + (error.message || '网络错误'));
+ } finally {
+ setLoading(false);
+ }
+ }}
+ loading={loading}
+ >
+ 刷新信息
+ </Button>
+ <Button
+ type="primary"
+ icon={<EditOutlined />}
+ onClick={showEditModal}
+ >
+ 编辑资料
+ </Button>
+ </Space>
</div>
<Row gutter={[24, 24]}>
@@ -246,7 +328,7 @@
color={getUserClassColor(ptStats.userClass)}
className="text-lg px-3 py-1"
>
- 用户等级{user.level}
+ 用户等级 {user?.level || ptStats.level}
</Tag>
<Text type="secondary">邮箱:{user?.email || '未设置'}</Text>
@@ -308,7 +390,7 @@
<div className="mb-4">
<Text strong>当前分享率:{ptStats.ratio.toFixed(2)}</Text>
<Progress
- percent={Math.min(ptStats.ratio * 50, 100)} // 转换为百分比显示
+ percent={ptStats.ratio >= 999 ? 100 : Math.min(ptStats.ratio * 50, 100)} // 转换为百分比显示
strokeColor={getRatioColor(ptStats.ratio)}
format={() => ptStats.ratio.toFixed(2)}
/>