From d90126b45c11e5f7d21296ec1a15e2e86009fa5f Mon Sep 17 00:00:00 2001 From: 2991692032 Date: Thu, 15 May 2025 17:03:38 +0800 Subject: [PATCH] v1 --- Front/vue-unilife/src/api/forum.ts | 95 +++++++ Front/vue-unilife/src/api/post.ts | 14 +- Front/vue-unilife/src/api/request.ts | 22 +- Front/vue-unilife/src/router/index.ts | 2 +- Front/vue-unilife/src/stores/postStore.ts | 16 +- .../src/views/forum/MyPostsView.vue | 248 ++++++++++++++++++ .../src/views/forum/PostListView.vue | 8 +- 7 files changed, 397 insertions(+), 8 deletions(-) create mode 100644 Front/vue-unilife/src/api/forum.ts create mode 100644 Front/vue-unilife/src/views/forum/MyPostsView.vue diff --git a/Front/vue-unilife/src/api/forum.ts b/Front/vue-unilife/src/api/forum.ts new file mode 100644 index 0000000..27ba637 --- /dev/null +++ b/Front/vue-unilife/src/api/forum.ts @@ -0,0 +1,95 @@ +import request from './request'; + +/** + * 获取帖子列表 + * @param page 页码 + * @param size 每页数量 + * @param categoryId 分类ID,可选 + * @param sort 排序方式(latest, hot, likes, comments),默认latest + * @param userId 用户ID,可选,获取指定用户的帖子 + */ +export function getPosts(page = 1, size = 10, categoryId?: number | null, sort = 'latest', userId?: number | null) { + if (userId) { + // 获取指定用户的帖子 + return request({ + url: `/posts/user/${userId}`, + method: 'get', + params: { page, size, sort } + }); + } else { + // 获取所有帖子或者按分类筛选 + return request({ + url: '/posts', + method: 'get', + params: { page, size, categoryId, sort } + }); + } +} + +/** + * 获取帖子详情 + * @param id 帖子ID + */ +export function getPostDetail(id: number) { + return request({ + url: `/posts/${id}`, + method: 'get' + }); +} + +/** + * 创建帖子 + * @param data 帖子数据 + */ +export function createPost(data: any) { + return request({ + url: '/posts', + method: 'post', + data + }); +} + +/** + * 更新帖子 + * @param id 帖子ID + * @param data 更新数据 + */ +export function updatePost(id: number, data: any) { + return request({ + url: `/posts/${id}`, + method: 'put', + data + }); +} + +/** + * 删除帖子 + * @param id 帖子ID + */ +export function deletePost(id: number) { + return request({ + url: `/posts/${id}`, + method: 'delete' + }); +} + +/** + * 点赞或取消点赞帖子 + * @param id 帖子ID + */ +export function likePost(id: number) { + return request({ + url: `/posts/${id}/like`, + method: 'post' + }); +} + +/** + * 获取所有分类 + */ +export function getCategories() { + return request({ + url: '/categories', + method: 'get' + }); +} diff --git a/Front/vue-unilife/src/api/post.ts b/Front/vue-unilife/src/api/post.ts index c39c0aa..3853718 100644 --- a/Front/vue-unilife/src/api/post.ts +++ b/Front/vue-unilife/src/api/post.ts @@ -35,7 +35,19 @@ export interface CreatePostParams { export default { // 获取帖子列表 getPosts(params: { pageNum?: number; pageSize?: number; categoryId?: number; sort?: string }) { - return get<{ code: number; data: { total: number; list: PostItem[]; pages: number; pageNum: number; pageSize: number } }>('/posts', params); + // 将前端参数名转换为后端参数名 + const serverParams: any = { + page: params.pageNum, + size: params.pageSize, + sort: params.sort + }; + + // 保留categoryId参数 + if (params.categoryId !== undefined) { + serverParams.categoryId = params.categoryId; + } + + return get<{ code: number; data: { total: number; list: PostItem[]; pages: number; pageNum: number; pageSize: number } }>('/posts', serverParams); }, // 获取帖子详情 diff --git a/Front/vue-unilife/src/api/request.ts b/Front/vue-unilife/src/api/request.ts index 5be10b1..774a7f7 100644 --- a/Front/vue-unilife/src/api/request.ts +++ b/Front/vue-unilife/src/api/request.ts @@ -45,7 +45,9 @@ service.interceptors.response.use( if (res.code === 401) { // 未授权,清除token并重定向到登录页 localStorage.removeItem('token'); - window.location.href = '/login'; + const currentPath = window.location.pathname; + window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`; + return Promise.reject(new Error('未登录或登录已过期')); } return Promise.reject(new Error(res.message || '请求失败')); @@ -56,7 +58,23 @@ service.interceptors.response.use( (error) => { console.error('响应错误:', error); - // 显示错误信息 + // 处理HTTP 401错误 + if (error.response && error.response.status === 401) { + ElMessage({ + message: '未登录或登录已过期,请重新登录', + type: 'warning', + duration: 3000 + }); + + // 清除token + localStorage.removeItem('token'); + + // 获取当前页面路径,并重定向到登录页面 + const currentPath = window.location.pathname; + window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`; + return Promise.reject(error); + } + ElMessage({ message: error.message || '请求失败', type: 'error', diff --git a/Front/vue-unilife/src/router/index.ts b/Front/vue-unilife/src/router/index.ts index 4e1dccf..1169e27 100644 --- a/Front/vue-unilife/src/router/index.ts +++ b/Front/vue-unilife/src/router/index.ts @@ -102,7 +102,7 @@ const routes: Array = [ { path: 'posts', // URL: /personal/posts name: 'MyPosts', - component: () => import('../views/NotFound.vue'), // 占位符 + component: () => import('../views/forum/MyPostsView.vue'), meta: { title: '我的帖子 - UniLife' } }, { diff --git a/Front/vue-unilife/src/stores/postStore.ts b/Front/vue-unilife/src/stores/postStore.ts index da0a0cb..9277bb6 100644 --- a/Front/vue-unilife/src/stores/postStore.ts +++ b/Front/vue-unilife/src/stores/postStore.ts @@ -93,9 +93,19 @@ export const usePostStore = defineStore('post', { throw new Error(errorMessage); } } catch (error: any) { - // Ensure this.error is set from error.message, and ElMessage shows this.error or a default. - this.error = error.message || '加载帖子详情时发生未知错误'; - ElMessage.error(this.error); + // 检查是否是未登录错误 + if (error.response && error.response.status === 401) { + this.error = '您需要登录后才能查看帖子详情'; + ElMessage.warning(this.error); + // 将用户重定向到登录页面,并记录需要返回的帖子详情页面 + const currentPath = `/post/${id}`; + window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`; + return; + } else { + // 处理其他错误 + this.error = error.message || '加载帖子详情时发生未知错误'; + ElMessage.error(this.error); + } } finally { this.loading = false; } diff --git a/Front/vue-unilife/src/views/forum/MyPostsView.vue b/Front/vue-unilife/src/views/forum/MyPostsView.vue new file mode 100644 index 0000000..bfb82c7 --- /dev/null +++ b/Front/vue-unilife/src/views/forum/MyPostsView.vue @@ -0,0 +1,248 @@ + + + + + diff --git a/Front/vue-unilife/src/views/forum/PostListView.vue b/Front/vue-unilife/src/views/forum/PostListView.vue index e330400..92e2e90 100644 --- a/Front/vue-unilife/src/views/forum/PostListView.vue +++ b/Front/vue-unilife/src/views/forum/PostListView.vue @@ -71,11 +71,13 @@
@@ -138,6 +140,10 @@ const handleCurrentChange = (page: number) => { postStore.fetchPosts({ pageNum: page }); }; +const handleSizeChange = (size: number) => { + postStore.fetchPosts({ pageNum: 1, pageSize: size }); +}; + onMounted(async () => { await postStore.fetchCategories(); // Fetch categories first // Fetch posts, it will use the default selectedCategoryId (null) from store initially