feat(api): 重构 API 调用并优化用户认证流程

- 新增 auth、forum 和 user API 文件夹,重新组织 API 调用结构
- 重构 AuthContext,使用新 API 进行用户认证和信息管理
- 更新 AdminPanel、ForumPage 等组件,使用新的 API 调用
- 删除旧的 authApi.js 文件,清理冗余代码
- 优化用户登录、注册和登出流程,改进错误处理和用户提示

Change-Id: If664193e1bf30036c197f164edc5b10df75f1331
diff --git a/src/features/profile/pages/ProfilePage.jsx b/src/features/profile/pages/ProfilePage.jsx
index 79fbfe4..bdbdb0a 100644
--- a/src/features/profile/pages/ProfilePage.jsx
+++ b/src/features/profile/pages/ProfilePage.jsx
@@ -1,19 +1,365 @@
-import React from 'react';
-import { Typography, Button, Empty } from 'antd';
+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 } = Typography;
+const { Title, Text, Paragraph } = Typography;
 
-const ProfilePage = () => (
-  <div className="space-y-6">
-    <Title level={2}>个人资料</Title>
+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,
+    joinDate: '2023-05-15',
+    lastActive: '2024-12-28 15:30:00'
+  });
+
+  // 获取用户统计信息
+  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('头像上传失败');
+    }
     
-    <div className="text-center py-12">
-      <Empty description="用户资料页面正在开发中" />
-      <Button type="primary" className="mt-4">
-        编辑资料
-      </Button>
+    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"
+                >
+                  {ptStats.userClass}
+                </Tag>
+                
+                <Text type="secondary">邮箱:{user?.email || '未设置'}</Text>
+                <Text type="secondary">注册时间:{ptStats.joinDate}</Text>
+                <Text type="secondary">最后活跃:{ptStats.lastActive}</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>
-  </div>
-);
+  );
+};
 
 export default ProfilePage; 
\ No newline at end of file