feat: 支持审批步骤绑定部门与多对象
- 新增审批对象关联表和存量数据迁移 - 支持用户、角色、部门多选及办理权限匹配 - 完善部门状态与批量管理交互
This commit is contained in:
@@ -1,27 +1,38 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.approval.entity.ApprovalFlowScope;
|
||||
import tech.easyflow.approval.entity.ApprovalFlowStepAssignee;
|
||||
import tech.easyflow.approval.enums.ApprovalAssigneeType;
|
||||
import tech.easyflow.approval.enums.ApprovalScopeType;
|
||||
import tech.easyflow.approval.mapper.ApprovalFlowScopeMapper;
|
||||
import tech.easyflow.approval.mapper.ApprovalFlowStepAssigneeMapper;
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.constant.enums.EnumDataStatus;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.entity.SysAccount;
|
||||
import tech.easyflow.system.entity.SysDept;
|
||||
import tech.easyflow.system.service.SysAccountService;
|
||||
import tech.easyflow.system.service.SysDeptService;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 部门表 控制层。
|
||||
@@ -33,18 +44,47 @@ import java.util.List;
|
||||
@RequestMapping("/api/v1/sysDept")
|
||||
public class SysDeptController extends BaseCurdController<SysDeptService, SysDept> {
|
||||
|
||||
@Resource
|
||||
private SysAccountService sysAccountService;
|
||||
private final SysAccountService sysAccountService;
|
||||
private final ApprovalFlowStepAssigneeMapper approvalFlowStepAssigneeMapper;
|
||||
private final ApprovalFlowScopeMapper approvalFlowScopeMapper;
|
||||
|
||||
public SysDeptController(SysDeptService service) {
|
||||
/**
|
||||
* 创建部门管理控制器。
|
||||
*
|
||||
* @param service 部门服务
|
||||
* @param sysAccountService 用户服务
|
||||
* @param approvalFlowStepAssigneeMapper 审批步骤对象 Mapper
|
||||
* @param approvalFlowScopeMapper 审批范围 Mapper
|
||||
*/
|
||||
public SysDeptController(SysDeptService service,
|
||||
SysAccountService sysAccountService,
|
||||
ApprovalFlowStepAssigneeMapper approvalFlowStepAssigneeMapper,
|
||||
ApprovalFlowScopeMapper approvalFlowScopeMapper) {
|
||||
super(service);
|
||||
this.sysAccountService = sysAccountService;
|
||||
this.approvalFlowStepAssigneeMapper = approvalFlowStepAssigneeMapper;
|
||||
this.approvalFlowScopeMapper = approvalFlowScopeMapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取部门列表默认排序规则。
|
||||
*
|
||||
* @return 默认排序表达式
|
||||
*/
|
||||
@Override
|
||||
protected String getDefaultOrderBy() {
|
||||
return "sort_no asc";
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询部门列表并组装为树形结构。
|
||||
*
|
||||
* @param entity 查询条件
|
||||
* @param asTree 是否返回树形结构
|
||||
* @param sortKey 排序字段
|
||||
* @param sortType 排序方向
|
||||
* @return 部门树
|
||||
*/
|
||||
@Override
|
||||
@GetMapping("list")
|
||||
public Result<List<SysDept>> list(SysDept entity, Boolean asTree, String sortKey, String sortType) {
|
||||
@@ -54,9 +94,64 @@ public class SysDeptController extends BaseCurdController<SysDeptService, SysDep
|
||||
return Result.ok(Tree.tryToTree(sysMenus, "id", "parentId"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量修改部门状态。
|
||||
*
|
||||
* @param ids 部门主键集合
|
||||
* @param status 目标状态
|
||||
* @return 实际更新数量
|
||||
*/
|
||||
@PostMapping("changeStatusBatch")
|
||||
@SaCheckPermission("/api/v1/sysDept/save")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Result<Integer> changeStatusBatch(
|
||||
@JsonBody(value = "ids", required = true) List<BigInteger> ids,
|
||||
@JsonBody(value = "status", required = true) Integer status) {
|
||||
Set<BigInteger> uniqueIds = normalizeIds(ids);
|
||||
if (uniqueIds.isEmpty()) {
|
||||
return Result.fail("请选择需要操作的部门", null);
|
||||
}
|
||||
if (!EnumDataStatus.AVAILABLE.getCode().equals(status)
|
||||
&& !EnumDataStatus.UNAVAILABLE.getCode().equals(status)) {
|
||||
return Result.fail("部门状态不合法", null);
|
||||
}
|
||||
|
||||
List<SysDept> records = service.listByIds(uniqueIds);
|
||||
if (records.size() != uniqueIds.size()) {
|
||||
return Result.fail("部分部门不存在或已删除,请刷新后重试", null);
|
||||
}
|
||||
if (EnumDataStatus.UNAVAILABLE.getCode().equals(status) && containsRootDept(records)) {
|
||||
return Result.fail("根部门不能禁用", null);
|
||||
}
|
||||
if (EnumDataStatus.UNAVAILABLE.getCode().equals(status)
|
||||
&& isUsedByApprovalFlow(uniqueIds)) {
|
||||
return Result.fail("所选部门已被审批流程使用,不能禁用", null);
|
||||
}
|
||||
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
SysDept update = new SysDept();
|
||||
update.setStatus(status);
|
||||
update.setModified(new Date());
|
||||
update.setModifiedBy(loginUser.getId());
|
||||
|
||||
QueryWrapper updateWrapper = QueryWrapper.create();
|
||||
updateWrapper.in(SysDept::getId, uniqueIds);
|
||||
int updated = service.getMapper().updateByQuery(update, updateWrapper);
|
||||
if (updated <= 0) {
|
||||
return Result.fail("部门状态修改失败", null);
|
||||
}
|
||||
return Result.ok(updated);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysDept entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave && entity.getStatus() == null) {
|
||||
entity.setStatus(EnumDataStatus.AVAILABLE.getCode());
|
||||
}
|
||||
BigInteger parentId = entity.getParentId();
|
||||
if (parentId.equals(BigInteger.ZERO)) {
|
||||
entity.setAncestors(parentId.toString());
|
||||
@@ -65,7 +160,7 @@ public class SysDeptController extends BaseCurdController<SysDeptService, SysDep
|
||||
entity.setAncestors(parent.getAncestors() + "," + parentId);
|
||||
}
|
||||
if (isSave) {
|
||||
commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
|
||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
@@ -73,20 +168,87 @@ public class SysDeptController extends BaseCurdController<SysDeptService, SysDep
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
List<SysDept> records = service.listByIds(ids);
|
||||
for (SysDept dept : records) {
|
||||
if (Constants.ROOT_DEPT.equals(dept.getDeptCode())) {
|
||||
return Result.fail(1, "无法删除根部门");
|
||||
}
|
||||
if (records.size() != ids.size()) {
|
||||
return Result.fail(1, "部分部门不存在或已删除,请刷新后重试");
|
||||
}
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.in(SysAccount::getDeptId, ids);
|
||||
long count = sysAccountService.count(w);
|
||||
if (containsRootDept(records)) {
|
||||
return Result.fail(1, "无法删除根部门");
|
||||
}
|
||||
|
||||
QueryWrapper childQuery = QueryWrapper.create();
|
||||
childQuery.in(SysDept::getParentId, ids);
|
||||
childQuery.notIn(SysDept::getId, ids);
|
||||
if (service.count(childQuery) > 0) {
|
||||
return Result.fail(1, "所选部门包含未选中的下级部门,不能删除");
|
||||
}
|
||||
if (isUsedByApprovalFlow(ids)) {
|
||||
return Result.fail(1, "所选部门已被审批流程使用,请先调整审批配置");
|
||||
}
|
||||
|
||||
QueryWrapper accountQuery = QueryWrapper.create();
|
||||
accountQuery.in(SysAccount::getDeptId, ids);
|
||||
long count = sysAccountService.count(accountQuery);
|
||||
if (count > 0) {
|
||||
return Result.fail(1, "该部门下有员工,不能删除");
|
||||
return Result.fail(1, "所选部门下有员工,不能删除");
|
||||
}
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 去重并过滤无效部门主键。
|
||||
*
|
||||
* @param ids 原始部门主键集合
|
||||
* @return 有效且去重后的主键集合
|
||||
*/
|
||||
private Set<BigInteger> normalizeIds(Collection<BigInteger> ids) {
|
||||
Set<BigInteger> uniqueIds = new LinkedHashSet<>();
|
||||
if (ids == null) {
|
||||
return uniqueIds;
|
||||
}
|
||||
for (BigInteger id : ids) {
|
||||
if (id != null) {
|
||||
uniqueIds.add(id);
|
||||
}
|
||||
}
|
||||
return uniqueIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断部门集合中是否包含根部门。
|
||||
*
|
||||
* @param records 部门集合
|
||||
* @return 包含根部门时返回 {@code true}
|
||||
*/
|
||||
private boolean containsRootDept(Collection<SysDept> records) {
|
||||
return records.stream()
|
||||
.anyMatch(dept -> Constants.ROOT_DEPT.equals(dept.getDeptCode()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断部门是否仍被审批步骤或审批范围引用。
|
||||
*
|
||||
* @param ids 部门主键集合
|
||||
* @return 存在审批流程引用时返回 {@code true}
|
||||
*/
|
||||
private boolean isUsedByApprovalFlow(Collection<? extends Serializable> ids) {
|
||||
QueryWrapper assigneeQuery = QueryWrapper.create();
|
||||
assigneeQuery.eq(
|
||||
ApprovalFlowStepAssignee::getAssigneeType,
|
||||
ApprovalAssigneeType.DEPT.getCode());
|
||||
assigneeQuery.in(ApprovalFlowStepAssignee::getTargetId, ids);
|
||||
if (approvalFlowStepAssigneeMapper.selectCountByQuery(assigneeQuery) > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QueryWrapper scopeQuery = QueryWrapper.create();
|
||||
scopeQuery.eq(ApprovalFlowScope::getScopeType, ApprovalScopeType.DEPT.getCode());
|
||||
scopeQuery.in(ApprovalFlowScope::getScopeValue, ids);
|
||||
return approvalFlowScopeMapper.selectCountByQuery(scopeQuery) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user