diff --git a/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/OrgPersonnelController.java b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/OrgPersonnelController.java index 6d9d0435..279a9ea6 100644 --- a/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/OrgPersonnelController.java +++ b/safety-eval-adapter/src/main/java/org/qinan/safetyeval/adapter/web/OrgPersonnelController.java @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import org.qinan.safetyeval.client.api.OrgPersonnelApi; import org.qinan.safetyeval.client.co.OrgPersonnelCO; +import org.qinan.safetyeval.client.co.OrgPersonnelDeptCountCO; import org.qinan.safetyeval.client.co.OrgPersonnelImportResultCO; import org.qinan.safetyeval.client.co.QualFilingPersonnelInfoCO; import org.qinan.safetyeval.client.dto.*; @@ -95,4 +96,10 @@ public class OrgPersonnelController { public SingleResponse> getOrgPersonnel() { return orgPersonnelApi.getOrgPersonnel(); } + + @ApiOperation("按部门批量统计人员数量") + @GetMapping("/deptPersonCount") + public SingleResponse> deptPersonCount() { + return orgPersonnelApi.deptPersonCount(); + } } diff --git a/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/OrgPersonnelExecutor.java b/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/OrgPersonnelExecutor.java index 8c3a94d7..60619c50 100644 --- a/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/OrgPersonnelExecutor.java +++ b/safety-eval-app/src/main/java/org/qinan/safetyeval/app/executor/OrgPersonnelExecutor.java @@ -34,6 +34,7 @@ import org.qinan.safetyeval.infrastructure.adapter.auth.AuthUserContextAdapter; import org.qinan.safetyeval.infrastructure.adapter.gbs.GbsUserFacadeClient; import org.qinan.safetyeval.infrastructure.convertor.OrgPersonnelCertConvertor; import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDO; +import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDeptCountDO; import org.qinan.safetyeval.infrastructure.mapper.OrgPersonnelMapper; import org.qinan.safetyeval.infrastructure.mapper.QualFilingPersonnelCertMapper; import org.qinan.safetyeval.infrastructure.support.UserOrgIdResolver; @@ -459,6 +460,22 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi { return SingleResponse.success(orgPersonnelCOS); } + @Override + public SingleResponse> deptPersonCount() { + Long orgId = ThreadLocalUserInfoAdapter.getOrgId(); + List rows = orgPersonnelMapper.countPersonGroupByDept(orgId); + if (CollectionUtils.isEmpty(rows)) { + return SingleResponse.success(Collections.emptyList()); + } + List list = rows.stream().map(row -> { + OrgPersonnelDeptCountCO co = new OrgPersonnelDeptCountCO(); + co.setDeptId(row.getDeptId() != null ? String.valueOf(row.getDeptId()) : null); + co.setPersonCount(row.getPersonCount() != null ? row.getPersonCount() : 0); + return co; + }).collect(Collectors.toList()); + return SingleResponse.success(list); + } + @Override public SingleResponse professionalCapabilityProofMaterialUpdate(ProfessionalCapabilityProofMaterialUpdateCmd cmd) { orgPersonnelMapper.update(new LambdaUpdateWrapper() diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/OrgPersonnelApi.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/OrgPersonnelApi.java index b77876db..290569ca 100644 --- a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/OrgPersonnelApi.java +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/api/OrgPersonnelApi.java @@ -1,6 +1,7 @@ package org.qinan.safetyeval.client.api; import org.qinan.safetyeval.client.co.OrgPersonnelCO; +import org.qinan.safetyeval.client.co.OrgPersonnelDeptCountCO; import org.qinan.safetyeval.client.co.OrgPersonnelImportResultCO; import org.qinan.safetyeval.client.co.QualFilingPersonnelInfoCO; import org.qinan.safetyeval.client.dto.*; @@ -51,6 +52,10 @@ public interface OrgPersonnelApi { SingleResponse> getOrgPersonnel(); + /** + * 按部门批量统计人员数量(直接归属,一次返回)。 + */ + SingleResponse> deptPersonCount(); SingleResponse professionalCapabilityProofMaterialUpdate(ProfessionalCapabilityProofMaterialUpdateCmd cmd); } diff --git a/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/OrgPersonnelDeptCountCO.java b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/OrgPersonnelDeptCountCO.java new file mode 100644 index 00000000..27d233a2 --- /dev/null +++ b/safety-eval-client/src/main/java/org/qinan/safetyeval/client/co/OrgPersonnelDeptCountCO.java @@ -0,0 +1,19 @@ +package org.qinan.safetyeval.client.co; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 部门人员数量统计 CO + * + * @author safety-eval + */ +@Data +public class OrgPersonnelDeptCountCO { + + @ApiModelProperty(value = "部门ID") + private String deptId; + + @ApiModelProperty(value = "人员数量(直接归属该部门)") + private Integer personCount; +} diff --git a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/exception/ErrorCode.java b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/exception/ErrorCode.java index e2cddd5e..5ad0c866 100644 --- a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/exception/ErrorCode.java +++ b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/exception/ErrorCode.java @@ -14,6 +14,7 @@ public enum ErrorCode { DATA_NOT_EXIST("01-02-101", "数据不存在"), // ---- 部门 ---- ORG_DEPARTMENT_NOT_FOUND("01-02-001", "部门不存在"), + ORG_DEPARTMENT_HAS_PERSONNEL("01-02-002", "该部门(含子部门)下存在人员,无法删除"), // ---- 装备信息 ---- ORG_EQUIPMENT_NOT_FOUND("01-03-001", "装备信息不存在"), @@ -54,6 +55,7 @@ public enum ErrorCode { ORG_POSITION_NOT_FOUND("01-08-001", "岗位不存在"), ORG_POSITION_GBS_ROLE_REQUIRED("01-08-002", "岗位关联GBS角色编码不能为空"), ORG_POSITION_GBS_ROLE_SYNC_ERROR("01-08-003", "岗位关联人员GBS角色同步失败"), + ORG_POSITION_HAS_PERSONNEL("01-08-004", "该岗位下存在人员,无法删除"), // ---- 机构资质证书 ---- ORG_QUALIFICATION_NOT_FOUND("01-09-001", "机构资质证书不存在"), diff --git a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgDepartmentGateway.java b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgDepartmentGateway.java index f810d7f8..1087409b 100644 --- a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgDepartmentGateway.java +++ b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgDepartmentGateway.java @@ -30,4 +30,9 @@ public interface OrgDepartmentGateway { * 按机构ID + 部门名称集合批量精确查询未删除部门(用于导入名称解析)。 */ List listByOrgIdAndNames(Long orgId, Collection deptNames); + + /** + * 查询部门自身及所有未删除子部门 ID(含自身)。 + */ + List listSelfAndDescendantIds(Long deptId); } diff --git a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgPersonnelGateway.java b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgPersonnelGateway.java index 6681ff91..f2693d88 100644 --- a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgPersonnelGateway.java +++ b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/gateway/OrgPersonnelGateway.java @@ -47,4 +47,14 @@ public interface OrgPersonnelGateway { * 按主键批量查询未删除人员(WPS 用户展示等)。 */ java.util.List listByIds(Collection ids); + + /** + * 指定部门集合下是否存在未删除人员(直接归属)。 + */ + boolean existsByDeptIds(Collection deptIds); + + /** + * 指定岗位下是否存在未删除人员。 + */ + boolean existsByPostId(Long postId); } diff --git a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgDepartmentDomainService.java b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgDepartmentDomainService.java index b4a396bb..89e2553d 100644 --- a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgDepartmentDomainService.java +++ b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgDepartmentDomainService.java @@ -4,6 +4,7 @@ import org.qinan.safetyeval.domain.entity.OrgDepartmentEntity; import org.qinan.safetyeval.domain.exception.BizException; import org.qinan.safetyeval.domain.exception.ErrorCode; import org.qinan.safetyeval.domain.gateway.OrgDepartmentGateway; +import org.qinan.safetyeval.domain.gateway.OrgPersonnelGateway; import org.qinan.safetyeval.domain.query.OrgDepartmentQuery; import org.qinan.safetyeval.domain.query.PageResult; @@ -23,6 +24,9 @@ public class OrgDepartmentDomainService { @Resource private OrgDepartmentGateway orgDepartmentGateway; + @Resource + private OrgPersonnelGateway orgPersonnelGateway; + public OrgDepartmentEntity add(OrgDepartmentEntity entity) { return orgDepartmentGateway.save(entity); } @@ -44,6 +48,10 @@ public class OrgDepartmentDomainService { if (existing == null) { throw new BizException(ErrorCode.ORG_DEPARTMENT_NOT_FOUND); } + List deptIds = orgDepartmentGateway.listSelfAndDescendantIds(id); + if (orgPersonnelGateway.existsByDeptIds(deptIds)) { + throw new BizException(ErrorCode.ORG_DEPARTMENT_HAS_PERSONNEL); + } orgDepartmentGateway.delete(id); } diff --git a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgPositionDomainService.java b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgPositionDomainService.java index a9027a3f..e1b01010 100644 --- a/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgPositionDomainService.java +++ b/safety-eval-domain/src/main/java/org/qinan/safetyeval/domain/service/OrgPositionDomainService.java @@ -3,6 +3,7 @@ package org.qinan.safetyeval.domain.service; import org.qinan.safetyeval.domain.entity.OrgPositionEntity; import org.qinan.safetyeval.domain.exception.BizException; import org.qinan.safetyeval.domain.exception.ErrorCode; +import org.qinan.safetyeval.domain.gateway.OrgPersonnelGateway; import org.qinan.safetyeval.domain.gateway.OrgPositionGateway; import org.qinan.safetyeval.domain.query.OrgPositionQuery; import org.qinan.safetyeval.domain.query.PageResult; @@ -21,6 +22,9 @@ public class OrgPositionDomainService { @Resource private OrgPositionGateway orgPositionGateway; + @Resource + private OrgPersonnelGateway orgPersonnelGateway; + public OrgPositionEntity add(OrgPositionEntity entity) { return orgPositionGateway.save(entity); } @@ -42,6 +46,9 @@ public class OrgPositionDomainService { if (existing == null) { throw new BizException(ErrorCode.ORG_POSITION_NOT_FOUND); } + if (orgPersonnelGateway.existsByPostId(id)) { + throw new BizException(ErrorCode.ORG_POSITION_HAS_PERSONNEL); + } orgPositionGateway.delete(id); } diff --git a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/dataobject/OrgPersonnelDeptCountDO.java b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/dataobject/OrgPersonnelDeptCountDO.java new file mode 100644 index 00000000..86bbcf83 --- /dev/null +++ b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/dataobject/OrgPersonnelDeptCountDO.java @@ -0,0 +1,16 @@ +package org.qinan.safetyeval.infrastructure.dataobject; + +import lombok.Data; + +/** + * 部门人员数量统计结果 + * + * @author safety-eval + */ +@Data +public class OrgPersonnelDeptCountDO { + + private Long deptId; + + private Integer personCount; +} diff --git a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgDepartmentGatewayImpl.java b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgDepartmentGatewayImpl.java index 9cf38afa..efe0ad50 100644 --- a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgDepartmentGatewayImpl.java +++ b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgDepartmentGatewayImpl.java @@ -15,8 +15,13 @@ import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.annotation.Resource; +import java.util.ArrayDeque; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; /** @@ -97,6 +102,49 @@ public class OrgDepartmentGatewayImpl implements OrgDepartmentGateway { .collect(Collectors.toList()); } + @Override + public List listSelfAndDescendantIds(Long deptId) { + if (deptId == null) { + return Collections.emptyList(); + } + OrgDepartmentDO root = orgDepartmentMapper.selectById(deptId); + if (root == null) { + return Collections.emptyList(); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(OrgDepartmentDO::getDeleteEnum, "false"); + if (root.getOrgId() != null) { + wrapper.eq(OrgDepartmentDO::getOrgId, root.getOrgId()); + } + wrapper.select(OrgDepartmentDO::getId, OrgDepartmentDO::getParentId); + List all = orgDepartmentMapper.selectList(wrapper); + + Map> childrenMap = new HashMap<>(); + for (OrgDepartmentDO item : all) { + if (item.getId() == null) { + continue; + } + Long parentId = item.getParentId(); + if (parentId == null) { + continue; + } + childrenMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(item.getId()); + } + + List result = new ArrayList<>(); + ArrayDeque queue = new ArrayDeque<>(); + queue.add(deptId); + while (!queue.isEmpty()) { + Long current = queue.poll(); + result.add(current); + List children = childrenMap.get(current); + if (children != null) { + queue.addAll(children); + } + } + return result; + } + private LambdaQueryWrapper buildQueryWrapper(OrgDepartmentQuery query) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(OrgDepartmentDO::getDeleteEnum, "false"); diff --git a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgPersonnelGatewayImpl.java b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgPersonnelGatewayImpl.java index 7c48e1b4..d990d8c6 100644 --- a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgPersonnelGatewayImpl.java +++ b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/gatewayimpl/OrgPersonnelGatewayImpl.java @@ -215,5 +215,29 @@ public class OrgPersonnelGatewayImpl implements OrgPersonnelGateway { return orgPersonnelDoConvertor.converDosToEes(orgPersonnelMapper.selectList(wrapper)); } + @Override + public boolean existsByDeptIds(Collection deptIds) { + if (deptIds == null || deptIds.isEmpty()) { + return false; + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(OrgPersonnelDO::getDeleteEnum, "false"); + wrapper.in(OrgPersonnelDO::getDeptId, deptIds); + wrapper.last("LIMIT 1"); + return orgPersonnelMapper.selectCount(wrapper) > 0; + } + + @Override + public boolean existsByPostId(Long postId) { + if (postId == null) { + return false; + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(OrgPersonnelDO::getDeleteEnum, "false"); + wrapper.eq(OrgPersonnelDO::getPostId, postId); + wrapper.last("LIMIT 1"); + return orgPersonnelMapper.selectCount(wrapper) > 0; + } + } diff --git a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/mapper/OrgPersonnelMapper.java b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/mapper/OrgPersonnelMapper.java index d18e556a..c6aa6953 100644 --- a/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/mapper/OrgPersonnelMapper.java +++ b/safety-eval-infrastructure/src/main/java/org/qinan/safetyeval/infrastructure/mapper/OrgPersonnelMapper.java @@ -9,6 +9,7 @@ import org.qinan.safetyeval.client.co.IndustryProfessionalPersonCo; import org.qinan.safetyeval.client.co.QualFilingPersonnelInfoCO; import org.qinan.safetyeval.client.dto.OrgFilingPersonnelPageQuery; import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDO; +import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDeptCountDO; import org.qinan.safetyeval.infrastructure.persistence.domainobject.OrgPersonnelLeaderCountDO; import java.util.List; @@ -16,6 +17,14 @@ import java.util.List; @Mapper public interface OrgPersonnelMapper extends BaseMapper { + /** + * 按部门批量统计未删除人员数量(直接归属,不含下级部门汇总) + * + * @param orgId 机构ID + * @return 各部门人员数量 + */ + List countPersonGroupByDept(@Param("orgId") Long orgId); + /** * 根据人员id列表统计技术负责人和过程控制负责人数量(按业务范围 qual_scope 分组) * diff --git a/safety-eval-infrastructure/src/main/resources/mapper/OrgPersonnelMapper.xml b/safety-eval-infrastructure/src/main/resources/mapper/OrgPersonnelMapper.xml index 380ac1ce..4a66a0dd 100644 --- a/safety-eval-infrastructure/src/main/resources/mapper/OrgPersonnelMapper.xml +++ b/safety-eval-infrastructure/src/main/resources/mapper/OrgPersonnelMapper.xml @@ -41,6 +41,16 @@ `id`, `org_id`, `dept_id`, `post_id`, `user_name`, `account`, `gender_code`, `gender_name`, `birth_date`, `id_card_no`, `current_address`, `office_address`, `education_code`, `education_name`, `graduate_school`, `major`, `employment_status_code`, `employment_status_name`, `evaluator_flag`, `delete_enum`, `remarks`, `create_name`, `update_name`, `tenant_id`, `version`, `create_time`, `update_time`, `create_id`, `update_id`, `env` + + +