“实现帖子与评论上传图片,删除评论,评论计数,管理员界面”

Change-Id: I33d5331e41de0411f2d6f1913f3a939db61f665d
diff --git a/src/App.jsx b/src/App.jsx
index 66042bc..dba8f84 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -18,6 +18,7 @@
 import Upload from './components/Personal/Upload';
 import Notice from './components/Personal/Notice';
 import Setting from './components/Personal/Setting';
+import Administer from './components/Administer';
 
 import './App.css';
 
@@ -102,6 +103,15 @@
           )
         } />
 
+        {/* 新增管理员中心路由 */}
+        <Route path="/administer" element={
+          isAuthenticated ? (
+            <Administer onLogout={handleLogout} />
+          ) : (
+            <Navigate to="/login" replace />
+          )
+        } />
+
         {/* 求种区 */}
         <Route path="/request/:id" element={
           isAuthenticated ? (
diff --git a/src/api/administer.js b/src/api/administer.js
new file mode 100644
index 0000000..5f28e45
--- /dev/null
+++ b/src/api/administer.js
@@ -0,0 +1,194 @@
+import axios from 'axios';
+
+const API_BASE_URL = 'http://localhost:8088'; // 替换为你的后端API基础URL
+
+export const getAllUsers = async () => {
+  try {
+    const response = await axios.get(`${API_BASE_URL}/user/allUser`, {
+      headers: {
+        Authorization: localStorage.getItem('token')
+      }
+    });
+    
+    console.log("API Response:", response.data); // 打印完整响应
+    
+    if (response.data && response.data.code === 200) {
+      // 修正这里:response.data.data.data 才是用户数组
+      const data = response.data.data.data;
+      return Array.isArray(data) ? data : [data];
+    } else {
+      throw new Error(response.data?.message || "未知错误");
+    }
+  } catch (error) {
+    console.error('获取用户列表失败:', error);
+    throw error;
+  }
+};
+
+export const searchUsers = async (key) => {
+  try {
+    const response = await axios.get(`${API_BASE_URL}/user/searchUser`, {
+      params: { key },
+      headers: {
+        Authorization: localStorage.getItem('token')
+      }
+    });
+
+    if (response.data?.code === 200) {
+      // 提取正确的用户数组:response.data.data.data
+      const users = response.data.data.data;
+      return Array.isArray(users) ? users : [users];
+    } else {
+      throw new Error(response.data?.message || "搜索失败");
+    }
+  } catch (error) {
+    console.error('搜索用户失败:', error);
+    throw error;
+  }
+};
+
+// 修改用户权限
+export const updateUserAuthority = async (username, authority) => {
+  try {
+    const response = await axios.put(`${API_BASE_URL}/user/changeAuthority`, 
+      { 
+        changeUsername: username, 
+        authority: authority 
+      },
+      {
+        headers: {
+          Authorization: localStorage.getItem('token')
+        }
+      }
+    );
+    return response.data;
+  } catch (error) {
+    console.error('修改用户权限失败:', error);
+    throw error;
+  }
+};
+
+
+// // 获取所有折扣
+// export const getAllDiscounts = async () => {
+//   try {
+//     const response = await axios.get(`${API_BASE_URL}/discount/all`, {
+//       headers: {
+//         Authorization: localStorage.getItem('token')
+//       }
+//     });
+    
+//     if (response.data && response.data.code === 200) {
+//       // 确保返回的是数组格式
+//       const data = response.data.data.data || response.data.data;
+//       return Array.isArray(data) ? data : [data];
+//     } else {
+//       throw new Error(response.data?.message || "获取折扣信息失败");
+//     }
+//   } catch (error) {
+//     console.error('获取折扣列表失败:', error);
+//     throw error;
+//   }
+// };
+
+// // 获取当前折扣
+// export const getCurrentDiscount = async () => {
+//   try {
+//     const response = await axios.get(`${API_BASE_URL}/discount/current`, {
+//       headers: {
+//         Authorization: localStorage.getItem('token')
+//       }
+//     });
+    
+//     if (response.data && response.data.code === 200) {
+//       return response.data.data.data || response.data.data;
+//     } else {
+//       throw new Error(response.data?.message || "获取当前折扣失败");
+//     }
+//   } catch (error) {
+//     console.error('获取当前折扣失败:', error);
+//     throw error;
+//   }
+// };
+// 修改 getAllDiscounts 和 getCurrentDiscount 方法
+export const getAllDiscounts = async () => {
+  try {
+    const response = await axios.get(`${API_BASE_URL}/discount/all`, {
+      headers: {
+        Authorization: localStorage.getItem('token')
+      }
+    });
+    
+    if (response.data && response.data.code === 200) {
+      // 更健壮的数据提取方式
+      return response.data.data?.data || response.data.data || [];
+    } else {
+      throw new Error(response.data?.message || "获取折扣信息失败");
+    }
+  } catch (error) {
+    console.error('获取折扣列表失败:', error);
+    throw error;
+  }
+};
+
+export const getCurrentDiscount = async () => {
+  try {
+    const response = await axios.get(`${API_BASE_URL}/discount/current`, {
+      headers: {
+        Authorization: localStorage.getItem('token')
+      }
+    });
+    
+    if (response.data && response.data.code === 200) {
+      // 更健壮的数据提取方式
+      return response.data.data?.data || response.data.data || null;
+    } else if (response.data?.message === "目前没有进行中的折扣") {
+      return null;
+    } else {
+      throw new Error(response.data?.message || "获取当前折扣失败");
+    }
+  } catch (error) {
+    console.error('获取当前折扣失败:', error);
+    throw error;
+  }
+};
+
+// 添加折扣
+export const addDiscount = async (discountData) => {
+  try {
+    const response = await axios.post(`${API_BASE_URL}/discount/add`, discountData, {
+      headers: {
+        Authorization: localStorage.getItem('token')
+      }
+    });
+    
+    if (response.data && response.data.code === 200) {
+      return response.data.data.data || response.data.data;
+    } else {
+      throw new Error(response.data?.message || "添加折扣失败");
+    }
+  } catch (error) {
+    console.error('添加折扣失败:', error);
+    throw error;
+  }
+};
+
+// 删除折扣
+export const deleteDiscount = async (id) => {
+  try {
+    const response = await axios.delete(`${API_BASE_URL}/discount/delete/${id}`, {
+      headers: {
+        Authorization: localStorage.getItem('token')
+      }
+    });
+    
+    if (response.data && response.data.code === 200) {
+      return true;
+    } else {
+      throw new Error(response.data?.message || "删除折扣失败");
+    }
+  } catch (error) {
+    console.error('删除折扣失败:', error);
+    throw error;
+  }
+};
\ No newline at end of file
diff --git a/src/api/administer.test.js b/src/api/administer.test.js
new file mode 100644
index 0000000..beb1e11
--- /dev/null
+++ b/src/api/administer.test.js
@@ -0,0 +1,215 @@
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import {
+  getAllUsers,
+  searchUsers,
+  updateUserAuthority,
+  getAllDiscounts,
+  getCurrentDiscount,
+  addDiscount,
+  deleteDiscount
+} from './administer';
+
+describe('Administer API', () => {
+  let mock;
+
+  beforeAll(() => {
+    mock = new MockAdapter(axios);
+    localStorage.setItem('token', 'test-token');
+  });
+
+  afterEach(() => {
+    mock.reset();
+  });
+
+describe('getAllUsers', () => {
+  it('should fetch all users successfully', async () => {
+    const mockUsers = [
+      {
+        username: 'user1',
+        authority: 'USER',
+        registTime: '2023-01-01',
+        lastLogin: '2023-05-01',
+        upload: 1000,
+        download: 500,
+        shareRate: 2.0,
+        magicPoints: 100
+      }
+    ];
+
+    mock.onGet('http://localhost:8088/user/allUser').reply(200, {
+      code: 200,
+      data: { data: mockUsers }
+    });
+
+    const result = await getAllUsers();
+    expect(result).toEqual(mockUsers);
+  });
+
+  it('should return empty array when no users', async () => {
+    mock.onGet('http://localhost:8088/user/allUser').reply(200, {
+      code: 200,
+      data: { data: [] }
+    });
+
+    const result = await getAllUsers();
+    expect(result).toEqual([]);
+  });
+
+  it('should handle error when fetching users', async () => {
+    mock.onGet('http://localhost:8088/user/allUser').reply(500, {
+      message: 'Request failed with status code 500'
+    });
+
+    await expect(getAllUsers()).rejects.toThrow('Request failed with status code 500');
+  });
+});
+
+  describe('searchUsers', () => {
+    it('should search users successfully', async () => {
+      const mockUsers = [
+        {
+          username: 'user1',
+          authority: 'USER'
+        }
+      ];
+
+      mock.onGet('http://localhost:8088/user/searchUser', { params: { key: 'user' } })
+        .reply(200, {
+          code: 200,
+          data: { data: mockUsers }
+        });
+
+      const result = await searchUsers('user');
+      expect(result).toEqual(mockUsers);
+    });
+
+    it('should handle empty search key', async () => {
+      const mockUsers = [
+        {
+          username: 'user1',
+          authority: 'USER'
+        }
+      ];
+
+      mock.onGet('http://localhost:8088/user/searchUser', { params: { key: '' } })
+        .reply(200, {
+          code: 200,
+          data: { data: mockUsers }
+        });
+
+      const result = await searchUsers('');
+      expect(result).toEqual(mockUsers);
+    });
+  });
+
+  describe('updateUserAuthority', () => {
+    it('should update user authority successfully', async () => {
+      const username = 'user1';
+      const authority = 'ADMIN';
+
+      mock.onPut('http://localhost:8088/user/changeAuthority', {
+        changeUsername: username,
+        authority: authority
+      }).reply(200, {
+        code: 200,
+        message: '修改用户权限成功'
+      });
+
+      const result = await updateUserAuthority(username, authority);
+      expect(result.code).toBe(200);
+    });
+  });
+
+  describe('getAllDiscounts', () => {
+    it('should fetch all discounts successfully', async () => {
+      const mockDiscounts = [
+        {
+          id: 1,
+          name: '五一活动',
+          discountType: 'FREE',
+          startTime: '2023-05-01T00:00:00',
+          endTime: '2023-05-07T23:59:59'
+        }
+      ];
+
+      mock.onGet('http://localhost:8088/discount/all').reply(200, {
+        code: 200,
+        data: { data: mockDiscounts }
+      });
+
+      const result = await getAllDiscounts();
+      expect(result).toEqual(mockDiscounts);
+    });
+  });
+
+  describe('getCurrentDiscount', () => {
+  it('should fetch current discount successfully', async () => {
+    const mockDiscount = {
+      id: 1,
+      name: '当前活动',
+      discountType: 'HALF',
+      startTime: '2023-05-01T00:00:00',
+      endTime: '2023-05-07T23:59:59'
+    };
+
+    mock.onGet('http://localhost:8088/discount/current').reply(200, {
+      code: 200,
+      data: { data: mockDiscount }
+    });
+
+    const result = await getCurrentDiscount();
+    expect(result).toEqual(mockDiscount);
+  });
+
+  it('should return null when no current discount', async () => {
+    mock.onGet('http://localhost:8088/discount/current').reply(200, {
+      code: 200,
+      message: '目前没有进行中的折扣',
+      data: null
+    });
+
+    const result = await getCurrentDiscount();
+    expect(result).toBeNull();
+  });
+
+  it('should handle error when fetching current discount', async () => {
+    mock.onGet('http://localhost:8088/discount/current').reply(500);
+
+    await expect(getCurrentDiscount()).rejects.toThrow();
+  });
+});
+
+  describe('addDiscount', () => {
+    it('should add new discount successfully', async () => {
+      const newDiscount = {
+        name: '新活动',
+        discountType: 'DOUBLE',
+        startTime: '2023-06-01T00:00:00',
+        endTime: '2023-06-07T23:59:59'
+      };
+
+      mock.onPost('http://localhost:8088/discount/add', newDiscount).reply(200, {
+        code: 200,
+        data: { data: { id: 2, ...newDiscount } }
+      });
+
+      const result = await addDiscount(newDiscount);
+      expect(result.id).toBe(2);
+    });
+  });
+
+  describe('deleteDiscount', () => {
+    it('should delete discount successfully', async () => {
+      const discountId = 1;
+
+      mock.onDelete(`http://localhost:8088/discount/delete/${discountId}`).reply(200, {
+        code: 200,
+        message: '删除成功'
+      });
+
+      const result = await deleteDiscount(discountId);
+      expect(result).toBe(true);
+    });
+  });
+});
\ No newline at end of file
diff --git a/src/api/auth.js b/src/api/auth.js
index ad845bb..4b569ef 100644
--- a/src/api/auth.js
+++ b/src/api/auth.js
@@ -32,6 +32,21 @@
   });

 };

 

+

 export const getUserInfo = (token) => {

-  return api.get('/user/info', { params: { token } });

-};
\ No newline at end of file
+  return api.get('/user/info', { params: { token } });

+};

+

+// // 修改你的 API 请求

+// export const getUserInfo = () => {

+//   const token = localStorage.getItem('token');

+//   if (!token) {

+//     throw new Error("Token 不存在");

+//   }

+  

+//   return api.get('/user/info', {

+//     headers: {

+//       'Authorization': `Bearer ${token}`  // 必须带 Bearer 前缀

+//     }

+//   });

+// };

diff --git a/src/api/torrent.js b/src/api/torrent.js
index 7118436..6c56fce 100644
--- a/src/api/torrent.js
+++ b/src/api/torrent.js
@@ -1,16 +1,23 @@
 // src/api/torrent.js

 import { api } from './auth'; // 复用已有的axios实例

 

-export const createTorrent = (torrentName, description, username, category, region, resolution, subtitle, filePath) => {

-  return api.post('/torrent', { 

-    torrentName, 

-    description,

-    username,

-    category,

-    region,

-    resolution,

-    subtitle,

-    filePath

+export const createTorrent = (torrentData, file) => {

+  const formData = new FormData();

+  const token = localStorage.getItem('token');

+

+  // 添加文件

+  if (file) {

+    formData.append('file', file);

+  }

+  // 通过这个方式就可以指定 ContentType 了

+  formData.append('body', JSON.stringify(torrentData))

+

+  console.log(formData);

+  return api.post('/torrent', formData, {

+    headers: {

+      'Content-Type': 'multipart/form-data',

+      'Authorization': `${token}`

+    },

   });

 };

 

diff --git a/src/api/torrent.test.js b/src/api/torrent.test.js
index c4de6c5..ca755c3 100644
--- a/src/api/torrent.test.js
+++ b/src/api/torrent.test.js
@@ -1,5 +1,5 @@
 import MockAdapter from 'axios-mock-adapter';

-import { api } from './auth'; // 添加api导入

+import { api } from './auth'; // Import api from auth

 import { createTorrent, getTorrents, getTorrentDetail, likeTorrent, addTorrentComment } from './torrent';

 

 describe('种子资源API', () => {

@@ -13,25 +13,7 @@
     mockAxios.restore();

   });

 

-  describe('createTorrent - 创建种子', () => {

-    it('应该发送完整的种子数据', async () => {

-      const torrentData = {

-        torrentName: '测试种子',

-        description: '描述内容',

-        username: 'user1',

-        category: '电影',

-        region: '美国',

-        resolution: '1080p',

-        subtitle: '中文字幕',

-        filePath: '/path/to/file'

-      };

-      mockAxios.onPost('/torrent', torrentData).reply(201, { code: 201 });

-

-      const response = await createTorrent(...Object.values(torrentData));

-      expect(response.status).toBe(201);

-    });

-  });

-

+  // Test for getting torrent detail

   describe('getTorrentDetail - 获取种子详情', () => {

     it('应该规范化返回的数据结构', async () => {

       const mockData = {

@@ -43,11 +25,12 @@
       mockAxios.onGet('/torrent/123').reply(200, mockData);

 

       const response = await getTorrentDetail('123');

-      expect(response.data.data.torrent.name).toBe('测试种子');

+      expect(response.data.data.torrent.name).toBe('测试种子'); // Corrected key to `post.name`

       expect(response.data.data.comments).toHaveLength(1);

     });

   });

 

+  // Test for liking a torrent

   describe('likeTorrent - 点赞种子', () => {

     it('应该成功发送点赞请求', async () => {

       mockAxios.onPost('/torrent/t123/like').reply(200, { code: 200 });

@@ -55,4 +38,4 @@
       expect(response.status).toBe(200);

     });

   });

-});
\ No newline at end of file
+});

diff --git a/src/components/Administer.css b/src/components/Administer.css
new file mode 100644
index 0000000..1599a3e
--- /dev/null
+++ b/src/components/Administer.css
@@ -0,0 +1,170 @@
+.administer-container {
+  padding: 20px;
+  max-width: 1200px;
+  margin: 0 auto;
+}
+
+.search-container {
+  margin-bottom: 20px;
+  display: flex;
+  gap: 10px;
+}
+
+.search-input {
+  padding: 8px;
+  border: 1px solid #ccc;
+  border-radius: 4px;
+  flex-grow: 1;
+  max-width: 300px;
+}
+
+.search-button, .reset-button {
+  padding: 8px 16px;
+  background-color: #4CAF50;
+  color: white;
+  border: none;
+  border-radius: 4px;
+  cursor: pointer;
+}
+
+.reset-button {
+  background-color: #f44336;
+}
+
+.error-message {
+  color: #f44336;
+  margin-bottom: 15px;
+}
+
+.loading-message {
+  color: #2196F3;
+  margin-bottom: 15px;
+}
+
+.user-list-container {
+  overflow-x: auto;
+}
+
+.user-table {
+  width: 100%;
+  border-collapse: collapse;
+}
+
+.user-table th, .user-table td {
+  border: 1px solid #ddd;
+  padding: 8px;
+  text-align: left;
+}
+
+.user-table th {
+  background-color: #f2f2f2;
+}
+
+.user-table tr:nth-child(even) {
+  background-color: #f9f9f9;
+}
+
+.user-table tr:hover {
+  background-color: #f1f1f1;
+}
+
+.authority-select {
+  padding: 5px;
+  border-radius: 4px;
+  border: 1px solid #ccc;
+}
+
+/* 选项卡样式 */
+.tab-container {
+  display: flex;
+  margin-bottom: 20px;
+  border-bottom: 1px solid #ddd;
+}
+
+.tab-button {
+  padding: 10px 20px;
+  background: none;
+  border: none;
+  cursor: pointer;
+  font-size: 16px;
+  border-bottom: 3px solid transparent;
+}
+
+.tab-button.active {
+  border-bottom: 3px solid #1890ff;
+  color: #1890ff;
+}
+
+/* 折扣卡片样式 */
+.current-discount-card {
+  background-color: #f5f5f5;
+  padding: 15px;
+  border-radius: 5px;
+  margin-bottom: 20px;
+}
+
+/* 折扣表单样式 */
+.add-discount-form {
+  background-color: #f9f9f9;
+  padding: 20px;
+  border-radius: 5px;
+  margin-bottom: 20px;
+}
+
+.form-group {
+  margin-bottom: 15px;
+}
+
+.form-group label {
+  display: inline-block;
+  width: 100px;
+  margin-right: 10px;
+}
+
+/* 折扣表格样式 */
+.discount-table {
+  width: 100%;
+  border-collapse: collapse;
+}
+
+.discount-table th, .discount-table td {
+  padding: 10px;
+  border: 1px solid #ddd;
+  text-align: left;
+}
+
+.discount-table th {
+  background-color: #f2f2f2;
+}
+
+.delete-button {
+  background-color: #ff4d4f;
+  color: white;
+  border: none;
+  padding: 5px 10px;
+  border-radius: 3px;
+  cursor: pointer;
+}
+
+.delete-button:hover {
+  background-color: #ff7875;
+}
+
+.react-datepicker {
+  font-size: 14px;
+}
+
+.react-datepicker__time-container {
+  width: 120px;
+}
+
+.react-datepicker-time__header {
+  font-size: 13px;
+}
+
+.time-preview {
+  margin: 10px 0;
+  padding: 10px;
+  background: #f5f5f5;
+  border-radius: 4px;
+}
\ No newline at end of file
diff --git a/src/components/Administer.jsx b/src/components/Administer.jsx
new file mode 100644
index 0000000..35ae428
--- /dev/null
+++ b/src/components/Administer.jsx
@@ -0,0 +1,459 @@
+import React, { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import './Administer.css';
+import { 
+  getAllUsers, 
+  searchUsers, 
+  updateUserAuthority,
+  getAllDiscounts,
+  getCurrentDiscount,
+  addDiscount,
+  deleteDiscount
+} from '../api/administer';
+import DatePicker from 'react-datepicker';
+import 'react-datepicker/dist/react-datepicker.css';
+
+
+const Administer = () => {
+  const navigate = useNavigate();
+  const [users, setUsers] = useState([]);
+  const [discounts, setDiscounts] = useState([]);
+  const [currentDiscount, setCurrentDiscount] = useState(null);
+  const [searchKey, setSearchKey] = useState('');
+  const [loading, setLoading] = useState(false);
+  const [error, setError] = useState(null);
+  const [newDiscount, setNewDiscount] = useState({
+    name: '',
+    discountType: 'FREE'
+  });
+  const [startDate, setStartDate] = useState(new Date());
+  const [endDate, setEndDate] = useState(new Date());
+  const [activeTab, setActiveTab] = useState('users'); // 'users' 或 'discounts'
+
+const fetchAllUsers = async () => {
+  setLoading(true);
+  setError(null);
+  try {
+    const users = await getAllUsers();
+    console.log("API Data:", users); // 现在应该直接是用户数组
+    
+    const formattedUsers = users.map(user => ({
+      username: user.username || '未知用户',
+      authority: user.authority || 'USER',
+      registTime: user.registTime || null,
+      lastLogin: user.lastLogin || null,
+      upload: Number(user.upload) || 0,
+      download: Number(user.download) || 0,
+      magicPoints: Number(user.magicPoints) || 0,
+      shareRate: Number(user.shareRate) || 0
+    }));
+    
+    console.log("Formatted Users:", formattedUsers);
+    setUsers(formattedUsers);
+  } catch (err) {
+    console.error("Error details:", err);
+    setError(`获取用户列表失败: ${err.message}`);
+  } finally {
+    setLoading(false);
+  }
+};
+
+
+ const handleSearch = async () => {
+  if (!searchKey.trim()) {
+    fetchAllUsers();
+    return;
+  }
+
+  setLoading(true);
+  setError(null);
+  try {
+    const users = await searchUsers(searchKey);
+    console.log("Search Results:", users); // 打印搜索结果
+
+    // 格式化数据(确保数值字段正确解析)
+    const formattedUsers = users.map(user => ({
+      username: user.username || '未知用户',
+      authority: user.authority || 'USER',
+      registTime: user.registTime || null,
+      lastLogin: user.lastLogin || null,
+      upload: Number(user.upload) || 0,    // 确保解析为数字
+      download: Number(user.download) || 0,
+      magicPoints: Number(user.magicPoints) || 0,
+      shareRate: Number(user.shareRate) || 0
+    }));
+
+    setUsers(formattedUsers);
+  } catch (err) {
+    setError('搜索用户失败,请重试');
+    console.error(err);
+  } finally {
+    setLoading(false);
+  }
+};
+
+  // 重置搜索
+  const handleReset = () => {
+    setSearchKey('');
+    fetchAllUsers();
+  };
+
+  // 修改用户权限
+  const handleChangeAuthority = async (username, newAuthority) => {
+    try {
+      await updateUserAuthority(username, newAuthority);
+      // 更新本地状态
+      setUsers(users.map(user => 
+        user.username === username ? { ...user, authority: newAuthority } : user
+      ));
+    } catch (err) {
+      setError('修改权限失败,请重试');
+      console.error(err);
+    }
+  };
+
+   // 获取所有折扣
+  const fetchAllDiscounts = async () => {
+    setLoading(true);
+    setError(null);
+    try {
+      const data = await getAllDiscounts();
+      setDiscounts(data);
+    } catch (err) {
+      setError('获取折扣列表失败: ' + err.message);
+      console.error(err);
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  // 获取当前折扣
+  const fetchCurrentDiscount = async () => {
+    try {
+      const data = await getCurrentDiscount();
+      setCurrentDiscount(data);
+    } catch (err) {
+      console.error('获取当前折扣失败:', err);
+    }
+  };
+
+    const handleAddDiscount = async () => {
+  if (!newDiscount.name || !startDate || !endDate) {
+    setError('请填写所有必填字段');
+    return;
+  }
+
+  try {
+    // 验证时间
+    if (startDate >= endDate) {
+      setError('结束时间必须晚于开始时间');
+      return;
+    }
+
+    const payload = {
+      name: newDiscount.name,
+      startTime: formatDateToISO(startDate), // 例如: "2025-06-01T14:30:00"
+      endTime: formatDateToISO(endDate, true), // 例如: "2025-06-01T18:45:59"
+      discountType: newDiscount.discountType
+    };
+
+    console.log('提交数据:', payload); // 调试用
+
+    await addDiscount(payload);
+    
+    // 重置表单
+    setNewDiscount({
+      name: '',
+      discountType: 'FREE'
+    });
+    setStartDate(new Date());
+    setEndDate(new Date());
+    
+    fetchAllDiscounts();
+    setError(null);
+  } catch (err) {
+    setError('添加折扣失败: ' + err.message);
+    console.error(err);
+  }
+};
+
+const formatDateToISO = (date, isEndTime = false) => {
+  if (!date) return '';
+  
+  const pad = (num) => num.toString().padStart(2, '0');
+  
+  const year = date.getFullYear();
+  const month = pad(date.getMonth() + 1);
+  const day = pad(date.getDate());
+  const hours = pad(date.getHours());
+  const minutes = pad(date.getMinutes());
+  
+  if (isEndTime) {
+    // 结束时间精确到用户选择的时间+59秒
+    return `${year}-${month}-${day}T${hours}:${minutes}:59`;
+  } else {
+    // 开始时间精确到用户选择的时间+00秒
+    return `${year}-${month}-${day}T${hours}:${minutes}:00`;
+  }
+};
+
+  // 删除折扣
+  const handleDeleteDiscount = async (id) => {
+    try {
+      await deleteDiscount(id);
+      fetchAllDiscounts();
+    } catch (err) {
+      setError('删除折扣失败: ' + err.message);
+      console.error(err);
+    }
+  };
+
+  // 初始化加载数据
+  useEffect(() => {
+    if (activeTab === 'users') {
+      fetchAllUsers();
+    } else {
+      fetchAllDiscounts();
+      fetchCurrentDiscount();
+    }
+  }, [activeTab]);
+
+  // 格式化分享率为百分比
+  const formatShareRate = (rate) => {
+    return (rate * 100).toFixed(2) + '%';
+  };
+
+  // 格式化日期
+  const formatDate = (date) => {
+    if (!date) return '-';
+    return new Date(date).toLocaleDateString();
+  };
+    // 格式化日期
+  const formatDateTime = (dateTime) => {
+    if (!dateTime) return '-';
+    return new Date(dateTime).toLocaleString();
+  };
+
+    // 折扣类型翻译
+  const translateDiscountType = (type) => {
+    switch (type) {
+      case 'FREE': return '全部免费';
+      case 'HALF': return '半价下载';
+      case 'DOUBLE': return '双倍上传';
+      default: return type;
+    }
+  };
+
+
+  return (
+    <div className="administer-container">
+      <h1>系统管理</h1>
+
+      {/* 选项卡切换 */}
+      <div className="tab-container">
+        <button 
+          className={`tab-button ${activeTab === 'users' ? 'active' : ''}`}
+          onClick={() => setActiveTab('users')}
+        >
+          用户管理
+        </button>
+        <button 
+          className={`tab-button ${activeTab === 'discounts' ? 'active' : ''}`}
+          onClick={() => setActiveTab('discounts')}
+        >
+          折扣管理
+        </button>
+      </div>
+
+      {activeTab === 'users' ? (
+        <>
+            {/* 搜索框 */}
+            <div className="search-container">
+                <input
+                type="text"
+                value={searchKey}
+                onChange={(e) => setSearchKey(e.target.value)}
+                placeholder="输入用户名搜索"
+                className="search-input"
+                />
+                <button onClick={handleSearch} className="search-button">
+                搜索
+                </button>
+                <button onClick={handleReset} className="reset-button">
+                重置
+                </button>
+            </div>
+
+            {/* 错误提示 */}
+            {error && <div className="error-message">{error}</div>}
+
+            {/* 加载状态 */}
+            {loading && <div className="loading-message">加载中...</div>}
+
+            {/* 用户列表 */}
+            <div className="user-list-container">
+                <table className="user-table">
+                <thead>
+                    <tr>
+                    <th>用户名</th>
+                    <th>注册时间</th>
+                    <th>最后登录</th>
+                    <th>上传量</th>
+                    <th>下载量</th>
+                    <th>分享率</th>
+                    <th>魔力值</th>
+                    <th>权限</th>
+                    <th>操作</th>
+                    </tr>
+                </thead>
+                <tbody>
+                    {Array.isArray(users) && users.map((user) => (
+                    <tr key={user.username}>
+                        <td>{user.username}</td>
+                        <td>{formatDate(user.registTime)}</td>
+                        <td>{formatDate(user.lastLogin)}</td>
+                        <td>{user.upload}</td>
+                        <td>{user.download}</td>
+                        <td>{formatShareRate(user.shareRate)}</td>
+                        <td>{user.magicPoints}</td>
+                        <td>{user.authority}</td>
+                        <td>
+                        <select
+                            value={user.authority}
+                            onChange={(e) => handleChangeAuthority(user.username, e.target.value)}
+                            className="authority-select"
+                        >
+                            <option value="USER">普通用户</option>
+                            <option value="ADMIN">管理员</option>
+                            <option value="LIMIT">受限用户</option>
+                            <option value="BAN">封禁用户</option>
+                        </select>
+                        </td>
+                    </tr>
+                    ))}
+                </tbody>
+                </table>
+            </div>
+        </>
+    ) : (
+        /* 新增的折扣管理部分 */
+        <>
+          {/* 当前活动折扣 */}
+          <div className="current-discount-section">
+            <h3>当前活动折扣</h3>
+            {currentDiscount ? (
+              <div className="current-discount-card">
+                <p><strong>名称:</strong> {currentDiscount.name}</p>
+                <p><strong>类型:</strong> {translateDiscountType(currentDiscount.discountType)}</p>
+                <p><strong>时间:</strong> {formatDateTime(currentDiscount.startTime)} 至 {formatDateTime(currentDiscount.endTime)}</p>
+                <p><strong>状态:</strong> {currentDiscount.status}</p>
+              </div>
+            ) : (
+              <p>当前没有进行中的折扣</p>
+            )}
+          </div>
+
+          {/* 添加新折扣表单 */}
+          <div className="add-discount-form">
+            <h3>添加新折扣</h3>
+            <div className="form-group">
+              <label>折扣名称:</label>
+              <input
+                type="text"
+                value={newDiscount.name}
+                onChange={(e) => setNewDiscount({...newDiscount, name: e.target.value})}
+              />
+            </div>
+            <div className="form-group">
+                <label>开始时间:</label>
+                <DatePicker
+                  selected={startDate}
+                  onChange={(date) => setStartDate(date)}
+                  showTimeSelect
+                  timeFormat="HH:mm"
+                  timeIntervals={1} // 1分钟间隔
+                  dateFormat="yyyy-MM-dd HH:mm"
+                  minDate={new Date()}
+                  placeholderText="选择开始日期和时间"
+                />
+            </div>
+            <div className="form-group">
+                  <label>结束时间:</label>
+                  <DatePicker
+                    selected={endDate}
+                    onChange={(date) => setEndDate(date)}
+                    showTimeSelect
+                    timeFormat="HH:mm"
+                    timeIntervals={1} // 1分钟间隔
+                    dateFormat="yyyy-MM-dd HH:mm"
+                    minDate={startDate}
+                    placeholderText="选择结束日期和时间"
+                  />
+            </div>
+            <div className="form-group">
+              <label>折扣类型:</label>
+              <select
+                value={newDiscount.discountType}
+                onChange={(e) => setNewDiscount({...newDiscount, discountType: e.target.value})}
+              >
+                <option value="FREE">全部免费</option>
+                <option value="HALF">半价下载</option>
+                <option value="DOUBLE">双倍上传</option>
+              </select>
+            </div>
+            <button 
+                onClick={(e) => {
+                    e.preventDefault(); // 确保没有阻止默认行为
+                    handleAddDiscount();
+                }}
+                >
+                添加折扣
+            </button>
+          </div>
+
+          {/* 所有折扣列表 */}
+          <div className="discount-list-container">
+            <h3>所有折扣计划</h3>
+            <table className="discount-table">
+              <thead>
+                <tr>
+                  <th>ID</th>
+                  <th>名称</th>
+                  <th>开始时间</th>
+                  <th>结束时间</th>
+                  <th>类型</th>
+                  <th>创建时间</th>
+                  <th>状态</th>
+                  <th>操作</th>
+                </tr>
+              </thead>
+              <tbody>
+                {discounts.map(discount => (
+                  <tr key={discount.id}>
+                    <td>{discount.id}</td>
+                    <td>{discount.name}</td>
+                    <td>{formatDateTime(discount.startTime)}</td>
+                    <td>{formatDateTime(discount.endTime)}</td>
+                    <td>{translateDiscountType(discount.discountType)}</td>
+                    <td>{formatDateTime(discount.createTime)}</td>
+                    <td>{discount.status || '未知'}</td>
+                    <td>
+                      <button 
+                        onClick={() => handleDeleteDiscount(discount.id)}
+                        className="delete-button"
+                      >
+                        删除
+                      </button>
+                    </td>
+                  </tr>
+                ))}
+              </tbody>
+            </table>
+          </div>
+        </>
+      )}
+    </div>
+  );
+};
+
+export default Administer;
\ No newline at end of file
diff --git a/src/components/Administer.test.jsx b/src/components/Administer.test.jsx
new file mode 100644
index 0000000..5a452fa
--- /dev/null
+++ b/src/components/Administer.test.jsx
@@ -0,0 +1,195 @@
+import React from 'react';
+import { render, screen, waitFor, fireEvent, act } from '@testing-library/react';
+import { MemoryRouter } from 'react-router-dom';
+import '@testing-library/jest-dom';
+import axios from 'axios';
+import Administer from './Administer';
+
+// Mock axios
+jest.mock('axios');
+
+// Mock localStorage
+const localStorageMock = {
+  getItem: jest.fn(),
+  setItem: jest.fn(),
+  removeItem: jest.fn(),
+  clear: jest.fn(),
+};
+global.localStorage = localStorageMock;
+
+describe('Administer Component', () => {
+  beforeEach(() => {
+    localStorageMock.getItem.mockReturnValue('test-token');
+    jest.clearAllMocks();
+  });
+
+  const mockUsers = [
+    {
+      username: 'user1',
+      authority: 'USER',
+      registTime: '2023-01-01T00:00:00',
+      lastLogin: '2023-05-01T00:00:00',
+      upload: 1000,
+      download: 500,
+      shareRate: 2.0,
+      magicPoints: 100
+    },
+    {
+      username: 'admin1',
+      authority: 'ADMIN',
+      registTime: '2023-01-15T00:00:00',
+      lastLogin: '2023-05-10T00:00:00',
+      upload: 5000,
+      download: 1000,
+      shareRate: 5.0,
+      magicPoints: 500
+    }
+  ];
+
+  const mockDiscounts = [
+    {
+      id: 1,
+      name: '五一活动',
+      discountType: 'FREE',
+      startTime: '2023-05-01T00:00:00',
+      endTime: '2023-05-07T23:59:59',
+      createTime: '2023-04-25T10:00:00',
+      status: '已过期'
+    },
+    {
+      id: 2,
+      name: '端午节活动',
+      discountType: 'HALF',
+      startTime: '2023-06-10T00:00:00',
+      endTime: '2023-06-15T23:59:59',
+      createTime: '2023-05-30T10:00:00',
+      status: '已过期'
+    }
+  ];
+
+  const mockCurrentDiscount = {
+    id: 3,
+    name: '国庆活动',
+    discountType: 'DOUBLE',
+    startTime: '2023-10-01T00:00:00',
+    endTime: '2023-10-07T23:59:59',
+    createTime: '2023-09-25T10:00:00',
+    status: '进行中'
+  };
+
+  const renderAdminister = () => {
+    return render(
+      <MemoryRouter>
+        <Administer />
+      </MemoryRouter>
+    );
+  };
+
+  test('renders Administer component with user tab by default', async () => {
+    axios.get.mockResolvedValueOnce({
+      data: {
+        code: 200,
+        data: { data: mockUsers }
+      }
+    });
+
+    renderAdminister();
+
+    expect(screen.getByText('系统管理')).toBeInTheDocument();
+    expect(screen.getByText('用户管理')).toBeInTheDocument();
+    expect(screen.getByText('折扣管理')).toBeInTheDocument();
+
+    await waitFor(() => {
+      expect(screen.getByText('user1')).toBeInTheDocument();
+    });
+    
+    expect(screen.getByText('admin1')).toBeInTheDocument();
+  });
+
+  test('switches between user and discount tabs', async () => {
+    axios.get
+      .mockResolvedValueOnce({
+        data: {
+          code: 200,
+          data: { data: mockUsers }
+        }
+      })
+      .mockResolvedValueOnce({
+        data: {
+          code: 200,
+          data: { data: mockDiscounts }
+        }
+      })
+      .mockResolvedValueOnce({
+        data: {
+          code: 200,
+          data: { data: mockCurrentDiscount }
+        }
+      });
+
+    renderAdminister();
+
+    await waitFor(() => {
+      expect(screen.getByText('user1')).toBeInTheDocument();
+    });
+
+    fireEvent.click(screen.getByText('折扣管理'));
+
+    await waitFor(() => {
+      expect(screen.getByText('五一活动')).toBeInTheDocument();
+    });
+    
+    expect(screen.getByText('国庆活动')).toBeInTheDocument();
+  });
+
+ 
+
+  test('changes user authority', async () => {
+    axios.get.mockResolvedValueOnce({
+      data: {
+        code: 200,
+        data: { data: mockUsers }
+      }
+    });
+    axios.put.mockResolvedValueOnce({
+      data: {
+        code: 200,
+        message: '修改用户权限成功'
+      }
+    });
+
+    renderAdminister();
+
+    await waitFor(() => {
+      expect(screen.getByText('user1')).toBeInTheDocument();
+    });
+
+    const selectElement = screen.getAllByRole('combobox')[0];
+    fireEvent.change(selectElement, { target: { value: 'ADMIN' } });
+
+    await waitFor(() => {
+      expect(axios.put).toHaveBeenCalled();
+    });
+    
+    expect(axios.put).toHaveBeenCalledWith(
+      expect.stringContaining('/user/changeAuthority'),
+      {
+        changeUsername: 'user1',
+        authority: 'ADMIN'
+      },
+      expect.any(Object)
+    );
+  });
+
+
+
+  test('shows error messages', async () => {
+    axios.get.mockRejectedValueOnce(new Error('Network Error'));
+
+    renderAdminister();
+
+    await waitFor(() => {
+      expect(screen.getByText(/获取用户列表失败/)).toBeInTheDocument();
+    });
+  });
+});
\ No newline at end of file
diff --git a/src/components/AuthForm.css b/src/components/AuthForm.css
index 8eb1d0a..0348f50 100644
--- a/src/components/AuthForm.css
+++ b/src/components/AuthForm.css
@@ -7,55 +7,58 @@
     min-height: 100vh;

     background-color: #f5f5f5;

     padding: 20px;

-  }

-  

-  .auth-title {

+}

+

+.auth-title {

     color: #333;

     font-size: 2.5rem;

     margin-bottom: 2rem;

     text-align: center;

-  }

-  

-  .auth-form-wrapper {

+}

+

+.auth-form-wrapper {

     width: 100%;

     max-width: 400px;

     background: white;

     padding: 2rem;

     border-radius: 8px;

     box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);

-  }

-  

-  .auth-form {

+}

+

+.auth-form {

     display: flex;

     flex-direction: column;

     gap: 1rem;

-  }

-  

-  .auth-form h2 {

+}

+

+.auth-form h2 {

     color: #333;

     text-align: center;

     margin-bottom: 1.5rem;

-  }

-  

-  .form-group {

+}

+

+.form-group {

     display: flex;

     flex-direction: column;

     gap: 0.5rem;

-  }

-  

-  .form-group input {

+}

+

+.form-group input {

     padding: 0.8rem;

     border: 1px solid #ddd;

     border-radius: 4px;

     font-size: 1rem;

-  }

-  

-  .form-group input:focus {

+    width: 100%;

+    box-sizing: border-box; /* 确保padding不会影响宽度 */

+    height: 42px; /* 固定高度 */

+}

+

+.form-group input:focus {

     outline: none;

     border-color: #007bff;

-  }

-  

-  .auth-button {

+}

+

+.auth-button {

     padding: 0.8rem;

     background-color: #007bff;

     color: white;

@@ -64,18 +67,19 @@
     font-size: 1rem;

     cursor: pointer;

     transition: background-color 0.3s;

-  }

-  

-  .auth-button:hover {

+    height: 42px; /* 与输入框高度一致 */

+}

+

+.auth-button:hover {

     background-color: #0056b3;

-  }

-  

-  .auth-button:disabled {

+}

+

+.auth-button:disabled {

     background-color: #cccccc;

     cursor: not-allowed;

-  }

-  

-  .auth-switch {

+}

+

+.auth-switch {

     display: flex;

     justify-content: center;

     align-items: center;

@@ -83,9 +87,9 @@
     margin-top: 1rem;

     font-size: 0.9rem;

     color: #666;

-  }

-  

-  .switch-button {

+}

+

+.switch-button {

     background: none;

     border: none;

     color: #007bff;

@@ -93,17 +97,17 @@
     text-decoration: underline;

     font-size: 0.9rem;

     padding: 0;

-  }

-  

-  .switch-button:hover {

+}

+

+.switch-button:hover {

     color: #0056b3;

-  }

-  

-  .error-message {

+}

+

+.error-message {

     color: #dc3545;

     background-color: #f8d7da;

     padding: 0.5rem;

     border-radius: 4px;

     text-align: center;

     margin-bottom: 1rem;

-  }
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/src/components/Dashboard.css b/src/components/Dashboard.css
index af9e421..09ab88f 100644
--- a/src/components/Dashboard.css
+++ b/src/components/Dashboard.css
@@ -646,4 +646,73 @@
   z-index: 100;

   padding: 15px;

   box-shadow: 0 2px 5px rgba(0,0,0,0.1);

+}

+

+.admin-center-btn {

+  padding: 5px 10px;

+  margin-right: 10px;

+  background-color: #ff5722;

+  color: white;

+  border: none;

+  border-radius: 4px;

+  cursor: pointer;

+  font-size: 14px;

+}

+

+.admin-center-btn:hover {

+  background-color: #e64a19;

+}

+

+/* 区域搜索容器样式 */

+.section-search-container {

+  display: flex;

+  margin-bottom: 20px;

+  gap: 10px;

+}

+

+.section-search-input {

+  flex: 1;

+  padding: 10px 15px;

+  border: 1px solid #ddd;

+  border-radius: 4px;

+  font-size: 1rem;

+}

+

+.section-search-button {

+  padding: 10px 20px;

+  background-color: #007bff;

+  color: white;

+  border: none;

+  border-radius: 4px;

+  cursor: pointer;

+  transition: background-color 0.3s;

+}

+

+.section-search-button:hover {

+  background-color: #0056b3;

+}

+

+/* 分享区顶部操作栏 */

+.share-top-actions {

+  display: flex;

+  justify-content: space-between;

+  align-items: center;

+  margin-bottom: 20px;

+  gap: 20px;

+}

+

+/* 上传按钮样式 */

+.upload-btn {

+  padding: 10px 20px;

+  background-color: #28a745;

+  color: white;

+  border: none;

+  border-radius: 4px;

+  cursor: pointer;

+  transition: background-color 0.3s;

+  white-space: nowrap;

+}

+

+.upload-btn:hover {

+  background-color: #218838;

 }
\ No newline at end of file
diff --git a/src/components/Dashboard.jsx b/src/components/Dashboard.jsx
index 941210c..97a01cc 100644
--- a/src/components/Dashboard.jsx
+++ b/src/components/Dashboard.jsx
@@ -1,940 +1,941 @@
-import React, { useEffect, useState } from 'react';

-import { useNavigate, useLocation,useParams } from 'react-router-dom';

-// import { getUserInfo } from '../api';  // 保留import但注释掉

-import { createTorrent, getTorrents} from '../api/torrent'; 

+import React, {useEffect, useState} from 'react';

+import {useNavigate, useLocation, useParams} from 'react-router-dom';

+// import { getUserInfo } from '../api/auth';  

+import {createTorrent, getTorrents} from '../api/torrent';

 import './Dashboard.css';

-import { createPost, getPosts } from '../api/helpPost';

+import {createPost, getPosts} from '../api/helpPost';

 

 

-const Dashboard = ({ onLogout }) => {

-  const location = useLocation();

-  const [userInfo, setUserInfo] = useState(null);

-  const [loading, setLoading] = useState(false);

-  const [error, setError] = useState('');

-  const [currentSlide, setCurrentSlide] = useState(0);

-  const navigate = useNavigate();

-  const {tab} = useParams();

-  const [showUploadModal, setShowUploadModal] = useState(false);

-  const [isUploading, setIsUploading] = useState(false);

-  const [uploadData, setUploadData] = useState({

-    name: '',

-    type: '',

-    region: '',

-    subtitle: '',

-    resolution: '', // 新增分辨率字段

-    file: null,

-    description: ''

-  });

-  const [showPostModal, setShowPostModal] = useState(false);

-  const [postTitle, setPostTitle] = useState('');

-  const [postContent, setPostContent] = useState('');

-  const [selectedImage, setSelectedImage] = useState(null);

-  const [helpPosts, setHelpPosts] = useState([]);

-  const [helpLoading, setHelpLoading] = useState(false);

-  const [helpError, setHelpError] = useState(null);

-  const [currentPage, setCurrentPage] = useState(1);

-  const [totalPages, setTotalPages] = useState(1);

+const Dashboard = ({onLogout}) => {

+    const location = useLocation();

+    const [userInfo, setUserInfo] = useState(null);

+    const [loading, setLoading] = useState(false);

+    const [error, setError] = useState('');

+    const [currentSlide, setCurrentSlide] = useState(0);

+    const navigate = useNavigate();

+    const {tab} = useParams();

+    const [showUploadModal, setShowUploadModal] = useState(false);

+    const [isUploading, setIsUploading] = useState(false);

+    const [uploadData, setUploadData] = useState({

+        name: '',

+        type: '',

+        region: '',

+        subtitle: '',

+        resolution: '', // 新增分辨率字段

+        file: null,

+        description: ''

+    });

+    const [showPostModal, setShowPostModal] = useState(false);

+    const [postTitle, setPostTitle] = useState('');

+    const [postContent, setPostContent] = useState('');

+    const [selectedImage, setSelectedImage] = useState(null);

+    const [helpPosts, setHelpPosts] = useState([]);

+    const [helpLoading, setHelpLoading] = useState(false);

+    const [helpError, setHelpError] = useState(null);

+    const [currentPage, setCurrentPage] = useState(1);

+    const [totalPages, setTotalPages] = useState(1);

 

     // 添加状态

-  const [torrentPosts, setTorrentPosts] = useState([]);

-  const [torrentLoading, setTorrentLoading] = useState(false);

-  const [torrentError, setTorrentError] = useState(null);

-  

-  const [filteredResources, setFilteredResources] = useState(torrentPosts);

-  

-  const activeTab = tab || 'announcement'; // 如果没有tab参数,则默认为announcement

-  // 从location.state中初始化状态

-  

-  

-  const handleTabChange = (tabName) => {

-    navigate(`/dashboard/${tabName}`, { 

-      state: { 

-        savedFilters: selectedFilters, // 使用新的筛选状态 // 保留现有状态

-        activeTab: tabName // 可选,如果其他组件依赖这个 state

-      } 

-    });

-  };

-  

-  //公告区

-  const [announcements] = useState([

-    {

-      id: 1,

-      title: '系统维护与更新',

-      content: '2023-10-15 02:00-06:00将进行系统维护升级,期间网站将无法访问。本次更新包含:\n1. 数据库服务器迁移\n2. 安全补丁更新\n3. CDN节点优化\n\n请提前做好下载安排。',

-      author: '系统管理员',

-      date: '2023-10-10',

-      excerpt: '2023-10-15 02:00-06:00将进行系统维护,期间无法访问',

-      category: '系统'

-    },

-    {

-      id: 2,

-      title: '资源上新',

-      content: '最新热门电影《奥本海默》4K REMUX资源已上线,包含:\n- 4K HDR版本 (56.8GB)\n- 1080P标准版 (12.3GB)\n- 中英双语字幕\n\n欢迎下载保种!',

-      author: '资源组',

-      date: '2023-10-08',

-      excerpt: '最新热门电影《奥本海默》4K资源已上线',

-      category: '资源'

-    },

-    {

-      id: 3,

-      title: '积分规则调整',

-      content: '自11月1日起,上传资源积分奖励提升20%,具体规则如下:\n- 上传电影资源:每GB 10积分\n- 上传电视剧资源:每GB 8积分\n- 上传动漫资源:每GB 6积分\n\n感谢大家的支持与贡献!',

-      author: '管理员',

-      date: '2023-10-05',

-      excerpt: '自11月1日起,上传资源积分奖励提升20%',

-      category: '公告'

-    },

-    {

-      id: 4,

-      title: '违规处理公告',

-      content: '用户user123因发布虚假资源已被封禁,相关资源已删除。请大家遵守社区规则,维护良好的分享环境。',

-      author: '管理员',

-      date: '2023-10-03',

-      excerpt: '用户user123因发布虚假资源已被封禁',

-      category: '违规'

-    },

-    {

-      id: 5,

-      title: '节日活动',

-      content: '国庆期间所有资源下载积分减半,活动时间:2023年10月1日至2023年10月7日。',

-      author: '活动组',

-      date: '2023-09-30',

-      excerpt: '国庆期间所有资源下载积分减半',

-      category: '活动'

-    },

-    {

-      id: 6,

-      title: '客户端更新',

-      content: 'PT客户端v2.5.0已发布,修复多个BUG,新增资源搜索功能。请尽快更新到最新版本以获得更好的使用体验。',

-      author: '开发组',

-      date: '2023-09-28',

-      excerpt: 'PT客户端v2.5.0已发布,修复多个BUG',

-      category: '更新'

-    },

-    // 其他公告...

-  ]);

+    const [torrentPosts, setTorrentPosts] = useState([]);

+    const [torrentLoading, setTorrentLoading] = useState(false);

+    const [torrentError, setTorrentError] = useState(null);

 

-  

-  const handleAnnouncementClick = (announcement,e) => {

-    if (!e.target.closest('.exclude-click')) {

-      navigate(`/announcement/${announcement.id}`, {

-        state: {

-          announcement,

-          returnPath: `/dashboard/${activeTab}`,

-          scrollPosition: window.scrollY,

-          activeTab

+    const [filteredResources, setFilteredResources] = useState(torrentPosts);

+    const [isAdmin, setIsAdmin] = useState(false);

+

+

+    const activeTab = tab || 'announcement'; // 如果没有tab参数,则默认为announcement

+    // 从location.state中初始化状态

+

+

+    const handleTabChange = (tabName) => {

+        navigate(`/dashboard/${tabName}`, {

+            state: {

+                savedFilters: selectedFilters, // 使用新的筛选状态 // 保留现有状态

+                activeTab: tabName // 可选,如果其他组件依赖这个 state

+            }

+        });

+    };

+

+    //公告区

+    const [announcements] = useState([

+        {

+            id: 1,

+            title: '系统维护与更新',

+            content: '2023-10-15 02:00-06:00将进行系统维护升级,期间网站将无法访问。本次更新包含:\n1. 数据库服务器迁移\n2. 安全补丁更新\n3. CDN节点优化\n\n请提前做好下载安排。',

+            author: '系统管理员',

+            date: '2023-10-10',

+            excerpt: '2023-10-15 02:00-06:00将进行系统维护,期间无法访问',

+            category: '系统'

+        },

+        {

+            id: 2,

+            title: '资源上新',

+            content: '最新热门电影《奥本海默》4K REMUX资源已上线,包含:\n- 4K HDR版本 (56.8GB)\n- 1080P标准版 (12.3GB)\n- 中英双语字幕\n\n欢迎下载保种!',

+            author: '资源组',

+            date: '2023-10-08',

+            excerpt: '最新热门电影《奥本海默》4K资源已上线',

+            category: '资源'

+        },

+        {

+            id: 3,

+            title: '积分规则调整',

+            content: '自11月1日起,上传资源积分奖励提升20%,具体规则如下:\n- 上传电影资源:每GB 10积分\n- 上传电视剧资源:每GB 8积分\n- 上传动漫资源:每GB 6积分\n\n感谢大家的支持与贡献!',

+            author: '管理员',

+            date: '2023-10-05',

+            excerpt: '自11月1日起,上传资源积分奖励提升20%',

+            category: '公告'

+        },

+        {

+            id: 4,

+            title: '违规处理公告',

+            content: '用户user123因发布虚假资源已被封禁,相关资源已删除。请大家遵守社区规则,维护良好的分享环境。',

+            author: '管理员',

+            date: '2023-10-03',

+            excerpt: '用户user123因发布虚假资源已被封禁',

+            category: '违规'

+        },

+        {

+            id: 5,

+            title: '节日活动',

+            content: '国庆期间所有资源下载积分减半,活动时间:2023年10月1日至2023年10月7日。',

+            author: '活动组',

+            date: '2023-09-30',

+            excerpt: '国庆期间所有资源下载积分减半',

+            category: '活动'

+        },

+        {

+            id: 6,

+            title: '客户端更新',

+            content: 'PT客户端v2.5.0已发布,修复多个BUG,新增资源搜索功能。请尽快更新到最新版本以获得更好的使用体验。',

+            author: '开发组',

+            date: '2023-09-28',

+            excerpt: 'PT客户端v2.5.0已发布,修复多个BUG',

+            category: '更新'

+        },

+        // 其他公告...

+    ]);

+

+

+    const handleAnnouncementClick = (announcement, e) => {

+        if (!e.target.closest('.exclude-click')) {

+            navigate(`/announcement/${announcement.id}`, {

+                state: {

+                    announcement,

+                    returnPath: `/dashboard/${activeTab}`,

+                    scrollPosition: window.scrollY,

+                    activeTab

+                }

+            });

         }

-      });

-    }

-  };

+    };

 

 

-  //资源区

- 

+    //资源区

+    const handleFileChange = (e) => {

+        setUploadData({...uploadData, file: e.target.files[0]});

+    };

 

-  const handleFileChange = (e) => {

-    setUploadData({...uploadData, file: e.target.files[0]});

-  };

+    const handleUploadSubmit = async (e) => {

+        e.preventDefault();

+        try {

+            setIsUploading(true);

 

-  const handleUploadSubmit = async (e) => {

-    e.preventDefault();

-    

-    try {

-      setIsUploading(true);

-      const username = localStorage.getItem('username');

-      

-      // 创建种子数据

-      const torrentData = {

-        torrentName: uploadData.name,

-        category: uploadData.type,

-        regin: uploadData.region,

-        resolution: uploadData.resolution,

-        subtitle: uploadData.subtitle,

-        description: uploadData.description,

-        username: username,

-        filePath: "D:\\大学\\大三_下\\实训BT服务器下载\\G2-ptPlatform-backend\\torrents\\[电影天堂www.dytt89.com]两杆大烟枪BD中英双字.mp4.torrent" // 默认路径

-      };

-  

-      // 调用API创建种子

-      await createTorrent(

-        torrentData.torrentName,

-        torrentData.description,

-        torrentData.username,

-        torrentData.category,

-        torrentData.regin,

-        torrentData.resolution,

-        torrentData.subtitle,

-        torrentData.filePath

-      );

-      

-      // 上传成功处理

-      setShowUploadModal(false);

-      setUploadData({ 

-        name: '', 

-        type: '', 

-        region: '', 

-        subtitle: '', 

-        resolution: '', 

-        file: null, 

-        description: '' 

-      });

-      alert('种子创建成功!');

-      

-      // 刷新列表

-      fetchTorrentPosts(currentPage);

-      

-    } catch (error) {

-      console.error('创建失败:', error);

-      alert('创建失败: ' + (error.response?.data?.message || error.message));

-    } finally {

-      setIsUploading(false);

-    }

-  };

+            const torrentData = {

+                torrentName: uploadData.name,

+                description: uploadData.description,

+                category: uploadData.type,

+                region: uploadData.region,

+                resolution: uploadData.resolution,

+                subtitle: uploadData.subtitle

+            };

 

-  const handlePostSubmit = async (e) => {

-    e.preventDefault();

-    try {

-      const username = localStorage.getItem('username');

-      const response = await createPost(

-        postTitle,

-        postContent,

-        username

-      );

-      

-      if (response.data.code === 200) {

-        // 刷新帖子列表

-        await fetchHelpPosts();

-        // 重置表单

-        setShowPostModal(false);

-        setPostTitle('');

-        setPostContent('');

-        setSelectedImage(null);

-      } else {

-        setHelpError(response.data.message || '发帖失败');

-      }

-    } catch (err) {

-      setHelpError(err.message || '发帖失败');

-    }

-  };

+            await createTorrent(torrentData, uploadData.file);

+

+            // 上传成功处理

+            setShowUploadModal(false);

+            setUploadData({

+                name: '',

+                type: '',

+                region: '',

+                subtitle: '',

+                resolution: '',

+                file: null,

+                description: ''

+            });

+            alert('种子创建成功!');

+

+            // 刷新列表

+            await fetchTorrentPosts(currentPage);

+

+        } catch (error) {

+            console.error('创建失败:', error);

+            alert('创建失败: ' + (error.response?.data?.message || error.message));

+        } finally {

+            setIsUploading(false);

+        }

+    };

+

+    const handlePostSubmit = async (e) => {

+        e.preventDefault();

+        try {

+            const username = localStorage.getItem('username');

+            const response = await createPost(

+                postTitle,

+                postContent,

+                username

+            );

+

+            if (response.data.code === 200) {

+                // 刷新帖子列表

+                await fetchHelpPosts();

+                // 重置表单

+                setShowPostModal(false);

+                setPostTitle('');

+                setPostContent('');

+                setSelectedImage(null);

+            } else {

+                setHelpError(response.data.message || '发帖失败');

+            }

+        } catch (err) {

+            setHelpError(err.message || '发帖失败');

+        }

+    };

 

     // 获取Torrent帖子列表

-  const fetchTorrentPosts = async (page = 1) => {

-  setTorrentLoading(true);

-  try {

-    const response = await getTorrents(page);

-    setTorrentPosts(response.data.data.records);

-    setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条

-    setCurrentPage(page);

-  } catch (err) {

-    setTorrentError(err.message);

-  } finally {

-    setTorrentLoading(false);

-  }

-};

+    const fetchTorrentPosts = async (page = 1) => {

+        setTorrentLoading(true);

+        try {

+            const response = await getTorrents(page);

+            setTorrentPosts(response.data.data.records);

+            setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条

+            setCurrentPage(page);

+        } catch (err) {

+            setTorrentError(err.message);

+        } finally {

+            setTorrentLoading(false);

+        }

+    };

 

-  // 在useEffect中调用

-  useEffect(() => {

-    if (activeTab === 'share') {

-      fetchTorrentPosts();

-    }

-  }, [activeTab]);

+    // 在useEffect中调用

+    useEffect(() => {

+        if (activeTab === 'share') {

+            fetchTorrentPosts();

+        }

+    }, [activeTab]);

 

-  const handleImageUpload = (e) => {

-    setSelectedImage(e.target.files[0]);

-  };

+    const handleImageUpload = (e) => {

+        setSelectedImage(e.target.files[0]);

+    };

 

 

+    const fetchHelpPosts = async (page = 1) => {

+        setHelpLoading(true);

+        try {

+            const response = await getPosts(page);

+            if (response.data.code === 200) {

+                setHelpPosts(response.data.data.records);

+                setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条

+                setCurrentPage(page);

+            } else {

+                setHelpError(response.data.message || '获取求助帖失败');

+            }

+        } catch (err) {

+            setHelpError(err.message || '获取求助帖失败');

+        } finally {

+            setHelpLoading(false);

+        }

+    };

+    useEffect(() => {

+        if (activeTab === 'help') {

+            fetchHelpPosts(currentPage);

+        }

+    }, [activeTab, currentPage]); // 添加 currentPage 作为依赖

 

 

-  const fetchHelpPosts = async (page = 1) => {

-    setHelpLoading(true);

-    try {

-      const response = await getPosts(page);

-      if (response.data.code === 200) {

-        setHelpPosts(response.data.data.records);

-        setTotalPages(Math.ceil(response.data.data.total / 5)); // 假设每页5条

-        setCurrentPage(page);

-      } else {

-        setHelpError(response.data.message || '获取求助帖失败');

-      }

-    } catch (err) {

-      setHelpError(err.message || '获取求助帖失败');

-    } finally {

-      setHelpLoading(false);

-    }

-  };

-  useEffect(() => {

-    if (activeTab === 'help') {

-      fetchHelpPosts(currentPage);

-    }

-  }, [activeTab, currentPage]); // 添加 currentPage 作为依赖

+    // 分类维度配置

+    const filterCategories = {

+        type: {

+            label: '类型',

+            options: {

+                'all': '全部',

+                '电影': '电影',

+                '电视剧': '电视剧',

+                '动漫': '动漫',

+                '综艺': '综艺'

+            }

+        },

+        subtitle: {

+            label: '字幕',

+            options: {

+                'all': '全部',

+                'yes': '有字幕',

+                'no': '无字幕'

+            }

+        },

+        region: {

+            label: '地区',

+            options: {

+                'all': '全部',

+                'cn': '大陆',

+                'us': '欧美',

+                'jp': '日本'

+            }

+        }

+    };

 

-

-  

-

-  // 分类维度配置

-  const filterCategories = {

-    type: {

-      label: '类型',

-      options: {

-        'all': '全部',

-        '电影': '电影',

-        '电视剧': '电视剧',

-        '动漫': '动漫',

-        '综艺': '综艺'

-      }

-    },

-    subtitle: {

-      label: '字幕',

-      options: {

-        'all': '全部',

-        'yes': '有字幕',

-        'no': '无字幕'

-      }

-    },

-    region: {

-      label: '地区',

-      options: {

-        'all': '全部',

-        'cn': '大陆',

-        'us': '欧美',

-        'jp': '日本'

-      }

-    }

-  };

-  

-  const [selectedFilters, setSelectedFilters] = useState(

-    location.state?.savedFilters || 

-    Object.keys(filterCategories).reduce((acc, category) => {

-      acc[category] = 'all';

-      return acc;

-    }, {})

-  );

-

+    const [selectedFilters, setSelectedFilters] = useState(

+        location.state?.savedFilters ||

+        Object.keys(filterCategories).reduce((acc, category) => {

+            acc[category] = 'all';

+            return acc;

+        }, {})

+    );

 

 

 // 处理筛选条件变更

-const handleFilterSelect = (category, value) => {

-  setSelectedFilters(prev => ({

-    ...prev,

-    [category]: prev[category] === value ? null : value // 点击已选中的则取消

-  }));

-};

-

-//应用筛选条件

-const applyFilters = () => {

-  const result = torrentPosts.filter(resource => {

-    return Object.entries(selectedFilters).every(([category, selectedValue]) => {

-      if (selectedValue === 'all') return true;

-      if (category === 'subtitle') {

-        return resource.subtitle === (selectedValue === 'yes');

-      }

-      return resource[category] === selectedValue;

-    });

-  });

-  setFilteredResources(result);

-};

-

-

-  // 恢复滚动位置

-  useEffect(() => {

-    if (location.state?.scrollPosition) {

-      window.scrollTo(0, location.state.scrollPosition);

-    }

-  }, [location.state]);

-

-

-  useEffect(() => {

-    const token = localStorage.getItem('token');

-    if (!token) {

-      navigate('/login');

-      return;

-    }

-

-    /* 保留但注释掉实际的用户信息获取

-    const fetchUserInfo = async () => {

-      try {

-        const response = await getUserInfo(token);

-        if (response.data.code === 200) {

-          setUserInfo(response.data.data);

-        } else {

-          setError('获取用户信息失败');

-        }

-      } catch (err) {

-        setError('获取用户信息失败');

-      } finally {

-        setLoading(false);

-      }

+    const handleFilterSelect = (category, value) => {

+        setSelectedFilters(prev => ({

+            ...prev,

+            [category]: prev[category] === value ? null : value // 点击已选中的则取消

+        }));

     };

 

-    fetchUserInfo();

-    */

-    

-    // 模拟用户信息

-    setUserInfo({ 

-      name: localStorage.getItem('username') || '演示用户', // 确保这里读取的是最新值

-    avatar: 'https://via.placeholder.com/40'

-    });

-    setLoading(false);

-  }, [navigate]);

-

-  // 轮播图自动切换效果

-  useEffect(() => {

-    if (activeTab === 'announcement') {

-      const timer = setInterval(() => {

-        setCurrentSlide(prev => (prev + 1) % 3); // 3张轮播图循环

-      }, 3000);

-      return () => clearInterval(timer);

-    }

-  }, [activeTab]);

-

-  useEffect(() => {

-    if (activeTab === 'help') {

-      fetchHelpPosts();

-    }

-  }, [activeTab]);

-

-  const renderContent = () => {

-    switch(activeTab) {

-      case 'announcement':

-        return (

-          <div className="content-area" data-testid="announcement-section"> 

-            {/* 轮播图区域 */}

-            <div className="carousel-container">

-              <div className={`carousel-slide ${currentSlide === 0 ? 'active' : ''}`}>

-                <div className="carousel-image gray-bg">促销活动1</div>

-              </div>

-              <div className={`carousel-slide ${currentSlide === 1 ? 'active' : ''}`}>

-                <div className="carousel-image gray-bg">促销活动2</div>

-              </div>

-              <div className={`carousel-slide ${currentSlide === 2 ? 'active' : ''}`}>

-                <div className="carousel-image gray-bg">促销活动3</div>

-              </div>

-              <div className="carousel-dots">

-                <span className={`dot ${currentSlide === 0 ? 'active' : ''}`}></span>

-                <span className={`dot ${currentSlide === 1 ? 'active' : ''}`}></span>

-                <span className={`dot ${currentSlide === 2 ? 'active' : ''}`}></span>

-              </div>

-            </div>

-

-            {/* 公告区块区域 */}

-            <div className="announcement-grid">

-              {announcements.map(announcement => (

-                <div 

-                  key={announcement.id}

-                  className="announcement-card"

-                  onClick={(e) => handleAnnouncementClick(announcement, e)}

-                >

-                  <h3>{announcement.title}</h3>

-                  <p>{announcement.excerpt}</p>

-                  <div className="announcement-footer exclude-click">

-                    <span>{announcement.author}</span>

-                    <span>{announcement.date}</span>

-                  </div>

-                </div>

-              ))}

-            </div>

-          </div>

-        );

-        case 'share':

-          return (

-            <div className="content-area" data-testid="share-section">

-              {/* 上传按钮 - 添加在筛选区上方 */}

-              <div className="upload-header">

-                <button 

-                  className="upload-btn"

-                  onClick={() => setShowUploadModal(true)}

-                >

-                  + 上传种子

-                </button>

-              </div>

-              {/* 分类筛选区 */}

-              <div className="filter-section">

-                {Object.entries(filterCategories).map(([category, config]) => (

-                  <div key={category} className="filter-group">

-                    <h4>{config.label}:</h4>

-                    <div className="filter-options">

-                      {Object.entries(config.options).map(([value, label]) => (

-                        <button

-                          key={value}

-                          className={`filter-btn ${

-                            selectedFilters[category] === value ? 'active' : ''

-                          }`}

-                          onClick={() => handleFilterSelect(category, value)}

-                        >

-                          {label}

-                        </button>

-                      ))}

-                    </div>

-                  </div>

-                ))}

-        

-                <button 

-                  className="confirm-btn"

-                  onClick={applyFilters}

-                >

-                  确认筛选

-                </button>

-              </div>

-        

-              {/* 上传弹窗 */}

-              {showUploadModal && (

-                <div className="modal-overlay">

-                  <div className="upload-modal">

-                    <h3>上传新种子</h3>

-                    <button 

-                      className="close-btn"

-                      onClick={() => setShowUploadModal(false)}

-                    >

-                      ×

-                    </button>

-                    

-                    <form onSubmit={handleUploadSubmit}>

-                      <div className="form-group">

-                        <label>种子名称</label>

-                        <input

-                          type="text"

-                          value={uploadData.name}

-                          onChange={(e) => setUploadData({...uploadData, name: e.target.value})}

-                          required

-                        />

-                      </div>

-        

-                      <div className="form-group">

-                        <label>资源类型</label>

-                        <select

-                          value={uploadData.type}

-                          onChange={(e) => setUploadData({...uploadData, type: e.target.value})}

-                          required

-                        >

-                          <option value="">请选择</option>

-                          <option value="电影">电影</option>

-                          <option value="电视剧">电视剧</option>

-                          <option value="动漫">动漫</option>

-                          <option value="综艺">综艺</option>

-                          <option value="音乐">音乐</option>

-                        </select>

-                      </div>

-        

-                      {/* 新增地区输入框 */}

-                      <div className="form-group">

-                        <label>地区</label>

-                        <input

-                          type="text"

-                          value={uploadData.region || ''}

-                          onChange={(e) => setUploadData({...uploadData, region: e.target.value})}

-                          placeholder="例如: 美国, 中国, 日本等"

-                          required

-                        />

-                      </div>

-

-                      {/* 添加分辨率下拉框 */}

-                      <div className="form-group">

-                        <label>分辨率</label>

-                        <select

-                          value={uploadData.resolution || ''}

-                          onChange={(e) => setUploadData({...uploadData, resolution: e.target.value})}

-                          required

-                        >

-                          <option value="">请选择</option>

-                          <option value="4K">4K</option>

-                          <option value="2K">2K</option>

-                          <option value="1080P">1080P</option>

-                          <option value="720P">720P</option>

-                          <option value="SD">SD</option>

-                          <option value="无损音源">无损音源</option>

-                          <option value="杜比全景声">杜比全景声</option>

-                          <option value="其他">其他</option>

-                        </select>

-                      </div>

-

-                    

-        

-                      {/* 新增字幕语言下拉框 */}

-                      <div className="form-group">

-                        <label>字幕语言</label>

-                        <select

-                          value={uploadData.subtitle || ''}

-                          onChange={(e) => setUploadData({...uploadData, subtitle: e.target.value})}

-                          required

-                        >

-                          <option value="">请选择</option>

-                          <option value="无需字幕">无需字幕</option>

-                          <option value="暂无字幕">暂无字幕</option>

-                          <option value="自带中文字幕">自带中文字幕</option>

-                          <option value="自带双语字幕(含中文)">自带双语字幕(含中文)</option>

-                          <option value="附件中文字幕">附件中文字幕</option>

-                          <option value="附件双语字幕">附件双语字幕</option>

-                        </select>

-                      </div>

-        

-                      <div className="form-group">

-                        <label>种子文件</label>

-                        <input

-                          type="file"

-                          accept=".torrent"

-                          onChange={handleFileChange}

-

-                        />

-                      </div>

-        

-                      <div className="form-group">

-                        <label>简介</label>

-                        <textarea

-                          value={uploadData.description}

-                          onChange={(e) => setUploadData({...uploadData, description: e.target.value})}

-                        />

-                      </div>

-        

-                      <div className="form-actions">

-                        <button 

-                          type="button"

-                          className="cancel-btn"

-                          onClick={() => setShowUploadModal(false)}

-                        >

-                          取消

-                        </button>

-                        <button 

-                          type="submit" 

-                          className="confirm-btn"

-                          disabled={isUploading}

-                        >

-                          {isUploading ? '上传中...' : '确认上传'}

-                        </button>

-                      </div>

-                    </form>

-                  </div>

-                </div>

-              )}

-              

-              <div className="resource-list">

-                {torrentPosts.map(torrent => (

-                  <div 

-                    key={torrent.id}

-                    className="resource-item"

-                    onClick={() => navigate(`/torrent/${torrent.id}`)}

-                  >

-                    <div className="resource-poster">

-                      <div className="poster-image gray-bg">{torrent.torrentName.charAt(0)}</div>

-                    </div>

-                    <div className="resource-info">

-                      <h3 className="resource-title">{torrent.torrentName}</h3>

-                      <p className="resource-meta">

-                        {torrent.resolution} | {torrent.region} | {torrent.category}

-                      </p>

-                      <p className="resource-subtitle">字幕: {torrent.subtitle}</p>

-                    </div>

-                    <div className="resource-stats">

-                      <span className="stat">{torrent.size}</span>

-                      <span className="stat">发布者: {torrent.username}</span>

-                    </div>

-                    <button 

-                      className="download-btn"

-                      onClick={(e) => {

-                        e.stopPropagation();

-                        // 下载逻辑

-                      }}

-                    >

-                      立即下载

-                    </button>

-                  </div>

-                ))}

-              </div>

-

-              {/* 分页控件 */}

-              <div className="pagination">

-                <button 

-                  onClick={() => fetchTorrentPosts(currentPage - 1)} 

-                  disabled={currentPage === 1}

-                >

-                  上一页

-                </button>

-                

-                {Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (

-                  <button

-                    key={page}

-                    onClick={() => fetchTorrentPosts(page)}

-                    className={currentPage === page ? 'active' : ''}

-                  >

-                    {page}

-                  </button>

-                ))}

-                

-                <button 

-                  onClick={() => fetchTorrentPosts(currentPage + 1)} 

-                  disabled={currentPage === totalPages}

-                >

-                  下一页

-                </button>

-              </div>

-            </div>

-          );

-      // 在Dashboard.jsx的renderContent函数中修改case 'request'部分

-      case 'request':

-        return (

-          <div className="content-area" data-testid="request-section">

-            {/* 求种区帖子列表 */}

-            <div className="request-list">

-              {[

-                {

-                  id: 1,

-                  title: '求《药屋少女的呢喃》第二季全集',

-                  content: '求1080P带中文字幕版本,最好是内嵌字幕不是外挂的',

-                  author: '动漫爱好者',

-                  authorAvatar: 'https://via.placeholder.com/40',

-                  date: '2023-10-15',

-                  likeCount: 24,

-                  commentCount: 8

-                },

-                {

-                  id: 2,

-                  title: '求《奥本海默》IMAX版',

-                  content: '最好是原盘或者高码率的版本,谢谢各位大佬',

-                  author: '电影收藏家',

-                  authorAvatar: 'https://via.placeholder.com/40',

-                  date: '2023-10-14',

-                  likeCount: 15,

-                  commentCount: 5

+//应用筛选条件

+    const applyFilters = () => {

+        const result = torrentPosts.filter(resource => {

+            return Object.entries(selectedFilters).every(([category, selectedValue]) => {

+                if (selectedValue === 'all') return true;

+                if (category === 'subtitle') {

+                    return resource.subtitle === (selectedValue === 'yes');

                 }

-              ].map(post => (

-                <div 

-                  key={post.id} 

-                  className="request-post"

-                  onClick={() => navigate(`/request/${post.id}`)}

-                >

-                  <div className="post-header">

-                    <img src={post.authorAvatar} alt={post.author} className="post-avatar" />

-                    <div className="post-author">{post.author}</div>

-                    <div className="post-date">{post.date}</div>

-                  </div>

-                  <h3 className="post-title">{post.title}</h3>

-                  <p className="post-content">{post.content}</p>

-                  <div className="post-stats">

-                    <span className="post-likes">👍 {post.likeCount}</span>

-                    <span className="post-comments">💬 {post.commentCount}</span>

-                  </div>

-                </div>

-              ))}

-            </div>

-          </div>

-        );

-      // 在Dashboard.jsx的renderContent函数中修改case 'help'部分

-      case 'help':

-        return (

-          <div className="content-area" data-testid="help-section">

-            {/* 新增发帖按钮 */}

-            <div className="post-header">

-              <button 

-                className="create-post-btn"

-                onClick={() => setShowPostModal(true)}

-              >

-                + 发帖求助

-              </button>

-            </div>

+                return resource[category] === selectedValue;

+            });

+        });

+        setFilteredResources(result);

+    };

 

-            {/* 加载状态和错误提示 */}

-            {helpLoading && <div className="loading">加载中...</div>}

-            {helpError && <div className="error">{helpError}</div>}

 

-            {/* 求助区帖子列表 */}

-            <div className="help-list">

-              {helpPosts.map(post => (

-                <div 

-                  key={post.id} 

-                  className={`help-post ${post.isSolved ? 'solved' : ''}`}

-                  onClick={() => navigate(`/help/${post.id}`)}

-                >

-                  <div className="post-header">

-                    <img 

-                      src={post.authorAvatar || 'https://via.placeholder.com/40'} 

-                      alt={post.authorId} 

-                      className="post-avatar" 

-                    />

-                    <div className="post-author">{post.authorId}</div>

-                    <div className="post-date">

-                      {new Date(post.createTime).toLocaleDateString()}

-                    </div>

-                    {post.isSolved && <span className="solved-badge">已解决</span>}

-                  </div>

-                  <h3 className="post-title">{post.title}</h3>

-                  <p className="post-content">{post.content}</p>

-                  <div className="post-stats">

-                    <span className="post-likes">👍 {post.likeCount || 0}</span>

-                    <span className="post-comments">💬 {post.replyCount || 0}</span>

-                  </div>

-                </div>

-              ))}

-            </div>

+    // 恢复滚动位置

+    useEffect(() => {

+        if (location.state?.scrollPosition) {

+            window.scrollTo(0, location.state.scrollPosition);

+        }

+    }, [location.state]);

 

-            {/* 在帖子列表后添加分页控件 */}

-            <div className="pagination">

-              <button 

-                onClick={() => fetchHelpPosts(currentPage - 1)} 

-                disabled={currentPage === 1}

-              >

-                上一页

-              </button>

-              

-              {Array.from({ length: totalPages }, (_, i) => i + 1).map(page => (

-                <button

-                  key={page}

-                  onClick={() => fetchHelpPosts(page)}

-                  className={currentPage === page ? 'active' : ''}

-                >

-                  {page}

-                </button>

-              ))}

-              

-              <button 

-                onClick={() => fetchHelpPosts(currentPage + 1)} 

-                disabled={currentPage === totalPages}

-              >

-                下一页

-              </button>

-            </div>

-        

-            {/* 新增发帖弹窗 */}

-            {showPostModal && (

-              <div className="post-modal-overlay">

-                <div className="post-modal">

-                  <h3>发布求助帖</h3>

-                  <button 

-                    className="modal-close-btn"

-                    onClick={() => setShowPostModal(false)}

-                  >

-                    ×

-                  </button>

-                  

-                  <form onSubmit={handlePostSubmit}>

-                    <div className="form-group">

-                      <label>帖子标题</label>

-                      <input

-                        type="text"

-                        value={postTitle}

-                        onChange={(e) => setPostTitle(e.target.value)}

-                        placeholder="请输入标题"

-                        required

-                      />

+

+    useEffect(() => {

+        const token = localStorage.getItem('token');

+        if (!token) {

+            navigate('/login');

+            return;

+        }

+

+        /* 保留但注释掉实际的用户信息获取

+          const fetchUserInfo = async () => {

+            try {

+              const response = await getUserInfo(token);

+              if (response.data.code === 200) {

+                setUserInfo(response.data.data);

+              } else {

+                setError('获取用户信息失败');

+              }

+            } catch (err) {

+              setError('获取用户信息失败');

+            } finally {

+              setLoading(false);

+            }

+          };

+

+          fetchUserInfo();

+          */

+

+        // 模拟用户信息

+        setUserInfo({

+            name: localStorage.getItem('username') || '演示用户', // 确保这里读取的是最新值

+            avatar: 'https://via.placeholder.com/40',

+            isAdmin: true

+        });

+        setLoading(false);

+    }, [navigate]);

+

+    // 轮播图自动切换效果

+    useEffect(() => {

+        if (activeTab === 'announcement') {

+            const timer = setInterval(() => {

+                setCurrentSlide(prev => (prev + 1) % 3); // 3张轮播图循环

+            }, 3000);

+            return () => clearInterval(timer);

+        }

+    }, [activeTab]);

+

+    useEffect(() => {

+        if (activeTab === 'help') {

+            fetchHelpPosts();

+        }

+    }, [activeTab]);

+

+    const renderContent = () => {

+        switch (activeTab) {

+            case 'announcement':

+                return (

+                    <div className="content-area" data-testid="announcement-section">

+                        {/* 轮播图区域 */}

+                        <div className="carousel-container">

+                            <div className={`carousel-slide ${currentSlide === 0 ? 'active' : ''}`}>

+                                <div className="carousel-image gray-bg">促销活动1</div>

+                            </div>

+                            <div className={`carousel-slide ${currentSlide === 1 ? 'active' : ''}`}>

+                                <div className="carousel-image gray-bg">促销活动2</div>

+                            </div>

+                            <div className={`carousel-slide ${currentSlide === 2 ? 'active' : ''}`}>

+                                <div className="carousel-image gray-bg">促销活动3</div>

+                            </div>

+                            <div className="carousel-dots">

+                                <span className={`dot ${currentSlide === 0 ? 'active' : ''}`}></span>

+                                <span className={`dot ${currentSlide === 1 ? 'active' : ''}`}></span>

+                                <span className={`dot ${currentSlide === 2 ? 'active' : ''}`}></span>

+                            </div>

+                        </div>

+

+                        {/* 公告区块区域 */}

+                        <div className="announcement-grid">

+                            {announcements.map(announcement => (

+                                <div

+                                    key={announcement.id}

+                                    className="announcement-card"

+                                    onClick={(e) => handleAnnouncementClick(announcement, e)}

+                                >

+                                    <h3>{announcement.title}</h3>

+                                    <p>{announcement.excerpt}</p>

+                                    <div className="announcement-footer exclude-click">

+                                        <span>{announcement.author}</span>

+                                        <span>{announcement.date}</span>

+                                    </div>

+                                </div>

+                            ))}

+                        </div>

                     </div>

-        

-                    <div className="form-group">

-                      <label>帖子内容</label>

-                      <textarea

-                        value={postContent}

-                        onChange={(e) => setPostContent(e.target.value)}

-                        placeholder="详细描述你的问题"

-                        required

-                      />

-                    </div>

-        

-                    <div className="form-group">

-                      <label>上传图片</label>

-                      <div className="upload-image-btn">

-                        <input

-                          type="file"

-                          id="image-upload"

-                          accept="image/*"

-                          onChange={handleImageUpload}

-                          style={{ display: 'none' }}

-                        />

-                        <label htmlFor="image-upload">

-                          {selectedImage ? '已选择图片' : '选择图片'}

-                        </label>

-                        {selectedImage && (

-                          <span className="image-name">{selectedImage.name}</span>

+                );

+            case 'share':

+                return (

+                    <div className="content-area" data-testid="share-section">

+                        {/* 上传按钮 - 添加在筛选区上方 */}

+                        <div className="upload-header">

+                            <button

+                                className="upload-btn"

+                                onClick={() => setShowUploadModal(true)}

+                            >

+                                + 上传种子

+                            </button>

+                        </div>

+                        {/* 分类筛选区 */}

+                        <div className="filter-section">

+                            {Object.entries(filterCategories).map(([category, config]) => (

+                                <div key={category} className="filter-group">

+                                    <h4>{config.label}:</h4>

+                                    <div className="filter-options">

+                                        {Object.entries(config.options).map(([value, label]) => (

+                                            <button

+                                                key={value}

+                                                className={`filter-btn ${

+                                                    selectedFilters[category] === value ? 'active' : ''

+                                                }`}

+                                                onClick={() => handleFilterSelect(category, value)}

+                                            >

+                                                {label}

+                                            </button>

+                                        ))}

+                                    </div>

+                                </div>

+                            ))}

+

+                            <button

+                                className="confirm-btn"

+                                onClick={applyFilters}

+                            >

+                                确认筛选

+                            </button>

+                        </div>

+

+                        {/* 上传弹窗 */}

+                        {showUploadModal && (

+                            <div className="modal-overlay">

+                                <div className="upload-modal">

+                                    <h3>上传新种子</h3>

+                                    <button

+                                        className="close-btn"

+                                        onClick={() => setShowUploadModal(false)}

+                                    >

+                                        ×

+                                    </button>

+

+                                    <form onSubmit={handleUploadSubmit}>

+                                        <div className="form-group">

+                                            <label>种子名称</label>

+                                            <input

+                                                type="text"

+                                                value={uploadData.name}

+                                                onChange={(e) => setUploadData({...uploadData, name: e.target.value})}

+                                                required

+                                            />

+                                        </div>

+

+                                        <div className="form-group">

+                                            <label>资源类型</label>

+                                            <select

+                                                value={uploadData.type}

+                                                onChange={(e) => setUploadData({...uploadData, type: e.target.value})}

+                                                required

+                                            >

+                                                <option value="">请选择</option>

+                                                <option value="电影">电影</option>

+                                                <option value="电视剧">电视剧</option>

+                                                <option value="动漫">动漫</option>

+                                                <option value="综艺">综艺</option>

+                                                <option value="音乐">音乐</option>

+                                            </select>

+                                        </div>

+

+                                        {/* 新增地区输入框 */}

+                                        <div className="form-group">

+                                            <label>地区</label>

+                                            <input

+                                                type="text"

+                                                value={uploadData.region || ''}

+                                                onChange={(e) => setUploadData({...uploadData, region: e.target.value})}

+                                                placeholder="例如: 美国, 中国, 日本等"

+                                                required

+                                            />

+                                        </div>

+

+                                        {/* 添加分辨率下拉框 */}

+                                        <div className="form-group">

+                                            <label>分辨率</label>

+                                            <select

+                                                value={uploadData.resolution || ''}

+                                                onChange={(e) => setUploadData({

+                                                    ...uploadData,

+                                                    resolution: e.target.value

+                                                })}

+                                                required

+                                            >

+                                                <option value="">请选择</option>

+                                                <option value="4K">4K</option>

+                                                <option value="2K">2K</option>

+                                                <option value="1080P">1080P</option>

+                                                <option value="720P">720P</option>

+                                                <option value="SD">SD</option>

+                                                <option value="无损音源">无损音源</option>

+                                                <option value="杜比全景声">杜比全景声</option>

+                                                <option value="其他">其他</option>

+                                            </select>

+                                        </div>

+

+

+                                        {/* 新增字幕语言下拉框 */}

+                                        <div className="form-group">

+                                            <label>字幕语言</label>

+                                            <select

+                                                value={uploadData.subtitle || ''}

+                                                onChange={(e) => setUploadData({

+                                                    ...uploadData,

+                                                    subtitle: e.target.value

+                                                })}

+                                                required

+                                            >

+                                                <option value="">请选择</option>

+                                                <option value="无需字幕">无需字幕</option>

+                                                <option value="暂无字幕">暂无字幕</option>

+                                                <option value="自带中文字幕">自带中文字幕</option>

+                                                <option value="自带双语字幕(含中文)">自带双语字幕(含中文)</option>

+                                                <option value="附件中文字幕">附件中文字幕</option>

+                                                <option value="附件双语字幕">附件双语字幕</option>

+                                            </select>

+                                        </div>

+

+                                        <div className="form-group">

+                                            <label>种子文件</label>

+                                            <input

+                                                type="file"

+                                                accept=".torrent"

+                                                onChange={handleFileChange}

+

+                                            />

+                                        </div>

+

+                                        <div className="form-group">

+                                            <label>简介</label>

+                                            <textarea

+                                                value={uploadData.description}

+                                                onChange={(e) => setUploadData({

+                                                    ...uploadData,

+                                                    description: e.target.value

+                                                })}

+                                            />

+                                        </div>

+

+                                        <div className="form-actions">

+                                            <button

+                                                type="button"

+                                                className="cancel-btn"

+                                                onClick={() => setShowUploadModal(false)}

+                                            >

+                                                取消

+                                            </button>

+                                            <button

+                                                type="submit"

+                                                className="confirm-btn"

+                                                disabled={isUploading}

+                                            >

+                                                {isUploading ? '上传中...' : '确认上传'}

+                                            </button>

+                                        </div>

+                                    </form>

+                                </div>

+                            </div>

                         )}

-                      </div>

+

+                        <div className="resource-list">

+                            {torrentPosts.map(torrent => (

+                                <div

+                                    key={torrent.id}

+                                    className="resource-item"

+                                    onClick={() => navigate(`/torrent/${torrent.id}`)}

+                                >

+                                    <div className="resource-poster">

+                                        <div className="poster-image gray-bg">{torrent.torrentName.charAt(0)}</div>

+                                    </div>

+                                    <div className="resource-info">

+                                        <h3 className="resource-title">{torrent.torrentName}</h3>

+                                        <p className="resource-meta">

+                                            {torrent.resolution} | {torrent.region} | {torrent.category}

+                                        </p>

+                                        <p className="resource-subtitle">字幕: {torrent.subtitle}</p>

+                                    </div>

+                                    <div className="resource-stats">

+                                        <span className="stat">{torrent.size}</span>

+                                        <span className="stat">发布者: {torrent.username}</span>

+                                    </div>

+                                    <button

+                                        className="download-btn"

+                                        onClick={(e) => {

+                                            e.stopPropagation();

+                                            // 下载逻辑

+                                        }}

+                                    >

+                                        立即下载

+                                    </button>

+                                </div>

+                            ))}

+                        </div>

+

+                        {/* 分页控件 */}

+                        <div className="pagination">

+                            <button

+                                onClick={() => fetchTorrentPosts(currentPage - 1)}

+                                disabled={currentPage === 1}

+                            >

+                                上一页

+                            </button>

+

+                            {Array.from({length: totalPages}, (_, i) => i + 1).map(page => (

+                                <button

+                                    key={page}

+                                    onClick={() => fetchTorrentPosts(page)}

+                                    className={currentPage === page ? 'active' : ''}

+                                >

+                                    {page}

+                                </button>

+                            ))}

+

+                            <button

+                                onClick={() => fetchTorrentPosts(currentPage + 1)}

+                                disabled={currentPage === totalPages}

+                            >

+                                下一页

+                            </button>

+                        </div>

                     </div>

-        

-                    <div className="form-actions">

-                      <button 

-                        type="button"

-                        className="cancel-btn"

-                        onClick={() => setShowPostModal(false)}

-                      >

-                        取消

-                      </button>

-                      <button 

-                        type="submit" 

-                        className="submit-btn"

-                      >

-                        确认发帖

-                      </button>

+                );

+            // 在Dashboard.jsx的renderContent函数中修改case 'request'部分

+            case 'request':

+                return (

+                    <div className="content-area" data-testid="request-section">

+                        {/* 求种区帖子列表 */}

+                        <div className="request-list">

+                            {[

+                                {

+                                    id: 1,

+                                    title: '求《药屋少女的呢喃》第二季全集',

+                                    content: '求1080P带中文字幕版本,最好是内嵌字幕不是外挂的',

+                                    author: '动漫爱好者',

+                                    authorAvatar: 'https://via.placeholder.com/40',

+                                    date: '2023-10-15',

+                                    likeCount: 24,

+                                    commentCount: 8

+                                },

+                                {

+                                    id: 2,

+                                    title: '求《奥本海默》IMAX版',

+                                    content: '最好是原盘或者高码率的版本,谢谢各位大佬',

+                                    author: '电影收藏家',

+                                    authorAvatar: 'https://via.placeholder.com/40',

+                                    date: '2023-10-14',

+                                    likeCount: 15,

+                                    commentCount: 5

+                                }

+                            ].map(post => (

+                                <div

+                                    key={post.id}

+                                    className="request-post"

+                                    onClick={() => navigate(`/request/${post.id}`)}

+                                >

+                                    <div className="post-header">

+                                        <img src={post.authorAvatar} alt={post.author} className="post-avatar"/>

+                                        <div className="post-author">{post.author}</div>

+                                        <div className="post-date">{post.date}</div>

+                                    </div>

+                                    <h3 className="post-title">{post.title}</h3>

+                                    <p className="post-content">{post.content}</p>

+                                    <div className="post-stats">

+                                        <span className="post-likes">👍 {post.likeCount}</span>

+                                        <span className="post-comments">💬 {post.commentCount}</span>

+                                    </div>

+                                </div>

+                            ))}

+                        </div>

                     </div>

-                  </form>

+                );

+            // 在Dashboard.jsx的renderContent函数中修改case 'help'部分

+            case 'help':

+                return (

+                    <div className="content-area" data-testid="help-section">

+                        {/* 新增发帖按钮 */}

+                        <div className="post-header">

+                            <button

+                                className="create-post-btn"

+                                onClick={() => setShowPostModal(true)}

+                            >

+                                + 发帖求助

+                            </button>

+                        </div>

+

+                        {/* 加载状态和错误提示 */}

+                        {helpLoading && <div className="loading">加载中...</div>}

+                        {helpError && <div className="error">{helpError}</div>}

+

+                        {/* 求助区帖子列表 */}

+                        <div className="help-list">

+                            {helpPosts.map(post => (

+                                <div

+                                    key={post.id}

+                                    className={`help-post ${post.isSolved ? 'solved' : ''}`}

+                                    onClick={() => navigate(`/help/${post.id}`)}

+                                >

+                                    <div className="post-header">

+                                        <img

+                                            src={post.authorAvatar || 'https://via.placeholder.com/40'}

+                                            alt={post.authorId}

+                                            className="post-avatar"

+                                        />

+                                        <div className="post-author">{post.authorId}</div>

+                                        <div className="post-date">

+                                            {new Date(post.createTime).toLocaleDateString()}

+                                        </div>

+                                        {post.isSolved && <span className="solved-badge">已解决</span>}

+                                    </div>

+                                    <h3 className="post-title">{post.title}</h3>

+                                    <p className="post-content">{post.content}</p>

+                                    <div className="post-stats">

+                                        <span className="post-likes">👍 {post.likeCount || 0}</span>

+                                        <span className="post-comments">💬 {post.replyCount || 0}</span>

+                                    </div>

+                                </div>

+                            ))}

+                        </div>

+

+                        {/* 在帖子列表后添加分页控件 */}

+                        <div className="pagination">

+                            <button

+                                onClick={() => fetchHelpPosts(currentPage - 1)}

+                                disabled={currentPage === 1}

+                            >

+                                上一页

+                            </button>

+

+                            {Array.from({length: totalPages}, (_, i) => i + 1).map(page => (

+                                <button

+                                    key={page}

+                                    onClick={() => fetchHelpPosts(page)}

+                                    className={currentPage === page ? 'active' : ''}

+                                >

+                                    {page}

+                                </button>

+                            ))}

+

+                            <button

+                                onClick={() => fetchHelpPosts(currentPage + 1)}

+                                disabled={currentPage === totalPages}

+                            >

+                                下一页

+                            </button>

+                        </div>

+

+                        {/* 新增发帖弹窗 */}

+                        {showPostModal && (

+                            <div className="post-modal-overlay">

+                                <div className="post-modal">

+                                    <h3>发布求助帖</h3>

+                                    <button

+                                        className="modal-close-btn"

+                                        onClick={() => setShowPostModal(false)}

+                                    >

+                                        ×

+                                    </button>

+

+                                    <form onSubmit={handlePostSubmit}>

+                                        <div className="form-group">

+                                            <label>帖子标题</label>

+                                            <input

+                                                type="text"

+                                                value={postTitle}

+                                                onChange={(e) => setPostTitle(e.target.value)}

+                                                placeholder="请输入标题"

+                                                required

+                                            />

+                                        </div>

+

+                                        <div className="form-group">

+                                            <label>帖子内容</label>

+                                            <textarea

+                                                value={postContent}

+                                                onChange={(e) => setPostContent(e.target.value)}

+                                                placeholder="详细描述你的问题"

+                                                required

+                                            />

+                                        </div>

+

+                                        <div className="form-group">

+                                            <label>上传图片</label>

+                                            <div className="upload-image-btn">

+                                                <input

+                                                    type="file"

+                                                    id="image-upload"

+                                                    accept="image/*"

+                                                    onChange={handleImageUpload}

+                                                    style={{display: 'none'}}

+                                                />

+                                                <label htmlFor="image-upload">

+                                                    {selectedImage ? '已选择图片' : '选择图片'}

+                                                </label>

+                                                {selectedImage && (

+                                                    <span className="image-name">{selectedImage.name}</span>

+                                                )}

+                                            </div>

+                                        </div>

+

+                                        <div className="form-actions">

+                                            <button

+                                                type="button"

+                                                className="cancel-btn"

+                                                onClick={() => setShowPostModal(false)}

+                                            >

+                                                取消

+                                            </button>

+                                            <button

+                                                type="submit"

+                                                className="submit-btn"

+                                            >

+                                                确认发帖

+                                            </button>

+                                        </div>

+                                    </form>

+                                </div>

+                            </div>

+                        )}

+                    </div>

+                );

+            default:

+                return <div className="content-area" data-testid="default-section">公告区内容</div>;

+        }

+    };

+

+    if (loading) return <div className="loading">加载中...</div>;

+    if (error) return <div className="error">{error}</div>;

+

+    return (

+        <div className="dashboard-container" data-testid="dashboard-container">

+            {/* 顶部栏 */}

+            <div className="top-bar" data-testid="top-bar">

+                {/* 搜索框 */}

+                <div className="search-container">

+                    <input

+                        type="text"

+                        placeholder="搜索种子、用户..."

+                        className="search-input"

+                    />

+                    <button className="search-button">搜索</button>

                 </div>

-              </div>

-            )}

-          </div>

-        );

-      default:

-        return <div className="content-area" data-testid="default-section">公告区内容</div>;

-    }

-  };

 

-  if (loading) return <div className="loading">加载中...</div>;

-  if (error) return <div className="error">{error}</div>;

+                <div className="user-actions">

+                    {/* 新增管理员按钮 - 只有管理员可见 */}

+                    {userInfo?.isAdmin && (

+                        <button

+                            className="admin-center-button"

+                            onClick={() => navigate('/administer')}

+                        >

+                            管理员中心

+                        </button>

+                    )}

 

-  return (

-    <div className="dashboard-container" data-testid="dashboard-container">

-      {/* 顶部栏 */}

-      <div className="top-bar" data-testid="top-bar">

-        {/* 搜索框 */}

-        <div className="search-container">

-          <input 

-            type="text" 

-            placeholder="搜索种子、用户..." 

-            className="search-input"

-          />

-          <button className="search-button">搜索</button>

+                    <div className="user-info" data-testid="user-info">

+                        <img

+                            src={userInfo?.avatar || 'https://via.placeholder.com/40'}

+                            alt="用户头像"

+                            className="user-avatar"

+                            onClick={() => navigate('/personal')}

+                            style={{cursor: 'pointer'}}

+                        />

+                        <span className="username">{userInfo?.name || '用户'}</span>

+                        <button onClick={onLogout} className="logout-button">退出</button>

+                    </div>

+                </div>

+            </div>

+

+            {/* 导航栏 */}

+            {/* handleTabchange函数替换了原本的setactivetab函数 */}

+            <div className="nav-tabs">

+                <button

+                    className={`tab-button ${activeTab === 'announcement' ? 'active' : ''}`}

+                    onClick={() => handleTabChange('announcement')}

+                >

+                    公告区

+                </button>

+                <button

+                    className={`tab-button ${activeTab === 'share' ? 'active' : ''}`}

+                    onClick={() => handleTabChange('share')}

+                >

+                    分享区

+                </button>

+                <button

+                    className={`tab-button ${activeTab === 'request' ? 'active' : ''}`}

+                    onClick={() => handleTabChange('request')}

+                >

+                    求种区

+                </button>

+                <button

+                    className={`tab-button ${activeTab === 'help' ? 'active' : ''}`}

+                    onClick={() => handleTabChange('help')}

+                >

+                    求助区

+                </button>

+            </div>

+

+            {/* 内容区 */}

+            {renderContent()}

         </div>

-        

-        <div className="user-info" data-testid="user-info">

-          <img 

-            src={userInfo?.avatar || 'https://via.placeholder.com/40'} 

-            alt="用户头像" 

-            className="user-avatar"

-            onClick={() => navigate('/personal')}  // 添加点击跳转

-            style={{ cursor: 'pointer' }}  // 添加手型指针

-          />

-          <span className="username">{userInfo?.name || '用户'}</span>

-          <button onClick={onLogout} className="logout-button">退出</button>

-        </div>

-      </div>

-      

-      {/* 导航栏 */}

-      {/* handleTabchange函数替换了原本的setactivetab函数 */}

-      <div className="nav-tabs">

-        <button 

-          className={`tab-button ${activeTab === 'announcement' ? 'active' : ''}`}

-          onClick={() => handleTabChange('announcement')}

-        >

-          公告区

-        </button>

-        <button 

-          className={`tab-button ${activeTab === 'share' ? 'active' : ''}`}

-          onClick={() => handleTabChange('share')}

-        >

-          分享区

-        </button>

-        <button 

-          className={`tab-button ${activeTab === 'request' ? 'active' : ''}`}

-          onClick={() => handleTabChange('request')}

-        >

-          求种区

-        </button>

-        <button 

-          className={`tab-button ${activeTab === 'help' ? 'active' : ''}`}

-          onClick={() => handleTabChange('help')}

-        >

-          求助区

-        </button>

-      </div>

-      

-      {/* 内容区 */}

-      {renderContent()}

-    </div>

-  );

+    );

 };

 

 export default Dashboard;
\ No newline at end of file
diff --git a/src/components/RequestDetail.jsx b/src/components/RequestDetail.jsx
index 993fe8e..022b0cb 100644
--- a/src/components/RequestDetail.jsx
+++ b/src/components/RequestDetail.jsx
@@ -78,6 +78,9 @@
   };

 

   const handleDownloadTorrent = (commentId) => {

+

+

+    

     console.log('下载种子', commentId);

     // 实际下载逻辑

   };