feat(admin): 实现管理员登录和删除功能

- 前端完成个人信息用户上传下载量和后端的连接,不再使用默认值
- 后端添加更新用户流量的方法定时更新所有用户的流量

Change-Id: I9e67475721c0e94fb1c4dac552a41bba86b92c91
diff --git a/src/features/profile/pages/ProfilePage.jsx b/src/features/profile/pages/ProfilePage.jsx
index 6957580..d39589b 100644
--- a/src/features/profile/pages/ProfilePage.jsx
+++ b/src/features/profile/pages/ProfilePage.jsx
@@ -45,15 +45,16 @@
 
   // 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,
+    uploadSize: 0, // GB
+    downloadSize: 0, // GB
+    ratio: 0,
+    points: 0, // 确保初始值为0
+    userClass: '新用户',
+    level: 1,
+    seedingCount: 0,
+    leechingCount: 0,
+    completedCount: 0,
+    invites: 0,
     warnings: 0,
     hitAndRuns: 0
   });
@@ -65,19 +66,31 @@
     }
   }, [user]);
 
+  // 监听ptStats的变化
+  useEffect(() => {
+    console.log('ptStats updated:', ptStats);
+  }, [ptStats]);
+
   const fetchUserStats = async () => {
     try {
       setLoading(true);
       const response = await getUserStats(user.username);
+      
       if (response && response.data) {
-        setPtStats(prevStats => ({
-          ...prevStats,
+        const newStats = {
+          ...ptStats,
           ...response.data
-        }));
+        };
+        setPtStats(newStats);
+      } else {
+        message.error('获取用户统计信息失败:数据格式错误');
       }
     } catch (error) {
-      console.error('获取用户统计信息失败:', error);
-      // 使用默认数据,不显示错误信息
+      if (error.response) {
+        message.error(error.response.data.message || '获取用户统计信息失败');
+      } else {
+        message.error('获取用户统计信息失败,请检查网络连接');
+      }
     } finally {
       setLoading(false);
     }
@@ -271,8 +284,7 @@
               <Col xs={12} sm={6}>
                 <Statistic
                   title="分享率"
-                  value={ptStats.ratio}
-                  precision={2}
+                  value={ptStats.ratio.toFixed(2)}
                   valueStyle={{ color: getRatioColor(ptStats.ratio) }}
                 />
               </Col>
@@ -294,18 +306,18 @@
         <Row gutter={[24, 16]}>
           <Col xs={24} md={12}>
             <div className="mb-4">
-              <Text strong>当前分享率:{ptStats.ratio}</Text>
+              <Text strong>当前分享率:{ptStats.ratio.toFixed(2)}</Text>
               <Progress
                 percent={Math.min(ptStats.ratio * 50, 100)} // 转换为百分比显示
                 strokeColor={getRatioColor(ptStats.ratio)}
-                format={() => ptStats.ratio}
+                format={() => ptStats.ratio.toFixed(2)}
               />
             </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>
+              <Tag color="green">≥2.00 优秀</Tag>
+              <Tag color="blue">≥1.00 良好</Tag>
+              <Tag color="orange">≥0.50 及格</Tag>
+              <Tag color="red">&lt;0.50 需要改善</Tag>
             </Space>
           </Col>
           <Col xs={24} md={12}>
diff --git a/src/services/api.js b/src/services/api.js
new file mode 100644
index 0000000..36ccab4
--- /dev/null
+++ b/src/services/api.js
@@ -0,0 +1,44 @@
+import axios from 'axios';
+
+// 创建axios实例
+const api = axios.create({
+    baseURL: '/api',  // 使用相对路径,让Vite代理处理
+    timeout: 10000,
+    headers: {
+        'Content-Type': 'application/json',
+    }
+});
+
+// 请求拦截器
+api.interceptors.request.use(
+    config => {
+        // 从localStorage获取token
+        const token = localStorage.getItem('token');
+        if (token) {
+            config.headers.Authorization = `Bearer ${token}`;
+        }
+        return config;
+    },
+    error => {
+        return Promise.reject(error);
+    }
+);
+
+// 响应拦截器
+api.interceptors.response.use(
+    response => {
+        return response.data;
+    },
+    error => {
+        if (error.response) {
+            // 处理401未授权错误
+            if (error.response.status === 401) {
+                localStorage.removeItem('token');
+                window.location.href = '/login';
+            }
+        }
+        return Promise.reject(error);
+    }
+);
+
+export default api; 
\ No newline at end of file
diff --git a/src/utils/request.js b/src/utils/request.js
index 478b9fb..a82602a 100644
--- a/src/utils/request.js
+++ b/src/utils/request.js
@@ -3,7 +3,7 @@
 
 // 创建 axios 实例
 const request = axios.create({
-  baseURL: "http://192.168.10.174:8080/api",
+  baseURL: "/api",
   timeout: 10000,
 });