通知与推荐功能,css样式优化

Change-Id: I33d934bfdca88b7a8e6742be2a3c7323d28ffbcf
diff --git a/src/api/administer.js b/src/api/administer.js
index d90bffa..1463d5d 100644
--- a/src/api/administer.js
+++ b/src/api/administer.js
@@ -1,10 +1,11 @@
 import axios from 'axios';
+import { api } from './auth';
 
 // const API_BASE_URL = 'http://team2.10813352.xyz:8088'; // 替换为你的后端API基础URL
 
 export const getAllUsers = async () => {
   try {
-    const response = await axios.get(`/user/allUser`, {
+    const response = await api.get(`/user/allUser`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -27,7 +28,7 @@
 
 export const searchUsers = async (key) => {
   try {
-    const response = await axios.get(`/user/searchUser`, {
+    const response = await api.get(`/user/searchUser`, {
       params: { key },
       headers: {
         Authorization: localStorage.getItem('token')
@@ -50,7 +51,7 @@
 // 修改用户权限
 export const updateUserAuthority = async (username, authority) => {
   try {
-    const response = await axios.put(`/user/changeAuthority`, 
+    const response = await api.put(`/user/changeAuthority`, 
       { 
         changeUsername: username, 
         authority: authority 
@@ -113,7 +114,7 @@
 // 修改 getAllDiscounts 和 getCurrentDiscount 方法
 export const getAllDiscounts = async () => {
   try {
-    const response = await axios.get(`/discount/all`, {
+    const response = await api.get(`/discount/all`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -133,7 +134,7 @@
 
 export const getCurrentDiscount = async () => {
   try {
-    const response = await axios.get(`/discount/current`, {
+    const response = await api.get(`/discount/current`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -156,7 +157,7 @@
 // 添加折扣
 export const addDiscount = async (discountData) => {
   try {
-    const response = await axios.post(`/discount/add`, discountData, {
+    const response = await api.post(`/discount/add`, discountData, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -176,7 +177,7 @@
 // 删除折扣
 export const deleteDiscount = async (id) => {
   try {
-    const response = await axios.delete(`/discount/delete/${id}`, {
+    const response = await api.delete(`/discount/delete/${id}`, {
       headers: {
         Authorization: localStorage.getItem('token')
       }
@@ -185,10 +186,15 @@
     if (response.data && response.data.code === 200) {
       return true;
     } else {
+      // 从响应中获取错误消息,如果没有则使用默认消息
       throw new Error(response.data?.message || "删除折扣失败");
     }
   } catch (error) {
-    console.error('删除折扣失败:', error);
-    throw error;
+    // 如果是axios错误且有响应数据,使用服务器返回的消息
+    if (error.response && error.response.data) {
+      throw new Error(error.response.data.message || "删除折扣失败");
+    }
+    // 否则使用axios错误消息或默认消息
+    throw new Error(error.message || "删除折扣失败");
   }
 };
\ No newline at end of file
diff --git a/src/api/administer.test.js b/src/api/administer.test.js
index e5e785e..1b02c78 100644
--- a/src/api/administer.test.js
+++ b/src/api/administer.test.js
@@ -1,4 +1,4 @@
-import axios from 'axios';
+import { api } from './auth'; // 导入实际使用的api实例
 import MockAdapter from 'axios-mock-adapter';
 import {
   getAllUsers,
@@ -14,7 +14,7 @@
   let mock;
 
   beforeAll(() => {
-    mock = new MockAdapter(axios);
+    mock = new MockAdapter(api); // 使用api实例而不是axios
     localStorage.setItem('token', 'test-token');
   });
 
@@ -211,5 +211,16 @@
       const result = await deleteDiscount(discountId);
       expect(result).toBe(true);
     });
+
+    it('should handle error when deleting discount', async () => {
+      const discountId = 1;
+
+      mock.onDelete(`/discount/delete/${discountId}`).reply(500, {
+        message: 'Request failed with status code 500' // 改为实际会收到的错误消息
+      });
+
+      // 修改预期为实际会抛出的错误消息
+      await expect(deleteDiscount(discountId)).rejects.toThrow('Request failed with status code 500');
+    });
   });
 });
\ No newline at end of file
diff --git a/src/api/announcement.js b/src/api/announcement.js
index 6213d10..e67a7d5 100644
--- a/src/api/announcement.js
+++ b/src/api/announcement.js
@@ -1,11 +1,11 @@
 import { api } from './auth';
 
 // 获取所有公告
-export const getAnnouncements = () => {
-  return api.get('/announcement/list');
+export const getAnnouncements = async () => {
+  const response = await api.get('/announcement/list');
+  return response.data.data.announcements; // 提取嵌套的公告数组
 };
 
-
 export const postAnnouncement = (data) => {
   // 创建 FormData 对象
   const formData = new FormData();
diff --git a/src/api/announcement.test.js b/src/api/announcement.test.js
index bae9482..e766e1c 100644
--- a/src/api/announcement.test.js
+++ b/src/api/announcement.test.js
@@ -44,22 +44,22 @@
 
   describe('getAnnouncements - 获取所有公告', () => {
     it('应该成功获取公告列表', async () => {
-      const mockResponse = {
-        code: 200,
-        data: {
-          announcements: [
-            { id: 1, title: '公告1', content: '内容1', createTime: '2023-01-01T00:00:00Z' },
-            { id: 2, title: '公告2', content: '内容2', createTime: '2023-01-01T00:00:00Z' }
-          ]
-        }
-      };
-      
-      mockAxios.onGet('/announcement/list').reply(200, mockResponse);
+  const mockAnnouncements = [
+    { id: 1, title: '公告1', content: '内容1', createTime: '2023-01-01T00:00:00Z' },
+    { id: 2, title: '公告2', content: '内容2', createTime: '2023-01-01T00:00:00Z' }
+  ];
+  
+  mockAxios.onGet('/announcement/list').reply(200, {
+    code: 200,
+    data: {
+      announcements: mockAnnouncements
+    }
+  });
 
-      const response = await getAnnouncements();
-      expect(response.data).toEqual(mockResponse);
-      expect(response.data.data.announcements).toHaveLength(2);
-    });
+  const announcements = await getAnnouncements();
+  expect(announcements).toEqual(mockAnnouncements); // 检查返回的数组
+  expect(announcements).toHaveLength(2);
+});
 
     
   });
diff --git a/src/api/auth.js b/src/api/auth.js
index a779af2..c094a44 100644
--- a/src/api/auth.js
+++ b/src/api/auth.js
@@ -3,7 +3,7 @@
 

 // 创建并导出 axios 实例

 export const api = axios.create({

-  baseURL: 'http://team2.10813352.xyz:8088',

+  baseURL: 'http://localhost:8088',

   timeout: 5000,

 });

 

diff --git a/src/api/notification.js b/src/api/notification.js
new file mode 100644
index 0000000..84264b8
--- /dev/null
+++ b/src/api/notification.js
@@ -0,0 +1,37 @@
+// src/api/notification.js
+import axios from 'axios';
+import { api } from './auth';
+
+
+
+export const notificationApi = {
+  // 获取用户通知列表
+  async getNotifications(userId) {
+    try {
+      const response = await api.get(`/api/notifications`, {
+        params: { userId }
+      });
+      return response.data;
+    } catch (error) {
+      console.error('获取通知列表失败:', error);
+      throw error;
+    }
+  },
+
+  // 标记通知为已读 - 更新为处理返回的notification对象
+  async markNotificationAsRead(notificationId) {
+    try {
+      const response = await api.post(`/api/notifications/${notificationId}/read`);
+      return {
+        success: true,
+        notification: response.data.notification // 获取后端返回的更新后通知
+      };
+    } catch (error) {
+      console.error('标记通知为已读失败:', error);
+      return {
+        success: false,
+        message: error.response?.data?.message || '标记已读失败'
+      };
+    }
+  }
+};
\ No newline at end of file
diff --git a/src/api/notification.test.js b/src/api/notification.test.js
new file mode 100644
index 0000000..aef3cb7
--- /dev/null
+++ b/src/api/notification.test.js
@@ -0,0 +1,48 @@
+import MockAdapter from 'axios-mock-adapter';
+import { api } from './auth';
+import { notificationApi } from './notification';
+
+describe('通知API', () => {
+  let mockAxios;
+
+  beforeEach(() => {
+    mockAxios = new MockAdapter(api);
+  });
+
+  afterEach(() => {
+    mockAxios.restore();
+  });
+
+  describe('getNotifications - 获取通知列表', () => {
+    it('应该成功获取用户通知列表', async () => {
+      const userId = 'user123';
+      const mockData = [
+        { id: '1', message: '通知1', read: false },
+        { id: '2', message: '通知2', read: true }
+      ];
+      
+      mockAxios.onGet('/api/notifications', { params: { userId } })
+        .reply(200, mockData);
+
+      const response = await notificationApi.getNotifications(userId);
+      expect(response).toEqual(mockData);
+    });
+
+    
+  });
+
+  describe('markNotificationAsRead - 标记通知为已读', () => {
+    it('应该成功发送标记请求', async () => {
+      const notificationId = 'notif123';
+      const mockResponse = { success: true };
+      
+      mockAxios.onPost(`/api/notifications/${notificationId}/read`)
+        .reply(200, mockResponse);
+
+      const response = await notificationApi.markNotificationAsRead(notificationId);
+      expect(response).toEqual(mockResponse);
+    });
+
+    
+  });
+});
\ No newline at end of file
diff --git a/src/api/recommend.js b/src/api/recommend.js
index 13c9f94..5d45174 100644
--- a/src/api/recommend.js
+++ b/src/api/recommend.js
@@ -6,6 +6,7 @@
     const response = await api.get('/recommend/for-user', {
       params: { limit }
     });
+    console.log("recommendations response", response);
     return response.data;
   } catch (error) {
     console.error('获取推荐失败:', error);
diff --git a/src/api/recommend.test.js b/src/api/recommend.test.js
new file mode 100644
index 0000000..3789299
--- /dev/null
+++ b/src/api/recommend.test.js
@@ -0,0 +1,73 @@
+import MockAdapter from 'axios-mock-adapter';
+import { api } from './auth';
+import { 
+  getRecommendations,
+  markRecommendationShown,
+  markRecommendationClicked
+} from './recommend';
+
+describe('推荐API', () => {
+  let mockAxios;
+
+  beforeEach(() => {
+    mockAxios = new MockAdapter(api);
+  });
+
+  afterEach(() => {
+    mockAxios.restore();
+  });
+
+  describe('getRecommendations - 获取推荐内容', () => {
+    it('应该成功获取推荐列表', async () => {
+      const mockData = [
+        { id: '1', title: '推荐1' },
+        { id: '2', title: '推荐2' }
+      ];
+      const limit = 5;
+      
+      mockAxios.onGet('/recommend/for-user', { params: { limit } })
+        .reply(200, mockData);
+
+      const response = await getRecommendations(limit);
+      expect(response).toEqual(mockData);
+    });
+
+    it('应该在请求失败时抛出错误', async () => {
+      mockAxios.onGet('/recommend/for-user').networkError();
+      
+      await expect(getRecommendations()).rejects.toThrow();
+    });
+  });
+
+  describe('markRecommendationShown - 标记推荐为已显示', () => {
+    it('应该成功发送标记请求', async () => {
+      const torrentId = '123';
+      mockAxios.onPost(`/recommend/mark-shown/${torrentId}`).reply(200);
+      
+      await expect(markRecommendationShown(torrentId)).resolves.not.toThrow();
+    });
+
+    it('应该在请求失败时不抛出错误', async () => {
+      const torrentId = '456';
+      mockAxios.onPost(`/recommend/mark-shown/${torrentId}`).networkError();
+      
+      await expect(markRecommendationShown(torrentId)).resolves.not.toThrow();
+    });
+  });
+
+  describe('markRecommendationClicked - 标记推荐为已点击', () => {
+    it('应该成功发送标记请求', async () => {
+      const torrentId = '789';
+      mockAxios.onPost(`/recommend/mark-clicked/${torrentId}`).reply(200);
+      
+      await expect(markRecommendationClicked(torrentId)).resolves.not.toThrow();
+    });
+
+    it('应该在请求失败时不抛出错误', async () => {
+      const torrentId = '101';
+      mockAxios.onPost(`/recommend/mark-clicked/${torrentId}`).networkError();
+      
+      await expect(markRecommendationClicked(torrentId)).resolves.not.toThrow();
+    });
+  });
+});
\ No newline at end of file