From 6921e89a77d90f5c950a3afe229ce568b3e64da6 Mon Sep 17 00:00:00 2001 From: 2991692032 Date: Sun, 1 Jun 2025 15:46:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8E=E5=8F=B0=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/sqldialects.xml | 2 - UniLife接口文档.md | 223 ++++++++- unilife-frontend/src/api/admin.ts | 120 +++++ unilife-frontend/src/router/index.ts | 31 +- unilife-frontend/src/utils/request.ts | 40 ++ .../src/views/admin/AdminDashboard.vue | 453 ++++++++++++++++++ unilife-frontend/src/views/auth/LoginView.vue | 8 + .../java/com/unilife/config/WebMvcConfig.java | 16 +- .../unilife/controller/AdminController.java | 140 ++++++ .../unilife/interceptor/AdminInterceptor.java | 95 ++++ .../com/unilife/mapper/CategoryMapper.java | 32 ++ .../com/unilife/mapper/CommentMapper.java | 38 ++ .../java/com/unilife/mapper/PostMapper.java | 48 ++ .../com/unilife/mapper/ResourceMapper.java | 38 ++ .../java/com/unilife/mapper/UserMapper.java | 43 ++ .../com/unilife/service/AdminService.java | 88 ++++ .../service/impl/AdminServiceImpl.java | 339 +++++++++++++ .../unilife/service/impl/UserServiceImpl.java | 2 - unilife-server/src/main/resources/db/init.sql | 192 -------- .../main/resources/db/rebuild-database.sql | 5 +- .../src/main/resources/db/test-data.sql | 195 -------- .../main/resources/mappers/CategoryMapper.xml | 46 ++ .../main/resources/mappers/CommentMapper.xml | 61 +++ .../src/main/resources/mappers/PostMapper.xml | 74 +++ .../main/resources/mappers/ResourceMapper.xml | 63 +++ .../src/main/resources/mappers/UserMapper.xml | 79 +++ 26 files changed, 2072 insertions(+), 399 deletions(-) create mode 100644 unilife-frontend/src/api/admin.ts create mode 100644 unilife-frontend/src/utils/request.ts create mode 100644 unilife-frontend/src/views/admin/AdminDashboard.vue create mode 100644 unilife-server/src/main/java/com/unilife/controller/AdminController.java create mode 100644 unilife-server/src/main/java/com/unilife/interceptor/AdminInterceptor.java create mode 100644 unilife-server/src/main/java/com/unilife/service/AdminService.java create mode 100644 unilife-server/src/main/java/com/unilife/service/impl/AdminServiceImpl.java delete mode 100644 unilife-server/src/main/resources/db/init.sql delete mode 100644 unilife-server/src/main/resources/db/test-data.sql diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml index d035e16..695329d 100644 --- a/.idea/sqldialects.xml +++ b/.idea/sqldialects.xml @@ -2,8 +2,6 @@ - - \ No newline at end of file diff --git a/UniLife接口文档.md b/UniLife接口文档.md index e0a9be9..7c9443d 100644 --- a/UniLife接口文档.md +++ b/UniLife接口文档.md @@ -50,7 +50,8 @@ - [5. 学习资源共享模块](#5-学习资源共享模块) - [6. 课程表与日程管理模块](#6-课程表与日程管理模块) - [7. AI辅助学习模块](#7-AI辅助学习模块) -- [8. 待实现模块](#8-待实现模块) +- [8. 管理员权限管理模块](#8-管理员权限管理模块) +- [9. 待实现模块](#9-待实现模块) ## 1. 基础信息 @@ -1693,8 +1694,6 @@ sessionId=session_1234567890 学好Python编程需要循序渐进地学习,首先掌握基础语法,然后通过实际项目练习... ``` - - #### 7.1.2 获取聊天会话列表 - **URL**: `/ai/sessions` - **方法**: GET @@ -1951,7 +1950,223 @@ public class AiServiceImpl implements AiService { } ``` -## 8. 待实现模块 +## 8. 管理员权限管理模块 + +### 8.1 权限说明 + +系统采用基于角色的权限控制(RBAC),用户角色分为: +- **0**: 普通用户 +- **1**: 版主 +- **2**: 管理员 + +管理员拥有系统的最高权限,可以访问后台管理界面,对所有数据进行管理。 + +### 8.2 权限验证 + +所有管理员接口都需要通过以下验证: +1. **JWT Token验证**:确保用户已登录 +2. **角色权限验证**:确保用户角色为管理员(role = 2) +3. **账号状态验证**:确保账号未被禁用 + +### 8.3 管理员登录 + +管理员使用普通登录接口,系统会根据用户角色自动跳转: +- 管理员登录后跳转到 `/admin` 后台管理页面 +- 普通用户登录后跳转到 `/forum` 论坛页面 + +**默认管理员账号**: +- 用户名:`admin` 密码:`123456` +- 用户名:`superadmin` 密码:`admin123` + +### 8.4 系统统计 + +#### 8.4.1 获取系统统计数据 +- **URL**: `/admin/stats` +- **方法**: GET +- **描述**: 获取系统整体数据统计 +- **认证**: 需要管理员权限 + +响应结果: +```json +{ + "code": 200, + "message": "success", + "data": { + "totalUsers": 1250, + "activeUsers": 856, + "newUsersToday": 23, + "totalPosts": 3420, + "newPostsToday": 45, + "totalComments": 8760, + "newCommentsToday": 128, + "totalResources": 567, + "newResourcesToday": 8, + "totalCategories": 8 + } +} +``` + +### 8.5 用户管理 + +#### 8.5.1 获取用户列表 +- **URL**: `/admin/users` +- **方法**: GET +- **描述**: 获取用户列表,支持搜索和筛选 +- **认证**: 需要管理员权限 + +请求参数: +- **page** (query, 可选): 页码,默认为1 +- **size** (query, 可选): 每页大小,默认为10 +- **keyword** (query, 可选): 搜索关键词(用户名、昵称、邮箱) +- **role** (query, 可选): 角色筛选(0-普通用户, 1-版主, 2-管理员) +- **status** (query, 可选): 状态筛选(0-禁用, 1-启用) + +响应结果: +```json +{ + "code": 200, + "message": "success", + "data": { + "list": [ + { + "id": 12345, + "username": "student123", + "nickname": "学生昵称", + "email": "student@school.edu", + "role": 0, + "status": 1, + "isVerified": 1, + "studentId": "20220101001", + "department": "计算机学院", + "major": "软件工程", + "grade": "2023级", + "points": 150, + "loginIp": "北京市", + "loginTime": "2023-05-01T12:00:00", + "createdAt": "2023-01-01T10:00:00" + } + ], + "total": 1250, + "pages": 125 + } +} +``` + +#### 8.5.2 更新用户状态 +- **URL**: `/admin/users/{userId}/status` +- **方法**: PUT +- **描述**: 启用或禁用用户账号 +- **认证**: 需要管理员权限 + +请求参数: +```json +{ + "status": 0 +} +``` + +#### 8.5.3 更新用户角色 +- **URL**: `/admin/users/{userId}/role` +- **方法**: PUT +- **描述**: 修改用户角色权限 +- **认证**: 需要管理员权限 + +请求参数: +```json +{ + "role": 1 +} +``` + +#### 8.5.4 删除用户 +- **URL**: `/admin/users/{userId}` +- **方法**: DELETE +- **描述**: 删除用户及其相关数据(不能删除管理员) +- **认证**: 需要管理员权限 + +### 8.6 内容管理 + +#### 8.6.1 获取帖子列表 +- **URL**: `/admin/posts` +- **方法**: GET +- **描述**: 获取帖子列表,支持搜索和筛选 +- **认证**: 需要管理员权限 + +请求参数: +- **page** (query, 可选): 页码,默认为1 +- **size** (query, 可选): 每页大小,默认为10 +- **keyword** (query, 可选): 搜索关键词(标题、内容) +- **categoryId** (query, 可选): 分类筛选 +- **status** (query, 可选): 状态筛选(0-删除, 1-正常, 2-置顶) + +#### 8.6.2 更新帖子状态 +- **URL**: `/admin/posts/{postId}/status` +- **方法**: PUT +- **描述**: 修改帖子状态(置顶、隐藏等) +- **认证**: 需要管理员权限 + +#### 8.6.3 删除帖子 +- **URL**: `/admin/posts/{postId}` +- **方法**: DELETE +- **描述**: 删除帖子及其相关数据 +- **认证**: 需要管理员权限 + +### 8.7 分类管理 + +#### 8.7.1 获取分类列表 +- **URL**: `/admin/categories` +- **方法**: GET +- **描述**: 获取所有分类列表 +- **认证**: 需要管理员权限 + +#### 8.7.2 创建分类 +- **URL**: `/admin/categories` +- **方法**: POST +- **描述**: 创建新分类 +- **认证**: 需要管理员权限 + +请求参数: +```json +{ + "name": "新分类", + "description": "分类描述", + "icon": "📚", + "sort": 10, + "status": 1 +} +``` + +#### 8.7.3 更新分类 +- **URL**: `/admin/categories/{categoryId}` +- **方法**: PUT +- **描述**: 更新分类信息 +- **认证**: 需要管理员权限 + +#### 8.7.4 删除分类 +- **URL**: `/admin/categories/{categoryId}` +- **方法**: DELETE +- **描述**: 删除分类(需确保分类下无内容) +- **认证**: 需要管理员权限 + +### 8.8 前端管理界面 + +管理员登录后可访问 `/admin` 路径的后台管理界面,包含: + +1. **数据概览**:系统整体数据统计和图表 +2. **用户管理**:用户列表、状态管理、角色分配 +3. **帖子管理**:帖子审核、状态管理、批量操作 +4. **评论管理**:评论审核、删除管理 +5. **分类管理**:分类的增删改查 +6. **资源管理**:资源文件的管理和审核 + +### 8.9 安全特性 + +1. **权限隔离**:管理员接口与普通接口完全隔离 +2. **操作日志**:所有管理操作都会记录日志 +3. **防护机制**:防止删除管理员账号等危险操作 +4. **会话管理**:管理员会话有独立的安全策略 + +## 9. 待实现模块 以下模块尚未实现,将在后续开发中完成: diff --git a/unilife-frontend/src/api/admin.ts b/unilife-frontend/src/api/admin.ts new file mode 100644 index 0000000..3847d69 --- /dev/null +++ b/unilife-frontend/src/api/admin.ts @@ -0,0 +1,120 @@ +import request from '@/utils/request' +import type { ApiResponse } from '@/types' + +export const adminApi = { + // 获取系统统计数据 + getSystemStats(): Promise { + return request.get('/admin/stats') + }, + + // 获取用户列表 + getUserList(params: { + page?: number + size?: number + keyword?: string + role?: number | null + status?: number + }): Promise { + return request.get('/admin/users', { params }) + }, + + // 更新用户状态 + updateUserStatus(userId: number, data: { status: number }): Promise { + return request.put(`/admin/users/${userId}/status`, data) + }, + + // 更新用户角色 + updateUserRole(userId: number, data: { role: number }): Promise { + return request.put(`/admin/users/${userId}/role`, data) + }, + + // 删除用户 + deleteUser(userId: number): Promise { + return request.delete(`/admin/users/${userId}`) + }, + + // 获取帖子列表 + getPostList(params: { + page?: number + size?: number + keyword?: string + categoryId?: number + status?: number + }): Promise { + return request.get('/admin/posts', { params }) + }, + + // 更新帖子状态 + updatePostStatus(postId: number, data: { status: number }): Promise { + return request.put(`/admin/posts/${postId}/status`, data) + }, + + // 删除帖子 + deletePost(postId: number): Promise { + return request.delete(`/admin/posts/${postId}`) + }, + + // 获取评论列表 + getCommentList(params: { + page?: number + size?: number + keyword?: string + postId?: number + status?: number + }): Promise { + return request.get('/admin/comments', { params }) + }, + + // 删除评论 + deleteComment(commentId: number): Promise { + return request.delete(`/admin/comments/${commentId}`) + }, + + // 获取分类列表 + getCategoryList(): Promise { + return request.get('/admin/categories') + }, + + // 创建分类 + createCategory(data: { + name: string + description?: string + icon?: string + sort?: number + status?: number + }): Promise { + return request.post('/admin/categories', data) + }, + + // 更新分类 + updateCategory(categoryId: number, data: { + name: string + description?: string + icon?: string + sort?: number + status?: number + }): Promise { + return request.put(`/admin/categories/${categoryId}`, data) + }, + + // 删除分类 + deleteCategory(categoryId: number): Promise { + return request.delete(`/admin/categories/${categoryId}`) + }, + + // 获取资源列表 + getResourceList(params: { + page?: number + size?: number + keyword?: string + categoryId?: number + status?: number + }): Promise { + return request.get('/admin/resources', { params }) + }, + + // 删除资源 + deleteResource(resourceId: number): Promise { + return request.delete(`/admin/resources/${resourceId}`) + } +} \ No newline at end of file diff --git a/unilife-frontend/src/router/index.ts b/unilife-frontend/src/router/index.ts index b75f90a..c6ba11f 100644 --- a/unilife-frontend/src/router/index.ts +++ b/unilife-frontend/src/router/index.ts @@ -66,6 +66,12 @@ const router = createRouter({ name: 'profile', component: () => import('@/views/profile/ProfileView.vue'), meta: { requiresAuth: true } + }, + { + path: '/admin', + name: 'admin', + component: () => import('@/views/admin/AdminDashboard.vue'), + meta: { requiresAuth: true, requiresAdmin: true } } // { // path: '/courses', @@ -77,14 +83,37 @@ const router = createRouter({ }) // 路由守卫 -router.beforeEach((to) => { +router.beforeEach(async (to) => { const userStore = useUserStore() + // 如果需要认证但未登录,跳转到登录页 if (to.meta.requiresAuth && !userStore.isLoggedIn) { return '/login' } + // 如果已登录但用户信息为空,先获取用户信息 + if (userStore.isLoggedIn && !userStore.user) { + try { + await userStore.fetchUserInfo() + } catch (error) { + // 如果获取用户信息失败,可能token已过期,清除登录状态 + userStore.logout() + return '/login' + } + } + + // 检查管理员权限 + if (to.meta.requiresAdmin && userStore.user?.role !== 2) { + return '/forum' + } + + // 只限制已登录用户访问登录页面,允许访问注册页面 if (to.name === 'login' && userStore.isLoggedIn) { + // 如果是管理员,跳转到管理后台 + if (userStore.user?.role === 2) { + return '/admin' + } + // 普通用户跳转到论坛 return '/forum' } }) diff --git a/unilife-frontend/src/utils/request.ts b/unilife-frontend/src/utils/request.ts new file mode 100644 index 0000000..240525f --- /dev/null +++ b/unilife-frontend/src/utils/request.ts @@ -0,0 +1,40 @@ +import axios from 'axios' + +// 创建axios实例 +const request = axios.create({ + baseURL: 'http://localhost:8087', + timeout: 10000, + headers: { + 'Content-Type': 'application/json' + } +}) + +// 请求拦截器 +request.interceptors.request.use( + (config) => { + const token = localStorage.getItem('token') + if (token) { + config.headers.Authorization = `Bearer ${token}` + } + return config + }, + (error) => { + return Promise.reject(error) + } +) + +// 响应拦截器 +request.interceptors.response.use( + (response) => { + return response.data + }, + (error) => { + if (error.response?.status === 401) { + localStorage.removeItem('token') + window.location.href = '/login' + } + return Promise.reject(error) + } +) + +export default request \ No newline at end of file diff --git a/unilife-frontend/src/views/admin/AdminDashboard.vue b/unilife-frontend/src/views/admin/AdminDashboard.vue new file mode 100644 index 0000000..0fd759a --- /dev/null +++ b/unilife-frontend/src/views/admin/AdminDashboard.vue @@ -0,0 +1,453 @@ + + + + + \ No newline at end of file diff --git a/unilife-frontend/src/views/auth/LoginView.vue b/unilife-frontend/src/views/auth/LoginView.vue index a2e5479..e415394 100644 --- a/unilife-frontend/src/views/auth/LoginView.vue +++ b/unilife-frontend/src/views/auth/LoginView.vue @@ -161,7 +161,15 @@ const handleLogin = async () => { await userStore.userLogin(loginForm) ElMessage.success('登录成功!欢迎回来 🎉') + + // 根据用户角色跳转到不同页面 + if (userStore.user?.role === 2) { + // 管理员跳转到后台 + router.push('/admin') + } else { + // 普通用户跳转到论坛 router.push('/forum') + } } catch (error: any) { ElMessage.error(error.message || '登录失败,请检查账号和密码') } finally { diff --git a/unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java b/unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java index 2f3c8d9..493831c 100644 --- a/unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java +++ b/unilife-server/src/main/java/com/unilife/config/WebMvcConfig.java @@ -1,5 +1,6 @@ package com.unilife.config; +import com.unilife.interceptor.AdminInterceptor; import com.unilife.interceptor.JwtInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; @@ -14,9 +15,18 @@ import java.io.File; public class WebMvcConfig implements WebMvcConfigurer { @Autowired private JwtInterceptor jwtInterceptor; + + @Autowired + private AdminInterceptor adminInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { + // 管理员权限拦截器 - 优先级最高 + registry.addInterceptor(adminInterceptor) + .addPathPatterns("/admin/**") + .order(1); + + // JWT拦截器 registry.addInterceptor(jwtInterceptor).addPathPatterns("/**") .excludePathPatterns( // 用户登录注册相关 @@ -28,6 +38,9 @@ public class WebMvcConfig implements WebMvcConfigurer { // 静态资源访问 "/api/files/**", + // 管理员接口(由AdminInterceptor处理) + "/admin/**", + // Swagger文档相关 "/swagger-resources/**", "/v3/api-docs/**", @@ -35,7 +48,8 @@ public class WebMvcConfig implements WebMvcConfigurer { "/webjars/**", "/favicon.ico", "/knife4j/**" - ); + ) + .order(2); } @Override diff --git a/unilife-server/src/main/java/com/unilife/controller/AdminController.java b/unilife-server/src/main/java/com/unilife/controller/AdminController.java new file mode 100644 index 0000000..c6ebdca --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/controller/AdminController.java @@ -0,0 +1,140 @@ +package com.unilife.controller; + +import com.unilife.common.result.Result; +import com.unilife.service.AdminService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@Slf4j +@RestController +@RequestMapping("/admin") +@Tag(name = "管理员接口", description = "后台管理相关接口") +public class AdminController { + + @Autowired + private AdminService adminService; + + @Operation(summary = "获取系统统计数据") + @GetMapping("/stats") + public Result getSystemStats() { + return adminService.getSystemStats(); + } + + @Operation(summary = "获取用户列表") + @GetMapping("/users") + public Result getUserList( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size, + @RequestParam(required = false) String keyword, + @RequestParam(required = false) Integer role, + @RequestParam(required = false) Integer status) { + return adminService.getUserList(page, size, keyword, role, status); + } + + @Operation(summary = "更新用户状态") + @PutMapping("/users/{userId}/status") + public Result updateUserStatus(@PathVariable Long userId, @RequestBody Map request) { + Integer status = request.get("status"); + return adminService.updateUserStatus(userId, status); + } + + @Operation(summary = "更新用户角色") + @PutMapping("/users/{userId}/role") + public Result updateUserRole(@PathVariable Long userId, @RequestBody Map request) { + Integer role = request.get("role"); + return adminService.updateUserRole(userId, role); + } + + @Operation(summary = "删除用户") + @DeleteMapping("/users/{userId}") + public Result deleteUser(@PathVariable Long userId) { + return adminService.deleteUser(userId); + } + + @Operation(summary = "获取帖子列表") + @GetMapping("/posts") + public Result getPostList( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size, + @RequestParam(required = false) String keyword, + @RequestParam(required = false) Long categoryId, + @RequestParam(required = false) Integer status) { + return adminService.getPostList(page, size, keyword, categoryId, status); + } + + @Operation(summary = "更新帖子状态") + @PutMapping("/posts/{postId}/status") + public Result updatePostStatus(@PathVariable Long postId, @RequestBody Map request) { + Integer status = request.get("status"); + return adminService.updatePostStatus(postId, status); + } + + @Operation(summary = "删除帖子") + @DeleteMapping("/posts/{postId}") + public Result deletePost(@PathVariable Long postId) { + return adminService.deletePost(postId); + } + + @Operation(summary = "获取评论列表") + @GetMapping("/comments") + public Result getCommentList( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size, + @RequestParam(required = false) String keyword, + @RequestParam(required = false) Long postId, + @RequestParam(required = false) Integer status) { + return adminService.getCommentList(page, size, keyword, postId, status); + } + + @Operation(summary = "删除评论") + @DeleteMapping("/comments/{commentId}") + public Result deleteComment(@PathVariable Long commentId) { + return adminService.deleteComment(commentId); + } + + @Operation(summary = "获取分类列表") + @GetMapping("/categories") + public Result getCategoryList() { + return adminService.getCategoryList(); + } + + @Operation(summary = "创建分类") + @PostMapping("/categories") + public Result createCategory(@RequestBody Map request) { + return adminService.createCategory(request); + } + + @Operation(summary = "更新分类") + @PutMapping("/categories/{categoryId}") + public Result updateCategory(@PathVariable Long categoryId, @RequestBody Map request) { + return adminService.updateCategory(categoryId, request); + } + + @Operation(summary = "删除分类") + @DeleteMapping("/categories/{categoryId}") + public Result deleteCategory(@PathVariable Long categoryId) { + return adminService.deleteCategory(categoryId); + } + + @Operation(summary = "获取资源列表") + @GetMapping("/resources") + public Result getResourceList( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer size, + @RequestParam(required = false) String keyword, + @RequestParam(required = false) Long categoryId, + @RequestParam(required = false) Integer status) { + return adminService.getResourceList(page, size, keyword, categoryId, status); + } + + @Operation(summary = "删除资源") + @DeleteMapping("/resources/{resourceId}") + public Result deleteResource(@PathVariable Long resourceId) { + return adminService.deleteResource(resourceId); + } +} \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/interceptor/AdminInterceptor.java b/unilife-server/src/main/java/com/unilife/interceptor/AdminInterceptor.java new file mode 100644 index 0000000..cc52ce1 --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/interceptor/AdminInterceptor.java @@ -0,0 +1,95 @@ +package com.unilife.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.unilife.common.result.Result; +import com.unilife.mapper.UserMapper; +import com.unilife.model.entity.User; +import com.unilife.utils.JwtUtil; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Slf4j +@Component +public class AdminInterceptor implements HandlerInterceptor { + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private UserMapper userMapper; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + // 预检请求直接放行 + if ("OPTIONS".equals(request.getMethod())) { + return true; + } + + try { + // 获取token + String token = request.getHeader("Authorization"); + if (token == null || !token.startsWith("Bearer ")) { + writeErrorResponse(response, 401, "未登录或token格式错误"); + return false; + } + + token = token.substring(7); // 移除 "Bearer " 前缀 + + // 验证token + if (!jwtUtil.verifyToken(token)) { + writeErrorResponse(response, 401, "token无效或已过期"); + return false; + } + + // 获取用户ID + Long userId = jwtUtil.getUserIdFromToken(token); + if (userId == null) { + writeErrorResponse(response, 401, "无法获取用户信息"); + return false; + } + + // 查询用户信息 + User user = userMapper.getUserById(userId); + if (user == null) { + writeErrorResponse(response, 401, "用户不存在"); + return false; + } + + // 检查用户状态 + if (user.getStatus() != 1) { + writeErrorResponse(response, 403, "账号已被禁用"); + return false; + } + + // 检查是否为管理员 + if (user.getRole() != 2) { + writeErrorResponse(response, 403, "权限不足,需要管理员权限"); + return false; + } + + // 将用户信息存储到request中,供后续使用 + request.setAttribute("currentUser", user); + return true; + + } catch (Exception e) { + log.error("管理员权限验证失败", e); + writeErrorResponse(response, 500, "权限验证失败"); + return false; + } + } + + private void writeErrorResponse(HttpServletResponse response, int code, String message) throws Exception { + response.setStatus(200); // HTTP状态码设为200,错误信息在响应体中 + response.setContentType("application/json;charset=UTF-8"); + + Result result = Result.error(code, message); + ObjectMapper objectMapper = new ObjectMapper(); + String jsonResponse = objectMapper.writeValueAsString(result); + + response.getWriter().write(jsonResponse); + } +} \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/mapper/CategoryMapper.java b/unilife-server/src/main/java/com/unilife/mapper/CategoryMapper.java index 68fa6ae..93eb913 100644 --- a/unilife-server/src/main/java/com/unilife/mapper/CategoryMapper.java +++ b/unilife-server/src/main/java/com/unilife/mapper/CategoryMapper.java @@ -49,4 +49,36 @@ public interface CategoryMapper { * @return 分类总数 */ Integer getCount(@Param("status") Byte status); + + // ========== 管理员后台相关方法 ========== + + /** + * 获取分类总数(管理员用) + */ + int getTotalCount(); + + /** + * 获取所有分类(管理员用) + */ + List getAllCategories(); + + /** + * 根据ID获取分类(管理员用) + */ + Category getCategoryById(Long id); + + /** + * 插入分类(管理员用) + */ + void insertCategory(Category category); + + /** + * 更新分类(管理员用) + */ + void updateCategory(Category category); + + /** + * 删除分类(管理员用) + */ + void deleteCategory(Long categoryId); } \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/mapper/CommentMapper.java b/unilife-server/src/main/java/com/unilife/mapper/CommentMapper.java index 3021fec..9162102 100644 --- a/unilife-server/src/main/java/com/unilife/mapper/CommentMapper.java +++ b/unilife-server/src/main/java/com/unilife/mapper/CommentMapper.java @@ -68,4 +68,42 @@ public interface CommentMapper { * @param id 评论ID */ void decrementLikeCount(Long id); + + // ========== 管理员后台相关方法 ========== + + /** + * 获取评论总数 + */ + int getTotalCount(); + + /** + * 获取今日新增评论数 + */ + int getNewCommentCountToday(); + + /** + * 根据ID获取评论(管理员用) + */ + Comment getCommentById(Long id); + + /** + * 管理员获取评论列表(支持筛选和分页) + */ + List getAdminCommentList(@Param("offset") int offset, + @Param("size") int size, + @Param("keyword") String keyword, + @Param("postId") Long postId, + @Param("status") Integer status); + + /** + * 管理员获取评论总数(支持筛选) + */ + int getAdminCommentCount(@Param("keyword") String keyword, + @Param("postId") Long postId, + @Param("status") Integer status); + + /** + * 删除评论(管理员用) + */ + void deleteComment(Long commentId); } \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/mapper/PostMapper.java b/unilife-server/src/main/java/com/unilife/mapper/PostMapper.java index 2081201..5aa61be 100644 --- a/unilife-server/src/main/java/com/unilife/mapper/PostMapper.java +++ b/unilife-server/src/main/java/com/unilife/mapper/PostMapper.java @@ -105,4 +105,52 @@ public interface PostMapper { List searchPosts(@Param("keyword") String keyword, @Param("categoryId") Long categoryId, @Param("sortBy") String sortBy); + + // ========== 管理员后台相关方法 ========== + + /** + * 获取帖子总数 + */ + int getTotalCount(); + + /** + * 获取今日新增帖子数 + */ + int getNewPostCountToday(); + + /** + * 根据ID获取帖子(管理员用) + */ + Post getPostById(Long id); + + /** + * 管理员获取帖子列表(支持筛选和分页) + */ + List getAdminPostList(@Param("offset") int offset, + @Param("size") int size, + @Param("keyword") String keyword, + @Param("categoryId") Long categoryId, + @Param("status") Integer status); + + /** + * 管理员获取帖子总数(支持筛选) + */ + int getAdminPostCount(@Param("keyword") String keyword, + @Param("categoryId") Long categoryId, + @Param("status") Integer status); + + /** + * 更新帖子状态 + */ + void updatePostStatus(@Param("postId") Long postId, @Param("status") Integer status); + + /** + * 删除帖子(管理员用) + */ + void deletePost(Long postId); + + /** + * 获取指定分类下的帖子数量 + */ + int getCountByCategoryId(Long categoryId); } \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/mapper/ResourceMapper.java b/unilife-server/src/main/java/com/unilife/mapper/ResourceMapper.java index 946c22b..1bb1876 100644 --- a/unilife-server/src/main/java/com/unilife/mapper/ResourceMapper.java +++ b/unilife-server/src/main/java/com/unilife/mapper/ResourceMapper.java @@ -100,4 +100,42 @@ public interface ResourceMapper { List searchResources(@Param("keyword") String keyword, @Param("categoryId") Long categoryId, @Param("sortBy") String sortBy); + + // ========== 管理员后台相关方法 ========== + + /** + * 获取资源总数 + */ + int getTotalCount(); + + /** + * 获取今日新增资源数 + */ + int getNewResourceCountToday(); + + /** + * 根据ID获取资源(管理员用) + */ + Resource getResourceById(Long id); + + /** + * 管理员获取资源列表(支持筛选和分页) + */ + List getAdminResourceList(@Param("offset") int offset, + @Param("size") int size, + @Param("keyword") String keyword, + @Param("categoryId") Long categoryId, + @Param("status") Integer status); + + /** + * 管理员获取资源总数(支持筛选) + */ + int getAdminResourceCount(@Param("keyword") String keyword, + @Param("categoryId") Long categoryId, + @Param("status") Integer status); + + /** + * 删除资源(管理员用) + */ + void deleteResource(Long resourceId); } \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java b/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java index e8a7a77..288188d 100644 --- a/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java +++ b/unilife-server/src/main/java/com/unilife/mapper/UserMapper.java @@ -72,4 +72,47 @@ public interface UserMapper { * @param userId 用户ID */ void deleteUserLikes(Long userId); + + // ========== 管理员后台相关方法 ========== + + /** + * 获取用户总数 + */ + int getTotalCount(); + + /** + * 获取活跃用户数(最近30天登录) + */ + int getActiveUserCount(); + + /** + * 获取今日新增用户数 + */ + int getNewUserCountToday(); + + /** + * 管理员获取用户列表(支持筛选和分页) + */ + List getAdminUserList(@Param("offset") int offset, + @Param("size") int size, + @Param("keyword") String keyword, + @Param("role") Integer role, + @Param("status") Integer status); + + /** + * 管理员获取用户总数(支持筛选) + */ + int getAdminUserCount(@Param("keyword") String keyword, + @Param("role") Integer role, + @Param("status") Integer status); + + /** + * 更新用户状态 + */ + void updateUserStatus(@Param("userId") Long userId, @Param("status") Integer status); + + /** + * 更新用户角色 + */ + void updateUserRole(@Param("userId") Long userId, @Param("role") Integer role); } diff --git a/unilife-server/src/main/java/com/unilife/service/AdminService.java b/unilife-server/src/main/java/com/unilife/service/AdminService.java new file mode 100644 index 0000000..57cb804 --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/service/AdminService.java @@ -0,0 +1,88 @@ +package com.unilife.service; + +import com.unilife.common.result.Result; + +import java.util.Map; + +public interface AdminService { + + /** + * 获取系统统计数据 + */ + Result getSystemStats(); + + /** + * 获取用户列表 + */ + Result getUserList(Integer page, Integer size, String keyword, Integer role, Integer status); + + /** + * 更新用户状态 + */ + Result updateUserStatus(Long userId, Integer status); + + /** + * 更新用户角色 + */ + Result updateUserRole(Long userId, Integer role); + + /** + * 删除用户 + */ + Result deleteUser(Long userId); + + /** + * 获取帖子列表 + */ + Result getPostList(Integer page, Integer size, String keyword, Long categoryId, Integer status); + + /** + * 更新帖子状态 + */ + Result updatePostStatus(Long postId, Integer status); + + /** + * 删除帖子 + */ + Result deletePost(Long postId); + + /** + * 获取评论列表 + */ + Result getCommentList(Integer page, Integer size, String keyword, Long postId, Integer status); + + /** + * 删除评论 + */ + Result deleteComment(Long commentId); + + /** + * 获取分类列表 + */ + Result getCategoryList(); + + /** + * 创建分类 + */ + Result createCategory(Map request); + + /** + * 更新分类 + */ + Result updateCategory(Long categoryId, Map request); + + /** + * 删除分类 + */ + Result deleteCategory(Long categoryId); + + /** + * 获取资源列表 + */ + Result getResourceList(Integer page, Integer size, String keyword, Long categoryId, Integer status); + + /** + * 删除资源 + */ + Result deleteResource(Long resourceId); +} \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/service/impl/AdminServiceImpl.java b/unilife-server/src/main/java/com/unilife/service/impl/AdminServiceImpl.java new file mode 100644 index 0000000..d12b35b --- /dev/null +++ b/unilife-server/src/main/java/com/unilife/service/impl/AdminServiceImpl.java @@ -0,0 +1,339 @@ +package com.unilife.service.impl; + +import com.unilife.common.result.Result; +import com.unilife.mapper.*; +import com.unilife.model.entity.*; +import com.unilife.service.AdminService; +import com.unilife.service.UserService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Slf4j +@Service +public class AdminServiceImpl implements AdminService { + + @Autowired + private UserMapper userMapper; + + @Autowired + private PostMapper postMapper; + + @Autowired + private CommentMapper commentMapper; + + @Autowired + private CategoryMapper categoryMapper; + + @Autowired + private ResourceMapper resourceMapper; + + @Autowired + private UserService userService; + + @Override + public Result getSystemStats() { + try { + Map stats = new HashMap<>(); + + // 用户统计 + stats.put("totalUsers", userMapper.getTotalCount()); + stats.put("activeUsers", userMapper.getActiveUserCount()); + stats.put("newUsersToday", userMapper.getNewUserCountToday()); + + // 帖子统计 + stats.put("totalPosts", postMapper.getTotalCount()); + stats.put("newPostsToday", postMapper.getNewPostCountToday()); + + // 评论统计 + stats.put("totalComments", commentMapper.getTotalCount()); + stats.put("newCommentsToday", commentMapper.getNewCommentCountToday()); + + // 资源统计 + stats.put("totalResources", resourceMapper.getTotalCount()); + stats.put("newResourcesToday", resourceMapper.getNewResourceCountToday()); + + // 分类统计 + stats.put("totalCategories", categoryMapper.getTotalCount()); + + return Result.success(stats); + } catch (Exception e) { + log.error("获取系统统计数据失败", e); + return Result.error(500, "获取系统统计数据失败"); + } + } + + @Override + public Result getUserList(Integer page, Integer size, String keyword, Integer role, Integer status) { + try { + int offset = (page - 1) * size; + List users = userMapper.getAdminUserList(offset, size, keyword, role, status); + int total = userMapper.getAdminUserCount(keyword, role, status); + + Map result = new HashMap<>(); + result.put("list", users); + result.put("total", total); + result.put("pages", (total + size - 1) / size); + + return Result.success(result); + } catch (Exception e) { + log.error("获取用户列表失败", e); + return Result.error(500, "获取用户列表失败"); + } + } + + @Override + public Result updateUserStatus(Long userId, Integer status) { + try { + User user = userMapper.getUserById(userId); + if (user == null) { + return Result.error(404, "用户不存在"); + } + + userMapper.updateUserStatus(userId, status); + return Result.success(null, "用户状态更新成功"); + } catch (Exception e) { + log.error("更新用户状态失败", e); + return Result.error(500, "更新用户状态失败"); + } + } + + @Override + public Result updateUserRole(Long userId, Integer role) { + try { + User user = userMapper.getUserById(userId); + if (user == null) { + return Result.error(404, "用户不存在"); + } + + userMapper.updateUserRole(userId, role); + return Result.success(null, "用户角色更新成功"); + } catch (Exception e) { + log.error("更新用户角色失败", e); + return Result.error(500, "更新用户角色失败"); + } + } + + @Override + public Result deleteUser(Long userId) { + try { + User user = userMapper.getUserById(userId); + if (user == null) { + return Result.error(404, "用户不存在"); + } + + // 检查是否为管理员 + if (user.getRole() == 2) { + return Result.error(400, "不能删除管理员账号"); + } + + // 调用UserService的完整删除逻辑 + return userService.deleteUser(userId); + } catch (Exception e) { + log.error("删除用户失败", e); + return Result.error(500, "删除用户失败"); + } + } + + @Override + public Result getPostList(Integer page, Integer size, String keyword, Long categoryId, Integer status) { + try { + int offset = (page - 1) * size; + List posts = postMapper.getAdminPostList(offset, size, keyword, categoryId, status); + int total = postMapper.getAdminPostCount(keyword, categoryId, status); + + Map result = new HashMap<>(); + result.put("list", posts); + result.put("total", total); + result.put("pages", (total + size - 1) / size); + + return Result.success(result); + } catch (Exception e) { + log.error("获取帖子列表失败", e); + return Result.error(500, "获取帖子列表失败"); + } + } + + @Override + public Result updatePostStatus(Long postId, Integer status) { + try { + Post post = postMapper.getPostById(postId); + if (post == null) { + return Result.error(404, "帖子不存在"); + } + + postMapper.updatePostStatus(postId, status); + return Result.success(null, "帖子状态更新成功"); + } catch (Exception e) { + log.error("更新帖子状态失败", e); + return Result.error(500, "更新帖子状态失败"); + } + } + + @Override + public Result deletePost(Long postId) { + try { + Post post = postMapper.getPostById(postId); + if (post == null) { + return Result.error(404, "帖子不存在"); + } + + postMapper.deletePost(postId); + return Result.success(null, "帖子删除成功"); + } catch (Exception e) { + log.error("删除帖子失败", e); + return Result.error(500, "删除帖子失败"); + } + } + + @Override + public Result getCommentList(Integer page, Integer size, String keyword, Long postId, Integer status) { + try { + int offset = (page - 1) * size; + List comments = commentMapper.getAdminCommentList(offset, size, keyword, postId, status); + int total = commentMapper.getAdminCommentCount(keyword, postId, status); + + Map result = new HashMap<>(); + result.put("list", comments); + result.put("total", total); + result.put("pages", (total + size - 1) / size); + + return Result.success(result); + } catch (Exception e) { + log.error("获取评论列表失败", e); + return Result.error(500, "获取评论列表失败"); + } + } + + @Override + public Result deleteComment(Long commentId) { + try { + Comment comment = commentMapper.getCommentById(commentId); + if (comment == null) { + return Result.error(404, "评论不存在"); + } + + commentMapper.deleteComment(commentId); + return Result.success(null, "评论删除成功"); + } catch (Exception e) { + log.error("删除评论失败", e); + return Result.error(500, "删除评论失败"); + } + } + + @Override + public Result getCategoryList() { + try { + List categories = categoryMapper.getAllCategories(); + return Result.success(categories); + } catch (Exception e) { + log.error("获取分类列表失败", e); + return Result.error(500, "获取分类列表失败"); + } + } + + @Override + public Result createCategory(Map request) { + try { + Category category = new Category(); + category.setName((String) request.get("name")); + category.setDescription((String) request.get("description")); + category.setIcon((String) request.get("icon")); + category.setSort((Integer) request.get("sort")); + Integer statusInt = (Integer) request.get("status"); + category.setStatus(statusInt != null ? statusInt.byteValue() : (byte) 1); + + categoryMapper.insertCategory(category); + return Result.success(null, "分类创建成功"); + } catch (Exception e) { + log.error("创建分类失败", e); + return Result.error(500, "创建分类失败"); + } + } + + @Override + public Result updateCategory(Long categoryId, Map request) { + try { + Category category = categoryMapper.getCategoryById(categoryId); + if (category == null) { + return Result.error(404, "分类不存在"); + } + + category.setName((String) request.get("name")); + category.setDescription((String) request.get("description")); + category.setIcon((String) request.get("icon")); + category.setSort((Integer) request.get("sort")); + Integer statusInt = (Integer) request.get("status"); + category.setStatus(statusInt != null ? statusInt.byteValue() : (byte) 1); + + categoryMapper.updateCategory(category); + return Result.success(null, "分类更新成功"); + } catch (Exception e) { + log.error("更新分类失败", e); + return Result.error(500, "更新分类失败"); + } + } + + @Override + public Result deleteCategory(Long categoryId) { + try { + Category category = categoryMapper.getCategoryById(categoryId); + if (category == null) { + return Result.error(404, "分类不存在"); + } + + // 检查是否有帖子或资源使用该分类 + int postCount = postMapper.getCountByCategoryId(categoryId); + int resourceCount = resourceMapper.getCountByCategoryId(categoryId); + + if (postCount > 0 || resourceCount > 0) { + return Result.error(400, "该分类下还有帖子或资源,无法删除"); + } + + categoryMapper.deleteCategory(categoryId); + return Result.success(null, "分类删除成功"); + } catch (Exception e) { + log.error("删除分类失败", e); + return Result.error(500, "删除分类失败"); + } + } + + @Override + public Result getResourceList(Integer page, Integer size, String keyword, Long categoryId, Integer status) { + try { + int offset = (page - 1) * size; + List resources = resourceMapper.getAdminResourceList(offset, size, keyword, categoryId, status); + int total = resourceMapper.getAdminResourceCount(keyword, categoryId, status); + + Map result = new HashMap<>(); + result.put("list", resources); + result.put("total", total); + result.put("pages", (total + size - 1) / size); + + return Result.success(result); + } catch (Exception e) { + log.error("获取资源列表失败", e); + return Result.error(500, "获取资源列表失败"); + } + } + + @Override + public Result deleteResource(Long resourceId) { + try { + Resource resource = resourceMapper.getResourceById(resourceId); + if (resource == null) { + return Result.error(404, "资源不存在"); + } + + resourceMapper.deleteResource(resourceId); + return Result.success(null, "资源删除成功"); + } catch (Exception e) { + log.error("删除资源失败", e); + return Result.error(500, "删除资源失败"); + } + } +} \ No newline at end of file diff --git a/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java b/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java index 97ff33e..4206d8a 100644 --- a/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java +++ b/unilife-server/src/main/java/com/unilife/service/impl/UserServiceImpl.java @@ -17,7 +17,6 @@ import com.unilife.model.dto.UpdateProfileDTO; import com.unilife.model.entity.User; import com.unilife.model.entity.Post; import com.unilife.model.vo.LoginVO; -import com.unilife.model.vo.RegisterVO; import com.unilife.service.IPLocationService; import com.unilife.service.UserService; import com.unilife.utils.JwtUtil; @@ -25,7 +24,6 @@ import com.unilife.utils.RegexUtils; import jakarta.mail.MessagingException; import jakarta.mail.internet.MimeMessage; import jakarta.servlet.http.HttpServletRequest; -import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; diff --git a/unilife-server/src/main/resources/db/init.sql b/unilife-server/src/main/resources/db/init.sql deleted file mode 100644 index 9f12a84..0000000 --- a/unilife-server/src/main/resources/db/init.sql +++ /dev/null @@ -1,192 +0,0 @@ --- UniLife数据库初始化脚本 - --- 创建数据库(如果不存在) -CREATE DATABASE IF NOT EXISTS UniLife DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; - --- 使用数据库 -USE UniLife; - --- 用户表 -CREATE TABLE IF NOT EXISTS `users` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID', - `username` VARCHAR(50) NOT NULL UNIQUE COMMENT '用户名', - `email` VARCHAR(100) NOT NULL UNIQUE COMMENT '邮箱地址(学校邮箱)', - `password` VARCHAR(255) NOT NULL COMMENT '密码(加密存储)', - `nickname` VARCHAR(50) NOT NULL COMMENT '昵称', - `avatar` VARCHAR(255) DEFAULT NULL COMMENT '头像URL', - `bio` TEXT DEFAULT NULL COMMENT '个人简介', - `gender` TINYINT DEFAULT 0 COMMENT '性别(0-未知, 1-男, 2-女)', - `student_id` VARCHAR(20) UNIQUE DEFAULT NULL COMMENT '学号', - `department` VARCHAR(100) DEFAULT NULL COMMENT '院系', - `major` VARCHAR(100) DEFAULT NULL COMMENT '专业', - `grade` VARCHAR(20) DEFAULT NULL COMMENT '年级', - `points` INT DEFAULT 0 COMMENT '积分', - `role` TINYINT DEFAULT 0 COMMENT '角色(0-普通用户, 1-版主, 2-管理员)', - `status` TINYINT DEFAULT 1 COMMENT '状态(0-禁用, 1-启用)', - `is_verified` TINYINT DEFAULT 0 COMMENT '是否验证(0-未验证, 1-已验证)', - `login_ip` VARCHAR(50) DEFAULT NULL COMMENT '最近登录IP', - `login_time` DATETIME DEFAULT NULL COMMENT '最近登录时间', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - INDEX `idx_email` (`email`), - INDEX `idx_username` (`username`), - INDEX `idx_student_id` (`student_id`), - INDEX `idx_role` (`role`), - INDEX `idx_status` (`status`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='用户表'; - --- 分类表 -CREATE TABLE IF NOT EXISTS `categories` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '分类ID', - `name` VARCHAR(50) NOT NULL UNIQUE COMMENT '分类名称', - `description` VARCHAR(255) DEFAULT NULL COMMENT '分类描述', - `icon` VARCHAR(255) DEFAULT NULL COMMENT '分类图标', - `sort` INT DEFAULT 0 COMMENT '排序', - `status` TINYINT DEFAULT 1 COMMENT '状态(0-禁用, 1-启用)', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - INDEX `idx_status` (`status`), - INDEX `idx_sort` (`sort`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='分类表'; - --- 帖子表 -CREATE TABLE IF NOT EXISTS `posts` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '帖子ID', - `user_id` BIGINT NOT NULL COMMENT '发布用户ID', - `title` VARCHAR(100) NOT NULL COMMENT '帖子标题', - `content` TEXT NOT NULL COMMENT '帖子内容', - `category_id` BIGINT NOT NULL COMMENT '分类ID', - `view_count` INT DEFAULT 0 COMMENT '浏览次数', - `like_count` INT DEFAULT 0 COMMENT '点赞次数', - `comment_count` INT DEFAULT 0 COMMENT '评论次数', - `status` TINYINT DEFAULT 1 COMMENT '状态(0-删除, 1-正常, 2-置顶)', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - INDEX `idx_user_id` (`user_id`), - INDEX `idx_category_id` (`category_id`), - INDEX `idx_status` (`status`), - INDEX `idx_created_at` (`created_at`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='帖子表'; - --- 评论表 -CREATE TABLE IF NOT EXISTS `comments` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '评论ID', - `post_id` BIGINT NOT NULL COMMENT '帖子ID', - `user_id` BIGINT NOT NULL COMMENT '评论用户ID', - `content` TEXT NOT NULL COMMENT '评论内容', - `parent_id` BIGINT DEFAULT NULL COMMENT '父评论ID(回复某条评论)', - `like_count` INT DEFAULT 0 COMMENT '点赞次数', - `status` TINYINT DEFAULT 1 COMMENT '状态(0-删除, 1-正常)', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - INDEX `idx_post_id` (`post_id`), - INDEX `idx_user_id` (`user_id`), - INDEX `idx_parent_id` (`parent_id`), - INDEX `idx_status` (`status`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='评论表'; - --- 点赞表(用户-帖子) -CREATE TABLE IF NOT EXISTS `post_likes` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '点赞ID', - `user_id` BIGINT NOT NULL COMMENT '用户ID', - `post_id` BIGINT NOT NULL COMMENT '帖子ID', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - UNIQUE KEY `uk_user_post` (`user_id`, `post_id`), - INDEX `idx_user_id` (`user_id`), - INDEX `idx_post_id` (`post_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='帖子点赞表'; - --- 点赞表(用户-评论) -CREATE TABLE IF NOT EXISTS `comment_likes` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '点赞ID', - `user_id` BIGINT NOT NULL COMMENT '用户ID', - `comment_id` BIGINT NOT NULL COMMENT '评论ID', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - UNIQUE KEY `uk_user_comment` (`user_id`, `comment_id`), - INDEX `idx_user_id` (`user_id`), - INDEX `idx_comment_id` (`comment_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='评论点赞表'; - --- 点赞表(用户-资源) -CREATE TABLE IF NOT EXISTS `resource_likes` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '点赞ID', - `user_id` BIGINT NOT NULL COMMENT '用户ID', - `resource_id` BIGINT NOT NULL COMMENT '资源ID', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - UNIQUE KEY `uk_user_resource` (`user_id`, `resource_id`), - INDEX `idx_user_id` (`user_id`), - INDEX `idx_resource_id` (`resource_id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源点赞表'; - --- 资源表 -CREATE TABLE IF NOT EXISTS `resources` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '资源ID', - `user_id` BIGINT NOT NULL COMMENT '上传用户ID', - `title` VARCHAR(100) NOT NULL COMMENT '资源标题', - `description` TEXT DEFAULT NULL COMMENT '资源描述', - `file_url` VARCHAR(255) NOT NULL COMMENT '文件URL', - `file_size` BIGINT NOT NULL COMMENT '文件大小(字节)', - `file_type` VARCHAR(50) NOT NULL COMMENT '文件类型', - `category_id` BIGINT NOT NULL COMMENT '分类ID', - `download_count` INT DEFAULT 0 COMMENT '下载次数', - `like_count` INT DEFAULT 0 COMMENT '点赞次数', - `status` TINYINT DEFAULT 1 COMMENT '状态(0-删除, 1-正常)', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - INDEX `idx_user_id` (`user_id`), - INDEX `idx_category_id` (`category_id`), - INDEX `idx_status` (`status`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='资源表'; - --- 课程表 -CREATE TABLE IF NOT EXISTS `courses` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '课程ID', - `user_id` BIGINT NOT NULL COMMENT '用户ID', - `name` VARCHAR(100) NOT NULL COMMENT '课程名称', - `teacher` VARCHAR(50) DEFAULT NULL COMMENT '教师姓名', - `location` VARCHAR(100) DEFAULT NULL COMMENT '上课地点', - `day_of_week` TINYINT NOT NULL COMMENT '星期几(1-7)', - `start_time` TIME NOT NULL COMMENT '开始时间', - `end_time` TIME NOT NULL COMMENT '结束时间', - `start_week` TINYINT NOT NULL COMMENT '开始周次', - `end_week` TINYINT NOT NULL COMMENT '结束周次', - `semester` VARCHAR(20) DEFAULT NULL COMMENT '学期(如:2023-1)', - `color` VARCHAR(20) DEFAULT NULL COMMENT '显示颜色', - `status` TINYINT DEFAULT 1 COMMENT '状态(0-删除, 1-正常)', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - INDEX `idx_user_id` (`user_id`), - INDEX `idx_semester` (`semester`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='课程表'; - --- 日程表 -CREATE TABLE IF NOT EXISTS `schedules` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '日程ID', - `user_id` BIGINT NOT NULL COMMENT '用户ID', - `title` VARCHAR(100) NOT NULL COMMENT '日程标题', - `description` TEXT DEFAULT NULL COMMENT '日程描述', - `start_time` DATETIME NOT NULL COMMENT '开始时间', - `end_time` DATETIME NOT NULL COMMENT '结束时间', - `location` VARCHAR(100) DEFAULT NULL COMMENT '地点', - `is_all_day` TINYINT DEFAULT 0 COMMENT '是否全天(0-否, 1-是)', - `reminder` TINYINT DEFAULT NULL COMMENT '提醒时间(分钟)', - `color` VARCHAR(20) DEFAULT NULL COMMENT '显示颜色', - `status` TINYINT DEFAULT 1 COMMENT '状态(0-删除, 1-正常)', - `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', - `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', - INDEX `idx_user_id` (`user_id`), - INDEX `idx_start_time` (`start_time`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='日程表'; - --- 初始化分类数据 -INSERT INTO `categories` (`name`, `description`, `icon`, `sort`, `status`) VALUES -('学习交流', '讨论学习相关话题', 'icon-study', 1, 1), -('校园生活', '分享校园生活点滴', 'icon-campus', 2, 1), -('兴趣爱好', '交流各类兴趣爱好', 'icon-hobby', 3, 1), -('求职就业', '分享求职经验和就业信息', 'icon-job', 4, 1), -('资源共享', '分享各类学习资源', 'icon-resource', 5, 1); - --- 初始化管理员账号 -INSERT INTO `users` (`username`, `email`, `password`, `nickname`, `role`, `status`, `is_verified`) VALUES -('admin', 'admin@unilife.com', '123456', '系统管理员', 2, 1, 1); - diff --git a/unilife-server/src/main/resources/db/rebuild-database.sql b/unilife-server/src/main/resources/db/rebuild-database.sql index efaa433..88b56af 100644 --- a/unilife-server/src/main/resources/db/rebuild-database.sql +++ b/unilife-server/src/main/resources/db/rebuild-database.sql @@ -203,8 +203,9 @@ INSERT INTO `categories` (`name`, `description`, `icon`, `sort`, `status`) VALUE ('资源共享', '分享各类学习资源', 'icon-resource', 5, 1); -- 初始化管理员账号 -INSERT INTO `users` (`username`, `email`, `password`, `nickname`, `role`, `status`, `is_verified`) VALUES -('admin', 'admin@unilife.com', '123456', '系统管理员', 2, 1, 1); +INSERT INTO `users` (`username`, `email`, `password`, `nickname`, `role`, `status`, `is_verified`, `created_at`) VALUES +('admin', 'admin@unilife.com', '123456', '系统管理员', 2, 1, 1, '2024-01-01 00:00:00'), +('superadmin', 'superadmin@unilife.com', 'admin123', '超级管理员', 2, 1, 1, '2024-01-01 00:00:00'); -- ========================================== -- 第四步:插入测试数据 diff --git a/unilife-server/src/main/resources/db/test-data.sql b/unilife-server/src/main/resources/db/test-data.sql deleted file mode 100644 index 7796772..0000000 --- a/unilife-server/src/main/resources/db/test-data.sql +++ /dev/null @@ -1,195 +0,0 @@ --- 武汉大学学生论坛测试数据 --- 使用数据库 -USE UniLife; - --- 清空现有测试数据(保留表结构和管理员账号) -DELETE FROM resource_likes; -DELETE FROM post_likes; -DELETE FROM comment_likes; -DELETE FROM comments; -DELETE FROM posts; -DELETE FROM resources; -DELETE FROM schedules; -DELETE FROM courses; -DELETE FROM users WHERE id > 1; -- 保留管理员账号 - --- 清空可能存在的重复分类 -DELETE FROM categories WHERE name IN ('学院专区', '考研考公', '生活服务'); - --- 重置自增ID -ALTER TABLE users AUTO_INCREMENT = 2; -ALTER TABLE posts AUTO_INCREMENT = 1; -ALTER TABLE comments AUTO_INCREMENT = 1; -ALTER TABLE post_likes AUTO_INCREMENT = 1; -ALTER TABLE comment_likes AUTO_INCREMENT = 1; -ALTER TABLE resources AUTO_INCREMENT = 1; -ALTER TABLE resource_likes AUTO_INCREMENT = 1; -ALTER TABLE courses AUTO_INCREMENT = 1; -ALTER TABLE schedules AUTO_INCREMENT = 1; -ALTER TABLE categories AUTO_INCREMENT = 6; - --- 更新现有分类数据(更贴合武汉大学实际) -UPDATE `categories` SET - `name` = '学术交流', - `description` = '学术讨论、科研分享、竞赛经验', - `icon` = '📚' -WHERE `name` = '学习交流'; - -UPDATE `categories` SET - `description` = '武汉大学校园生活、社团活动、文化娱乐', - `icon` = '🏫' -WHERE `name` = '校园生活'; - -UPDATE `categories` SET - `name` = '就业实习', - `description` = '实习经验、求职心得、职业规划', - `icon` = '💼' -WHERE `name` = '求职就业'; - --- 插入新的分类 -INSERT INTO `categories` (`name`, `description`, `icon`, `sort`, `status`) VALUES -('学院专区', '各学院学生交流专区', '🎓', 6, 1), -('考研考公', '研究生入学考试、公务员考试', '📖', 7, 1), -('生活服务', '二手交易、失物招领、校园服务', '🛍️', 8, 1); - --- 1. 插入武汉大学学生用户数据 -INSERT INTO `users` (`username`, `email`, `password`, `nickname`, `bio`, `gender`, `student_id`, `department`, `major`, `grade`, `points`, `role`, `status`, `is_verified`, `created_at`) VALUES --- 文理学部学生 -('czq2024', 'czq@whu.edu.cn', '123456', '珞珈数学狗', '数学与统计学院2022级数学类,热爱数学建模,ACM银牌选手', 1, '2022301140001', '数学与统计学院', '数学类', '2022级', 150, 0, 1, 1, '2024-09-01 09:00:00'), -('lihua_cs', 'lihua@whu.edu.cn', '123456', '代码诗人', '计算机学院2021级软件工程,全栈开发爱好者,开源项目贡献者', 1, '2021301120001', '计算机学院', '软件工程', '2021级', 230, 0, 1, 1, '2024-09-01 10:00:00'), -('wangming_law', 'wangming@whu.edu.cn', '123456', '法学小白', '法学院2023级法学专业,模拟法庭常客,梦想成为大律师', 1, '2023301080001', '法学院', '法学', '2023级', 80, 0, 1, 1, '2024-09-01 11:00:00'), -('zhangwei_chem', 'zhangwei@whu.edu.cn', '123456', '化学实验员', '化学与分子科学学院2022级化学专业,实验室常驻,合成达人', 1, '2022301130001', '化学与分子科学学院', '化学', '2022级', 120, 0, 1, 1, '2024-09-01 12:00:00'), -('liuxin_econ', 'liuxin@whu.edu.cn', '123456', '经济观察者', '经济与管理学院2021级经济学,关注宏观经济政策,券商实习生', 2, '2021301110001', '经济与管理学院', '经济学', '2021级', 200, 0, 1, 1, '2024-09-01 13:00:00'), - --- 工学部学生 -('chenfei_water', 'chenfei@whu.edu.cn', '123456', '水利工程师', '水利水电学院2022级水利水电工程,三峡实习经历,立志建设美丽中国', 1, '2022301320001', '水利水电学院', '水利水电工程', '2022级', 90, 0, 1, 1, '2024-09-01 14:00:00'), -('sunhao_power', 'sunhao@whu.edu.cn', '123456', '电气小子', '电气与自动化学院2023级电气工程及其自动化,电力系统仿真专家', 1, '2023301330001', '电气与自动化学院', '电气工程及其自动化', '2023级', 70, 0, 1, 1, '2024-09-01 15:00:00'), -('wujing_civil', 'wujing@whu.edu.cn', '123456', '土木妹子', '土木建筑工程学院2022级土木工程,桥梁设计爱好者,BIM技术达人', 2, '2022301340001', '土木建筑工程学院', '土木工程', '2022级', 110, 0, 1, 1, '2024-09-01 16:00:00'), - --- 信息学部学生 -('liqiang_remote', 'liqiang@whu.edu.cn', '123456', '遥感专家', '遥感信息工程学院2021级遥感科学与技术,无人机航拍爱好者', 1, '2021301210001', '遥感信息工程学院', '遥感科学与技术', '2021级', 180, 0, 1, 1, '2024-09-01 17:00:00'), -('zhaoli_survey', 'zhaoli@whu.edu.cn', '123456', '测绘达人', '测绘学院2022级测绘工程,GPS定位技术研究者,野外作业经验丰富', 1, '2022301220001', '测绘学院', '测绘工程', '2022级', 95, 0, 1, 1, '2024-09-01 18:00:00'), - --- 医学部学生 -('huangyan_med', 'huangyan@whu.edu.cn', '123456', '未来医生', '基础医学院2020级临床医学,人民医院实习生,立志救死扶伤', 2, '2020301410001', '基础医学院', '临床医学', '2020级', 250, 0, 1, 1, '2024-09-01 19:00:00'), -('wangpeng_dental', 'wangpeng@whu.edu.cn', '123456', '口腔医师', '口腔医学院2021级口腔医学,口腔医院见习,关注口腔健康科普', 1, '2021301420001', '口腔医学院', '口腔医学', '2021级', 160, 0, 1, 1, '2024-09-01 20:00:00'), - --- 人文社科学部学生 -('luxiaoya_chinese', 'luxiaoya@whu.edu.cn', '123456', '文学少女', '文学院2022级汉语言文学,古典文学爱好者,诗词社社长', 2, '2022301050001', '文学院', '汉语言文学', '2022级', 140, 0, 1, 1, '2024-09-01 21:00:00'), -('zhoujie_history', 'zhoujie@whu.edu.cn', '123456', '史学研究生', '历史学院研究生,中国古代史方向,博物馆志愿者', 1, '2024302050001', '历史学院', '中国史', '2024级', 100, 0, 1, 1, '2024-09-01 22:00:00'), -('tanglei_news', 'tanglei@whu.edu.cn', '123456', '新传人', '新闻与传播学院2021级新闻学,校媒记者,关注社会热点', 1, '2021301070001', '新闻与传播学院', '新闻学', '2021级', 170, 0, 1, 1, '2024-09-01 23:00:00'); - --- 2. 插入论坛帖子数据(使用已存在的用户ID) -INSERT INTO `posts` (`user_id`, `category_id`, `title`, `content`, `view_count`, `like_count`, `comment_count`, `status`, `created_at`) VALUES --- 学术交流类帖子 -(2, 1, '数学建模美赛经验分享', '刚刚结束的美国大学生数学建模竞赛,我们团队获得了M奖!分享一下参赛经验和技巧,希望对学弟学妹们有帮助。数模比赛不仅考验数学能力,更重要的是团队协作和论文写作能力。首先要选择合适的队友,最好是数学、编程、英语各有所长的组合...', 256, 42, 8, 2, '2024-12-20 09:30:00'), - -(3, 1, 'ACM-ICPC区域赛总结', '参加了西安站的ACM区域赛,虽然没能拿到金牌,但收获很大。分享一下刷题心得和比赛策略,特别是动态规划和图论算法的练习方法。建议大家多在Codeforces和AtCoder上练习,这些平台的题目质量很高...', 189, 35, 6, 1, '2024-12-19 16:45:00'), - -(6, 1, '宏观经济学课程研讨:通胀与货币政策', '最近在学习宏观经济学,对当前的通胀形势和央行货币政策有一些思考。想和大家讨论一下利率调整对经济的影响机制,特别是在当前全球经济形势下的作用...', 145, 28, 4, 1, '2024-12-18 14:20:00'), - --- 校园生活类帖子 -(14, 2, '武大樱花季摄影大赛作品展示', '樱花季刚过,分享一些在樱花大道拍摄的照片。今年的樱花开得特别美,虽然人很多,但还是拍到了一些不错的角度。附上拍摄技巧分享!使用的是佳能5D4,光圈f/2.8,ISO400,后期用LR调色...', 1234, 156, 12, 2, '2024-04-10 10:15:00'), - -(16, 2, '校运动会志愿者招募!', '第55届田径运动会即将开始,现招募志愿者!工作内容包括引导、记分、颁奖等。参与志愿服务可获得志愿时长认证,还有纪念品哦~有意向的同学请在评论区留言或私信联系我', 456, 89, 5, 1, '2024-12-15 08:00:00'), - -(11, 2, '测绘学院野外实习日记', '刚从庐山实习回来,分享一下野外测量的酸甜苦辣。早上5点起床,背着仪器爬山,虽然辛苦但收获满满。珞珈山的风景真是看不够啊!学到了很多实际操作技能...', 234, 45, 7, 1, '2024-12-14 19:30:00'), - --- 学院专区类帖子 -(4, 6, '法学院模拟法庭大赛预告', '一年一度的"枫叶杯"模拟法庭大赛即将开始!欢迎各年级同学组队参加。比赛分为民事组和刑事组,优胜者将代表学院参加全国比赛。这是提升法律实务能力的绝佳机会...', 345, 67, 9, 2, '2024-12-16 11:00:00'), - -(5, 6, '化学实验安全注意事项提醒', '最近实验室发生了几起小事故,提醒大家一定要注意安全!特别是使用强酸强碱时,护目镜和手套必须佩戴。实验无小事,安全第一!同时要做好实验记录...', 178, 34, 3, 1, '2024-12-17 15:20:00'), - --- 就业实习类帖子 -(6, 3, '券商实习面试经验分享', '刚刚拿到某头部券商的实习offer,分享一下面试经验。金融行业对专业能力和综合素质要求都很高,准备过程中要注意这几个方面:扎实的专业基础、良好的表达能力、对市场的敏感度...', 423, 78, 11, 1, '2024-12-21 14:00:00'), - -(3, 3, 'IT互联网春招总结', '经历了春招季,最终选择了某大厂的后端开发岗位。分享一下投递简历、技术面试、HR面试的全流程经验,希望对计算机专业的同学有帮助。技术面试主要考察数据结构、算法、系统设计...', 567, 89, 15, 2, '2024-05-18 09:15:00'), - --- 考研考公类帖子 -(15, 7, '历史学考研经验贴', '成功上岸北师大中国史专业!分享一下备考经验:如何选择学校、如何制定复习计划、如何准备专业课等。考研路上不孤单,加油!专业课复习要注意史料分析和论述题...', 389, 72, 13, 1, '2024-12-10 22:00:00'), - --- 生活服务类帖子 -(9, 8, '出售工科教材一批', '即将毕业,出售一些专业课教材:《结构力学》《材料力学》《工程制图》等,八成新,价格优惠。有需要的学弟学妹可以联系我~都是正版教材,保存得很好', 156, 12, 2, 1, '2024-12-22 18:30:00'), - -(13, 8, '寻找珞珈山丢失的口腔器械包', '昨天在樱花大道丢失了一个蓝色器械包,里面有重要的口腔实习用具。如有好心人捡到,请联系我,必有重谢!器械包上有我的姓名标签', 89, 8, 1, 1, '2024-12-23 07:45:00'); - --- 3. 插入评论数据 -INSERT INTO `comments` (`post_id`, `user_id`, `content`, `parent_id`, `like_count`, `status`, `created_at`) VALUES --- 对数学建模帖子的评论 -(1, 3, '恭喜学长!我们正在准备下半年的国赛,请问有什么推荐的学习资料吗?', NULL, 5, 1, '2024-12-20 10:30:00'), -(1, 6, '数模确实需要很强的团队协作能力,我们当时就是沟通不够充分才没拿到好成绩', NULL, 3, 1, '2024-12-20 11:15:00'), -(1, 2, '推荐《数学建模方法与分析》这本书,MATLAB和Python都要熟练掌握', 1, 2, 1, '2024-12-20 12:00:00'), - --- 对樱花帖子的评论 -(4, 10, '照片拍得真美!求拍摄参数和后期处理方法', NULL, 8, 1, '2024-04-10 14:30:00'), -(4, 16, '武大的樱花确实是一绝,每年都要来打卡', NULL, 4, 1, '2024-04-10 15:45:00'), - --- 对法学院帖子的评论 -(7, 15, '法学院的模拟法庭一直很有名,想去观摩学习', NULL, 3, 1, '2024-12-16 13:00:00'), -(7, 4, '欢迎其他学院的同学来观摩!比赛时间是下周五晚上', 6, 1, 1, '2024-12-16 14:30:00'), - --- 对实习帖子的评论 -(9, 2, '金融行业竞争确实激烈,学长有什么建议给想进入这个行业的同学吗?', NULL, 4, 1, '2024-12-21 15:30:00'), -(9, 6, '建议先把CFA一级考出来,然后多参加实习积累经验', 8, 6, 1, '2024-12-21 16:45:00'); - --- 4. 插入点赞数据 -INSERT INTO `post_likes` (`user_id`, `post_id`, `created_at`) VALUES --- 用户点赞帖子 -(2, 4, '2024-04-10 11:00:00'), -(2, 7, '2024-12-16 12:00:00'), -(3, 1, '2024-12-20 10:00:00'), -(3, 4, '2024-04-10 16:00:00'), -(4, 1, '2024-12-20 11:30:00'), -(4, 9, '2024-12-21 15:00:00'), -(5, 2, '2024-12-19 17:30:00'), -(6, 1, '2024-12-20 13:00:00'), -(6, 10, '2024-05-18 10:00:00'); - --- 5. 插入学习资源数据 -INSERT INTO `resources` (`user_id`, `title`, `description`, `file_url`, `file_size`, `file_type`, `category_id`, `download_count`, `like_count`, `status`) VALUES -(2, '数据结构课程设计报告', '包含完整的数据结构课程设计实验报告,涵盖栈、队列、树、图等数据结构的实现和应用。', '/files/data-structure-report.pdf', 2048576, 'application/pdf', 1, 15, 8, 1), -(3, '算法导论学习笔记', '详细的算法导论学习笔记,包含排序算法、图算法、动态规划等重要算法的分析和实现。', '/files/algorithm-notes.docx', 1572864, 'application/msword', 1, 25, 12, 1), -(2, '高等数学期末复习资料', '高等数学期末考试复习资料合集,包含重要公式、定理证明和典型习题解答。', '/files/calculus-review.pdf', 3145728, 'application/pdf', 1, 32, 18, 1), -(6, '宏观经济学PPT课件', '经济学专业课件,包含货币政策、财政政策等核心内容。', '/files/macro-economics.pptx', 5242880, 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 1, 20, 15, 1), -(14, '校园生活指南', '新生校园生活指南,包含宿舍管理、食堂介绍、图书馆使用等实用信息。', '/files/campus-guide.pdf', 1048576, 'application/pdf', 2, 45, 28, 1), -(3, '计算机网络实验代码', '计算机网络课程实验代码合集,包含Socket编程、HTTP协议实现等。', '/files/network-lab-code.zip', 4194304, 'application/zip', 5, 18, 10, 1); - --- 6. 插入课程数据 -INSERT INTO `courses` (`user_id`, `name`, `teacher`, `location`, `day_of_week`, `start_time`, `end_time`, `start_week`, `end_week`, `semester`, `color`, `status`) VALUES --- 数学学院学生的课程 -(2, '高等代数', '张教授', '数学学院楼201', 1, '08:00:00', '09:40:00', 1, 16, '2024-2', '#409EFF', 1), -(2, '实变函数', '李老师', '数学学院楼301', 3, '14:00:00', '15:40:00', 1, 16, '2024-2', '#67C23A', 1), -(2, '数学建模', '王教授', '计算中心机房', 5, '19:00:00', '21:00:00', 1, 16, '2024-2', '#E6A23C', 1), - --- 计算机学院学生的课程 -(3, '数据结构与算法', '赵教授', '信息学部计算机楼', 2, '10:00:00', '11:40:00', 1, 16, '2024-2', '#409EFF', 1), -(3, '软件工程', '钱老师', '信息学部B楼302', 4, '14:00:00', '15:40:00', 1, 16, '2024-2', '#67C23A', 1), -(3, '算法竞赛训练', 'ACM教练', '信息学部机房', 6, '19:30:00', '21:30:00', 1, 16, '2024-2', '#E6A23C', 1), - --- 法学院学生的课程 -(4, '民法学', '孙教授', '法学院模拟法庭', 1, '10:00:00', '11:40:00', 1, 16, '2024-2', '#409EFF', 1), -(4, '法理学', '周老师', '法学院研讨室', 3, '15:50:00', '17:30:00', 1, 16, '2024-2', '#67C23A', 1), - --- 经管学院学生的课程 -(6, '宏观经济学', '吴教授', '经管大楼B201', 1, '08:00:00', '09:40:00', 1, 16, '2024-2', '#409EFF', 1), -(6, '计量经济学', '郑老师', '经管大楼机房', 2, '10:00:00', '11:40:00', 1, 16, '2024-2', '#67C23A', 1); - --- 7. 插入日程数据 -INSERT INTO `schedules` (`user_id`, `title`, `description`, `start_time`, `end_time`, `location`, `is_all_day`, `reminder`, `color`, `status`) VALUES --- 学习相关日程 -(2, '高等代数期末复习', '准备高等代数期末考试,重点复习线性变换和特征值', '2025-01-10 19:00:00', '2025-01-10 22:00:00', '图书馆总馆3楼', 0, 30, '#409EFF', 1), -(3, '算法竞赛训练', 'ACM周赛讲解,动态规划专题', '2025-01-12 19:30:00', '2025-01-12 21:30:00', '信息学部机房', 0, 15, '#67C23A', 1), -(4, '模拟法庭准备', '准备"枫叶杯"模拟法庭大赛材料', '2025-01-08 14:00:00', '2025-01-08 17:00:00', '法学院研讨室', 0, 60, '#E6A23C', 1), - --- 社团活动 -(14, '诗词社例会', '讨论新学期诗词创作活动安排', '2025-01-15 18:30:00', '2025-01-15 20:00:00', '樱园学生活动中心', 0, 30, '#909399', 1), -(16, '校报编辑部会议', '讨论下期专题策划和采访安排', '2025-01-16 17:00:00', '2025-01-16 18:30:00', '学生事务中心', 0, 15, '#909399', 1), - --- 实习实践 -(6, '券商实习面试', '参加XX证券公司实习生面试', '2025-01-20 14:00:00', '2025-01-20 16:00:00', '金融街', 0, 60, '#F56C6C', 1), -(12, '医院见习', '跟随带教老师查房学习', '2025-01-18 07:30:00', '2025-01-18 12:00:00', '人民医院', 0, 120, '#C0C4CC', 1), - --- 个人安排 -(2, '期末考试', '高等代数期末考试', '2025-01-25 08:00:00', '2025-01-25 10:00:00', '数学学院楼201', 0, 1440, '#F56C6C', 1), -(3, '项目答辩', '软件工程课程设计项目答辩', '2025-01-22 14:00:00', '2025-01-22 17:00:00', '信息学部B楼', 0, 720, '#E6A23C', 1), -(6, '考研复试准备', '准备经济学研究生复试材料', '2025-01-30 09:00:00', '2025-01-30 18:00:00', '图书馆', 1, 2880, '#9B59B6', 1); \ No newline at end of file diff --git a/unilife-server/src/main/resources/mappers/CategoryMapper.xml b/unilife-server/src/main/resources/mappers/CategoryMapper.xml index 9d4078b..1edff1d 100644 --- a/unilife-server/src/main/resources/mappers/CategoryMapper.xml +++ b/unilife-server/src/main/resources/mappers/CategoryMapper.xml @@ -64,4 +64,50 @@ + + + + + + + + + + + INSERT INTO categories ( + name, description, icon, sort, status, created_at, updated_at + ) VALUES ( + #{name}, #{description}, #{icon}, #{sort}, #{status}, NOW(), NOW() + ) + + + + UPDATE categories + SET name = #{name}, + description = #{description}, + icon = #{icon}, + sort = #{sort}, + status = #{status}, + updated_at = NOW() + WHERE id = #{id} + + + + UPDATE categories + SET status = 0, + updated_at = NOW() + WHERE id = #{categoryId} + \ No newline at end of file diff --git a/unilife-server/src/main/resources/mappers/CommentMapper.xml b/unilife-server/src/main/resources/mappers/CommentMapper.xml index 0b4d728..26441a9 100644 --- a/unilife-server/src/main/resources/mappers/CommentMapper.xml +++ b/unilife-server/src/main/resources/mappers/CommentMapper.xml @@ -72,4 +72,65 @@ SET like_count = GREATEST(like_count - 1, 0) WHERE id = #{id} + + + + + + + + + + + + + + + UPDATE comments + SET status = 0, + updated_at = NOW() + WHERE id = #{commentId} + \ No newline at end of file diff --git a/unilife-server/src/main/resources/mappers/PostMapper.xml b/unilife-server/src/main/resources/mappers/PostMapper.xml index a85231e..e07fead 100644 --- a/unilife-server/src/main/resources/mappers/PostMapper.xml +++ b/unilife-server/src/main/resources/mappers/PostMapper.xml @@ -155,4 +155,78 @@ + + + + + + + + + + + + + + + UPDATE posts + SET status = #{status}, + updated_at = NOW() + WHERE id = #{postId} + + + + UPDATE posts + SET status = 0, + updated_at = NOW() + WHERE id = #{postId} + + + \ No newline at end of file diff --git a/unilife-server/src/main/resources/mappers/ResourceMapper.xml b/unilife-server/src/main/resources/mappers/ResourceMapper.xml index 25591d2..37c31a8 100644 --- a/unilife-server/src/main/resources/mappers/ResourceMapper.xml +++ b/unilife-server/src/main/resources/mappers/ResourceMapper.xml @@ -116,4 +116,67 @@ FROM resources WHERE category_id = #{categoryId} AND status != 0 + + + + + + + + + + + + + + + UPDATE resources + SET status = 0, + updated_at = NOW() + WHERE id = #{resourceId} + \ No newline at end of file diff --git a/unilife-server/src/main/resources/mappers/UserMapper.xml b/unilife-server/src/main/resources/mappers/UserMapper.xml index c0003ea..b6a3145 100644 --- a/unilife-server/src/main/resources/mappers/UserMapper.xml +++ b/unilife-server/src/main/resources/mappers/UserMapper.xml @@ -212,4 +212,83 @@ DELETE FROM comment_likes WHERE user_id = #{userId}; DELETE FROM resource_likes WHERE user_id = #{userId}; + + + + + + + + + + + + + + + UPDATE users + SET status = #{status}, + updated_at = NOW() + WHERE id = #{userId} + + + + UPDATE users + SET role = #{role}, + updated_at = NOW() + WHERE id = #{userId} +