“实现帖子与评论上传图片,删除评论,评论计数,管理员界面”
Change-Id: I33d5331e41de0411f2d6f1913f3a939db61f665d
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
+});