Эх сурвалжийг харах

feat(OPLOG): 实现用户操作日志功能

- 添加UserOperationLog实体、Mapper、Service
- OperationLogController改用POST方法(安全要求)
- Web端API调用适配POST方法
- 改进Layout菜单和角色显示逻辑
- 路由守卫改进指导师权限检查
User 5 сар өмнө
parent
commit
f6f9d10adb

+ 28 - 12
zxyj-backend/src/main/java/com/zxyj/controller/admin/OperationLogController.java

@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.*;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 @Tag(name = "日志管理", description = "操作日志查询接口")
 @RestController
@@ -23,17 +24,31 @@ public class OperationLogController {
     private UserOperationLogService logService;
 
     @Operation(summary = "分页查询操作日志")
-    @GetMapping("/operations")
+    @PostMapping("/operations")
     public Result<Page<UserOperationLog>> queryLogs(
             @RequestAttribute("userId") Long adminId,
-            @RequestParam(required = false) Long userId,
-            @RequestParam(required = false) String operationType,
-            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate,
-            @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate,
-            @RequestParam(defaultValue = "1") Integer page,
-            @RequestParam(defaultValue = "20") Integer size) {
-
-        // 可以添加权限检查:admin角色才能查看
+            @RequestBody Map<String, Object> params) {
+        Long userId = params.get("userId") != null ? ((Number) params.get("userId")).longValue() : null;
+        String operationType = (String) params.get("operationType");
+        Integer page = params.get("page") != null ? (Integer) params.get("page") : 1;
+        Integer size = params.get("size") != null ? (Integer) params.get("size") : 20;
+
+        // 解析日期
+        Date startDate = null;
+        Date endDate = null;
+        try {
+            if (params.get("startDate") != null) {
+                java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
+                startDate = sdf.parse((String) params.get("startDate"));
+            }
+            if (params.get("endDate") != null) {
+                java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd");
+                endDate = sdf.parse((String) params.get("endDate"));
+            }
+        } catch (Exception e) {
+            // 日期解析失败
+        }
+
         Page<UserOperationLog> result = logService.queryLogs(
                 userId, operationType, startDate, endDate, page, size);
 
@@ -41,11 +56,12 @@ public class OperationLogController {
     }
 
     @Operation(summary = "获取用户最近操作记录")
-    @GetMapping("/recent/{userId}")
+    @PostMapping("/recent")
     public Result<List<UserOperationLog>> getRecentLogs(
             @RequestAttribute("userId") Long adminId,
-            @PathVariable Long userId,
-            @RequestParam(defaultValue = "10") Integer limit) {
+            @RequestBody Map<String, Object> params) {
+        Long userId = ((Number) params.get("userId")).longValue();
+        Integer limit = params.get("limit") != null ? (Integer) params.get("limit") : 10;
 
         List<UserOperationLog> logs = logService.getRecentLogs(userId, limit);
         return Result.success(logs);

+ 6 - 6
zxyj-web/src/api/operationLog.js

@@ -2,16 +2,16 @@ import request from '@/utils/request'
 
 export function getOperationLogs(params) {
   return request({
-    url: '/api/admin/',
-    method: 'get',
-    params
+    url: '/api/admin/logs/operations',
+    method: 'post',
+    data: params
   })
 }
 
 export function getRecentLogs(userId, limit = 10) {
   return request({
-    url: `/api/admin/logs/recent/${userId}`,
-    method: 'get',
-    params: { limit }
+    url: '/api/admin/logs/recent',
+    method: 'post',
+    data: { userId, limit }
   })
 }

+ 8 - 5
zxyj-web/src/router/index.js

@@ -111,21 +111,24 @@ const router = new VueRouter({
 router.beforeEach((to, from, next) => {
   const token = localStorage.getItem('token')
   const role = localStorage.getItem('role')
-  
+
   // authentication check
   if (to.path !== '/login' && !token) {
     return next('/login')
   }
-  
+
   // teacher role protection for guide routes (guide-packages, guide-family-task, teacher-consult)
   const guideRoutes = ['GuidePackages', 'GuideFamilyTask', 'TeacherConsult']
   if (guideRoutes.includes(to.name)) {
+    // If not logged in as teacher, redirect to dashboard with a message
     if (!role || role !== 'teacher') {
-      // 非指导师角色重定向到首页,避免重定向循环
-      return next(from.path ? { path: from.path, replace: false } : '/')
+      console.warn('Access denied: Teacher role required for', to.name)
+      // Redirect to dashboard instead of creating a loop
+      next({ path: '/dashboard', query: { accessDenied: 'teacher-only' }, replace: true })
+      return
     }
   }
-  
+
   return next()
 })
 

+ 24 - 2
zxyj-web/src/views/Layout.vue

@@ -59,7 +59,7 @@
             </el-menu-item>
           </el-submenu>
           
-          <el-submenu index="guide">
+          <el-submenu v-if="isTeacher" index="guide">
             <template slot="title">
               <i class="el-icon-s-custom"></i>
               <span>指导师管理</span>
@@ -101,7 +101,7 @@
     <el-container>
       <el-header>
         <div class="header-right">
-          <span class="username">管理员</span>
+          <span class="username">{{ displayUserLabel }}</span>
           <el-button type="text" @click="handleLogout">退出</el-button>
         </div>
       </el-header>
@@ -117,6 +117,25 @@ export default {
   computed: {
     activeMenu() {
       return this.$route.path
+    },
+    currentRole() {
+      return localStorage.getItem('role') || 'admin'
+    },
+    isTeacher() {
+      return this.currentRole === 'teacher'
+    },
+    displayRoleName() {
+      if (this.currentRole === 'teacher') {
+        return '指导师'
+      }
+      return '管理员'
+    },
+    displayUserLabel() {
+      const adminName = localStorage.getItem('adminName')
+      if (adminName) {
+        return adminName
+      }
+      return this.displayRoleName
     }
   },
   methods: {
@@ -127,6 +146,9 @@ export default {
         type: 'warning'
       }).then(() => {
         localStorage.removeItem('token')
+        localStorage.removeItem('role')
+        localStorage.removeItem('adminId')
+        localStorage.removeItem('adminName')
         this.$router.push('/login')
       })
     }