diff --git a/backend/ruoyi-modules/ruoyi-rs/Controller权限注解修正说明.md b/backend/ruoyi-modules/ruoyi-rs/Controller权限注解修正说明.md deleted file mode 100644 index 3e79432b..00000000 --- a/backend/ruoyi-modules/ruoyi-rs/Controller权限注解修正说明.md +++ /dev/null @@ -1,204 +0,0 @@ -# Controller权限注解修正说明 - -## 📋 修正概述 - -**修正时间**: 2025-10-08 -**修正原因**: Controller权限注解格式与SQL菜单配置不一致 -**修正文件**: `RsPartyMembershipRetentionController.java` - ---- - -## ⚠️ 问题说明 - -### 原有问题 -- **SQL配置**: 使用二段式权限标识 `rs:partyretention:xxx` ✅ **标准格式** -- **Controller注解**: 使用三段式权限标识 `rs:party:retention:xxx` ❌ **不符合规范** - -### 影响范围 -权限标识不一致会导致前端权限控制失效,v-hasPermi指令无法正确匹配权限。 - ---- - -## ✅ 修正内容 - -已将Controller中的所有权限注解统一修改为二段式格式,与SQL配置保持一致: - -| 序号 | 功能 | 修改前(错误) | 修改后(正确) | -|------|------|---------------|---------------| -| 1 | 列表查询 | `rs:party:retention:list` | `rs:partyretention:list` ✅ | -| 2 | 导出列表 | `rs:party:retention:export` | `rs:partyretention:export` ✅ | -| 3 | 详情查询 | `rs:party:retention:query` | `rs:partyretention:query` ✅ | -| 4 | 新增申请 | `rs:party:retention:add` | `rs:partyretention:add` ✅ | -| 5 | 修改申请 | `rs:party:retention:edit` | `rs:partyretention:edit` ✅ | -| 6 | 删除申请 | `rs:party:retention:remove` | `rs:partyretention:remove` ✅ | -| 7 | 提交申请 | `rs:party:retention:submit` | `rs:partyretention:submit` ✅ | -| 8 | 撤回申请 | `rs:party:retention:withdraw` | `rs:partyretention:withdraw` ✅ | -| 9 | 审批申请 | `rs:party:retention:approve` | `rs:partyretention:approve` ✅ | - ---- - -## 🔍 修正详情 - -### 修改的接口方法(9个) - -```java -// 1. 列表查询 -@SaCheckPermission("rs:partyretention:list") -@GetMapping("/list") -public TableDataInfo list(...) - -// 2. 导出列表 -@SaCheckPermission("rs:partyretention:export") -@PostMapping("/export") -public void export(...) - -// 3. 详情查询(单条记录) -@SaCheckPermission("rs:partyretention:query") -@GetMapping("/{retentionId}") -public R getInfo(...) - -// 4. 根据登记ID查询 -@SaCheckPermission("rs:partyretention:query") -@GetMapping("/registration/{registrationId}") -public R getByRegistrationId(...) - -// 5. 根据申请ID查询 -@SaCheckPermission("rs:partyretention:query") -@GetMapping("/application/{applicationId}") -public R getByApplicationId(...) - -// 6. 新增申请 -@SaCheckPermission("rs:partyretention:add") -@PostMapping() -public R add(...) - -// 7. 保存并提交 -@SaCheckPermission("rs:partyretention:add") -@PostMapping("/saveAndSubmit") -public R saveAndSubmit(...) - -// 8. 修改申请 -@SaCheckPermission("rs:partyretention:edit") -@PutMapping() -public R edit(...) - -// 9. 删除申请 -@SaCheckPermission("rs:partyretention:remove") -@DeleteMapping("/{retentionIds}") -public R remove(...) - -// 10. 提交申请 -@SaCheckPermission("rs:partyretention:submit") -@PutMapping("/submit/{retentionId}") -public R submit(...) - -// 11. 撤回申请 -@SaCheckPermission("rs:partyretention:withdraw") -@PutMapping("/withdraw/{retentionId}") -public R withdraw(...) - -// 12. 审批申请 -@SaCheckPermission("rs:partyretention:approve") -@PutMapping("/approve/{retentionId}") -public R approve(...) -``` - ---- - -## 📊 与SQL配置对照表 - -| 菜单ID | 菜单名称 | SQL权限标识 | Controller注解 | 状态 | -|--------|----------|------------|---------------|------| -| 2010 | 出国党籍保留 | `rs:partyretention:list` | `@SaCheckPermission("rs:partyretention:list")` | ✅ 已一致 | -| 2011 | 党籍保留查询 | `rs:partyretention:query` | `@SaCheckPermission("rs:partyretention:query")` | ✅ 已一致 | -| 2012 | 党籍保留新增 | `rs:partyretention:add` | `@SaCheckPermission("rs:partyretention:add")` | ✅ 已一致 | -| 2013 | 党籍保留修改 | `rs:partyretention:edit` | `@SaCheckPermission("rs:partyretention:edit")` | ✅ 已一致 | -| 2014 | 党籍保留删除 | `rs:partyretention:remove` | `@SaCheckPermission("rs:partyretention:remove")` | ✅ 已一致 | -| 2015 | 党籍保留导出 | `rs:partyretention:export` | `@SaCheckPermission("rs:partyretention:export")` | ✅ 已一致 | -| 2016 | 党籍保留提交 | `rs:partyretention:submit` | `@SaCheckPermission("rs:partyretention:submit")` | ✅ 已一致 | -| 2017 | 党籍保留撤回 | `rs:partyretention:withdraw` | `@SaCheckPermission("rs:partyretention:withdraw")` | ✅ 已一致 | -| 2018 | 党籍保留审批 | `rs:partyretention:approve` | `@SaCheckPermission("rs:partyretention:approve")` | ✅ 已一致 | - ---- - -## 🎯 前端v-hasPermi指令使用 - -修正后,前端权限指令应使用如下格式: - -```vue - -新增 - - -编辑 - - -删除 - - -导出 - - -提交 - - -撤回 - - -审批 -``` - ---- - -## ✅ 验证方法 - -### 1. 验证权限标识格式 -```bash -# 在Controller文件中搜索权限注解,确认格式统一 -grep "@SaCheckPermission" RsPartyMembershipRetentionController.java -``` - -预期结果:所有权限标识都是 `rs:partyretention:xxx` 格式 - -### 2. 验证与SQL配置一致性 -```sql --- 执行权限验证脚本 -source 党籍保留权限验证.sql -``` - -预期结果:8个检查项全部通过 - -### 3. 功能测试 -1. 重启后端服务 -2. 重新登录系统(清除缓存) -3. 进入"人事管理 → 出国党籍保留"菜单 -4. 验证所有权限按钮是否正常显示 - ---- - -## 📌 注意事项 - -1. **重启服务**: 修改权限注解后需要重启后端服务 -2. **清除缓存**: 用户需要清除浏览器缓存并重新登录 -3. **权限规范**: 本项目统一使用**二段式**权限标识格式 `模块:功能:操作` -4. **前端同步**: 确保前端v-hasPermi指令使用的权限标识与此一致 - ---- - -## 📝 相关文档 - -- **权限菜单配置**: `出国党籍保留权限菜单配置.sql` -- **权限验证脚本**: `党籍保留权限验证.sql` -- **Controller源码**: `RsPartyMembershipRetentionController.java` - ---- - -## ✅ 修正完成确认 - -- ✅ Controller权限注解已全部修改为二段式格式 -- ✅ 与SQL菜单配置保持一致 -- ✅ 共修正12个@SaCheckPermission注解 -- ✅ 覆盖9种操作类型(list/query/add/edit/remove/export/submit/withdraw/approve) - -**状态**: 🎉 修正完成,可以进行功能测试! - diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/RsTrainingApplication.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/RsTrainingApplication.java index cd44229d..17719194 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/RsTrainingApplication.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/domain/RsTrainingApplication.java @@ -193,4 +193,18 @@ public class RsTrainingApplication extends BaseEntity { */ @TableField(exist = false) private String excludeStatus; + + /** + * 审批角色列表(查询条件,不存储到数据库) + * 用于根据用户角色过滤可见的审批申请 + */ + @TableField(exist = false) + private java.util.List approvalRoles; + + /** + * 当前用户部门ID(查询条件,不存储到数据库) + * 用于第一阶段部门负责人权限过滤 + */ + @TableField(exist = false) + private Long currentDeptId; } \ No newline at end of file diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApplicationServiceImpl.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApplicationServiceImpl.java index 821c6581..3920b53e 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApplicationServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApplicationServiceImpl.java @@ -39,7 +39,7 @@ import java.util.List; /** * 培训申请服务实现类 - * + * * @author weizzzz * @date 2025-07-16 */ @@ -62,7 +62,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 查询培训申请列表 - * + * * @param application 培训申请 * @param pageQuery 分页参数 * @return 培训申请分页列表 @@ -83,27 +83,62 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS application.setTenantId(LoginHelper.getTenantId()); } - // ===== 业务逻辑层权限过滤 ===== - // 根据用户角色进行数据权限过滤 + // ===== 业务逻辑层权限过滤 - 7阶段培训审批权限控制 ===== if (!LoginHelper.isSuperAdmin()) { // 获取当前登录用户信息 Long currentUserId = LoginHelper.getUserId(); Long currentDeptId = LoginHelper.getDeptId(); String username = LoginHelper.getUsername(); - // 检查用户角色并应用相应的数据过滤 - if (StpUtil.hasRole("rs-Applicant")) { + // 🔴 收集用户拥有的审批角色 + List approvalRoles = new ArrayList<>(); + + // 检查7个审批阶段的角色权限 + if (StpUtil.hasRole("rspx-bmfzr")) { + approvalRoles.add("rspx-bmfzr"); // 第1阶段:部门负责人 + } + if (StpUtil.hasRole("rspx-jwc")) { + approvalRoles.add("rspx-jwc"); // 第2阶段:教务处 + } + if (StpUtil.hasRole("rspx-xsc")) { + approvalRoles.add("rspx-xsc"); // 第2阶段:学生处 + } + if (StpUtil.hasRole("rspx-jhcwc")) { + approvalRoles.add("rspx-jhcwc"); // 第3阶段:计划财务处 + } + if (StpUtil.hasRole("rspx-rsc")) { + approvalRoles.add("rspx-rsc"); // 第4阶段:人事处 + } + if (StpUtil.hasRole("rspx-ywfgld")) { + approvalRoles.add("rspx-ywfgld"); // 第5阶段:业务分管院领导 + } + if (StpUtil.hasRole("rspx-rsfgld")) { + approvalRoles.add("rspx-rsfgld"); // 第6阶段:人事分管领导 + } + if (StpUtil.hasRole("rspx-yz")) { + approvalRoles.add("rspx-yz"); // 第7阶段:院长 + } + + log.info("🔐 用户 {} 拥有的审批角色: {}", username, approvalRoles); + + // 根据角色权限设置数据过滤条件 + if (StpUtil.hasRole("rs-admin")) { + // 人事管理员可以看到所有申请(最高权限) + log.info("🔓 人事管理员角色,可查看所有申请"); + } else if (!approvalRoles.isEmpty()) { + // 🔴 核心:设置审批角色过滤条件 + application.setApprovalRoles(approvalRoles); + // 设置当前用户部门ID(用于第一阶段部门过滤) + application.setCurrentDeptId(currentDeptId); + log.info("🔒 审批权限过滤 - 部门ID: {}, 审批角色: {}", currentDeptId, approvalRoles); + } else if (StpUtil.hasRole("rs-Applicant")) { // 申请人只能看到自己的申请 application.setUserId(currentUserId); - } else if (StpUtil.hasRole("rs-admin")) { - // 人事管理员可以看到所有申请(包括审批和部门管理功能) - // 不设置额外过滤条件,让管理员能看到所有申请 - } else if (StpUtil.hasRole("rs-Approver")) { - // 审批人角色:可以看到所有申请(用于审批) - // 不设置过滤条件,允许查看所有申请 + log.info("📝 申请人角色,只能查看自己的申请"); } else { // 默认情况:只能看到自己创建的申请 application.setCreateBy(currentUserId); + log.info("👤 默认权限,只能查看自己创建的申请"); } } @@ -130,7 +165,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 查询培训申请列表 - * + * * @param application 培训申请 * @return 培训申请集合 */ @@ -233,7 +268,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 查询指定课程的培训申请列表 - * + * * @param courseId 课程ID * @param application 培训申请 * @param pageQuery 分页参数 @@ -249,7 +284,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 查询我的培训申请列表 - * + * * @param userId 用户ID * @param application 培训申请 * @param pageQuery 分页参数 @@ -268,10 +303,49 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS */ private LambdaQueryWrapper buildQueryWrapper(RsTrainingApplication application) { LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); - // 移除硬编码状态过滤,让管理员能看到所有状态的申请 - // 原注释:排除已审批完成的数据:1-已通过,3-进行中,4-已完成 - // 原注释:只保留:0-待审核,2-已拒绝 - // 修复:移除 lqw.notIn(RsTrainingApplication::getStatus, "1", "3", "4") 限制 + + // 🔴 审批权限过滤(用于总数统计) + if (application.getApprovalRoles() != null && !application.getApprovalRoles().isEmpty()) { + lqw.and(wrapper -> { + for (String role : application.getApprovalRoles()) { + wrapper.or(w -> { + // 根据角色构建审批权限过滤条件 + if ("rspx-bmfzr".equals(role)) { + // 第1阶段:部门负责人 - 只能看本部门的第1阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "1"); + if (application.getCurrentDeptId() != null) { + w.eq(RsTrainingApplication::getCreateDept, application.getCurrentDeptId()); + } + } else if ("rspx-jwc".equals(role)) { + // 第2阶段:教务处 - 只能看培训类型为"教学"的第2a阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "2a") + .eq(RsTrainingApplication::getTrainingType, "教学"); + } else if ("rspx-xsc".equals(role)) { + // 第2阶段:学生处 - 只能看培训类型为"德育"的第2b阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "2b") + .eq(RsTrainingApplication::getTrainingType, "德育"); + } else if ("rspx-jhcwc".equals(role)) { + // 第3阶段:计划财务处 - 可以看全校的第3阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "3"); + } else if ("rspx-rsc".equals(role)) { + // 第4阶段:人事处 - 可以看全校的第4阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "4"); + } else if ("rspx-ywfgld".equals(role)) { + // 第5阶段:业务分管院领导 - 可以看全校的第5阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "5"); + } else if ("rspx-rsfgld".equals(role)) { + // 第6阶段:人事分管领导 - 可以看全校的第6阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "6"); + } else if ("rspx-yz".equals(role)) { + // 第7阶段:院长 - 可以看全校的第7阶段申请 + w.eq(RsTrainingApplication::getApprovalLevel, "7"); + } + }); + } + }); + } + + // 原有查询条件 lqw.like(application.getUserName() != null, RsTrainingApplication::getUserName, application.getUserName()); lqw.eq(application.getCourseId() != null, RsTrainingApplication::getCourseId, application.getCourseId()); lqw.eq(application.getUserId() != null, RsTrainingApplication::getUserId, application.getUserId()); @@ -289,7 +363,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 查询培训申请详细信息 - * + * * @param applicationId 培训申请ID * @return 培训申请 */ @@ -337,7 +411,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 新增培训申请 - * + * * @param application 培训申请 * @return 结果 */ @@ -371,7 +445,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 修改培训申请 - * + * * @param application 培训申请 * @return 结果 */ @@ -383,7 +457,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 批量删除培训申请 - * + * * @param applicationIds 需要删除的培训申请ID数组 * @return 结果 */ @@ -403,7 +477,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 删除培训申请信息 - * + * * @param applicationId 培训申请ID * @return 结果 */ @@ -420,7 +494,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 取消培训申请 - * + * * @param applicationId 培训申请ID * @return 结果 */ @@ -445,7 +519,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 更新申请状态 - * + * * @param applicationId 培训申请ID * @param status 状态 * @return 结果 @@ -532,7 +606,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 根据培训申请创建培训记录 - * + * * @param application 培训申请 */ private void createTrainingRecordFromApplication(RsTrainingApplication application) { @@ -598,7 +672,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 审批培训申请(7级审批制度) - * + * * @param applicationId 申请ID * @param approverId 审批人ID * @param approverName 审批人姓名 @@ -696,7 +770,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 查询当前用户的待审批申请列表(动态权限方案 + 部门过滤) - * + * * @return 待审批申请列表 */ @Override @@ -760,7 +834,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 获取下一级审批级别(根据培训类型动态路由) - * + * * 7级审批制度: * 1-部门负责人 → 2a-教务处/2b-学生处/3-计划财务处(根据培训类型) * 2a-教务处 → 3-计划财务处 @@ -770,7 +844,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS * 5-业务分管领导 → 6-人事分管院领导 * 6-人事分管院领导 → 7-院长 * 7-院长 → 审批完成 - * + * * @param currentLevel 当前审批级别 * @param trainingType 培训类型 * @return 下一级审批级别 @@ -807,7 +881,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 根据审批级别获取审批环节描述 - * + * * @param approvalLevel 审批级别 * @return 审批环节描述 */ @@ -836,7 +910,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 根据当前登录用户的审批权限,获取其可审批的级别列表 - * + * * 权限到级别的映射: * - rs:training:approve1 → 审批级别 "1" (部门负责人) * - rs:training:approve2a → 审批级别 "2a" (教务处) @@ -846,7 +920,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS * - rs:training:approve5 → 审批级别 "5" (业务分管领导) * - rs:training:approve6 → 审批级别 "6" (人事分管院领导) * - rs:training:approve7 → 审批级别 "7" (院长) - * + * * @param userId 用户ID * @return 可审批的级别列表 */ @@ -889,7 +963,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS /** * 验证审批人权限级别 - * + * * @param approverId 审批人ID * @param approvalLevel 审批级别 * @return 是否有权限 @@ -915,4 +989,4 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS return hasPermission; } -} \ No newline at end of file +} diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsTrainingApplicationMapper.xml b/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsTrainingApplicationMapper.xml index 33d40c2d..702cba86 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsTrainingApplicationMapper.xml +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsTrainingApplicationMapper.xml @@ -94,10 +94,60 @@