From 138b3e4d1fe1cb52765f53ffb3585597b8fa2815 Mon Sep 17 00:00:00 2001 From: weizhong Date: Tue, 26 Aug 2025 00:46:38 +0800 Subject: [PATCH] =?UTF-8?q?=E2=80=9C=E4=BA=BA=E4=BA=8B=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E6=9B=B4=E6=96=B0weiz=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RsOverseasRecordController.java | 4 +- .../RsTrainingApplicationController.java | 186 +++++++++---- .../RsTrainingRecordController.java | 26 +- .../mapper/RsTrainingApplicationMapper.java | 14 + .../RsOverseasApplicationServiceImpl.java | 2 +- .../impl/RsOverseasApprovalServiceImpl.java | 37 ++- .../RsTrainingApplicationServiceImpl.java | 95 +++++-- .../impl/RsTrainingApprovalServiceImpl.java | 30 +- .../mapper/rs/RsOverseasRecordMapper.xml | 4 +- .../mapper/rs/RsTrainingApplicationMapper.xml | 14 +- docs/需求文档/人事管理/培训管理需求.md | 42 +-- web/src/api/rs/training.ts | 72 +---- web/src/views/rs/index.vue | 2 +- web/src/views/rs/overseas/approval.vue | 12 +- web/src/views/rs/overseas/index.vue | 38 ++- web/src/views/rs/overseasApproval/index.vue | 2 + web/src/views/rs/training/index.vue | 263 +++++++++--------- web/src/views/rs/trainingApproval/index.vue | 29 +- 18 files changed, 542 insertions(+), 330 deletions(-) diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsOverseasRecordController.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsOverseasRecordController.java index 0d37cb73..f95d4cf0 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsOverseasRecordController.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsOverseasRecordController.java @@ -118,7 +118,7 @@ public class RsOverseasRecordController extends BaseController { /** * 基于申请信息创建出国记录 */ - @SaCheckPermission("rs:overseas:create") + @SaCheckPermission("rs:overseas:add") @Log(title = "创建出国记录", businessType = BusinessType.INSERT) @PostMapping("/create/{applicationId}") public R createFromApplication(@NotNull(message = "申请ID不能为空") @PathVariable Long applicationId) { @@ -128,7 +128,7 @@ public class RsOverseasRecordController extends BaseController { /** * 更新出国记录完成状态 */ - @SaCheckPermission("rs:overseas:complete") + @SaCheckPermission("rs:overseas:edit") @Log(title = "更新出国记录完成状态", businessType = BusinessType.UPDATE) @PutMapping("/complete") public R updateCompletion(@RequestBody CompletionRequest request) { diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingApplicationController.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingApplicationController.java index f99313a0..3ecb90ed 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingApplicationController.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingApplicationController.java @@ -23,6 +23,11 @@ import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.stp.StpUtil; import jakarta.servlet.http.HttpServletResponse; +// 新增导入 +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.service.ISysUserService; +import org.dromara.common.core.utils.StringUtils; + /** * 培训申请控制器 * @@ -37,6 +42,10 @@ public class RsTrainingApplicationController extends BaseController { @Autowired private IRsTrainingApplicationService trainingApplicationService; + + // 新增用户服务注入 + @Autowired + private ISysUserService sysUserService; /** * 查询培训申请列表 @@ -67,6 +76,114 @@ public class RsTrainingApplicationController extends BaseController { return R.ok(trainingApplicationService.selectRsTrainingApplicationById(applicationId)); } + /** + * 获取当前登录用户的真实信息 + * + * @return 用户信息对象,包含用户ID和真实姓名 + */ + private UserInfo getCurrentUserInfo() { + try { + // 获取用户ID,处理可能的字符串格式 + Object loginId = StpUtil.getLoginId(); + Long userId = null; + + if (loginId != null) { + if (loginId instanceof Long) { + userId = (Long) loginId; + } else if (loginId instanceof String) { + String loginIdStr = (String) loginId; + // 处理 "sys_user:1" 这种格式,提取数字部分 + if (loginIdStr.contains(":")) { + String[] parts = loginIdStr.split(":"); + if (parts.length > 1) { + try { + userId = Long.parseLong(parts[1]); + } catch (NumberFormatException e) { + log.warn("无法解析用户ID字符串: {}", loginIdStr); + } + } + } else { + try { + userId = Long.parseLong(loginIdStr); + } catch (NumberFormatException e) { + log.warn("无法解析用户ID字符串: {}", loginIdStr); + } + } + } else if (loginId instanceof Number) { + userId = ((Number) loginId).longValue(); + } + } + + if (userId != null) { + log.info("获取当前登录用户信息: userId={}", userId); + + // 从系统用户表获取用户真实信息 + SysUserVo userVo = sysUserService.selectUserById(userId); + if (userVo != null) { + String nickName = userVo.getNickName(); + String userName = userVo.getUserName(); + + log.info("成功获取用户信息: userId={}, nickName={}, userName={}", userId, nickName, userName); + + // 使用用户名(根据前端要求) + String displayName = StringUtils.isNotBlank(userName) ? userName : "用户" + userId; + return new UserInfo(userId, displayName); + } else { + log.warn("未找到用户信息: userId={}", userId); + } + } else { + log.warn("获取登录用户ID失败或格式不正确: loginId={}", loginId); + } + } catch (Exception e) { + log.error("获取用户信息异常: loginId={}, error={}", StpUtil.getLoginId(), e.getMessage(), e); + } + + // 如果获取失败,尝试从Sa-Token获取基本信息 + try { + Object fallbackLoginId = StpUtil.getLoginId(); + if (fallbackLoginId != null) { + log.warn("使用备用方案获取用户信息: loginId={}", fallbackLoginId); + // 尝试提取数字ID + if (fallbackLoginId instanceof String) { + String loginIdStr = (String) fallbackLoginId; + if (loginIdStr.contains(":")) { + String[] parts = loginIdStr.split(":"); + if (parts.length > 1) { + try { + Long fallbackUserId = Long.parseLong(parts[1]); + return new UserInfo(fallbackUserId, "用户" + fallbackUserId); + } catch (NumberFormatException e) { + log.warn("备用方案也无法解析用户ID: {}", loginIdStr); + } + } + } + } + } + } catch (Exception e) { + log.error("备用方案也失败: {}", e.getMessage(), e); + } + + // 最后的备用方案 + log.error("所有用户信息获取方案都失败,返回默认值"); + return new UserInfo(1L, "系统用户"); + } + + /** + * 用户信息内部类 + */ + private static class UserInfo { + private final Long userId; + private final String userName; + + public UserInfo(Long userId, String userName) { + this.userId = userId; + this.userName = StringUtils.isNotBlank(userName) ? userName : "用户" + userId; + } + + public Long getUserId() { return userId; } + public String getUserName() { return userName; } + } + /** * 新增培训申请 */ @@ -76,30 +193,10 @@ public class RsTrainingApplicationController extends BaseController { @PostMapping public R add(@Validated @RequestBody RsTrainingApplication application) { try { - // 尝试设置申请人为当前登录用户 - String loginId = StpUtil.getLoginIdAsString(); - if (loginId != null && loginId.startsWith("sys_user:")) { - // 从"sys_user:1"格式中提取数字部分 - String[] parts = loginId.split(":"); - if (parts.length > 1) { - application.setUserId(Long.parseLong(parts[1])); - application.setUserName("用户" + parts[1]); // 临时用户名 - } else { - // 如果无法解析,使用默认值 - application.setUserId(1L); - application.setUserName("默认用户"); - } - } else { - // 尝试正常转换 - try { - application.setUserId(StpUtil.getLoginIdAsLong()); - application.setUserName(loginId); - } catch (Exception e) { - // 转换失败,使用默认值 - application.setUserId(1L); - application.setUserName("默认用户"); - } - } + // 获取当前登录用户的真实信息 + UserInfo userInfo = getCurrentUserInfo(); + application.setUserId(userInfo.getUserId()); + application.setUserName(userInfo.getUserName()); // 确保courseId的类型正确 if (application.getCourseId() == null) { @@ -144,7 +241,7 @@ public class RsTrainingApplicationController extends BaseController { /** * 取消培训申请 */ - @SaCheckPermission("rs:trainingapplication:edit") + @SaCheckPermission("rs:trainingapplication:cancel") @Log(title = "培训申请", businessType = BusinessType.UPDATE) @PutMapping("/cancel/{applicationId}") public R cancel(@PathVariable("applicationId") Long applicationId) { @@ -154,7 +251,7 @@ public class RsTrainingApplicationController extends BaseController { /** * 查询我的培训申请列表 */ - @SaCheckPermission("rs:trainingapplication:query") + @SaCheckPermission("rs:trainingapplication:list") @GetMapping("/my") public TableDataInfo listMyApplications(RsTrainingApplication application, PageQuery pageQuery) { return trainingApplicationService.selectPageMyApplications(StpUtil.getLoginIdAsLong(), application, pageQuery); @@ -170,39 +267,18 @@ public class RsTrainingApplicationController extends BaseController { } /** - * 新增培训申请(无需权限验证,供普通用户使用) + * 新增培训申请(供普通用户使用) */ - @SaIgnore + @SaCheckPermission("rs:trainingapplication:submit") @Log(title = "培训申请", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping("/submit") public R submit(@Validated @RequestBody RsTrainingApplication application) { try { - // 尝试设置申请人为当前登录用户,如果未登录则使用默认值 - try { - String loginId = StpUtil.getLoginIdAsString(); - if (loginId != null && loginId.startsWith("sys_user:")) { - // 从"sys_user:1"格式中提取数字部分 - String[] parts = loginId.split(":"); - if (parts.length > 1) { - application.setUserId(Long.parseLong(parts[1])); - application.setUserName("用户" + parts[1]); // 临时用户名 - } else { - // 如果无法解析,使用默认值 - application.setUserId(1L); - application.setUserName("默认用户"); - } - } else { - // 尝试正常转换 - application.setUserId(StpUtil.getLoginIdAsLong()); - application.setUserName(loginId); - } - } catch (Exception e) { - // 如果未登录或转换失败,使用默认值 - application.setUserId(1L); - application.setUserName("默认用户"); - log.info("用户未登录,使用默认用户信息"); - } + // 获取当前登录用户的真实信息 + UserInfo userInfo = getCurrentUserInfo(); + application.setUserId(userInfo.getUserId()); + application.setUserName(userInfo.getUserName()); // 确保courseId的类型正确 if (application.getCourseId() == null) { @@ -226,7 +302,7 @@ public class RsTrainingApplicationController extends BaseController { /** * 更新培训申请状态 */ - @SaCheckPermission("rs:trainingapplication:edit") + @SaCheckPermission("rs:trainingapplication:process") @Log(title = "培训申请状态", businessType = BusinessType.UPDATE) @PutMapping("/status/{applicationId}/{status}") public R updateStatus( @@ -239,7 +315,7 @@ public class RsTrainingApplicationController extends BaseController { /** * 重新提交被拒绝的培训申请 */ - @SaCheckPermission("rs:trainingapplication:edit") + @SaCheckPermission("rs:trainingapplication:submit") @Log(title = "重新提交培训申请", businessType = BusinessType.UPDATE) @RepeatSubmit() @PutMapping("/resubmit/{applicationId}") diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingRecordController.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingRecordController.java index 7dea5797..923eed17 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingRecordController.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/controller/RsTrainingRecordController.java @@ -45,7 +45,7 @@ public class RsTrainingRecordController extends BaseController { /** * 查询培训记录列表 */ - @SaCheckPermission("rs:training:record:list") + @SaCheckPermission("rs:trainingrecord:list") @GetMapping("/list") public TableDataInfo list(RsTrainingRecord record, PageQuery pageQuery) { return trainingRecordService.selectPageRsTrainingRecordList(record, pageQuery); @@ -54,7 +54,7 @@ public class RsTrainingRecordController extends BaseController { /** * 导出培训记录列表 */ - @SaCheckPermission("rs:training:record:export") + @SaCheckPermission("rs:trainingrecord:export") @Log(title = "培训记录", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(HttpServletResponse response, RsTrainingRecord record) { @@ -65,7 +65,7 @@ public class RsTrainingRecordController extends BaseController { /** * 获取培训记录详细信息 */ - @SaCheckPermission("rs:training:record:query") + @SaCheckPermission("rs:trainingrecord:query") @GetMapping("/{recordId}") public R getInfo(@PathVariable("recordId") Long recordId) { return R.ok(trainingRecordService.selectRsTrainingRecordById(recordId)); @@ -74,7 +74,7 @@ public class RsTrainingRecordController extends BaseController { /** * 新增培训记录 */ - @SaCheckPermission("rs:training:record:add") + @SaCheckPermission("rs:trainingrecord:add") @Log(title = "培训记录", businessType = BusinessType.INSERT) @RepeatSubmit() @PostMapping @@ -85,7 +85,7 @@ public class RsTrainingRecordController extends BaseController { /** * 修改培训记录 */ - @SaCheckPermission("rs:training:record:edit") + @SaCheckPermission("rs:trainingrecord:edit") @Log(title = "培训记录", businessType = BusinessType.UPDATE) @RepeatSubmit() @PutMapping @@ -96,7 +96,7 @@ public class RsTrainingRecordController extends BaseController { /** * 删除培训记录 */ - @SaCheckPermission("rs:training:record:remove") + @SaCheckPermission("rs:trainingrecord:remove") @Log(title = "培训记录", businessType = BusinessType.DELETE) @DeleteMapping("/{recordIds}") public R remove(@PathVariable Long[] recordIds) { @@ -106,7 +106,7 @@ public class RsTrainingRecordController extends BaseController { /** * 修复培训记录中缺失的课程信息 */ - @SaCheckPermission("rs:training:record:edit") + @SaCheckPermission("rs:trainingrecord:edit") @Log(title = "培训记录", businessType = BusinessType.UPDATE) @PostMapping("/fixCourseInfo") public R fixCourseInfo() { @@ -118,7 +118,7 @@ public class RsTrainingRecordController extends BaseController { /** * 查询我的培训记录列表 */ - @SaCheckPermission("rs:training:record:query") + @SaCheckPermission("rs:trainingrecord:query") @GetMapping("/my") public TableDataInfo listMyRecords(RsTrainingRecord record, PageQuery pageQuery) { return trainingRecordService.selectPageMyRecords(StpUtil.getLoginIdAsLong(), record, pageQuery); @@ -127,7 +127,7 @@ public class RsTrainingRecordController extends BaseController { /** * 更新培训记录完成状态 */ - @SaCheckPermission("rs:training:record:edit") + @SaCheckPermission("rs:trainingrecord:edit") @Log(title = "培训记录", businessType = BusinessType.UPDATE) @PutMapping("/status/{recordId}/{status}") public R updateCompletionStatus(@PathVariable("recordId") Long recordId, @PathVariable("status") String status) { @@ -137,7 +137,7 @@ public class RsTrainingRecordController extends BaseController { /** * 上传培训证书 */ - @SaCheckPermission("rs:training:record:edit") + @SaCheckPermission("rs:trainingrecord:edit") @Log(title = "培训记录", businessType = BusinessType.UPDATE) @PutMapping("/certificate/{recordId}") public R uploadCertificate(@PathVariable("recordId") Long recordId, @RequestBody Map params) { @@ -149,7 +149,7 @@ public class RsTrainingRecordController extends BaseController { /** * 上传培训证书文件 */ - @SaCheckPermission("rs:training:record:edit") + @SaCheckPermission("rs:trainingrecord:edit") @Log(title = "上传培训证书文件", businessType = BusinessType.UPDATE) @PostMapping("/certificate/upload/{recordId}") public R> uploadCertificateFile(@PathVariable Long recordId, @RequestParam("file") MultipartFile file) throws IOException { @@ -196,7 +196,7 @@ public class RsTrainingRecordController extends BaseController { /** * 获取培训统计数据 */ - @SaCheckPermission("rs:training:record:list") + @SaCheckPermission("rs:trainingrecord:list") @GetMapping("/statistics") public R> getStatistics() { // 这里可以实现培训统计数据的获取逻辑 @@ -207,7 +207,7 @@ public class RsTrainingRecordController extends BaseController { /** * 更新培训记录的证书附件ID */ - @SaCheckPermission("rs:training:record:edit") + @SaCheckPermission("rs:trainingrecord:edit") @Log(title = "更新培训记录证书附件", businessType = BusinessType.UPDATE) @PutMapping("/attachments/{recordId}") public R updateAttachments(@PathVariable Long recordId, @RequestBody Map params) { diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/mapper/RsTrainingApplicationMapper.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/mapper/RsTrainingApplicationMapper.java index 3d508efc..ac1bb059 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/mapper/RsTrainingApplicationMapper.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/mapper/RsTrainingApplicationMapper.java @@ -2,6 +2,8 @@ package org.dromara.rs.mapper; import org.dromara.rs.domain.RsTrainingApplication; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.common.mybatis.annotation.DataColumn; +import org.dromara.common.mybatis.annotation.DataPermission; import org.apache.ibatis.annotations.Param; import java.util.List; @@ -20,6 +22,10 @@ public interface RsTrainingApplicationMapper extends BaseMapperPlus selectRsTrainingApplicationList(RsTrainingApplication application); /** @@ -30,6 +36,10 @@ public interface RsTrainingApplicationMapper extends BaseMapperPlus selectRsTrainingApplicationListPage(@Param("app") RsTrainingApplication app, @Param("offset") long offset, @Param("limit") long limit); /** @@ -38,5 +48,9 @@ public interface RsTrainingApplicationMapper extends BaseMapperPlus buildQueryWrapper(RsOverseasApprovalQuery query) { LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + + // ===== 业务逻辑层权限过滤 ===== + // 根据用户角色进行数据权限过滤 + if (!LoginHelper.isSuperAdmin()) { + // 获取当前登录用户信息 + Long currentUserId = LoginHelper.getUserId(); + + // 检查用户角色并应用相应的数据过滤 + if (StpUtil.hasRole("rs-Applicant")) { + // 申请人只能看到与自己相关的审批记录 + lqw.exists("SELECT 1 FROM rs_overseas_application app WHERE app.application_id = rs_overseas_approval.application_id AND app.applicant_id = " + currentUserId); + } else if (StpUtil.hasRole("rs-admin")) { + // 人事管理员可以看到所有审批记录 + // 不设置额外过滤条件,让管理员能看到所有审批 + } else { + // 默认情况:只能看到自己创建或处理的审批 + lqw.and(wrapper -> wrapper.eq(RsOverseasApproval::getCreateBy, currentUserId) + .or().eq(RsOverseasApproval::getApproverId, currentUserId)); + } + } + + // 添加租户过滤 + lqw.eq(RsOverseasApproval::getTenantId, LoginHelper.getTenantId()); + lqw.eq(query.getApplicationId() != null, RsOverseasApproval::getApplicationId, query.getApplicationId()); lqw.eq(query.getApproverId() != null, RsOverseasApproval::getApproverId, query.getApproverId()); lqw.like(StringUtils.isNotBlank(query.getApproverName()), RsOverseasApproval::getApproverName, query.getApproverName()); lqw.eq(StringUtils.isNotBlank(query.getApprovalLevel()), RsOverseasApproval::getApprovalLevel, query.getApprovalLevel()); - // 如果指定了审批状态,使用指定的状态;否则只查询已完成审批的记录(排除待审核状态) + // 如果指定了审批状态,使用指定的状态;对于管理员,显示所有状态 if (StringUtils.isNotBlank(query.getApprovalStatus())) { lqw.eq(RsOverseasApproval::getApprovalStatus, query.getApprovalStatus()); - } else { - // 默认只查询已完成审批的记录:1-通过,2-拒绝(排除0-待审核) + } else if (!LoginHelper.isSuperAdmin() && !StpUtil.hasRole("rs-admin")) { + // 非管理员默认只查询已完成审批的记录:1-通过,2-拒绝(排除0-待审核) lqw.in(RsOverseasApproval::getApprovalStatus, "1", "2"); } + // 管理员和超级管理员可以看到所有状态的审批记录 lqw.ge(query.getApprovalTimeBegin() != null, RsOverseasApproval::getApprovalTime, query.getApprovalTimeBegin()); lqw.le(query.getApprovalTimeEnd() != null, RsOverseasApproval::getApprovalTime, query.getApprovalTimeEnd()); @@ -220,7 +247,7 @@ public class RsOverseasApprovalServiceImpl implements IRsOverseasApprovalService try { // 1. 清理现有测试数据(谨慎操作,只清理测试租户数据) baseMapper.delete(new LambdaQueryWrapper() - .eq(RsOverseasApproval::getTenantId, "000000") + .eq(RsOverseasApproval::getTenantId, LoginHelper.getTenantId()) .eq(RsOverseasApproval::getDeleted, "0")); // 2. 创建并插入标准测试数据 @@ -265,7 +292,7 @@ public class RsOverseasApprovalServiceImpl implements IRsOverseasApprovalService approval.setApprovalStatus(approvalStatuses[i]); approval.setApprovalOpinion(opinions[i]); approval.setApprovalTime(Date.from(LocalDateTime.now().minusDays(i + 1).atZone(ZoneId.systemDefault()).toInstant())); - approval.setTenantId("000000"); + approval.setTenantId(LoginHelper.getTenantId()); approval.setDeleted("0"); approval.setCreateBy(1L); approval.setCreateTime(Date.from(LocalDateTime.now().minusDays(i + 1).atZone(ZoneId.systemDefault()).toInstant())); 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 518a19f9..ba5482a7 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 @@ -1,5 +1,6 @@ package org.dromara.rs.service.impl; +import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -10,6 +11,7 @@ import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.satoken.utils.LoginHelper; import org.dromara.rs.domain.RsTrainingApplication; import org.dromara.rs.domain.RsTrainingRecord; import org.dromara.rs.domain.bo.RsTrainingApplicationBo; @@ -62,9 +64,30 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS // 计算偏移量 long offset = (current - 1) * size; - // 设置租户ID + // 设置租户ID - 使用当前登录用户的租户ID if (application.getTenantId() == null || application.getTenantId().isEmpty()) { - application.setTenantId("000000"); + application.setTenantId(LoginHelper.getTenantId()); + } + + // ===== 业务逻辑层权限过滤 ===== + // 根据用户角色进行数据权限过滤 + if (!LoginHelper.isSuperAdmin()) { + // 获取当前登录用户信息 + Long currentUserId = LoginHelper.getUserId(); + Long currentDeptId = LoginHelper.getDeptId(); + String username = LoginHelper.getUsername(); + + // 检查用户角色并应用相应的数据过滤 + if (StpUtil.hasRole("rs-Applicant")) { + // 申请人只能看到自己的申请 + application.setUserId(currentUserId); + } else if (StpUtil.hasRole("rs-admin")) { + // 人事管理员可以看到所有申请(包括审批和部门管理功能) + // 不设置额外过滤条件,让管理员能看到所有申请 + } else { + // 默认情况:只能看到自己创建的申请 + application.setCreateBy(currentUserId); + } } // 查询总数 @@ -95,6 +118,26 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS */ @Override public List selectRsTrainingApplicationList(RsTrainingApplication application) { + // ===== 业务逻辑层权限过滤 ===== + // 根据用户角色进行数据权限过滤 + if (!LoginHelper.isSuperAdmin()) { + // 获取当前登录用户信息 + Long currentUserId = LoginHelper.getUserId(); + Long currentDeptId = LoginHelper.getDeptId(); + + // 检查用户角色并应用相应的数据过滤 + if (StpUtil.hasRole("rs-Applicant")) { + // 申请人只能看到自己的申请 + application.setUserId(currentUserId); + } else if (StpUtil.hasRole("rs-admin")) { + // 人事管理员可以看到所有申请(包括审批和部门管理功能) + // 不设置额外过滤条件,让管理员能看到所有申请 + } else { + // 默认情况:只能看到自己创建的申请 + application.setCreateBy(currentUserId); + } + } + // 使用自定义的Mapper方法查询,已经关联了课程表获取课程名称 List list = trainingApplicationMapper.selectRsTrainingApplicationList(application); @@ -143,9 +186,10 @@ 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"); + // 移除硬编码状态过滤,让管理员能看到所有状态的申请 + // 原注释:排除已审批完成的数据:1-已通过,3-进行中,4-已完成 + // 原注释:只保留:0-待审核,2-已拒绝 + // 修复:移除 lqw.notIn(RsTrainingApplication::getStatus, "1", "3", "4") 限制 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()); @@ -166,6 +210,34 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS // 使用自定义的Mapper方法查询,已经关联了课程表获取课程名称 RsTrainingApplication application = trainingApplicationMapper.selectRsTrainingApplicationById(applicationId); + // ===== 业务逻辑层权限过滤 ===== + // 检查当前用户是否有权限查看此申请 + if (application != null && !LoginHelper.isSuperAdmin()) { + Long currentUserId = LoginHelper.getUserId(); + Long currentDeptId = LoginHelper.getDeptId(); + + boolean hasPermission = false; + + // 检查用户角色权限 + if (StpUtil.hasRole("rs-Applicant")) { + // 申请人只能查看自己的申请 + hasPermission = application.getUserId().equals(currentUserId); + } else if (StpUtil.hasRole("rs-admin")) { + // 人事管理员可以查看所有申请 + hasPermission = true; + } else { + // 默认情况:只能查看自己创建的申请 + hasPermission = application.getCreateBy() != null && + application.getCreateBy().equals(currentUserId); + } + + // 如果没有权限,返回null + if (!hasPermission) { + log.warn("用户 {} 尝试访问无权限的培训申请: {}", currentUserId, applicationId); + return null; + } + } + // 处理自定义培训课程(courseId=0)的情况 if (application != null && application.getCourseId() != null && application.getCourseId() == 0 && (application.getCourseName() == null || application.getCourseName().isEmpty())) { @@ -189,15 +261,6 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS application.setApplicationId(System.currentTimeMillis()); } - // 设置默认值,防止空指针异常 - if (application.getUserId() == null) { - application.setUserId(1L); // 默认用户ID - } - - if (application.getUserName() == null || application.getUserName().isEmpty()) { - application.setUserName("默认用户"); - } - // 处理自定义培训课程的情况(courseId = 0 或 null) // 确保courseName不为空 if (application.getCourseName() == null || application.getCourseName().isEmpty()) { @@ -207,7 +270,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS application.setCreateTime(now); application.setApplyTime(now); application.setStatus("0"); // 待审核状态 - application.setTenantId("000000"); // 设置默认租户ID + application.setTenantId(LoginHelper.getTenantId()); // 设置当前用户租户ID return trainingApplicationMapper.insert(application); // 以上代码已处理所有情况 @@ -420,7 +483,7 @@ public class RsTrainingApplicationServiceImpl implements IRsTrainingApplicationS record.setUpdateTime(now); // 设置租户和用户信息 - record.setTenantId(application.getTenantId() != null ? application.getTenantId() : "000000"); + record.setTenantId(application.getTenantId() != null ? application.getTenantId() : LoginHelper.getTenantId()); record.setCreateBy(application.getUserId()); // 创建者设为申请人 record.setUpdateBy(application.getUserId()); // 更新者设为申请人 record.setCreateDept(application.getCreateDept() != null ? application.getCreateDept() : 1L); // 使用createDept,如果没有则设为默认值 diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApprovalServiceImpl.java b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApprovalServiceImpl.java index 308c1f46..eb8b103b 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApprovalServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/java/org/dromara/rs/service/impl/RsTrainingApprovalServiceImpl.java @@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import cn.dev33.satoken.stp.StpUtil; import org.dromara.rs.mapper.RsTrainingApprovalMapper; import org.dromara.rs.mapper.RsTrainingApplicationMapper; import org.dromara.rs.domain.RsTrainingApproval; @@ -65,6 +66,31 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService */ private LambdaQueryWrapper buildQueryWrapper(RsTrainingApproval approval) { LambdaQueryWrapper lqw = new LambdaQueryWrapper<>(); + + // ===== 业务逻辑层权限过滤 ===== + // 根据用户角色进行数据权限过滤 + if (!LoginHelper.isSuperAdmin()) { + // 获取当前登录用户信息 + Long currentUserId = LoginHelper.getUserId(); + + // 检查用户角色并应用相应的数据过滤 + if (StpUtil.hasRole("rs-Applicant")) { + // 申请人只能看到与自己相关的审批记录 + // 这里需要通过申请表关联查询 + lqw.exists("SELECT 1 FROM rs_training_application app WHERE app.application_id = rs_training_approval.application_id AND app.user_id = " + currentUserId); + } else if (StpUtil.hasRole("rs-admin")) { + // 人事管理员可以看到所有审批记录 + // 不设置额外过滤条件,让管理员能看到所有审批 + } else { + // 默认情况:只能看到自己创建或处理的审批 + lqw.and(wrapper -> wrapper.eq(RsTrainingApproval::getCreateBy, currentUserId) + .or().eq(RsTrainingApproval::getApproverId, currentUserId)); + } + } + + // 添加租户过滤 + lqw.eq(RsTrainingApproval::getTenantId, LoginHelper.getTenantId()); + lqw.eq(approval.getApplicationId() != null, RsTrainingApproval::getApplicationId, approval.getApplicationId()); lqw.eq(approval.getApproverId() != null, RsTrainingApproval::getApproverId, approval.getApproverId()); lqw.eq(approval.getApprovalLevel() != null, RsTrainingApproval::getApprovalLevel, approval.getApprovalLevel()); @@ -158,9 +184,9 @@ public class RsTrainingApprovalServiceImpl implements IRsTrainingApprovalService // 计算偏移量 long offset = (current - 1) * size; - // 设置租户ID + // 设置租户ID - 使用当前登录用户的租户ID if (approval.getTenantId() == null || approval.getTenantId().isEmpty()) { - approval.setTenantId("000000"); + approval.setTenantId(LoginHelper.getTenantId()); } // 查询总数 diff --git a/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsOverseasRecordMapper.xml b/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsOverseasRecordMapper.xml index a12f3e98..f5ee6f0b 100644 --- a/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsOverseasRecordMapper.xml +++ b/backend/ruoyi-modules/ruoyi-rs/src/main/resources/mapper/rs/RsOverseasRecordMapper.xml @@ -88,9 +88,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" select 1 from rs_overseas_record ors where ors.application_id = oa.application_id and ors.deleted = '0' - and ors.tenant_id = '000000' + and ors.tenant_id = #{tenantId} ) - and oa.tenant_id = '000000' + and oa.tenant_id = #{tenantId} - - - AND a.status NOT IN ('1', '3', '4') + + + + and a.course_id = #{courseId} and a.user_id = #{userId} and a.user_name like concat('%', #{userName}, '%') @@ -66,9 +67,10 @@