yxk-20260803

改善提案-权限控制
根据菜单路由区分 mine/dept/institute:我的提案:仅本人数据,可新增、编辑草稿、删除草稿、发起流程。
部门提案:仅本人有效业务部门内已发起提案,只读查看。
全所提案:全所已发起提案;处理中记录可删除流程。

[ImprovementProposalController.java]对列表和导出强制应用范围过滤;部门范围只识别 org_type='2'、org_category='2' 的关联部门。草稿编辑、删除、发起流程也增加了创建人校验。
删除流程改用独立权限:improvementproposal:improvement_proposal:withdrawProcess。
新增全所/部门范围权限:deptView、instituteView。
This commit is contained in:
ye1023
2026-08-03 14:50:14 +08:00
parent a118d03042
commit 51a693c363
@@ -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<IPage<ImprovementProposal>> 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<ImprovementProposal> queryWrapper = QueryGenerator.initQueryWrapper(improvementProposal, req.getParameterMap());
String scope = requireProposalScope(proposalScope);
QueryWrapper<ImprovementProposal> queryWrapper = buildScopedQueryWrapper(improvementProposal, req, scope);
Page<ImprovementProposal> page = new Page<ImprovementProposal>(pageNo, pageSize);
IPage<ImprovementProposal> 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<String> 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<String> 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<ImprovementProposal> buildScopedQueryWrapper(ImprovementProposal improvementProposal,
HttpServletRequest request, String scope) {
Map<String, String[]> queryParams = new HashMap<>(request.getParameterMap());
queryParams.remove("proposalScope");
QueryWrapper<ImprovementProposal> 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<String> 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<String> handleBpmAction(BpmAction action) {
try {
action.run();
@@ -295,6 +367,7 @@ public class ImprovementProposalController {
@DeleteMapping(value = "/delete")
public Result<String> 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<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
try {
this.improvementProposalService.delBatchMain(Arrays.asList(ids.split(",")));
List<String> 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<ImprovementProposal> queryWrapper = QueryGenerator.initQueryWrapper(improvementProposal, request.getParameterMap());
String scope = requireProposalScope(request.getParameter("proposalScope"));
QueryWrapper<ImprovementProposal> queryWrapper = buildScopedQueryWrapper(improvementProposal, request, scope);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//配置选中数据查询条件