Merge changes I53afd377,I95718173,Iebe50bff,Ieeaa92b5

* changes:
  索要资源相关的前端以及管理员
  帖子的相关用户前端与管理员后端
  好友的相关前端
  举报的管理员前端
diff --git a/src/api/__tests__/complain.test.js b/src/api/__tests__/complain.test.js
new file mode 100644
index 0000000..94a06c6
--- /dev/null
+++ b/src/api/__tests__/complain.test.js
@@ -0,0 +1,96 @@
+const axios = require('axios');
+jest.mock('axios');
+
+const {
+    createComplain,
+    deleteComplain,
+    updateComplain,
+    getComplainsByTargetUser,
+    getComplainsByPostingUser,
+    getAllComplains,
+    getComplainDetailById
+} = require('../complain');
+
+describe('Complain API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    test('createComplain should post complain data', async () => {
+        const mockData = { data: { complainid: 1 } };
+        const complainPayload = { puse: 1, duser: 2, content: 'test', torrentid: 99 };
+        axios.post.mockResolvedValue(mockData);
+
+        const response = await createComplain(complainPayload);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/complain/create',
+            complainPayload
+        );
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('deleteComplain should send delete request', async () => {
+        const mockData = { data: true };
+        axios.delete.mockResolvedValue(mockData);
+
+        const response = await deleteComplain(1);
+
+        expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/complain/delete/1');
+        expect(response).toBe(true);
+    });
+
+    test('updateComplain should put complain data', async () => {
+        const complainPayload = { complainid: 1, content: 'updated' };
+        const mockData = { data: true };
+        axios.put.mockResolvedValue(mockData);
+
+        const response = await updateComplain(complainPayload);
+
+        expect(axios.put).toHaveBeenCalledWith(
+            'http://localhost:8080/complain/update',
+            complainPayload
+        );
+        expect(response).toBe(true);
+    });
+
+    test('getComplainsByTargetUser should fetch complains by duser', async () => {
+        const mockData = { data: [{ complainid: 1, duser: 2 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getComplainsByTargetUser(2);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/target/2');
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('getComplainsByPostingUser should fetch complains by puse', async () => {
+        const mockData = { data: [{ complainid: 1, puse: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getComplainsByPostingUser(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/from/1');
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('getAllComplains should fetch all complains', async () => {
+        const mockData = { data: [{ complainid: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getAllComplains();
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/all');
+        expect(response).toEqual(mockData.data);
+    });
+
+    test('getComplainDetailById should fetch detailed complain info', async () => {
+        const mockData = { data: { complainid: 1, puse: 1, duser: 2 } };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getComplainDetailById(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/complain/detail/1');
+        expect(response).toEqual(mockData.data);
+    });
+});
diff --git a/src/api/__tests__/friends.test.js b/src/api/__tests__/friends.test.js
new file mode 100644
index 0000000..2358e04
--- /dev/null
+++ b/src/api/__tests__/friends.test.js
@@ -0,0 +1,90 @@
+const axios = require('axios');
+jest.mock('axios'); // mock axios
+
+const {
+    addFriend,
+    acceptFriend,
+    rejectFriend,
+    deleteFriend,
+    getFriendsByUserId,
+    getPendingRequests
+} = require('../friends'); // 引入你的 API 方法
+
+describe('Friends API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks(); // 每个测试前清除 mock 状态
+    });
+
+    test('addFriend should post friend request data', async () => {
+        const mockFriendData = {
+            friend1: 1,
+            friend2: 2
+        };
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await addFriend(mockFriendData);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/add',
+            mockFriendData
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('acceptFriend should send accept request with params', async () => {
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await acceptFriend(1, 2);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/accept',
+            null,
+            { params: { friend1: 1, friend2: 2 } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('rejectFriend should delete pending friend request', async () => {
+        axios.delete.mockResolvedValue({ data: true });
+
+        const response = await rejectFriend(1, 2);
+
+        expect(axios.delete).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/delete',
+            { params: { friend1: 1, friend2: 2 } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('deleteFriend should delete a friend relationship', async () => {
+        axios.delete.mockResolvedValue({ data: true });
+
+        const response = await deleteFriend(3, 4);
+
+        expect(axios.delete).toHaveBeenCalledWith(
+            'http://localhost:8080/friends/delete',
+            { params: { friend1: 3, friend2: 4 } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('getFriendsByUserId should get all accepted friends for user', async () => {
+        const mockData = { data: [{ relationid: 1, friend1: 1, friend2: 2, status: 'accepted' }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getFriendsByUserId(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/friends/list/1');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('getPendingRequests should fetch pending friend requests', async () => {
+        const mockData = { data: [{ relationid: 2, friend1: 3, friend2: 1, status: 'pending' }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getPendingRequests(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/friends/pending/1');
+        expect(response.data).toEqual(mockData.data);
+    });
+});
diff --git a/src/api/__tests__/post.test.js b/src/api/__tests__/post.test.js
new file mode 100644
index 0000000..89fe48f
--- /dev/null
+++ b/src/api/__tests__/post.test.js
@@ -0,0 +1,160 @@
+const axios = require('axios');
+const MockAdapter = require('axios-mock-adapter');
+
+const {
+    createPost,
+    togglePinPost,
+    deletePost,
+    updatePost,
+    searchPosts,
+    likePost,
+    unlikePost,
+    pinPost,
+    unpinPost,
+    findPostsByUserId,
+    findPinnedPosts,
+    getAllPostsSorted,
+    getPostById
+} = require('../post'); // 注意根据你的实际路径修改
+
+jest.mock('axios');
+
+describe('Post API Tests', () => {
+    beforeEach(() => {
+        jest.clearAllMocks();
+    });
+
+    test('createPost should post form data', async () => {
+        const formData = new FormData();
+        formData.append('userid', '1');
+        formData.append('post_title', 'Test');
+        axios.post.mockResolvedValue({ data: true });
+
+        const response = await createPost(formData);
+
+        expect(axios.post).toHaveBeenCalledWith(
+            'http://localhost:8080/post/create',
+            formData,
+            { headers: { 'Content-Type': 'multipart/form-data' } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('togglePinPost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await togglePinPost(123);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/togglePin/123');
+        expect(response.data).toBe(true);
+    });
+
+    test('deletePost should send DELETE request', async () => {
+        axios.delete.mockResolvedValue({ data: true });
+
+        const response = await deletePost(123);
+
+        expect(axios.delete).toHaveBeenCalledWith('http://localhost:8080/post/delete/123');
+        expect(response.data).toBe(true);
+    });
+
+    test('updatePost should send PUT request with JSON', async () => {
+        const post = { postid: 1, post_title: 'Updated Title' };
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await updatePost(post);
+
+        expect(axios.put).toHaveBeenCalledWith(
+            'http://localhost:8080/post/update',
+            JSON.stringify(post),
+            { headers: { 'Content-Type': 'application/json' } }
+        );
+        expect(response.data).toBe(true);
+    });
+
+    test('searchPosts should send GET request with keyword', async () => {
+        const mockData = { data: [{ post_title: 'Keyword Match' }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await searchPosts('test');
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/search?keyword=test');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('likePost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await likePost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/like/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('unlikePost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await unlikePost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/unlike/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('pinPost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await pinPost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/pin/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('unpinPost should send PUT request', async () => {
+        axios.put.mockResolvedValue({ data: true });
+
+        const response = await unpinPost(1);
+
+        expect(axios.put).toHaveBeenCalledWith('http://localhost:8080/post/unpin/1');
+        expect(response.data).toBe(true);
+    });
+
+    test('findPostsByUserId should fetch user posts', async () => {
+        const mockData = { data: [{ postid: 1, userid: 2 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await findPostsByUserId(2);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/findByUserid?userid=2');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('findPinnedPosts should fetch pinned posts', async () => {
+        const mockData = { data: [{ postid: 1, is_pinned: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await findPinnedPosts();
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/findPinned');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('getAllPostsSorted should fetch all posts sorted', async () => {
+        const mockData = { data: [{ postid: 1 }] };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getAllPostsSorted();
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/all');
+        expect(response.data).toEqual(mockData.data);
+    });
+
+    test('getPostById should fetch post by ID', async () => {
+        const mockData = { data: { postid: 1 } };
+        axios.get.mockResolvedValue(mockData);
+
+        const response = await getPostById(1);
+
+        expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/post/get/1');
+        expect(response.data).toEqual(mockData.data);
+    });
+});
diff --git a/src/api/complain.js b/src/api/complain.js
new file mode 100644
index 0000000..8ac3e03
--- /dev/null
+++ b/src/api/complain.js
@@ -0,0 +1,80 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/complain';
+
+// 创建投诉
+export const createComplain = async (complainData) => {
+    try {
+        const response = await axios.post(`${BASE_URL}/create`, complainData);
+        return response.data;
+    } catch (error) {
+        console.error('创建投诉失败:', error);
+        throw error;
+    }
+};
+
+// 删除投诉(根据 complainid)
+export const deleteComplain = async (complainid) => {
+    try {
+        const response = await axios.delete(`${BASE_URL}/delete/${complainid}`);
+        return response.data;
+    } catch (error) {
+        console.error('删除投诉失败:', error);
+        throw error;
+    }
+};
+
+// 更新投诉
+export const updateComplain = async (complainData) => {
+    try {
+        const response = await axios.put(`${BASE_URL}/update`, complainData);
+        return response.data;
+    } catch (error) {
+        console.error('更新投诉失败:', error);
+        throw error;
+    }
+};
+
+// 获取某个被投诉用户的所有投诉记录(根据 duser)
+export const getComplainsByTargetUser = async (duser) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/target/${duser}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取被投诉用户的投诉记录失败:', error);
+        throw error;
+    }
+};
+
+// 获取某个投诉发起者的所有投诉记录(根据 puse)
+export const getComplainsByPostingUser = async (puse) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/from/${puse}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取用户提交的投诉记录失败:', error);
+        throw error;
+    }
+};
+
+// ✅ 获取所有投诉记录
+export const getAllComplains = async () => {
+    try {
+        const response = await axios.get(`${BASE_URL}/all`);
+        return response.data;
+    } catch (error) {
+        console.error('获取所有投诉记录失败:', error);
+        throw error;
+    }
+};
+
+// ✅ 根据投诉 ID 获取详情(包含投诉用户、被投诉用户、种子号等)
+export const getComplainDetailById = async (complainid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/detail/${complainid}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取投诉详情失败:', error);
+        throw error;
+    }
+};
diff --git a/src/api/friends.js b/src/api/friends.js
new file mode 100644
index 0000000..794e061
--- /dev/null
+++ b/src/api/friends.js
@@ -0,0 +1,39 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/friends';
+
+// 添加好友(发起好友请求)
+export const addFriend = (friendData) => {
+    return axios.post(`${BASE_URL}/add`, friendData);
+};
+
+// 同意好友申请
+export const acceptFriend = (friend1, friend2) => {
+    return axios.post(`${BASE_URL}/accept`, null, {
+        params: { friend1, friend2 }
+    });
+};
+
+// 拒绝好友申请(删除 pending 状态的好友关系)
+export const rejectFriend = (friend1, friend2) => {
+    return axios.delete(`${BASE_URL}/delete`, {
+        params: { friend1, friend2 }
+    });
+};
+
+// 删除好友
+export const deleteFriend = (friend1, friend2) => {
+    return axios.delete(`${BASE_URL}/delete`, {
+        params: { friend1, friend2 }
+    });
+};
+
+// 查询某用户所有已通过好友
+export const getFriendsByUserId = (userid) => {
+    return axios.get(`${BASE_URL}/list/${userid}`);
+};
+
+// 查询某用户收到的好友申请(pending 状态)
+export const getPendingRequests = (userid) => {
+    return axios.get(`${BASE_URL}/pending/${userid}`);
+};
diff --git a/src/api/post.js b/src/api/post.js
new file mode 100644
index 0000000..5891f99
--- /dev/null
+++ b/src/api/post.js
@@ -0,0 +1,128 @@
+const BASE_URL = 'http://localhost:8080/post';
+
+/**
+ * 创建帖子(带图片)
+ * @param {FormData} formData 包含 userid、post_title、post_content、tags、rannge、is_pinned、photo
+ */
+export const createPost = (formData) => {
+    return fetch(`${BASE_URL}/create`, {
+        method: 'POST',
+        body: formData,
+    }).then(res => res.json());
+};
+
+/**
+ * 切换置顶状态
+ * @param {number} postid 帖子 ID
+ */
+export const togglePinPost = (postid) => {
+    return fetch(`${BASE_URL}/togglePin/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 删除帖子
+ * @param {number} postid 帖子 ID
+ */
+export const deletePost = (postid) => {
+    return fetch(`${BASE_URL}/delete/${postid}`, {
+        method: 'DELETE',
+    }).then(res => res.json());
+};
+
+/**
+ * 更新帖子(JSON 格式)
+ * @param {Object} post 帖子对象
+ */
+export const updatePost = (post) => {
+    return fetch(`${BASE_URL}/update`, {
+        method: 'PUT',
+        headers: {
+            'Content-Type': 'application/json',
+        },
+        body: JSON.stringify(post),
+    }).then(res => res.json());
+};
+
+/**
+ * 关键词搜索帖子
+ * @param {string} keyword 搜索关键词
+ */
+export const searchPosts = (keyword) => {
+    return fetch(`${BASE_URL}/search?keyword=${encodeURIComponent(keyword)}`)
+        .then(res => res.json());
+};
+
+/**
+ * 点赞帖子
+ * @param {number} postid 帖子 ID
+ */
+export const likePost = (postid) => {
+    return fetch(`${BASE_URL}/like/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 取消点赞帖子
+ * @param {number} postid 帖子 ID
+ */
+export const unlikePost = (postid) => {
+    return fetch(`${BASE_URL}/unlike/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 置顶帖子
+ * @param {number} postid 帖子 ID
+ */
+export const pinPost = (postid) => {
+    return fetch(`${BASE_URL}/pin/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 取消置顶帖子
+ * @param {number} postid 帖子 ID
+ */
+export const unpinPost = (postid) => {
+    return fetch(`${BASE_URL}/unpin/${postid}`, {
+        method: 'PUT',
+    }).then(res => res.json());
+};
+
+/**
+ * 获取某用户所有帖子
+ * @param {number} userid 用户 ID
+ */
+export const findPostsByUserId = (userid) => {
+    return fetch(`${BASE_URL}/findByUserid?userid=${userid}`)
+        .then(res => res.json());
+};
+
+/**
+ * 获取所有置顶帖子
+ */
+export const findPinnedPosts = () => {
+    return fetch(`${BASE_URL}/findPinned`)
+        .then(res => res.json());
+};
+
+/**
+ * 获取所有帖子(排序后)
+ */
+export const getAllPostsSorted = () => {
+    return fetch(`${BASE_URL}/all`)
+        .then(res => res.json());
+};
+
+/**
+ * 根据 postid 获取帖子详情(若你后期需要)
+ */
+export const getPostById = (postid) => {
+    return fetch(`${BASE_URL}/get/${postid}`)
+        .then(res => res.json());
+};
diff --git a/src/api/request.js b/src/api/request.js
new file mode 100644
index 0000000..26d57b9
--- /dev/null
+++ b/src/api/request.js
@@ -0,0 +1,123 @@
+import axios from 'axios';
+
+const BASE_URL = 'http://localhost:8080/request';
+
+// 创建求助帖(支持上传图片)
+export const createRequest = (formData) => {
+    return axios.post(`${BASE_URL}/create`, formData, {
+        headers: {
+            'Content-Type': 'multipart/form-data',
+        },
+    });
+};
+
+// 修改求助帖金额
+export const updateMoney = (requestid, money) => {
+    return axios.put(`${BASE_URL}/updateMoney/${requestid}`, null, {
+        params: { money },
+    });
+};
+
+// 根据名称批量更新被协助用户 ID
+export const updateLoaduserByName = (name, loaduser) => {
+    return axios.post(`${BASE_URL}/updateLoaduserByName`, null, {
+        params: { name, loaduser },
+    });
+};
+
+// ✅ 新增:根据 requestid 更新 torrentid
+export const updateTorrentid = (requestid, torrentid) => {
+    return axios.put(`${BASE_URL}/updateTorrentid/${requestid}`, null, {
+        params: { torrentid },
+    });
+};
+
+// ✅ 新增:根据 requestid 获取 torrentid
+export const getTorrentid = async (requestid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/getTorrentid/${requestid}`);
+        return response.data;
+    } catch (error) {
+        console.error('获取 torrentid 失败', error);
+        return null;
+    }
+};
+
+// 删除求助帖
+export const deleteRequest = (requestid) => {
+    return axios.delete(`${BASE_URL}/delete/${requestid}`);
+};
+
+// 根据名称查找求助帖
+export const findByName = async (name) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/findByName`, {
+            params: { name },
+        });
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('按名称查找求助帖失败', error);
+        return [];
+    }
+};
+
+// 根据发帖用户 ID 查找求助帖
+export const findByUserid = async (userid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/findByUserid`, {
+            params: { userid },
+        });
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('按用户ID查找求助帖失败', error);
+        return [];
+    }
+};
+
+// 根据被协助用户 ID 查找求助帖
+export const findByLoaduser = async (loaduser) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/findByLoaduser`, {
+            params: { loaduser },
+        });
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('按被协助用户ID查找求助帖失败', error);
+        return [];
+    }
+};
+
+// 获取某名称的总金额
+export const getTotalMoneyByName = async (name) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/totalMoneyByName`, {
+            params: { name },
+        });
+        return typeof response.data === 'number' ? response.data : 0;
+    } catch (error) {
+        console.error('获取总金额失败', error);
+        return 0;
+    }
+};
+
+// 获取所有求助帖
+export const getAllRequests = async () => {
+    try {
+        const response = await axios.get(`${BASE_URL}/all`);
+        return Array.isArray(response.data) ? response.data : [];
+    } catch (error) {
+        console.error('获取全部求助帖失败', error);
+        return [];
+    }
+};
+
+// ✅ 新增:根据 requestid 获取求助帖的部分信息(torrentid、money、loaduser)
+export const getInfoByRequestId = async (requestid) => {
+    try {
+        const response = await axios.get(`${BASE_URL}/info/${requestid}`);
+        return response.data || {};
+    } catch (error) {
+        console.error('获取求助帖信息失败', error);
+        return {};
+    }
+};
diff --git a/src/components/ComplainAdminPanel.jsx b/src/components/ComplainAdminPanel.jsx
new file mode 100644
index 0000000..a7985be
--- /dev/null
+++ b/src/components/ComplainAdminPanel.jsx
@@ -0,0 +1,149 @@
+import React, { useEffect, useState } from 'react';
+import {
+    Table,
+    Button,
+    Modal,
+    message,
+    Tag,
+    Space,
+    Tooltip,
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import {
+    getAllComplains,
+    deleteComplain,
+    // 预留:你后续可以新增处理投诉的API
+} from '../api/complain';
+import { useNavigate } from 'react-router-dom';
+
+const { confirm } = Modal;
+
+const ComplainAdminPanel = () => {
+    const [complains, setComplains] = useState([]);
+    const [loading, setLoading] = useState(false);
+    const navigate = useNavigate();
+
+    const fetchComplains = async () => {
+        setLoading(true);
+        try {
+            const data = await getAllComplains();
+            setComplains(data);
+        } catch (error) {
+            message.error('获取投诉记录失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    useEffect(() => {
+        fetchComplains();
+    }, []);
+
+    const showDeleteConfirm = (complainid) => {
+        confirm({
+            title: '确认删除该投诉记录吗?',
+            icon: <ExclamationCircleOutlined />,
+            okText: '删除',
+            okType: 'danger',
+            cancelText: '取消',
+            onOk() {
+                handleDelete(complainid);
+            },
+        });
+    };
+
+    const handleDelete = async (complainid) => {
+        try {
+            const success = await deleteComplain(complainid);
+            if (success) {
+                message.success('删除成功');
+                fetchComplains();
+            } else {
+                message.error('删除失败');
+            }
+        } catch {
+            message.error('删除请求失败');
+        }
+    };
+
+    const handleProcess = (complain) => {
+        const { complainid, duser, torrentid } = complain;
+        navigate(`/complain-process/${complainid}`, {
+            state: { complainid, duser, torrentid },
+        });
+    };
+
+    const columns = [
+        {
+            title: '投诉ID',
+            dataIndex: 'complainid',
+            key: 'complainid',
+            width: 80,
+            fixed: 'left',
+        },
+        {
+            title: '投诉人ID',
+            dataIndex: 'puse',
+            key: 'puse',
+            width: 120,
+        },
+        {
+            title: '被投诉人ID',
+            dataIndex: 'duser',
+            key: 'duser',
+            width: 120,
+        },
+        {
+            title: '投诉内容',
+            dataIndex: 'content',
+            key: 'content',
+            ellipsis: { showTitle: false },
+            render: (text) => (
+                <Tooltip placement="topLeft" title={text}>
+                    {text}
+                </Tooltip>
+            ),
+        },
+        {
+            title: '相关种子ID',
+            dataIndex: 'torrentid',
+            key: 'torrentid',
+            width: 120,
+            render: (val) => val ?? <Tag color="default">无</Tag>,
+        },
+        {
+            title: '操作',
+            key: 'action',
+            fixed: 'right',
+            width: 150,
+            render: (_, record) => (
+                <Space size="middle">
+                    <Button type="primary" onClick={() => handleProcess(record)}>
+                        处理
+                    </Button>
+                    <Button danger onClick={() => showDeleteConfirm(record.complainid)}>
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
+    ];
+
+    return (
+        <div style={{ padding: 20 }}>
+            <h2 style={{ marginBottom: 20 }}>投诉管理面板</h2>
+            <Table
+                rowKey="complainid"
+                columns={columns}
+                dataSource={complains}
+                loading={loading}
+                scroll={{ x: 1000 }}
+                pagination={{ pageSize: 10 }}
+                bordered
+                size="middle"
+            />
+        </div>
+    );
+};
+
+export default ComplainAdminPanel;
diff --git a/src/components/FriendManager.css b/src/components/FriendManager.css
new file mode 100644
index 0000000..97cf2a9
--- /dev/null
+++ b/src/components/FriendManager.css
@@ -0,0 +1,155 @@
+/* FriendManager.css */
+
+.friend-manager-container {
+    max-width: 800px;
+    margin: 20px auto;
+    padding: 0 15px;
+}
+
+.friend-card {
+    border-radius: 10px;
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+}
+
+.friend-header {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+}
+
+.header-icon {
+    font-size: 24px;
+    color: #1890ff;
+    margin-right: 12px;
+}
+
+.header-title {
+    margin: 0 !important;
+}
+
+.search-section {
+    display: flex;
+    margin-bottom: 24px;
+    gap: 12px;
+}
+
+.search-input {
+    flex: 1;
+    border-radius: 20px;
+    padding: 10px 16px;
+}
+
+.search-button {
+    border-radius: 20px;
+    padding: 0 24px;
+    height: 40px;
+}
+
+.search-results-container {
+    margin-bottom: 24px;
+    background: #fafafa;
+    border-radius: 8px;
+    padding: 16px;
+    border: 1px solid #f0f0f0;
+}
+
+.results-title {
+    margin-bottom: 16px !important;
+    color: #333;
+}
+
+.user-item {
+    padding: 12px;
+    border-radius: 8px;
+    transition: all 0.3s;
+    cursor: pointer;
+}
+
+.user-item:hover {
+    background-color: #f5f7fa;
+}
+
+.user-avatar {
+    background-color: #1890ff;
+}
+
+.add-friend-button {
+    border-radius: 16px;
+}
+
+.section-title {
+    margin-bottom: 16px !important;
+    color: #333;
+    position: relative;
+    padding-left: 10px;
+}
+
+.section-title::before {
+    content: '';
+    position: absolute;
+    left: 0;
+    top: 5px;
+    height: 20px;
+    width: 4px;
+    background-color: #1890ff;
+    border-radius: 2px;
+}
+
+.request-item,
+.friend-item {
+    padding: 12px 16px;
+    border-radius: 8px;
+    margin-bottom: 8px;
+    border: 1px solid #f0f0f0;
+    transition: all 0.3s;
+}
+
+.request-item:hover,
+.friend-item:hover {
+    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+    transform: translateY(-2px);
+    border-color: #d0e0ff;
+}
+
+.accept-button {
+    background-color: #52c41a;
+    border-color: #52c41a;
+}
+
+.reject-button {
+    background-color: #f5222d;
+    border-color: #f5222d;
+    color: white;
+}
+
+.delete-button {
+    border-radius: 16px;
+}
+
+.friend-list-section {
+    margin-top: 24px;
+}
+
+.friend-list-header {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 16px;
+}
+
+.refresh-button {
+    color: #1890ff;
+}
+
+@media (max-width: 768px) {
+    .search-section {
+        flex-direction: column;
+    }
+
+    .search-button {
+        width: 100%;
+    }
+
+    .friend-card {
+        padding: 16px;
+    }
+}
\ No newline at end of file
diff --git a/src/components/FriendManager.jsx b/src/components/FriendManager.jsx
new file mode 100644
index 0000000..374ac83
--- /dev/null
+++ b/src/components/FriendManager.jsx
@@ -0,0 +1,359 @@
+import React, { useState, useEffect } from 'react';
+import {
+    Input,
+    Button,
+    List,
+    Typography,
+    Space,
+    Spin,
+    Popconfirm,
+    message,
+    Divider,
+    Avatar,
+} from 'antd';
+import {
+    UserAddOutlined,
+    DeleteOutlined,
+    ReloadOutlined,
+    CheckOutlined,
+    CloseOutlined,
+} from '@ant-design/icons';
+import {
+    addFriend,
+    deleteFriend,
+    getFriendsByUserId,
+    getPendingRequests,
+    acceptFriend,
+    rejectFriend,
+} from '../api/friends';
+import axios from 'axios';
+
+const { Title, Text } = Typography;
+
+const FriendManager = ({ currentUser, onSelectRelation }) => {
+    const currentUserId = currentUser?.userid;
+
+    const [friendName, setFriendName] = useState('');
+    const [friends, setFriends] = useState([]);
+    const [pendingRequests, setPendingRequests] = useState([]);
+    const [userInfoMap, setUserInfoMap] = useState({});
+    const [loading, setLoading] = useState(false);
+    const [refreshing, setRefreshing] = useState(false);
+    const [pendingLoading, setPendingLoading] = useState(false);
+
+    useEffect(() => {
+        if (currentUserId) {
+            refreshData();
+        }
+    }, [currentUserId]);
+
+    const refreshData = () => {
+        loadFriends(currentUserId);
+        loadPendingRequests(currentUserId);
+    };
+
+    const fetchUserInfo = async (userId) => {
+        if (userInfoMap[userId]) return;
+        try {
+            const res = await axios.get(`http://localhost:8080/user/getDecoration?userid=${userId}`);
+            const info = res.data?.data;
+            if (info) {
+                setUserInfoMap((prev) => ({
+                    ...prev,
+                    [userId]: {
+                        username: info.username,
+                        avatar: info.image,
+                    },
+                }));
+            }
+        } catch {
+            setUserInfoMap((prev) => ({
+                ...prev,
+                [userId]: {
+                    username: `用户${userId}`,
+                    avatar: null,
+                },
+            }));
+        }
+    };
+
+    const loadFriends = async (userId) => {
+        setRefreshing(true);
+        try {
+            const res = await getFriendsByUserId(userId);
+            const list = res.data || [];
+            setFriends(list);
+            list.forEach(f => fetchUserInfo(getFriendUserId(f)));
+        } catch {
+            message.error('加载好友失败,请稍后重试');
+        }
+        setRefreshing(false);
+    };
+
+    const loadPendingRequests = async (userId) => {
+        setPendingLoading(true);
+        try {
+            const res = await getPendingRequests(userId);
+            const list = res.data || [];
+            setPendingRequests(list);
+            list.forEach(req => {
+                const otherId = req.friend1 === currentUserId ? req.friend2 : req.friend1;
+                fetchUserInfo(otherId);
+            });
+        } catch {
+            message.error('加载好友申请失败');
+        }
+        setPendingLoading(false);
+    };
+
+    const handleAddFriend = async () => {
+        if (!friendName.trim()) return message.warning('请输入好友用户名');
+
+        setLoading(true);
+        try {
+            const res = await axios.get(`http://localhost:8080/user/getUserid?username=${friendName.trim()}`);
+            const newFriendId = res.data?.data;
+            if (!newFriendId) {
+                message.error('未找到该用户名对应的用户');
+                setLoading(false);
+                return;
+            }
+
+            if (newFriendId === currentUserId) {
+                message.warning('不能添加自己为好友');
+                setLoading(false);
+                return;
+            }
+
+            const isAlreadyFriend = friends.some(f =>
+                (f.friend1 === currentUserId && f.friend2 === newFriendId) ||
+                (f.friend1 === newFriendId && f.friend2 === currentUserId)
+            );
+            if (isAlreadyFriend) {
+                message.warning('该用户已是您的好友');
+                setLoading(false);
+                return;
+            }
+
+            const result = await addFriend({ friend1: currentUserId, friend2: newFriendId });
+            if (result.data) {
+                message.success('好友请求已发送');
+                setFriendName('');
+                loadPendingRequests(currentUserId);
+            } else {
+                message.error('添加失败');
+            }
+        } catch {
+            message.error('添加好友失败,请稍后重试');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    const handleDelete = async (friend1, friend2) => {
+        setLoading(true);
+        try {
+            const res = await deleteFriend(friend1, friend2);
+            if (res.data) {
+                message.success('删除成功');
+                loadFriends(currentUserId);
+            } else {
+                message.error('删除失败');
+            }
+        } catch {
+            message.error('删除好友失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    const handleAccept = async (friend1, friend2) => {
+        setPendingLoading(true);
+        try {
+            const res = await acceptFriend(friend1, friend2);
+            if (res.data) {
+                message.success('已同意好友请求');
+                refreshData();
+            } else {
+                message.error('操作失败');
+            }
+        } catch {
+            message.error('同意失败');
+        } finally {
+            setPendingLoading(false);
+        }
+    };
+
+    const handleReject = async (friend1, friend2) => {
+        setPendingLoading(true);
+        try {
+            const res = await rejectFriend(friend1, friend2);
+            if (res.data) {
+                message.info('已拒绝好友请求');
+                loadPendingRequests(currentUserId);
+            } else {
+                message.error('操作失败');
+            }
+        } catch {
+            message.error('拒绝失败');
+        } finally {
+            setPendingLoading(false);
+        }
+    };
+
+    const getFriendUserId = (f) => f.friend1 === currentUserId ? f.friend2 : f.friend1;
+
+    const renderUserMeta = (userId, timeLabel) => {
+        const user = userInfoMap[userId] || {};
+        return {
+            avatar: <Avatar src={user.avatar} />,
+            title: user.username ? `${user.username}(ID: ${userId})` : `用户ID:${userId}`,
+            description: timeLabel,
+        };
+    };
+
+    return (
+        <div style={{ maxWidth: 700, margin: 'auto', padding: 24 }}>
+            <Title level={3} style={{ textAlign: 'center', marginBottom: 24 }}>
+                好友管理
+            </Title>
+
+            <Space style={{ marginBottom: 24 }} align="start">
+                <Input
+                    placeholder="输入好友用户名"
+                    value={friendName}
+                    onChange={(e) => setFriendName(e.target.value)}
+                    style={{ width: 220 }}
+                    allowClear
+                    prefix={<UserAddOutlined />}
+                />
+                <Button
+                    type="primary"
+                    loading={loading}
+                    onClick={handleAddFriend}
+                    disabled={!friendName.trim()}
+                >
+                    添加好友
+                </Button>
+            </Space>
+
+            <Divider />
+
+            <Title level={4}>好友申请</Title>
+            <Spin spinning={pendingLoading}>
+                {pendingRequests.length === 0 ? (
+                    <Text type="secondary">暂无好友申请</Text>
+                ) : (
+                    <List
+                        itemLayout="horizontal"
+                        dataSource={pendingRequests}
+                        renderItem={(item) => {
+                            const otherId = item.friend1 === currentUserId ? item.friend2 : item.friend1;
+                            return (
+                                <List.Item
+                                    actions={[
+                                        <Button
+                                            key="accept"
+                                            type="primary"
+                                            icon={<CheckOutlined />}
+                                            onClick={() => handleAccept(item.friend1, item.friend2)}
+                                            loading={pendingLoading}
+                                            size="small"
+                                        >
+                                            同意
+                                        </Button>,
+                                        <Popconfirm
+                                            key="reject"
+                                            title="确定拒绝该好友请求?"
+                                            onConfirm={() => handleReject(item.friend1, item.friend2)}
+                                            okText="确认"
+                                            cancelText="取消"
+                                        >
+                                            <Button
+                                                danger
+                                                icon={<CloseOutlined />}
+                                                loading={pendingLoading}
+                                                size="small"
+                                            >
+                                                拒绝
+                                            </Button>
+                                        </Popconfirm>,
+                                    ]}
+                                >
+                                    <List.Item.Meta {...renderUserMeta(otherId, `申请时间:${new Date(item.requestTime).toLocaleString()}`)} />
+                                </List.Item>
+                            );
+                        }}
+                    />
+                )}
+            </Spin>
+
+            <Divider />
+
+            <Space align="center" style={{ marginBottom: 12, justifyContent: 'space-between', width: '100%' }}>
+                <Title level={4} style={{ margin: 0 }}>
+                    我的好友列表
+                </Title>
+                <Button
+                    icon={<ReloadOutlined />}
+                    onClick={() => refreshData()}
+                    loading={refreshing || pendingLoading}
+                    type="link"
+                >
+                    刷新
+                </Button>
+            </Space>
+            <Spin spinning={refreshing}>
+                {friends.length === 0 ? (
+                    <Text type="secondary">暂无好友</Text>
+                ) : (
+                    <List
+                        itemLayout="horizontal"
+                        dataSource={friends}
+                        renderItem={(f) => {
+                            const friendUserId = getFriendUserId(f);
+                            return (
+                                <List.Item
+                                    onClick={() =>
+                                        onSelectRelation({
+                                            relationid: f.relationid,
+                                            friendId: friendUserId,
+                                        })
+                                    }
+                                    style={{ cursor: 'pointer' }}
+                                    actions={[
+                                        <Popconfirm
+                                            title="确定删除该好友?"
+                                            onConfirm={(e) => {
+                                                e.stopPropagation();
+                                                handleDelete(f.friend1, f.friend2);
+                                            }}
+                                            okText="确认"
+                                            cancelText="取消"
+                                            key="delete"
+                                        >
+                                            <Button
+                                                danger
+                                                icon={<DeleteOutlined />}
+                                                loading={loading}
+                                                size="small"
+                                            >
+                                                删除
+                                            </Button>
+                                        </Popconfirm>,
+                                    ]}
+                                >
+                                    <List.Item.Meta
+                                        {...renderUserMeta(friendUserId, `添加时间:${new Date(f.requestTime).toLocaleString()}`)}
+                                    />
+                                </List.Item>
+                            );
+                        }}
+                    />
+                )}
+            </Spin>
+        </div>
+    );
+};
+
+export default FriendManager;
diff --git a/src/components/Post.css b/src/components/Post.css
new file mode 100644
index 0000000..40d787e
--- /dev/null
+++ b/src/components/Post.css
@@ -0,0 +1,483 @@
+.post-container {
+  padding: 2rem;
+  background: #f8f9fa;
+  min-height: 100vh;
+  max-width: 900px;
+  margin: auto;
+}
+
+.post-form-card {
+  background: white;
+  border-radius: 12px;
+  padding: 2rem;
+  box-shadow: 0 8px 20px rgba(255, 102, 0, 0.15);
+  margin-bottom: 2rem;
+  animation: fadeInUp 0.5s ease-in-out;
+}
+
+.post-form-title {
+  font-size: 1.5rem;
+  font-weight: bold;
+  margin-bottom: 1rem;
+  color: #ff6600;
+}
+
+.post-input,
+.post-textarea {
+  width: 100%;
+  padding: 12px 14px;
+  border-radius: 8px;
+  border: 1px solid #ffbf80;
+  margin-bottom: 1rem;
+  font-size: 1rem;
+  transition: border-color 0.3s ease;
+}
+
+.post-input:focus,
+.post-textarea:focus {
+  outline: none;
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+}
+
+.post-textarea {
+  height: 100px;
+  resize: vertical;
+}
+
+.post-file {
+  margin-bottom: 1rem;
+}
+
+.post-button {
+  padding: 10px 20px;
+  border: none;
+  border-radius: 8px;
+  font-size: 1rem;
+  font-weight: 600;
+  margin-right: 0.5rem;
+  transition: all 0.3s ease;
+  cursor: pointer;
+  box-shadow: 0 4px 6px rgba(255, 102, 0, 0.3);
+}
+
+/* 浅橙色实底按钮 */
+.primary {
+  background: linear-gradient(45deg, #FFB366, #FFC299);
+  color: white;
+  box-shadow: 0 6px 10px rgba(255, 179, 102, 0.5);
+}
+
+.primary:hover {
+  background: linear-gradient(45deg, #FFAA33, #FFBF66);
+  box-shadow: 0 8px 14px rgba(255, 170, 51, 0.7);
+}
+
+/* 橙色边框按钮 */
+.primary-outline {
+  background: transparent;
+  border: 2px solid #ff6600;
+  color: #ff6600;
+  box-shadow: none;
+}
+
+.primary-outline:hover {
+  background: #ff6600;
+  color: white;
+  box-shadow: 0 6px 10px rgba(255, 102, 0, 0.4);
+}
+
+.post-list {
+  display: flex;
+  flex-direction: column;
+  gap: 1.5rem;
+}
+
+.post-card {
+  background: white;
+  border-radius: 12px;
+  padding: 1.5rem;
+  box-shadow: 0 4px 15px rgba(255, 102, 0, 0.12);
+  animation: fadeInUp 0.3s ease-out;
+  transition: box-shadow 0.3s ease;
+}
+
+.post-card:hover {
+  box-shadow: 0 8px 30px rgba(255, 102, 0, 0.25);
+}
+
+.post-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: flex-start;
+  gap: 1rem;
+}
+
+.post-info {
+  flex: 1;
+}
+
+.post-title {
+  font-size: 1.5rem;
+  font-weight: 700;
+  color: #cc5200;
+  margin-bottom: 0.75rem;
+  padding-left: 12px;
+  border-left: 4px solid #ff6600;
+  transition: color 0.3s ease;
+}
+
+.post-title:hover {
+  color: #ff6600;
+}
+
+.post-content {
+  color: #444;
+  margin-bottom: 0.75rem;
+}
+
+.post-image {
+  width: 160px;
+  height: 120px;
+  object-fit: cover;
+  border-radius: 6px;
+  box-shadow: 0 4px 8px rgba(255, 102, 0, 0.3);
+  flex-shrink: 0;
+  cursor: pointer;
+  transition: transform 0.3s ease;
+}
+
+.post-image:hover {
+  transform: scale(1.05);
+}
+
+.post-meta {
+  font-size: 0.9rem;
+  color: #777;
+  margin-top: 0.5rem;
+}
+
+.post-actions-inline {
+  margin-top: 0.75rem;
+  display: flex;
+  align-items: center;
+  gap: 1rem;
+  font-size: 0.95rem;
+}
+
+.post-link {
+  cursor: pointer;
+  text-decoration: underline;
+  transition: color 0.3s ease;
+}
+
+.post-link.like {
+  color: #ff6600;
+}
+
+.post-link.like:hover {
+  color: #ff8533;
+}
+
+.post-link.unlike {
+  color: #cc3300;
+}
+
+.post-link.unlike:hover {
+  color: #ff3300;
+}
+
+.post-comment {
+  margin-top: 1rem;
+  border-top: 1px solid #ffe6cc;
+  padding-top: 1rem;
+}
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translateY(20px);
+  }
+
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
+
+/* 图片模态框 */
+.image-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100vw;
+  height: 100vh;
+  background: rgba(0, 0, 0, 0.75);
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  z-index: 9999;
+}
+
+.image-modal-content {
+  position: relative;
+  max-width: 90%;
+  max-height: 90%;
+}
+
+.image-modal-img {
+  width: 100%;
+  max-height: 80vh;
+  border-radius: 12px;
+  box-shadow: 0 0 20px rgba(255, 102, 0, 0.8);
+}
+
+.image-modal-close {
+  position: absolute;
+  top: -20px;
+  right: -20px;
+  background: white;
+  border: none;
+  border-radius: 50%;
+  width: 36px;
+  height: 36px;
+  font-size: 24px;
+  line-height: 36px;
+  text-align: center;
+  cursor: pointer;
+  box-shadow: 0 2px 10px rgba(255, 102, 0, 0.7);
+}
+
+.action-group {
+  display: flex;
+  gap: 0.5rem;
+  margin-bottom: 0.5rem;
+}
+
+.post-empty-state {
+  text-align: center;
+  padding: 2rem;
+  background: white;
+  border-radius: 12px;
+  box-shadow: 0 4px 15px rgba(255, 102, 0, 0.12);
+}
+
+.post-empty-message {
+  font-size: 1.2rem;
+  color: #cc5200;
+  margin-bottom: 1rem;
+}
+
+/* RequestBoard组件样式保持一致 */
+.request-board-container {
+  background: white;
+  border-radius: 12px;
+  padding: 1.5rem;
+  box-shadow: 0 4px 15px rgba(255, 102, 0, 0.12);
+  margin-top: 1rem;
+}
+
+.request-board-section {
+  margin-bottom: 1.5rem;
+}
+
+.request-board-form {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 1rem;
+  margin-bottom: 1.5rem;
+}
+
+.request-board-input {
+  padding: 10px 12px;
+  border-radius: 8px;
+  border: 1px solid #ffbf80;
+  font-size: 0.95rem;
+}
+
+.request-board-input:focus {
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+  outline: none;
+}
+
+.request-board-textarea {
+  grid-column: span 2;
+  padding: 10px 12px;
+  border-radius: 8px;
+  border: 1px solid #ffbf80;
+  resize: vertical;
+  min-height: 100px;
+}
+
+.request-board-textarea:focus {
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+  outline: none;
+}
+
+.request-board-file {
+  grid-column: span 2;
+}
+
+.request-board-list {
+  display: grid;
+  grid-template-columns: 1fr;
+  gap: 1rem;
+}
+
+.request-board-item {
+  background: white;
+  border-radius: 10px;
+  padding: 1.25rem;
+  box-shadow: 0 2px 8px rgba(255, 102, 0, 0.08);
+}
+
+.request-board-item-title {
+  font-size: 1.3rem;
+  font-weight: 700;
+  margin-bottom: 0.75rem;
+  color: hsl(24, 67%, 55%);
+  border-bottom: 2px solid #ffe0b3;
+  padding-bottom: 0.5rem;
+}
+
+.request-board-item-content {
+  color: #555;
+  margin-bottom: 1rem;
+}
+
+.request-board-item-meta {
+  display: flex;
+  gap: 1rem;
+  margin-bottom: 1rem;
+  color: #777;
+  font-size: 0.9rem;
+}
+
+.request-board-item-image {
+  max-width: 200px;
+  max-height: 150px;
+  border-radius: 6px;
+  margin-bottom: 1rem;
+}
+
+.request-board-item-actions {
+  display: flex;
+  gap: 0.75rem;
+  flex-wrap: wrap;
+}
+
+.request-board-small-input {
+  padding: 8px 10px;
+  border-radius: 6px;
+  border: 1px solid #ffbf80;
+  flex: 1;
+}
+
+.request-board-small-input:focus {
+  border-color: #ff6600;
+  box-shadow: 0 0 8px rgba(255, 102, 0, 0.5);
+  outline: none;
+}
+
+/* 新增的用户信息显示样式 */
+.post-form-user-info {
+  display: flex;
+  align-items: center;
+  margin-bottom: 20px;
+  padding: 10px;
+  background-color: #f8f9fa;
+  border-radius: 8px;
+  border: 1px solid #e9ecef;
+}
+
+.post-form-user-avatar {
+  width: 50px;
+  height: 50px;
+  border-radius: 50%;
+  object-fit: cover;
+  margin-right: 15px;
+  border: 2px solid #40a9ff;
+}
+
+.post-form-user-avatar-placeholder {
+  width: 50px;
+  height: 50px;
+  border-radius: 50%;
+  background-color: #e9ecef;
+  margin-right: 15px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 2px solid #40a9ff;
+}
+
+.avatar-initial {
+  font-size: 24px;
+  font-weight: bold;
+  color: #495057;
+}
+
+.post-form-username {
+  font-weight: 600;
+  font-size: 18px;
+  color: #212529;
+}
+
+.post-form-user-label {
+  margin-left: auto;
+  padding: 5px 10px;
+  background-color: #e6f7ff;
+  color: #1890ff;
+  border-radius: 4px;
+  font-size: 14px;
+}
+
+/* 帖子作者信息样式 */
+.post-author-info {
+  display: flex;
+  align-items: center;
+  padding: 10px 15px;
+  border-bottom: 1px solid #f0f0f0;
+  margin-bottom: 15px;
+}
+
+.post-author-avatar {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  object-fit: cover;
+  margin-right: 12px;
+  border: 1px solid #e8e8e8;
+}
+
+.post-author-avatar-placeholder {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  background-color: #f5f5f5;
+  margin-right: 12px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid #e8e8e8;
+}
+
+.post-author-details {
+  display: flex;
+  flex-direction: column;
+}
+
+.post-author-name {
+  font-weight: 600;
+  font-size: 16px;
+  margin-bottom: 3px;
+  color: #333;
+}
+
+.post-meta {
+  font-size: 12px;
+  color: #888;
+  margin: 2px 0;
+}
\ No newline at end of file
diff --git a/src/components/Post.jsx b/src/components/Post.jsx
new file mode 100644
index 0000000..c6b2e69
--- /dev/null
+++ b/src/components/Post.jsx
@@ -0,0 +1,294 @@
+import React, { useState, useEffect } from 'react';
+import {
+    createPost,
+    findPinnedPosts,
+    likePost,
+    unlikePost,
+    searchPosts,
+    getAllPostsSorted,
+    findPostsByUserId,
+} from '../api/post';
+import Comment from './Comment';
+import RequestBoard from './RequestBoard';
+import './Post.css';
+
+const Post = () => {
+    const [title, setTitle] = useState('');
+    const [content, setContent] = useState('');
+    const [tags, setTags] = useState('');
+    const [photo, setPhoto] = useState(null);
+    const [posts, setPosts] = useState([]);
+    const [searchKeyword, setSearchKeyword] = useState('');
+    const [imagePreview, setImagePreview] = useState(null);
+    const [showCreateForm, setShowCreateForm] = useState(false);
+    const [currentView, setCurrentView] = useState('posts');
+    const [currentUser, setCurrentUser] = useState(null);
+    const [userDecorations, setUserDecorations] = useState({});
+
+    useEffect(() => {
+        const storedUser = JSON.parse(localStorage.getItem('user'));
+        if (storedUser) setCurrentUser(storedUser);
+    }, []);
+
+    useEffect(() => {
+        loadPinnedPosts();
+    }, []);
+
+    useEffect(() => {
+        if (posts.length > 0) {
+            fetchUserDecorations(posts);
+        }
+    }, [posts]);
+
+    const fetchUserDecorations = async (posts) => {
+        const decorations = {};
+        await Promise.all(
+            posts.map(async (post) => {
+                if (!decorations[post.userid]) {
+                    try {
+                        const res = await fetch(`http://localhost:8080/user/getDecoration?userid=${post.userid}`);
+                        const json = await res.json();
+                        if (json.success) {
+                            decorations[post.userid] = json.data;
+                        }
+                    } catch (error) {
+                        console.error(`获取用户 ${post.userid} 的装饰信息失败`, error);
+                    }
+                }
+            })
+        );
+        setUserDecorations(decorations);
+    };
+
+    const loadPinnedPosts = async () => {
+        const data = await findPinnedPosts();
+        setPosts(data);
+        setCurrentView('posts');
+    };
+
+    const loadAllPosts = async () => {
+        const data = await getAllPostsSorted();
+        setPosts(data);
+        setCurrentView('posts');
+    };
+
+    const loadMyPosts = async () => {
+        if (!currentUser) return;
+        const data = await findPostsByUserId(currentUser.userid);
+        setPosts(data);
+        setCurrentView('posts');
+    };
+
+    const handleCreate = async () => {
+        if (!currentUser) {
+            alert('请先登录再发帖');
+            return;
+        }
+
+        const formData = new FormData();
+        formData.append('userid', currentUser.userid);
+        formData.append('post_title', title);
+        formData.append('post_content', content);
+        formData.append('tags', tags);
+        formData.append('rannge', 'public');
+        if (photo) formData.append('photo', photo);
+
+        const success = await createPost(formData);
+        if (success) {
+            alert('帖子创建成功');
+            loadPinnedPosts();
+            setTitle('');
+            setContent('');
+            setTags('');
+            setPhoto(null);
+            setShowCreateForm(false);
+        } else {
+            alert('创建失败');
+        }
+    };
+
+    const handleLike = async (postid) => {
+        await likePost(postid);
+        loadPinnedPosts();
+    };
+
+    const handleUnlike = async (postid) => {
+        await unlikePost(postid);
+        loadPinnedPosts();
+    };
+
+    const handleSearch = async () => {
+        const result = await searchPosts(searchKeyword);
+        setPosts(result);
+        setCurrentView('posts');
+    };
+
+    const showRequestBoard = () => {
+        setCurrentView('requests');
+    };
+
+    return (
+        <div className="post-container">
+            <div className="post-actions">
+                <div className="action-group">
+                    {currentUser && (
+                        <button
+                            className="post-button primary"
+                            onClick={() => setShowCreateForm(!showCreateForm)}
+                        >
+                            {showCreateForm ? '收起发布表单' : '创建新帖子'}
+                        </button>
+                    )}
+                    <input
+                        type="text"
+                        placeholder="搜索关键词"
+                        value={searchKeyword}
+                        onChange={(e) => setSearchKeyword(e.target.value)}
+                        className="post-input"
+                    />
+                    <button className="post-button primary-outline" onClick={handleSearch}>搜索</button>
+                </div>
+
+                <div className="action-group">
+                    <button className="post-button primary-outline" onClick={loadPinnedPosts}>置顶帖子</button>
+                    <button className="post-button primary-outline" onClick={loadAllPosts}>所有帖子</button>
+                    {currentUser && (
+                        <button className="post-button primary-outline" onClick={loadMyPosts}>我的帖子</button>
+                    )}
+                    <button className="post-button primary-outline" onClick={showRequestBoard}>需求帖子</button>
+                </div>
+            </div>
+
+            {showCreateForm && currentUser && currentView !== 'requests' && (
+                <div className="post-form-card">
+                    <div className="post-form-user-info">
+                        {currentUser.image ? (
+                            <img
+                                src={currentUser.image}
+                                alt="头像"
+                                className="post-form-user-avatar"
+                            />
+                        ) : (
+                            <div className="post-form-user-avatar-placeholder">
+                                <div className="avatar-initial">
+                                    {currentUser.username?.charAt(0) || 'U'}
+                                </div>
+                            </div>
+                        )}
+                        <div className="post-form-username">{currentUser.username}</div>
+                        <div className="post-form-user-label">发布者</div>
+                    </div>
+
+                    <h2 className="post-form-title">发布新帖子</h2>
+                    <input
+                        type="text"
+                        placeholder="标题"
+                        value={title}
+                        onChange={(e) => setTitle(e.target.value)}
+                        className="post-input"
+                    />
+                    <textarea
+                        placeholder="内容"
+                        value={content}
+                        onChange={(e) => setContent(e.target.value)}
+                        className="post-textarea"
+                    />
+                    <input
+                        type="text"
+                        placeholder="标签(逗号分隔)"
+                        value={tags}
+                        onChange={(e) => setTags(e.target.value)}
+                        className="post-input"
+                    />
+                    <input
+                        type="file"
+                        onChange={(e) => setPhoto(e.target.files[0])}
+                        className="post-file"
+                    />
+                    <button className="post-button primary" onClick={handleCreate}>
+                        发布
+                    </button>
+                </div>
+            )}
+
+            {currentView === 'requests' ? (
+                <RequestBoard
+                    currentUserId={currentUser?.userid}
+                    onBack={() => setCurrentView('posts')}
+                />
+            ) : (
+                posts.length > 0 ? (
+                    <div className="post-list">
+                        {posts.map((post) => {
+                            const decoration = userDecorations[post.userid] || {};
+                            const avatar = decoration.image || '';
+                            const username = decoration.username || '匿名用户';
+
+                            return (
+                                <div className="post-card" key={post.postid}>
+                                    <div className="post-author-info">
+                                        {avatar ? (
+                                            <img
+                                                src={avatar}
+                                                alt="头像"
+                                                className="post-author-avatar"
+                                            />
+                                        ) : (
+                                            <div className="post-author-avatar-placeholder">
+                                                <div className="avatar-initial">{username.charAt(0)}</div>
+                                            </div>
+                                        )}
+                                        <div className="post-author-details">
+                                            <div className="post-author-name">{username}</div>
+                                            <div className="post-meta">发布时间: {post.postCreatedTime}</div>
+                                        </div>
+                                    </div>
+
+                                    <div className="post-header">
+                                        <div className="post-info">
+                                            <h3 className="post-title">{post.postTitle}</h3>
+                                            <p className="post-content">{post.postContent}</p>
+                                            <div className="post-meta">标签: {post.tags || '无标签'}</div>
+                                            <div className="post-actions-inline">
+                                                <span>👍 {post.likes}</span>
+                                                <button className="post-link like" onClick={() => handleLike(post.postid)}>点赞</button>
+                                                <button className="post-link unlike" onClick={() => handleUnlike(post.postid)}>取消点赞</button>
+                                            </div>
+                                        </div>
+                                        {post.photo && (
+                                            <img
+                                                src={`http://localhost:8080${post.photo}`}
+                                                alt="post"
+                                                className="post-image"
+                                                onClick={() => setImagePreview(`http://localhost:8080${post.photo}`)}
+                                            />
+                                        )}
+                                    </div>
+
+                                    <div className="post-comment">
+                                        <Comment postId={post.postid} currentUser={currentUser} />
+                                    </div>
+                                </div>
+                            );
+                        })}
+                    </div>
+                ) : (
+                    <div className="post-empty-state">
+                        <p className="post-empty-message">暂无内容</p>
+                    </div>
+                )
+            )}
+
+            {imagePreview && (
+                <div className="image-modal" onClick={() => setImagePreview(null)}>
+                    <div className="image-modal-content" onClick={(e) => e.stopPropagation()}>
+                        <img src={imagePreview} alt="preview" className="image-modal-img" />
+                        <button className="image-modal-close" onClick={() => setImagePreview(null)}>×</button>
+                    </div>
+                </div>
+            )}
+        </div>
+    );
+};
+
+export default Post;
diff --git a/src/components/PostAdminPanel.jsx b/src/components/PostAdminPanel.jsx
new file mode 100644
index 0000000..a01df08
--- /dev/null
+++ b/src/components/PostAdminPanel.jsx
@@ -0,0 +1,232 @@
+import React, { useEffect, useState } from 'react';
+import {
+    Table,
+    Button,
+    Modal,
+    Image,
+    message,
+    Tag,
+    Space,
+    Input,
+    Tooltip,
+} from 'antd';
+import { ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons';
+import {
+    getAllPostsSorted,
+    searchPosts,
+    deletePost,
+    togglePinPost,
+} from '../api/post';
+
+const { confirm } = Modal;
+
+const PostAdminPanel = () => {
+    const [posts, setPosts] = useState([]);
+    const [loading, setLoading] = useState(false);
+    const [keyword, setKeyword] = useState('');
+
+    const fetchPosts = async () => {
+        setLoading(true);
+        try {
+            const data = keyword.trim()
+                ? await searchPosts(keyword.trim())
+                : await getAllPostsSorted();
+            setPosts(data);
+        } catch (error) {
+            message.error('获取帖子失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    useEffect(() => {
+        fetchPosts();
+    }, []);
+
+    const handleSearch = () => {
+        fetchPosts();
+    };
+
+    const handleDelete = (postid) => {
+        confirm({
+            title: '确认删除该帖子吗?',
+            icon: <ExclamationCircleOutlined />,
+            okText: '删除',
+            okType: 'danger',
+            cancelText: '取消',
+            onOk: async () => {
+                try {
+                    const res = await deletePost(postid);
+                    if (res) {
+                        message.success('删除成功');
+                        fetchPosts();
+                    } else {
+                        message.error('删除失败');
+                    }
+                } catch {
+                    message.error('删除请求失败');
+                }
+            },
+        });
+    };
+
+    const handlePinToggle = async (postid) => {
+        try {
+            const res = await togglePinPost(postid);
+            if (res === true || res === false) {
+                // ✅ 用后端返回的状态更新 UI
+                const newPosts = posts.map(post => {
+                    if (post.postid === postid) {
+                        return {
+                            ...post,
+                            is_pinned: res ? 1 : 0,
+                        };
+                    }
+                    return post;
+                });
+                setPosts(newPosts);
+                message.success(`帖子${res ? '已置顶' : '已取消置顶'}`);
+            } else {
+                message.error('更新失败');
+            }
+        } catch {
+            message.error('更新置顶状态失败');
+        }
+    };
+
+
+
+
+    const columns = [
+        {
+            title: 'ID',
+            dataIndex: 'postid',
+            key: 'postid',
+            width: 80,
+            fixed: 'left',
+        },
+        {
+            title: '用户ID',
+            dataIndex: 'userid',
+            key: 'userid',
+            width: 100,
+        },
+        {
+            title: '标题',
+            dataIndex: 'postTitle',
+            key: 'postTitle',
+            width: 200,
+            ellipsis: true,
+        },
+        {
+            title: '内容',
+            dataIndex: 'postContent',
+            key: 'postContent',
+            ellipsis: { showTitle: false },
+            render: (text) => (
+                <Tooltip placement="topLeft" title={text}>
+                    {text}
+                </Tooltip>
+            ),
+        },
+        {
+            title: '标签',
+            dataIndex: 'tags',
+            key: 'tags',
+            render: (tags) =>
+                tags ? tags.split(',').map((tag) => <Tag key={tag}>{tag}</Tag>) : <Tag color="default">无</Tag>,
+        },
+        {
+            title: '图片',
+            dataIndex: 'photo',
+            key: 'photo',
+            width: 100,
+            render: (url) =>
+                url ? (
+                    <Image
+                        src={`http://localhost:8080${url}`}
+                        width={80}
+                        height={80}
+                        style={{ objectFit: 'cover' }}
+                    />
+                ) : (
+                    <Tag color="default">无</Tag>
+                ),
+        },
+        {
+            title: '点赞数',
+            dataIndex: 'likes',
+            key: 'likes',
+            width: 100,
+            render: (likes) => <Tag color="blue">{likes}</Tag>,
+        },
+        {
+            title: '置顶状态',
+            dataIndex: 'is_pinned',
+            key: 'is_pinned',
+            width: 100,
+            render: (val) =>
+                val ? <Tag color="green">已置顶</Tag> : <Tag color="default">未置顶</Tag>,
+        },
+        {
+            title: '发布时间',
+            dataIndex: 'postCreatedTime',
+            key: 'postCreatedTime',
+            width: 180,
+            render: (time) =>
+                time ? new Date(time).toLocaleString() : <Tag color="default">暂无</Tag>,
+        },
+        {
+            title: '操作',
+            key: 'action',
+            width: 180,
+            fixed: 'right',
+            render: (_, record) => (
+                <Space size="middle">
+                    <Button
+                        type="primary"
+                        onClick={() => handlePinToggle(record.postid, record.is_pinned)}
+                    >
+                        {Boolean(record.is_pinned) ? '取消置顶' : '置顶'}
+                    </Button>
+
+                    <Button danger onClick={() => handleDelete(record.postid)}>
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
+    ];
+
+    return (
+        <div style={{ padding: 20 }}>
+            <h2 style={{ marginBottom: 20 }}>帖子管理面板</h2>
+            <Space style={{ marginBottom: 16 }}>
+                <Input
+                    placeholder="请输入关键词"
+                    value={keyword}
+                    onChange={(e) => setKeyword(e.target.value)}
+                    style={{ width: 300 }}
+                />
+                <Button type="primary" icon={<SearchOutlined />} onClick={handleSearch}>
+                    搜索
+                </Button>
+                <Button onClick={() => { setKeyword(''); fetchPosts(); }}>
+                    重置
+                </Button>
+            </Space>
+            <Table
+                rowKey="postid"
+                columns={columns}
+                dataSource={posts}
+                loading={loading}
+                scroll={{ x: 1600 }}
+                pagination={{ pageSize: 10 }}
+                bordered
+                size="middle"
+            />
+        </div>
+    );
+};
+
+export default PostAdminPanel;
diff --git a/src/components/PostCard.jsx b/src/components/PostCard.jsx
new file mode 100644
index 0000000..5051cec
--- /dev/null
+++ b/src/components/PostCard.jsx
@@ -0,0 +1,103 @@
+import React, { useState, useEffect } from 'react';
+import {
+    likePost,
+    unlikePost,
+    togglePinPost,
+    deletePost,
+} from '../api/post';
+
+const PostCard = ({ post, onDeleted, onUpdated }) => {
+    const [likes, setLikes] = useState(post.likes);
+    const [isLiked, setIsLiked] = useState(false); // 默认未点赞
+    const [isPinned, setIsPinned] = useState(post.is_pinned || false);
+    const [loading, setLoading] = useState(false);
+
+    useEffect(() => {
+        setIsPinned(post.is_pinned || false);
+    }, [post.is_pinned]);
+
+    const handleLike = async () => {
+        setLoading(true);
+        try {
+            if (!isLiked) {
+                const res = await likePost(post.postid);
+                if (res) {
+                    setLikes(likes + 1);
+                    setIsLiked(true);
+                }
+            } else {
+                const res = await unlikePost(post.postid);
+                if (res) {
+                    setLikes(likes - 1);
+                    setIsLiked(false);
+                }
+            }
+        } catch (error) {
+            console.error('点赞操作失败', error);
+        }
+        setLoading(false);
+    };
+
+    const handlePin = async () => {
+        setLoading(true);
+        try {
+            const res = await togglePinPost(post.postid);
+            if (res) {
+                onUpdated && onUpdated(); // 通知父组件刷新数据
+            }
+        } catch (error) {
+            console.error('置顶切换失败', error);
+        }
+        setLoading(false);
+    };
+
+    const handleDelete = async () => {
+        if (!window.confirm('确认删除该帖子吗?')) return;
+        setLoading(true);
+        try {
+            const res = await deletePost(post.postid);
+            if (res) {
+                onDeleted && onDeleted(post.postid);
+            }
+        } catch (error) {
+            console.error('删除失败', error);
+        }
+        setLoading(false);
+    };
+
+    return (
+        <div className="post-card" style={{ border: '1px solid #ddd', padding: 16, marginBottom: 12 }}>
+            <h3>{post.postTitle}</h3>
+            <p>{post.postContent}</p>
+            {post.photo && (
+                <img
+                    src={`http://localhost:8080${post.photo}`}
+                    alt="帖子图片"
+                    style={{ maxWidth: '100%', maxHeight: 200 }}
+                />
+            )}
+            <p>
+                <strong>标签:</strong> {post.tags || '无'}
+            </p>
+            <p>
+                <strong>作者ID:</strong> {post.userid} | <strong>点赞数:</strong> {likes}
+            </p>
+            <p>
+                <strong>发布时间:</strong> {new Date(post.postCreatedTime).toLocaleString()}
+            </p>
+            <p>
+                <button onClick={handleLike} disabled={loading}>
+                    {isLiked ? '取消点赞' : '点赞'}
+                </button>{' '}
+                <button onClick={handlePin} disabled={loading}>
+                    {isPinned ? '取消置顶' : '置顶'}
+                </button>{' '}
+                <button onClick={handleDelete} disabled={loading}>
+                    删除
+                </button>
+            </p>
+        </div>
+    );
+};
+
+export default PostCard;
diff --git a/src/components/RequestAdminPanel.jsx b/src/components/RequestAdminPanel.jsx
new file mode 100644
index 0000000..ecf4ee1
--- /dev/null
+++ b/src/components/RequestAdminPanel.jsx
@@ -0,0 +1,228 @@
+import React, { useEffect, useState } from 'react';
+import {
+    Table,
+    Button,
+    Modal,
+    Image,
+    message,
+    Tag,
+    Space,
+    Spin,
+    Tooltip,
+} from 'antd';
+import { ExclamationCircleOutlined } from '@ant-design/icons';
+import {
+    getAllRequests,
+    deleteRequest,
+} from '../api/request';
+import { useNavigate } from 'react-router-dom';
+
+const { confirm } = Modal;
+
+const RequestAdminPanel = () => {
+    const [requests, setRequests] = useState([]);
+    const [loading, setLoading] = useState(false);
+    const navigate = useNavigate();
+
+    // 获取所有求助帖
+    const fetchRequests = async () => {
+        setLoading(true);
+        try {
+            const data = await getAllRequests();
+            setRequests(data);
+        } catch (error) {
+            message.error('获取求助帖失败');
+        } finally {
+            setLoading(false);
+        }
+    };
+
+    useEffect(() => {
+        fetchRequests();
+    }, []);
+
+    // 删除确认弹窗
+    const showDeleteConfirm = (requestid) => {
+        confirm({
+            title: '确认删除该求助帖吗?',
+            icon: <ExclamationCircleOutlined />,
+            okText: '删除',
+            okType: 'danger',
+            cancelText: '取消',
+            onOk() {
+                handleDelete(requestid);
+            },
+        });
+    };
+
+    // 删除求助帖
+    const handleDelete = async (requestid) => {
+        try {
+            const success = await deleteRequest(requestid);
+            if (success) {
+                message.success('删除成功');
+                fetchRequests();
+            } else {
+                message.error('删除失败');
+            }
+        } catch {
+            message.error('删除请求失败');
+        }
+    };
+
+    // 处理按钮示例
+    const handleProcess = (request) => {
+        navigate(`/process/${request.requestid}`, {
+            state: {
+                requestid: request.requestid,
+                helpedid: request.userid,
+                loaduser: request.loaduser,
+                money: request.money,
+                torrentid: request.torrentid
+            },
+        });
+    };
+
+    console.log('请求数据:', requests);
+
+    // 表格列定义
+    const columns = [
+        {
+            title: 'ID',
+            dataIndex: 'requestid',
+            key: 'requestid',
+            width: 60,
+            fixed: 'left',
+        },
+        {
+            title: '发帖ID',
+            dataIndex: 'userid',
+            key: 'userid',
+            width: 100,
+        },
+        {
+            title: '上传者ID',
+            dataIndex: 'loaduser',
+            key: 'loaduser',
+            width: 100,
+            render: (val) => val ?? <Tag color="default">目前没有</Tag>,
+        },
+        {
+            title: '资源名字',
+            dataIndex: 'name',
+            key: 'name',
+            width: 120,
+            ellipsis: true,
+        },
+        {
+            title: '内容描述',
+            dataIndex: 'plot',
+            key: 'plot',
+            ellipsis: { showTitle: false },
+            render: (text) => (
+                <Tooltip placement="topLeft" title={text}>
+                    {text}
+                </Tooltip>
+            ),
+        },
+        {
+            title: '悬赏金额',
+            dataIndex: 'money',
+            key: 'money',
+            width: 80,
+            render: (money) => <Tag color="volcano">{money}元</Tag>,
+        },
+        {
+            title: '照片',
+            dataIndex: 'photo',
+            key: 'photo',
+            width: 100,
+            render: (url) =>
+                url ? (
+                    <Image
+                        src={`http://localhost:8080${url}`}
+                        width={80}
+                        height={80}
+                        style={{ objectFit: 'cover' }}
+                        placeholder={<Spin />}
+                    />
+                ) : (
+                    <Tag color="default">无</Tag>
+                ),
+        },
+        {
+            title: '年份',
+            dataIndex: 'year',
+            key: 'year',
+            width: 80,
+        },
+        {
+            title: '国家',
+            dataIndex: 'country',
+            key: 'country',
+            width: 100,
+        },
+        {
+            title: '种子号',
+            dataIndex: 'torrentid',
+            key: 'torrentid',
+            width: 120,
+            render: (val) =>
+                val !== null && val !== undefined ? (
+                    <Tag color="green">{val}</Tag>
+                ) : (
+                    <Tag color="default">暂无</Tag>
+                ),
+        },
+        {
+            title: '发布时间',
+            dataIndex: 'requesttime',
+            key: 'requesttime',
+            width: 180,
+            render: (text) => {
+                if (!text) return <Tag color="default">暂无</Tag>;
+                return new Date(text).toLocaleString();
+            },
+        },
+        {
+            title: '操作',
+            key: 'action',
+            fixed: 'right',
+            width: 150,
+            render: (_, record) => (
+                <Space size="middle">
+                    <Button
+                        type="primary"
+                        onClick={() => handleProcess(record)}
+                    >
+                        处理
+                    </Button>
+                    <Button
+                        danger
+                        onClick={() => showDeleteConfirm(record.requestid)}
+                    >
+                        删除
+                    </Button>
+                </Space>
+            ),
+        },
+    ];
+
+    return (
+        <div style={{ padding: 20 }}>
+            <h2 style={{ marginBottom: 20 }}>求助帖管理面板</h2>
+            <Table
+                rowKey="requestid"
+                columns={columns}
+                dataSource={requests}
+                loading={loading}
+                scroll={{ x: 1600 }}
+                pagination={{ pageSize: 10 }}
+                bordered
+                size="middle"
+            />
+        </div>
+    );
+};
+
+export default RequestAdminPanel;
diff --git a/src/components/RequestBoard.css b/src/components/RequestBoard.css
new file mode 100644
index 0000000..0fbe1a9
--- /dev/null
+++ b/src/components/RequestBoard.css
@@ -0,0 +1,443 @@
+/* 容器和布局 */
+.request-container {
+    max-width: 1200px;
+    margin: 0 auto;
+    padding: 20px;
+}
+
+.request-header {
+    margin-bottom: 30px;
+    border-bottom: 1px solid #f0f0f0;
+    padding-bottom: 20px;
+}
+
+.request-search {
+    background-color: #fff8f0;
+    border-radius: 10px;
+    padding: 20px;
+    margin-bottom: 30px;
+    box-shadow: 0 4px 12px rgba(255, 102, 0, 0.1);
+}
+
+.request-money-total {
+    background-color: #fff1e6;
+    border-radius: 8px;
+    padding: 10px 15px;
+    display: inline-block;
+    font-size: 16px;
+}
+
+/* 卡片样式 */
+.request-card {
+    background-color: white;
+    border-radius: 12px;
+    padding: 20px;
+    margin-bottom: 20px;
+    box-shadow: 0 4px 15px rgba(255, 102, 0, 0.08);
+    transition: all 0.3s ease;
+    border: 1px solid #ffe8d6;
+}
+
+.request-card:hover {
+    transform: translateY(-5px);
+    box-shadow: 0 10px 25px rgba(255, 102, 0, 0.15);
+}
+
+.request-card-title {
+    font-size: 18px;
+    font-weight: 700;
+    color: #d15700;
+    margin-bottom: 8px;
+}
+
+.request-card-money {
+    font-size: 20px;
+    font-weight: 800;
+    color: #ff5722;
+    letter-spacing: 0.5px;
+}
+
+.request-card-content {
+    color: #555;
+    line-height: 1.6;
+    margin: 15px 0;
+    padding: 15px;
+    background-color: #f9f9f9;
+    border-radius: 8px;
+    border-left: 4px solid #ffaa33;
+}
+
+.request-card-meta {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 15px;
+    margin: 15px 0;
+    padding: 10px 0;
+    border-top: 1px dashed #ffe0b3;
+    border-bottom: 1px dashed #ffe0b3;
+    font-size: 14px;
+}
+
+.request-meta-item {
+    display: flex;
+    align-items: center;
+    gap: 5px;
+}
+
+.request-meta-label {
+    font-weight: 600;
+    color: #ff8d00;
+}
+
+.request-card-image-container {
+    margin: 15px 0;
+}
+
+.request-card-image {
+    max-width: 300px;
+    border-radius: 8px;
+    border: 1px solid #ffd8b3;
+    box-shadow: 0 4px 8px rgba(255, 140, 0, 0.15);
+}
+
+/* 用户信息 - 重点修改 */
+.request-user-info-container {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+    padding: 10px;
+    background-color: #fffaf0;
+    border-radius: 10px;
+    box-shadow: 0 2px 8px rgba(255, 140, 0, 0.1);
+    min-width: 140px;
+}
+
+.request-user-divider {
+    height: 1px;
+    width: 100%;
+    background-color: #ffd8b3;
+    margin: 4px 0;
+}
+
+.request-user-info {
+    padding: 5px;
+}
+
+.request-user-details {
+    min-width: 60px;
+    overflow: hidden;
+}
+
+/* 按钮样式 */
+.request-button {
+    padding: 10px 16px;
+    border: none;
+    border-radius: 8px;
+    font-weight: 600;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    display: inline-flex;
+    align-items: center;
+    justify-content: center;
+    font-size: 14px;
+}
+
+.request-button:hover {
+    transform: translateY(-2px);
+}
+
+.request-button-back {
+    background-color: #f5f5f5;
+    color: #666;
+}
+
+.request-button-back:hover {
+    background-color: #e0e0e0;
+}
+
+.request-button-create {
+    background: linear-gradient(135deg, #ffa500, #ff7043);
+    color: white;
+    box-shadow: 0 4px 10px rgba(255, 140, 0, 0.3);
+}
+
+.request-button-create:hover {
+    background: linear-gradient(135deg, #ff8c00, #ff5722);
+    box-shadow: 0 6px 14px rgba(255, 140, 0, 0.4);
+}
+
+.request-button-search {
+    background: linear-gradient(135deg, #4db6ac, #26a69a);
+    color: white;
+    box-shadow: 0 4px 10px rgba(77, 182, 172, 0.3);
+}
+
+.request-button-search:hover {
+    background: linear-gradient(135deg, #26a69a, #00897b);
+}
+
+.request-button-submit {
+    background: linear-gradient(135deg, #ffa726, #fb8c00);
+    color: white;
+    padding: 12px 30px;
+    font-size: 16px;
+    box-shadow: 0 4px 12px rgba(255, 140, 0, 0.4);
+}
+
+.request-button-submit:hover {
+    background: linear-gradient(135deg, #fb8c00, #f57c00);
+}
+
+.request-button-takeover {
+    background: linear-gradient(135deg, #42a5f5, #1e88e5);
+    color: white;
+    box-shadow: 0 4px 10px rgba(66, 165, 245, 0.3);
+    width: 100%;
+    font-size: 13px;
+    padding: 8px 12px;
+}
+
+.request-button-takeover:hover {
+    background: linear-gradient(135deg, #1e88e5, #1565c0);
+}
+
+.request-button-delete {
+    background: linear-gradient(135deg, #ef5350, #e53935);
+    color: white;
+    box-shadow: 0 4px 10px rgba(239, 83, 80, 0.3);
+    font-size: 13px;
+    padding: 8px 12px;
+}
+
+.request-button-delete:hover {
+    background: linear-gradient(135deg, #e53935, #c62828);
+}
+
+/* 标签页 */
+.request-tab {
+    padding: 8px 16px;
+    border-radius: 20px;
+    background-color: #f1f1f1;
+    border: 1px solid #e0e0e0;
+    font-weight: 600;
+    color: #666;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    font-size: 13px;
+}
+
+.request-tab-active {
+    background: linear-gradient(135deg, #ffb74d, #ff9800);
+    color: white;
+    border-color: #ff9800;
+    box-shadow: 0 4px 8px rgba(255, 152, 0, 0.2);
+}
+
+/* 表单元素 */
+.request-form {
+    background-color: #fffaf5;
+    border-radius: 12px;
+    padding: 25px;
+    box-shadow: 0 5px 15px rgba(255, 140, 0, 0.1);
+    margin-top: 20px;
+}
+
+.request-label {
+    display: block;
+    margin-bottom: 8px;
+    font-weight: 600;
+    color: #ff8d00;
+    font-size: 14px;
+}
+
+.request-input {
+    width: 100%;
+    padding: 10px 12px;
+    border: 1px solid #ffd8b3;
+    border-radius: 8px;
+    font-size: 14px;
+    transition: all 0.3s ease;
+    background-color: #fffdfa;
+}
+
+.request-input:focus {
+    outline: none;
+    border-color: #ffaa33;
+    box-shadow: 0 0 0 3px rgba(255, 170, 51, 0.2);
+}
+
+.request-textarea {
+    width: 100%;
+    padding: 12px 15px;
+    border: 1px solid #ffd8b3;
+    border-radius: 8px;
+    min-height: 120px;
+    resize: vertical;
+    font-size: 14px;
+    background-color: #fffdfa;
+}
+
+.request-textarea:focus {
+    outline: none;
+    border-color: #ffaa33;
+    box-shadow: 0 0 0 3px rgba(255, 170, 51, 0.2);
+}
+
+.request-file {
+    width: 100%;
+    padding: 10px;
+    background: #f9f9f9;
+    border-radius: 8px;
+    font-size: 13px;
+}
+
+/* 空状态 */
+.request-empty {
+    text-align: center;
+    padding: 50px 20px;
+    background-color: white;
+    border-radius: 12px;
+    box-shadow: 0 4px 15px rgba(255, 102, 0, 0.08);
+}
+
+.request-empty-icon {
+    font-size: 48px;
+    color: #ffc107;
+    margin-bottom: 20px;
+}
+
+.request-empty-text {
+    font-size: 18px;
+    color: #ff8d00;
+    font-weight: 500;
+}
+
+/* 响应式调整 */
+@media (max-width: 768px) {
+    .request-container {
+        padding: 15px;
+    }
+
+    .request-card {
+        padding: 15px;
+    }
+
+    .request-header {
+        margin-bottom: 20px;
+    }
+
+    .request-card-title {
+        font-size: 16px;
+    }
+
+    .request-card-money {
+        font-size: 18px;
+    }
+
+    .request-user-info-container {
+        flex-direction: row;
+        flex-wrap: wrap;
+        gap: 10px;
+        min-width: 100%;
+        margin-top: 10px;
+    }
+
+    .request-user-info {
+        flex: 1;
+        min-width: 130px;
+    }
+
+    .request-user-divider {
+        display: none;
+    }
+
+    .request-card-actions {
+        flex-direction: column;
+        gap: 10px;
+    }
+
+    .request-button {
+        padding: 8px 12px;
+        font-size: 12px;
+    }
+
+    .request-button-takeover,
+    .request-button-delete {
+        font-size: 12px;
+    }
+
+    /* 在您的CSS文件中添加以下样式 */
+    @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
+
+    body {
+        font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
+        background-color: #fffaf5;
+    }
+
+    /* 全局动画效果 */
+    .transition {
+        transition: all 0.3s ease;
+    }
+
+    /* 卡片阴影效果 */
+    .shadow-lg {
+        box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
+    }
+
+    .shadow-md {
+        box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
+    }
+
+    /* 圆角 */
+    .rounded-xl {
+        border-radius: 1rem;
+    }
+
+    .rounded-lg {
+        border-radius: 0.75rem;
+    }
+
+    /* 渐变背景 */
+    .bg-gradient-to-r {
+        background-size: 200% auto;
+        transition: background-position 0.5s ease;
+    }
+
+    .bg-gradient-to-r:hover {
+        background-position: right center;
+    }
+
+    /* 表单输入框动画 */
+    input:focus,
+    textarea:focus {
+        transform: translateY(-1px);
+    }
+
+    /* 卡片悬停效果 */
+    .bg-white:hover {
+        transform: translateY(-3px);
+    }
+
+    /* 响应式调整 */
+    @media (max-width: 768px) {
+        .text-xl {
+            font-size: 1.25rem;
+        }
+
+        .text-2xl {
+            font-size: 1.5rem;
+        }
+
+        .p-6 {
+            padding: 1.25rem;
+        }
+
+        .p-12 {
+            padding: 2rem;
+        }
+
+        .grid-cols-2 {
+            grid-template-columns: 1fr;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/components/RequestBoard.jsx b/src/components/RequestBoard.jsx
new file mode 100644
index 0000000..3e63482
--- /dev/null
+++ b/src/components/RequestBoard.jsx
@@ -0,0 +1,660 @@
+import React, { useState, useEffect } from 'react';
+import {
+    createRequest,
+    deleteRequest,
+    updateMoney,
+    findByUserid,
+    findByName,
+    getTotalMoneyByName,
+    updateLoaduserByName,
+    getAllRequests
+} from '../api/request';
+import { useSetState } from '@mantine/hooks';
+import { useNavigate } from 'react-router-dom';
+import './RequestBoard.css';
+
+const RequestBoard = ({ currentUserId, onBack }) => {
+    const storedUser = localStorage.getItem('user');
+    //let currentUserId = null; // 初始化为 null
+
+    if (storedUser) {
+        try {
+            const parsedUser = JSON.parse(storedUser);
+            currentUserId = parsedUser.userid; // 直接赋值
+        } catch (error) {
+            console.error('解析用户数据失败:', error);
+            // 可以在这里处理 JSON 解析错误(如数据损坏)
+        }
+    } else {
+        console.log('用户未登录');
+    }
+
+    // 现在 currentUserId 可以在后续逻辑中使用
+    console.log('当前用户ID:', currentUserId);
+
+    const [requests, setRequests] = useState([]);
+    const [allRequests, setAllRequests] = useState([]);
+    const [searchedRequests, setSearchedRequests] = useState([]);
+    const [userInfos, setUserInfos] = useState({}); // 存储所有用户信息:{ userid: { username, avatar } }
+    const navigate = useNavigate();
+    const [formData, setFormData] = useState({
+        userid: currentUserId,
+        name: '',
+        plot: '',
+        money: '',
+        year: '',
+        country: '',
+        photo: null,
+    });
+    const [searchName, setSearchName] = useState('');
+    const [totalMoney, setTotalMoney] = useState(null);
+    const [viewMode, setViewMode] = useState('my');
+    const [showForm, setShowForm] = useState(false); // 控制表单折叠
+
+    // 获取用户信息的函数
+    const fetchUserInfo = async (userId) => {
+        try {
+            // 如果已经获取过该用户的信息,直接返回
+            if (userInfos[userId]) return;
+
+            const response = await fetch(`http://localhost:8080/user/getDecoration?userid=${userId}`);
+            if (response.ok) {
+                const data = await response.json();
+                if (data.success) {
+                    // 更新用户信息状态
+                    setUserInfos(prev => ({
+                        ...prev,
+                        [userId]: {
+                            username: data.data.username,
+                            avatar: data.data.image,
+                            decoration: data.data.decoration
+                        }
+                    }));
+                } else {
+                    console.error('获取用户信息失败:', data.message);
+                }
+            } else {
+                console.error('获取用户信息失败:', response.statusText);
+            }
+        } catch (error) {
+            console.error('获取用户信息出错:', error);
+        }
+    };
+
+    useEffect(() => {
+        loadUserRequests();
+        loadAllRequests();
+    }, [currentUserId]);
+
+    const loadUserRequests = async () => {
+        const data = await findByUserid(currentUserId);
+        setRequests(data);
+        // 为每个需求贴获取用户信息
+        data.forEach(request => {
+            fetchUserInfo(request.userid); // 获取创建者信息
+            if (request.loaduser) {
+                fetchUserInfo(request.loaduser); // 获取接管者信息
+            }
+        });
+    };
+
+    const loadAllRequests = async () => {
+        const data = await getAllRequests();
+        setAllRequests(data);
+        // 为每个需求贴获取用户信息
+        data.forEach(request => {
+            fetchUserInfo(request.userid); // 获取创建者信息
+            if (request.loaduser) {
+                fetchUserInfo(request.loaduser); // 获取接管者信息
+            }
+        });
+    };
+
+    // 处理搜索的需求贴
+    const processSearchedRequests = (data) => {
+        setSearchedRequests(data);
+        // 为每个需求贴获取用户信息
+        data.forEach(request => {
+            fetchUserInfo(request.userid); // 获取创建者信息
+            if (request.loaduser) {
+                fetchUserInfo(request.loaduser); // 获取接管者信息
+            }
+        });
+    };
+
+    const handleChange = (e) => {
+        const { name, value, files } = e.target;
+        setFormData((prev) => ({
+            ...prev,
+            [name]: files ? files[0] : value,
+        }));
+    };
+
+    const handleCreate = async (e) => {
+        e.preventDefault();
+        const fd = new FormData();
+        Object.entries(formData).forEach(([key, value]) => {
+            if (value !== '' && value !== null) fd.append(key, value);
+        });
+
+        const res = await createRequest(fd);
+        if (res.data === true) {
+            alert('创建成功');
+            setFormData(prev => ({
+                ...prev,
+                name: '',
+                plot: '',
+                money: '',
+                year: '',
+                country: '',
+                photo: null,
+            }));
+            setShowForm(false);
+            loadUserRequests();
+            loadAllRequests();
+        } else {
+            alert('创建失败');
+        }
+    };
+
+    const handleDelete = async (id) => {
+        if (window.confirm('确定要删除这个需求贴吗?')) {
+            await deleteRequest(id);
+            loadUserRequests();
+            loadAllRequests();
+        }
+    };
+
+    const handleUpdateMoney = async (id, newMoney) => {
+        if (!newMoney) return;
+        await updateMoney(id, newMoney);
+        loadUserRequests();
+    };
+
+    const handleSearch = async () => {
+        if (!searchName.trim()) {
+            alert('请输入搜索关键词');
+            return;
+        }
+        const data = await findByName(searchName);
+        const total = await getTotalMoneyByName(searchName);
+        setTotalMoney(total);
+        setViewMode('search');
+        processSearchedRequests(data);
+    };
+
+    const handleProcess = (request) => {
+        navigate(`/uploadfull/${request.requestid}`, {
+            state: {
+                requestid: request.requestid
+            },
+        });
+    };
+
+    const handleUploadLoaduser = async (name, requestid) => {
+        if (window.confirm(`确定要接管 "${name}" 的所有需求贴吗?`)) {
+            try {
+                await updateLoaduserByName(name, currentUserId);
+
+                alert('接管成功');
+                handleProcess({ requestid: requestid });
+                console.log(requestid);
+                loadUserRequests();
+                loadAllRequests();
+            } catch (error) {
+                alert('接管失败,请稍后重试');
+                console.error(error);
+            }
+        }
+    };
+
+    // 渲染用户信息展示
+    const renderUserInfo = (userId, prefix = '') => {
+        if (!userId) return null;
+
+        const userInfo = userInfos[userId];
+
+        return (
+            <div className="request-user-info">
+                <div className="flex items-center gap-2">
+                    <div className="request-user-avatar">
+                        {userInfo?.avatar ? (
+                            <img
+                                src={userInfo.avatar}
+                                alt={`${prefix}头像`}
+                                className="w-8 h-8 rounded-full object-cover border-2 border-orange-200 sm:w-6 sm:h-6"
+                            />
+                        ) : (
+                            <div className="w-8 h-8 bg-gray-100 rounded-full flex items-center justify-center text-gray-500 text-xs border-2 border-orange-200 sm:w-6 sm:h-6">
+                                {prefix.charAt(0)}
+                            </div>
+                        )}
+                    </div>
+                    <div className="request-user-details">
+                        <div className="text-xs sm:text-[11px] font-medium text-gray-600">
+                            {prefix}:
+                        </div>
+                        <div className="text-sm sm:text-xs font-medium text-orange-600 truncate max-w-[100px]">
+                            {userInfo?.username || `用户${userId}`}
+                        </div>
+                    </div>
+                </div>
+            </div>
+        );
+    };
+
+    const renderActions = (request) => {
+        if (request.userid === currentUserId) {
+            return (
+                <div className="flex flex-col sm:flex-row gap-2 w-full">
+                    <div className="flex gap-2 flex-1">
+                        <input
+                            type="number"
+                            placeholder="新金额"
+                            onChange={(e) => handleUpdateMoney(request.requestid, e.target.value)}
+                            className="request-input flex-1 text-center py-1 sm:py-0"
+                        />
+                        <button
+                            onClick={() => handleDelete(request.requestid)}
+                            className="request-button request-button-delete"
+                        >
+                            删除
+                        </button>
+                    </div>
+                </div>
+            );
+        }
+        return (
+            <button
+                onClick={() => handleUploadLoaduser(request.name, request.requestid)}
+                className="request-button request-button-takeover"
+            >
+                接管任务
+            </button>
+        );
+    };
+
+    return (
+        <div className="request-container">
+            <div className="request-header">
+                <div className="flex flex-col lg:flex-row justify-between gap-4 mb-6">
+                    <h1 className="text-2xl font-bold text-orange-700 sm:text-xl">需求贴发布区</h1>
+                    <div className="flex flex-wrap gap-2">
+                        <button
+                            className={`request-tab ${viewMode === 'my' ? 'request-tab-active' : ''}`}
+                            onClick={() => setViewMode('my')}
+                        >
+                            我的需求贴
+                        </button>
+                        <button
+                            className={`request-tab ${viewMode === 'all' ? 'request-tab-active' : ''}`}
+                            onClick={() => setViewMode('all')}
+                        >
+                            所有需求贴
+                        </button>
+                        <button
+                            className="request-button request-button-back"
+                            onClick={onBack}
+                        >
+                            返回主页面
+                        </button>
+                        <button
+                            onClick={() => setShowForm(!showForm)}
+                            className="request-button request-button-create"
+                        >
+                            {showForm ? '收起表单' : '创建新需求贴'}
+                        </button>
+                    </div>
+                </div>
+
+                {/* 折叠表单 */}
+                {showForm && (
+                    <form className="request-form" onSubmit={handleCreate}>
+                        <h2 className="text-xl font-semibold text-orange-700 mb-4 sm:text-lg">发布新需求</h2>
+                        <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+                            <div>
+                                <label className="request-label">需求标题 *</label>
+                                <input
+                                    name="name"
+                                    placeholder="请输入需求标题"
+                                    className="request-input"
+                                    value={formData.name}
+                                    onChange={handleChange}
+                                    required
+                                />
+                            </div>
+                            <div>
+                                <label className="request-label">所需金额 (¥) *</label>
+                                <input
+                                    name="money"
+                                    type="number"
+                                    placeholder="请输入金额"
+                                    className="request-input"
+                                    value={formData.money}
+                                    onChange={handleChange}
+                                    min="1"
+                                    required
+                                />
+                            </div>
+                        </div>
+
+                        <div className="mt-4">
+                            <label className="request-label">详细描述 *</label>
+                            <textarea
+                                name="plot"
+                                placeholder="请详细描述您的需求..."
+                                className="request-textarea"
+                                value={formData.plot}
+                                onChange={handleChange}
+                                required
+                            />
+                        </div>
+
+                        <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
+                            <div>
+                                <label className="request-label">年份</label>
+                                <input
+                                    name="year"
+                                    type="number"
+                                    placeholder="如:2023"
+                                    className="request-input"
+                                    value={formData.year}
+                                    onChange={handleChange}
+                                />
+                            </div>
+                            <div>
+                                <label className="request-label">国家/地区</label>
+                                <input
+                                    name="country"
+                                    placeholder="如:中国"
+                                    className="request-input"
+                                    value={formData.country}
+                                    onChange={handleChange}
+                                />
+                            </div>
+                            <div>
+                                <label className="request-label">相关图片</label>
+                                <input
+                                    name="photo"
+                                    type="file"
+                                    className="request-file"
+                                    onChange={handleChange}
+                                />
+                            </div>
+                        </div>
+
+                        <button
+                            type="submit"
+                            className="request-button request-button-submit mt-6"
+                        >
+                            发布需求贴
+                        </button>
+                    </form>
+                )}
+            </div>
+
+            {/* 搜索区域 */}
+            <div className="request-search">
+                <h2 className="text-xl font-semibold text-orange-700 mb-4 sm:text-lg">搜索需求贴</h2>
+                <div className="flex flex-col sm:flex-row gap-3">
+                    <input
+                        type="text"
+                        placeholder="输入需求标题关键词..."
+                        value={searchName}
+                        onChange={(e) => setSearchName(e.target.value)}
+                        className="request-input flex-1"
+                    />
+                    <button
+                        onClick={handleSearch}
+                        className="request-button request-button-search"
+                    >
+                        搜索需求
+                    </button>
+                </div>
+
+                {totalMoney !== null && viewMode === 'search' && (
+                    <div className="request-money-total mt-4">
+                        <span className="font-medium">"{searchName}" 需求总金额:</span>
+                        <span className="font-bold text-red-600 ml-2">¥{totalMoney}</span>
+                    </div>
+                )}
+            </div>
+
+            {/* 搜索结果 */}
+            {viewMode === 'search' && searchedRequests.length > 0 && (
+                <div className="request-results">
+                    <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center mb-6 gap-3">
+                        <h2 className="text-xl font-semibold text-orange-700 sm:text-lg">
+                            搜索结果:<span className="text-orange-500">{searchedRequests.length}</span> 条需求
+                        </h2>
+                        <button
+                            onClick={() => setViewMode('my')}
+                            className="request-button request-button-back"
+                        >
+                            返回我的需求
+                        </button>
+                    </div>
+
+                    <div className="request-cards">
+                        {searchedRequests.map((request) => (
+                            <div key={request.requestid} className="request-card">
+                                <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
+                                    <div className="flex-1 min-w-0">
+                                        <h3 className="request-card-title">{request.name}</h3>
+                                        <div className="request-card-money">¥{request.money}</div>
+                                    </div>
+                                    <div className="request-user-info-container">
+                                        {renderUserInfo(request.userid, '创建者')}
+                                        {request.loaduser && (
+                                            <>
+                                                <div className="request-user-divider"></div>
+                                                {renderUserInfo(request.loaduser, '接管者')}
+                                            </>
+                                        )}
+                                    </div>
+                                </div>
+
+                                <div className="request-card-content">
+                                    {request.plot}
+                                </div>
+
+                                <div className="request-card-meta">
+                                    {request.year && (
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">年份:</span>
+                                            <span>{request.year}</span>
+                                        </div>
+                                    )}
+                                    {request.country && (
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">地区:</span>
+                                            <span>{request.country}</span>
+                                        </div>
+                                    )}
+                                    <div className="request-meta-item">
+                                        <span className="request-meta-label">发布时间:</span>
+                                        <span>{new Date(request.requestTime).toLocaleString()}</span>
+                                    </div>
+                                </div>
+
+                                {request.photo && (
+                                    <div className="request-card-image-container">
+                                        <img
+                                            src={`http://localhost:8080${request.photo}`}
+                                            alt="需求贴配图"
+                                            className="request-card-image"
+                                        />
+                                    </div>
+                                )}
+
+                                <div className="request-card-actions">
+                                    {renderActions(request)}
+                                </div>
+                            </div>
+                        ))}
+                    </div>
+                </div>
+            )}
+
+            {/* 我的需求贴 */}
+            {viewMode === 'my' && (
+                <div className="request-my">
+                    <h2 className="text-xl font-semibold text-orange-700 mb-6 sm:text-lg">我的需求贴</h2>
+
+                    {requests.length === 0 ? (
+                        <div className="request-empty">
+                            <div className="request-empty-icon">📋</div>
+                            <p className="request-empty-text">您还没有发布任何需求贴</p>
+                            <button
+                                className="request-button request-button-create mt-4"
+                                onClick={() => {
+                                    setShowForm(true);
+                                    document.querySelector('.request-form')?.scrollIntoView({ behavior: 'smooth' });
+                                }}
+                            >
+                                立即发布需求
+                            </button>
+                        </div>
+                    ) : (
+                        <div className="request-cards">
+                            {requests.map((request) => (
+                                <div key={request.requestid} className="request-card">
+                                    <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
+                                        <div className="flex-1 min-w-0">
+                                            <h3 className="request-card-title">{request.name}</h3>
+                                            <div className="request-card-money">¥{request.money}</div>
+                                        </div>
+                                        <div className="request-user-info-container">
+                                            {renderUserInfo(request.userid, '创建者')}
+                                            {request.loaduser && (
+                                                <>
+                                                    <div className="request-user-divider"></div>
+                                                    {renderUserInfo(request.loaduser, '接管者')}
+                                                </>
+                                            )}
+                                        </div>
+                                    </div>
+
+                                    <div className="request-card-content">
+                                        {request.plot}
+                                    </div>
+
+                                    <div className="request-card-meta">
+                                        {request.year && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">年份:</span>
+                                                <span>{request.year}</span>
+                                            </div>
+                                        )}
+                                        {request.country && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">地区:</span>
+                                                <span>{request.country}</span>
+                                            </div>
+                                        )}
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">发布时间:</span>
+                                            <span>{new Date(request.requestTime).toLocaleString()}</span>
+                                        </div>
+                                    </div>
+
+                                    {request.photo && (
+                                        <div className="request-card-image-container">
+                                            <img
+                                                src={`http://localhost:8080${request.photo}`}
+                                                alt="需求贴配图"
+                                                className="request-card-image"
+                                            />
+                                        </div>
+                                    )}
+
+                                    <div className="request-card-actions">
+                                        {renderActions(request)}
+                                    </div>
+                                </div>
+                            ))}
+                        </div>
+                    )}
+                </div>
+            )}
+
+            {/* 所有需求贴 */}
+            {viewMode === 'all' && (
+                <div className="request-all">
+                    <div className="flex justify-between items-center mb-6">
+                        <h2 className="text-xl font-semibold text-orange-700 sm:text-lg">所有需求贴</h2>
+                        <span className="text-gray-600">共 {allRequests.length} 条需求</span>
+                    </div>
+
+                    {allRequests.length === 0 ? (
+                        <div className="request-empty">
+                            <div className="request-empty-icon">📭</div>
+                            <p className="request-empty-text">当前平台暂无需求贴</p>
+                        </div>
+                    ) : (
+                        <div className="request-cards">
+                            {allRequests.map((request) => (
+                                <div key={request.requestid} className="request-card">
+                                    <div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3">
+                                        <div className="flex-1 min-w-0">
+                                            <h3 className="request-card-title">{request.name}</h3>
+                                            <div className="request-card-money">¥{request.money}</div>
+                                        </div>
+                                        <div className="request-user-info-container">
+                                            {renderUserInfo(request.userid, '创建者')}
+                                            {request.loaduser && (
+                                                <>
+                                                    <div className="request-user-divider"></div>
+                                                    {renderUserInfo(request.loaduser, '接管者')}
+                                                </>
+                                            )}
+                                        </div>
+                                    </div>
+
+                                    <div className="request-card-content">
+                                        {request.plot}
+                                    </div>
+
+                                    <div className="request-card-meta">
+                                        {request.year && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">年份:</span>
+                                                <span>{request.year}</span>
+                                            </div>
+                                        )}
+                                        {request.country && (
+                                            <div className="request-meta-item">
+                                                <span className="request-meta-label">地区:</span>
+                                                <span>{request.country}</span>
+                                            </div>
+                                        )}
+                                        <div className="request-meta-item">
+                                            <span className="request-meta-label">发布时间:</span>
+                                            <span>{new Date(request.requestTime).toLocaleString()}</span>
+                                        </div>
+                                    </div>
+
+                                    {request.photo && (
+                                        <div className="request-card-image-container">
+                                            <img
+                                                src={`http://localhost:8080${request.photo}`}
+                                                alt="需求贴配图"
+                                                className="request-card-image"
+                                            />
+                                        </div>
+                                    )}
+
+                                    <div className="request-card-actions">
+                                        {renderActions(request)}
+                                    </div>
+                                </div>
+                            ))}
+                        </div>
+                    )}
+                </div>
+            )}
+        </div>
+    );
+};
+
+export default RequestBoard;
\ No newline at end of file
diff --git a/src/pages/Community.jsx b/src/pages/Community.jsx
new file mode 100644
index 0000000..38d6623
--- /dev/null
+++ b/src/pages/Community.jsx
@@ -0,0 +1,53 @@
+// src/pages/Home.jsx
+import React, { useState, useEffect } from 'react';
+import { getActivityPreviews, getFullActivities } from '../api/activity';
+import Post from '../components/Post';
+import Navbar from '../components/Navbar'; // ✅ 导入导航栏组件
+import { AppstoreOutlined } from '@ant-design/icons';
+import { Row, Col, Card, Space } from 'antd';
+import './Home.css';
+
+const Community = () => {
+    const [activityPreviews, setActivityPreviews] = useState([]);
+    const [fullActivities, setFullActivities] = useState([]);
+    const [selectedActivityId, setSelectedActivityId] = useState(null);
+
+    useEffect(() => {
+        getActivityPreviews().then(res => setActivityPreviews(res.data));
+        getFullActivities().then(res => setFullActivities(res.data));
+    }, []);
+
+    return (
+        <div style={{ minHeight: '100vh', backgroundColor: '#f0f2f5' }}>
+            {/* 导航栏 */}
+            <Navbar />
+
+            {/* 内容区域 */}
+            <div style={{ padding: 24 }}>
+                {/* 帖子区域 */}
+                <Row justify="center">
+                    <Col
+                        xs={24}
+                        sm={24}
+                        md={24}
+                        lg={22}
+                        xl={20}
+                        xxl={18}
+                        style={{ maxWidth: 1400, width: '100%' }}
+                    >
+                        <Card
+                            title={<Space><AppstoreOutlined />最新帖子</Space>}
+                            bordered={false}
+                            bodyStyle={{ padding: 24 }}
+                            style={{ boxShadow: '0 2px 8px rgba(0,0,0,0.15)', borderRadius: 8 }}
+                        >
+                            <Post />
+                        </Card>
+                    </Col>
+                </Row>
+            </div>
+        </div>
+    );
+};
+
+export default Community;
diff --git a/src/pages/Friend.css b/src/pages/Friend.css
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/pages/Friend.css
diff --git a/src/pages/Friend.jsx b/src/pages/Friend.jsx
new file mode 100644
index 0000000..fbb384d
--- /dev/null
+++ b/src/pages/Friend.jsx
@@ -0,0 +1,128 @@
+import React, { useState, useEffect } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { getActivityPreviews, getFullActivities } from '../api/activity';
+import FriendManager from '../components/FriendManager';
+import ChatBox from '../components/ChatBox';
+import Navbar from '../components/Navbar';
+import { TeamOutlined, MessageOutlined } from '@ant-design/icons';
+import { Layout, Row, Col, Typography, Empty, Spin } from 'antd';
+import './Friend.css';
+
+const { Title, Text } = Typography;
+const { Content } = Layout;
+
+const Friend = () => {
+    const navigate = useNavigate();
+
+    // 使用 localStorage 获取当前登录用户
+    const [currentUser, setCurrentUser] = useState(null);
+    const [loading, setLoading] = useState(true);
+
+    useEffect(() => {
+        // 从 localStorage 获取用户信息
+        const userData = localStorage.getItem('user');
+        if (userData) {
+            try {
+                const user = JSON.parse(userData);
+                setCurrentUser(user);
+            } catch (e) {
+                console.error('Failed to parse user data');
+                navigate('/login');
+            } finally {
+                setLoading(false);
+            }
+        } else {
+            // 未登录则重定向到登录页
+            navigate('/login');
+        }
+    }, [navigate]);
+
+    const [selectedRelation, setSelectedRelation] = useState(null);
+    const [activityPreviews, setActivityPreviews] = useState([]);
+    const [fullActivities, setFullActivities] = useState([]);
+    const [selectedActivityId, setSelectedActivityId] = useState(null);
+
+    useEffect(() => {
+        if (currentUser) {
+            getActivityPreviews().then(res => setActivityPreviews(res.data));
+            getFullActivities().then(res => setFullActivities(res.data));
+        }
+    }, [currentUser]);
+
+    if (loading) {
+        return (
+            <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
+                <Spin size="large" />
+            </div>
+        );
+    }
+
+    return (
+        <Layout style={{ minHeight: '100vh', background: '#f0f2f5', padding: '24px' }}>
+            <Content>
+                <Navbar />
+                <Row justify="space-between" align="middle" style={{ marginBottom: 24 }} />
+
+                <Row gutter={24} style={{ height: 'calc(100vh - 140px)' }}>
+                    {/* 好友管理 - 左侧 */}
+                    <Col xs={24} sm={24} md={10} lg={8} xl={6} style={{ background: '#fff', borderRadius: 8, padding: 24, boxShadow: '0 2px 8px rgba(0,0,0,0.1)', overflowY: 'auto' }}>
+                        <Title level={4} style={{ color: '#722ed1', marginBottom: 24 }}>
+                            <TeamOutlined style={{ marginRight: 8 }} />
+                            好友管理
+                        </Title>
+                        <FriendManager
+                            currentUser={currentUser} // 传递真实登录用户
+                            onSelectRelation={setSelectedRelation}
+                        />
+                    </Col>
+
+                    {/* 聊天窗口 - 右侧 */}
+                    <Col
+                        xs={24}
+                        sm={24}
+                        md={14}
+                        lg={16}
+                        xl={18}
+                        style={{
+                            background: '#fff',
+                            borderRadius: 8,
+                            padding: 24,
+                            boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
+                            display: 'flex',
+                            flexDirection: 'column',
+                        }}
+                    >
+                        <Title level={4} style={{ color: '#eb2f96', marginBottom: 24 }}>
+                            <MessageOutlined style={{ marginRight: 8 }} />
+                            聊天窗口
+                        </Title>
+
+                        <div style={{ flex: 1, minHeight: 0 }}>
+                            {selectedRelation ? (
+                                <div style={{ height: 'calc(100vh - 220px)' }}>
+                                    <ChatBox
+                                        senderId={currentUser.userid} // 使用真实用户ID
+                                        receiverId={selectedRelation.friendId}
+                                    />
+                                </div>
+                            ) : (
+                                <Empty
+                                    image={Empty.PRESENTED_IMAGE_SIMPLE}
+                                    description={<Text type="secondary">请选择一位好友开始聊天</Text>}
+                                    style={{
+                                        height: '100%',
+                                        display: 'flex',
+                                        justifyContent: 'center',
+                                        alignItems: 'center',
+                                    }}
+                                />
+                            )}
+                        </div>
+                    </Col>
+                </Row>
+            </Content>
+        </Layout>
+    );
+};
+
+export default Friend;
\ No newline at end of file