blob: 69575800de74c9854d1f6b08609aa09d9061f7a5 [file] [log] [blame]
import React, { useState, useEffect } from 'react';
import {
Typography,
Card,
Avatar,
Statistic,
Row,
Col,
Tag,
Progress,
Button,
Divider,
Space,
Tooltip,
message,
Modal,
Form,
Input,
Upload
} from 'antd';
import {
UserOutlined,
EditOutlined,
UploadOutlined,
DownloadOutlined,
TrophyOutlined,
HeartOutlined,
WarningOutlined,
CheckCircleOutlined,
SyncOutlined,
GiftOutlined,
SettingOutlined,
CameraOutlined
} from '@ant-design/icons';
import { useAuth } from '@/features/auth/contexts/AuthContext';
import { getUserStats, updateUserProfile, uploadAvatar } from '@/api/user';
const { Title, Text, Paragraph } = Typography;
const ProfilePage = () => {
const { user } = useAuth();
const [loading, setLoading] = useState(false);
const [editModalVisible, setEditModalVisible] = useState(false);
const [form] = Form.useForm();
// PT站统计数据
const [ptStats, setPtStats] = useState({
uploadSize: 157.89, // GB
downloadSize: 89.32, // GB
ratio: 1.77,
points: 12580,
userClass: 'Power User',
seedingCount: 12,
leechingCount: 2,
completedCount: 156,
invites: 3,
warnings: 0,
hitAndRuns: 0
});
// 获取用户统计信息
useEffect(() => {
if (user?.username) {
fetchUserStats();
}
}, [user]);
const fetchUserStats = async () => {
try {
setLoading(true);
const response = await getUserStats(user.username);
if (response && response.data) {
setPtStats(prevStats => ({
...prevStats,
...response.data
}));
}
} catch (error) {
console.error('获取用户统计信息失败:', error);
// 使用默认数据,不显示错误信息
} finally {
setLoading(false);
}
};
// 格式化文件大小
const formatSize = (sizeInGB) => {
if (sizeInGB >= 1024) {
return `${(sizeInGB / 1024).toFixed(2)} TB`;
}
return `${sizeInGB.toFixed(2)} GB`;
};
// 获取分享率颜色
const getRatioColor = (ratio) => {
if (ratio >= 2.0) return '#52c41a'; // 绿色
if (ratio >= 1.0) return '#1890ff'; // 蓝色
if (ratio >= 0.5) return '#faad14'; // 橙色
return '#f5222d'; // 红色
};
// 获取用户等级颜色
const getUserClassColor = (userClass) => {
const classColors = {
'User': 'default',
'Power User': 'blue',
'Elite User': 'purple',
'Crazy User': 'gold',
'Insane User': 'red',
'Veteran User': 'green',
'Extreme User': 'volcano',
'VIP': 'magenta'
};
return classColors[userClass] || 'default';
};
// 显示编辑对话框
const showEditModal = () => {
form.setFieldsValue({
username: user?.username,
email: user?.email
});
setEditModalVisible(true);
};
// 处理编辑提交
const handleEditSubmit = async () => {
try {
const values = await form.validateFields();
setLoading(true);
const response = await updateUserProfile({
username: user.username,
...values
});
if (response && response.data) {
message.success('资料更新成功');
setEditModalVisible(false);
// 可以触发AuthContext的用户信息更新
} else {
message.error('更新失败,请重试');
}
} catch (error) {
console.error('更新失败:', error);
message.error(error.message || '更新失败,请重试');
} finally {
setLoading(false);
}
};
// 头像上传处理
const handleAvatarUpload = async (file) => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('只能上传 JPG/PNG 格式的图片!');
return false;
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('图片大小不能超过 2MB!');
return false;
}
try {
const formData = new FormData();
formData.append('avatar', file);
formData.append('username', user.username);
const response = await uploadAvatar(formData);
if (response && response.data) {
message.success('头像上传成功');
// 可以触发AuthContext的用户信息更新或重新获取用户信息
} else {
message.error('头像上传失败');
}
} catch (error) {
console.error('头像上传失败:', error);
message.error('头像上传失败');
}
return false; // 阻止默认上传行为
};
// 头像上传配置
const uploadProps = {
name: 'avatar',
showUploadList: false,
beforeUpload: handleAvatarUpload,
};
return (
<div className="space-y-6">
<div className="flex justify-between items-center">
<Title level={2}>个人资料</Title>
<Button
type="primary"
icon={<EditOutlined />}
onClick={showEditModal}
>
编辑资料
</Button>
</div>
<Row gutter={[24, 24]}>
{/* 用户基本信息卡片 */}
<Col xs={24} lg={8}>
<Card>
<div className="text-center">
<div className="relative inline-block">
<Avatar
size={120}
src={user?.avatar}
icon={<UserOutlined />}
className="mb-4"
/>
<Upload {...uploadProps}>
<Button
type="primary"
shape="circle"
icon={<CameraOutlined />}
size="small"
className="absolute bottom-0 right-0"
/>
</Upload>
</div>
<Title level={3} className="mb-2">{user?.username || '用户'}</Title>
<Space direction="vertical" className="w-full">
<Tag
color={getUserClassColor(ptStats.userClass)}
className="text-lg px-3 py-1"
>
用户等级{user.level}
</Tag>
<Text type="secondary">邮箱:{user?.email || '未设置'}</Text>
</Space>
</div>
</Card>
</Col>
{/* PT站统计信息 */}
<Col xs={24} lg={16}>
<Card title={
<Space>
<TrophyOutlined />
<span>PT站统计</span>
</Space>
}>
<Row gutter={[16, 16]}>
{/* 上传下载统计 */}
<Col xs={12} sm={6}>
<Statistic
title="上传量"
value={formatSize(ptStats.uploadSize)}
prefix={<UploadOutlined style={{ color: '#52c41a' }} />}
valueStyle={{ color: '#52c41a' }}
/>
</Col>
<Col xs={12} sm={6}>
<Statistic
title="下载量"
value={formatSize(ptStats.downloadSize)}
prefix={<DownloadOutlined style={{ color: '#1890ff' }} />}
valueStyle={{ color: '#1890ff' }}
/>
</Col>
<Col xs={12} sm={6}>
<Statistic
title="分享率"
value={ptStats.ratio}
precision={2}
valueStyle={{ color: getRatioColor(ptStats.ratio) }}
/>
</Col>
<Col xs={12} sm={6}>
<Statistic
title="积分"
value={ptStats.points}
prefix={<HeartOutlined style={{ color: '#eb2f96' }} />}
valueStyle={{ color: '#eb2f96' }}
/>
</Col>
</Row>
</Card>
</Col>
</Row>
{/* 分享率进度条 */}
<Card title="分享率分析">
<Row gutter={[24, 16]}>
<Col xs={24} md={12}>
<div className="mb-4">
<Text strong>当前分享率:{ptStats.ratio}</Text>
<Progress
percent={Math.min(ptStats.ratio * 50, 100)} // 转换为百分比显示
strokeColor={getRatioColor(ptStats.ratio)}
format={() => ptStats.ratio}
/>
</div>
<Space wrap>
<Tag color="green">≥2.0 优秀</Tag>
<Tag color="blue">≥1.0 良好</Tag>
<Tag color="orange">≥0.5 及格</Tag>
<Tag color="red">&lt;0.5 需要改善</Tag>
</Space>
</Col>
<Col xs={24} md={12}>
<div className="space-y-2">
<Paragraph>
<Text strong>分享率说明:</Text>
</Paragraph>
<Paragraph type="secondary" className="text-sm">
分享率 = 上传量 ÷ 下载量<br/>
保持良好的分享率有助于维护账号状态<br/>
建议长期做种热门资源提升分享率<br/>
分享率过低可能导致账号受限
</Paragraph>
</div>
</Col>
</Row>
</Card>
{/* 编辑资料对话框 */}
<Modal
title="编辑个人资料"
open={editModalVisible}
onOk={handleEditSubmit}
onCancel={() => setEditModalVisible(false)}
confirmLoading={loading}
okText="保存"
cancelText="取消"
>
<Form form={form} layout="vertical">
<Form.Item
name="username"
label="用户名"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item
name="email"
label="邮箱"
rules={[
{ required: true, message: '请输入邮箱' },
{ type: 'email', message: '请输入有效的邮箱地址' }
]}
>
<Input placeholder="请输入邮箱" />
</Form.Item>
</Form>
</Modal>
</div>
);
};
export default ProfilePage;