diff --git a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java index e4780b9..90dc855 100644 --- a/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java +++ b/jeecg-module-supervision/src/main/java/org/jeecg/modules/improvementproposal/controller/ImprovementProposalController.java @@ -21,6 +21,7 @@ import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; import org.jeecg.common.system.vo.LoginUser; import org.apache.shiro.SecurityUtils; import org.jeecg.common.api.vo.Result; +import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.query.QueryRuleEnum; import org.jeecg.common.util.oConvertUtils; @@ -63,6 +64,11 @@ import org.apache.shiro.authz.annotation.RequiresPermissions; @RequestMapping("/improvementproposal/improvementProposal") @Slf4j public class ImprovementProposalController { + private static final String PROPOSAL_SCOPE_MINE = "mine"; + private static final String PROPOSAL_SCOPE_DEPT = "dept"; + private static final String PROPOSAL_SCOPE_INSTITUTE = "institute"; + private static final String DEPT_VIEW_PERMISSION = "improvementproposal:improvement_proposal:deptView"; + private static final String INSTITUTE_VIEW_PERMISSION = "improvementproposal:improvement_proposal:instituteView"; @Autowired private IImprovementProposalService improvementProposalService; @Autowired @@ -85,8 +91,10 @@ public class ImprovementProposalController { public Result> queryPageList(ImprovementProposal improvementProposal, @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, + @RequestParam(name="proposalScope", required=false) String proposalScope, HttpServletRequest req) { - QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(improvementProposal, req.getParameterMap()); + String scope = requireProposalScope(proposalScope); + QueryWrapper queryWrapper = buildScopedQueryWrapper(improvementProposal, req, scope); Page page = new Page(pageNo, pageSize); IPage pageList = improvementProposalService.page(page, queryWrapper); return Result.OK(pageList); @@ -140,6 +148,7 @@ public class ImprovementProposalController { @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST}) public Result edit(@RequestBody ImprovementProposalPage improvementProposalPage) { try { + requireDraftOwner(improvementProposalPage.getId()); ImprovementProposal improvementProposal = new ImprovementProposal(); BeanUtils.copyProperties(improvementProposalPage, improvementProposal); improvementProposalService.updateMain(improvementProposal, improvementProposalPage.getImprovementDeptScoreList(),improvementProposalPage.getImprovementInstituteVoteList()); @@ -164,6 +173,7 @@ public class ImprovementProposalController { } LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); try { + requireDraftOwner(id); String processInstanceId = improvementProposalService.startProcess(id, sysUser.getUsername()); return Result.OK("流程发起成功!", processInstanceId); } catch (IllegalStateException e) { @@ -176,7 +186,7 @@ public class ImprovementProposalController { */ @AutoLog(value = "改善提案-删除流程并回退草稿") @Operation(summary = "改善提案-删除流程并回退草稿") - @RequiresPermissions("improvementproposal:improvement_proposal:delete") + @RequiresPermissions("improvementproposal:improvement_proposal:withdrawProcess") @PostMapping(value = "/withdrawProcess") public Result withdrawProcess(@RequestParam(name = "id") String id) { try { @@ -269,6 +279,68 @@ public class ImprovementProposalController { return (LoginUser) SecurityUtils.getSubject().getPrincipal(); } + /** + * 台账范围由菜单路由传入,但最终必须在服务端按功能权限确认,避免通过修改请求参数扩大查询范围。 + */ + private String requireProposalScope(String proposalScope) { + String scope = oConvertUtils.isEmpty(proposalScope) ? PROPOSAL_SCOPE_MINE : proposalScope; + if (PROPOSAL_SCOPE_MINE.equals(scope)) { + return scope; + } + if (PROPOSAL_SCOPE_DEPT.equals(scope) + && SecurityUtils.getSubject().isPermitted(DEPT_VIEW_PERMISSION)) { + return scope; + } + if (PROPOSAL_SCOPE_INSTITUTE.equals(scope) + && SecurityUtils.getSubject().isPermitted(INSTITUTE_VIEW_PERMISSION)) { + return scope; + } + throw new JeecgBootException("无权访问该改善提案台账范围"); + } + + /** + * 生成台账查询条件。部门范围使用提案业务部门,而不是 sys_org_code, + * 以适配同一用户归属多个业务部门的场景。 + */ + private QueryWrapper buildScopedQueryWrapper(ImprovementProposal improvementProposal, + HttpServletRequest request, String scope) { + Map queryParams = new HashMap<>(request.getParameterMap()); + queryParams.remove("proposalScope"); + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(improvementProposal, queryParams); + LoginUser loginUser = currentUser(); + if (PROPOSAL_SCOPE_MINE.equals(scope)) { + queryWrapper.eq("create_by", loginUser.getUsername()); + return queryWrapper; + } + + // 部门和全所台账只呈现已发起过流程的提案,草稿仍只在“我的提案”维护。 + queryWrapper.ne("bpm_status", "1"); + if (PROPOSAL_SCOPE_DEPT.equals(scope)) { + List departmentIds = improvementProposalService.getMyProposalDepartments(loginUser).stream() + .map(ImprovementProposalDepartmentDTO::getId) + .collect(Collectors.toList()); + if (departmentIds.isEmpty()) { + queryWrapper.apply("1 = 0"); + } else { + queryWrapper.in("proposal_dept_id", departmentIds); + } + } + return queryWrapper; + } + + /** + * 草稿维护接口只允许创建人调用;列表范围只是界面入口,不能替代写操作的服务端校验。 + */ + private void requireDraftOwner(String id) { + ImprovementProposal proposal = improvementProposalService.getById(id); + if (proposal == null) { + throw new IllegalStateException("未找到对应提案"); + } + if (!currentUser().getUsername().equals(proposal.getCreateBy())) { + throw new IllegalStateException("仅提案创建人可以维护草稿"); + } + } + private Result handleBpmAction(BpmAction action) { try { action.run(); @@ -295,6 +367,7 @@ public class ImprovementProposalController { @DeleteMapping(value = "/delete") public Result delete(@RequestParam(name="id",required=true) String id) { try { + requireDraftOwner(id); improvementProposalService.delMain(id); return Result.OK("删除成功!"); } catch (IllegalStateException e) { @@ -314,7 +387,11 @@ public class ImprovementProposalController { @DeleteMapping(value = "/deleteBatch") public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) { try { - this.improvementProposalService.delBatchMain(Arrays.asList(ids.split(","))); + List idList = Arrays.asList(ids.split(",")); + for (String id : idList) { + requireDraftOwner(id); + } + this.improvementProposalService.delBatchMain(idList); return Result.OK("批量删除成功!"); } catch (IllegalStateException e) { return Result.error(e.getMessage()); @@ -385,7 +462,8 @@ public class ImprovementProposalController { public ModelAndView exportXls(HttpServletRequest request, ImprovementProposal improvementProposal) { // Step.1 组装查询条件查询数据 - QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(improvementProposal, request.getParameterMap()); + String scope = requireProposalScope(request.getParameter("proposalScope")); + QueryWrapper queryWrapper = buildScopedQueryWrapper(improvementProposal, request, scope); LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); //配置选中数据查询条件