Merge remote-tracking branch 'origin/dev-tmp1' into dev-tmp1

dev-tmp1
huwei 2026-08-28 19:16:43 +08:00
commit 15d86c176f
10 changed files with 188 additions and 60 deletions

View File

@ -61,6 +61,13 @@ public class OrgPersonnelController {
return orgPersonnelApi.page(query);
}
@ApiOperation("监管端评价师查询人员信息")
@GetMapping("/regulationPage")
public PageResponse<OrgPersonnelCO> regulationPage(@Validated OrgPersonnelPageQuery query) {
query.setEvaluatorList(true);
return orgPersonnelApi.page(query);
}
@ApiOperation("班级选择人员分页查询")
@GetMapping("/classSelect/page")
public PageResponse<ClassSelectPersonnelCO> classSelectPage(@Validated ClassSelectPersonnelPageQuery query) {

View File

@ -34,8 +34,10 @@ import org.qinan.safetyeval.infrastructure.adapter.ThreadLocalUserInfoAdapter;
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.OrgInfoDO;
import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDO;
import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDeptCountDO;
import org.qinan.safetyeval.infrastructure.mapper.OrgInfoMapper;
import org.qinan.safetyeval.infrastructure.mapper.OrgPersonnelMapper;
import org.qinan.safetyeval.infrastructure.mapper.QualFilingPersonnelCertMapper;
import org.qinan.safetyeval.infrastructure.support.UserOrgIdResolver;
@ -54,10 +56,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -122,6 +121,8 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
private boolean gbsUserSyncFailFast;
@Value("${template.personnel.import.url:}")
private String personImportTemplateUrl;
@Autowired
private OrgInfoMapper orgInfoMapper;
@Override
@ -241,21 +242,35 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
domainQuery.setPostId(query.getPostId());
domainQuery.setUserName(query.getUserName());
domainQuery.setAccount(query.getAccount());
domainQuery.setRegisterEngineerFlag(query.getRegisterEngineerFlag());
domainQuery.setEmploymentStatusCode(query.getEmploymentStatusCode());
domainQuery.setEvaluatorList(query.getEvaluatorList());
if (query.getResignAuditStatus() != null && orgResignApplyGateway != null) {
domainQuery.setPersonnelIds(orgResignApplyGateway.listPersonnelIdsByAuditStatus(
query.getResignAuditStatus(), query.getOrgId()));
}
PageResult<OrgPersonnelEntity> pageResult = orgPersonnelDomainService.page(domainQuery);
List<OrgPersonnelCO> records = pageResult.getRecords().stream()
.map(item -> orgPersonnelConvertor.toCO(item))
.collect(java.util.stream.Collectors.toList());
Map<Long, String> orgNameMap;
if (pageResult != null && !CollectionUtils.isEmpty(pageResult.getRecords())) {
List<Long> orgIds = pageResult.getRecords().stream().map(OrgPersonnelEntity::getOrgId).filter(Objects::nonNull).collect(Collectors.toList());
orgNameMap = orgInfoMapper.selectBatchIds(CollectionUtils.isEmpty(orgIds) ? Collections.singletonList(0) : orgIds).stream().collect(Collectors.toMap(OrgInfoDO::getId, OrgInfoDO::getUnitName));
} else {
orgNameMap = new HashMap<>();
}
List<OrgPersonnelCO> records = null;
if (pageResult != null) {
records = pageResult.getRecords().stream()
.map(item -> {
OrgPersonnelCO co = orgPersonnelConvertor.toCO(item);
co.setOrgName(orgNameMap.getOrDefault(item.getOrgId(), ""));
return co;
})
.collect(Collectors.toList());
}
if (orgPersonnelViewEnricher != null) {
orgPersonnelViewEnricher.enrichPersonnelBatch(records);
}
return PageResponse.of(records, pageResult.getTotal());
}

View File

@ -1,9 +1,8 @@
package org.qinan.safetyeval.app.executor.institution;
import org.qinan.safetyeval.app.executor.support.EvalProjectNodeOverviewAssembler;
import com.alibaba.fastjson2.JSON;
import org.qinan.safetyeval.client.api.institution.InstitutionDashboardApi;
import org.qinan.safetyeval.client.co.institution.EvalProjectNodeItemCO;
import org.qinan.safetyeval.client.co.institution.EvalProjectNodeOverviewCO;
import org.qinan.safetyeval.client.co.institution.ProjectNodeCO;
import org.qinan.safetyeval.client.co.institution.dashboard.InstitutionDashboardEvalTypeRatioCO;
import org.qinan.safetyeval.client.co.institution.dashboard.InstitutionDashboardIndustryStatCO;
import org.qinan.safetyeval.client.co.institution.dashboard.InstitutionDashboardNoticeCO;
@ -11,6 +10,7 @@ import org.qinan.safetyeval.client.co.institution.dashboard.InstitutionDashboard
import org.qinan.safetyeval.client.co.institution.dashboard.InstitutionDashboardProjectNodeStatsCO;
import org.qinan.safetyeval.client.dto.SingleResponse;
import org.qinan.safetyeval.domain.constant.EvalTypeEnum;
import org.qinan.safetyeval.domain.constant.ProjectStageEnum;
import org.qinan.safetyeval.domain.constant.basic.IndustryEnum;
import org.qinan.safetyeval.domain.entity.EvalCustomerEntity;
import org.qinan.safetyeval.domain.entity.EvalProjectEntity;
@ -27,11 +27,13 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
@ -47,9 +49,6 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Resource
private EvalProjectGateway evalProjectGateway;
@Resource
private EvalProjectNodeOverviewAssembler evalProjectNodeOverviewAssembler;
@Resource
private SafetyMessageGateway safetyMessageGateway;
@ -81,52 +80,19 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Override
public SingleResponse<InstitutionDashboardProjectNodeStatsCO> projectNodeStats() {
Long orgId = ThreadLocalUserInfoAdapter.getOrgId();
List<EvalProjectEntity> projects = listOrgProjects(orgId);
int total = projects.size();
int statutory = (int) projects.stream().filter(p -> Boolean.TRUE.equals(p.getIsStatutory())).count();
// 节点待办数(待办=节点状态为「未开始」)
LinkedHashMap<String, Integer> pending = new LinkedHashMap<>();
for (String code : NODE_DISPLAY.keySet()) {
pending.put(code, 0);
Long orgId = institutionOrgSupport.resolveCurrentOrgIdByUserId();
if (orgId == null) {
return SingleResponse.success(new InstitutionDashboardProjectNodeStatsCO());
}
for (EvalProjectEntity p : projects) {
try {
EvalProjectNodeOverviewCO ov = evalProjectNodeOverviewAssembler.buildForInstitution(p.getId());
if (ov == null || ov.getNodes() == null) {
continue;
}
for (EvalProjectNodeItemCO n : ov.getNodes()) {
String code = n.getNodeCode();
if (code != null && pending.containsKey(code) && "未开始".equals(n.getStatusName())) {
pending.put(code, pending.get(code) + 1);
}
}
} catch (Exception e) {
// 单项目装配异常忽略,保证其余节点统计可用
}
}
List<InstitutionDashboardProjectNodeStatsCO.NodeStat> nodeStats = new ArrayList<>();
for (Map.Entry<String, String> entry : NODE_DISPLAY.entrySet()) {
InstitutionDashboardProjectNodeStatsCO.NodeStat ns = new InstitutionDashboardProjectNodeStatsCO.NodeStat();
ns.setNodeCode(entry.getKey());
ns.setNodeName(entry.getValue());
ns.setPendingCount(pending.getOrDefault(entry.getKey(), 0));
nodeStats.add(ns);
}
int archived = (int) projects.stream().filter(p -> Boolean.TRUE.equals(p.getArchiveFlag())).count();
int delayed = (int) evalProjectGateway.countByOrgIdAndProgressStatus(orgId, "DELAY");
// 只查询统计所需最小字段id、project_node、plan_end_date、archive_flag、is_statutory
List<EvalProjectEntity> projects = evalProjectGateway.listNodeStatFieldsByOrgId(orgId);
InstitutionDashboardProjectNodeStatsCO co = new InstitutionDashboardProjectNodeStatsCO();
co.setTotalProjects(total);
co.setStatutoryProjects(statutory);
co.setNodeStats(nodeStats);
co.setArchivedProjectCount(archived);
co.setDelayedProjectCount(delayed);
co.setTotalProjects(projects.size());
co.setStatutoryProjects((int) projects.stream().filter(p -> Boolean.TRUE.equals(p.getIsStatutory())).count());
co.setArchivedProjectCount((int) projects.stream().filter(p -> Objects.equals(p.getArchiveFlag(), 1)).count());
co.setDelayedProjectCount(countDelayed(projects));
co.setNodeStats(buildNodeStats(projects));
return SingleResponse.success(co);
}
@ -249,6 +215,70 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
// ============================ 通用方法 ============================
/**
* =project_node JSON state=0
*
* @param projects
* @return 8
*/
private List<InstitutionDashboardProjectNodeStatsCO.NodeStat> buildNodeStats(List<EvalProjectEntity> projects) {
LinkedHashMap<String, Integer> pending = new LinkedHashMap<>();
for (String code : NODE_DISPLAY.keySet()) {
pending.put(code, 0);
}
for (EvalProjectEntity p : projects) {
for (ProjectNodeCO n : parseNodes(p.getProjectNode())) {
ProjectStageEnum stage = ProjectStageEnum.fromVal(n.getType());
if (stage != null && NODE_DISPLAY.containsKey(stage.getNode())
&& Integer.valueOf(0).equals(n.getState())) {
pending.put(stage.getNode(), pending.get(stage.getNode()) + 1);
}
}
}
List<InstitutionDashboardProjectNodeStatsCO.NodeStat> nodeStats = new ArrayList<>();
for (Map.Entry<String, String> entry : NODE_DISPLAY.entrySet()) {
InstitutionDashboardProjectNodeStatsCO.NodeStat ns = new InstitutionDashboardProjectNodeStatsCO.NodeStat();
ns.setNodeCode(entry.getKey());
ns.setNodeName(entry.getValue());
ns.setPendingCount(pending.getOrDefault(entry.getKey(), 0));
nodeStats.add(ns);
}
return nodeStats;
}
/**
* project_node JSON[{"type":"RISK_ANALYSIS","state":0}]/
*
* @param projectNodeJson JSON
* @return
*/
private List<ProjectNodeCO> parseNodes(String projectNodeJson) {
if (projectNodeJson == null || projectNodeJson.isEmpty()) {
return new ArrayList<>();
}
try {
List<ProjectNodeCO> nodes = JSON.parseArray(projectNodeJson, ProjectNodeCO.class);
return nodes != null ? nodes : new ArrayList<>();
} catch (Exception e) {
return new ArrayList<>();
}
}
/**
* =
*
* @param projects
* @return
*/
private int countDelayed(List<EvalProjectEntity> projects) {
LocalDate today = LocalDate.now();
return (int) projects.stream()
.filter(p -> p.getPlanEndDate() != null && p.getPlanEndDate().isBefore(today)
&& !Objects.equals(p.getArchiveFlag(), 1))
.count();
}
private List<EvalProjectEntity> listOrgProjects(Long orgId) {
EvalProjectQuery q = new EvalProjectQuery();
q.setOrgId(orgId);

View File

@ -1,5 +1,7 @@
package org.qinan.safetyeval.client.co;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.qinan.safetyeval.domain.entity.CapabilityAssessmentDTO;
@ -20,6 +22,7 @@ public class OrgPersonnelCO {
private Long id;
@ApiModelProperty(value = "部门ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long deptId;
@ApiModelProperty(value = "岗位ID")
@ -168,4 +171,9 @@ public class OrgPersonnelCO {
@ApiModelProperty(value = "租户ID")
private Long tenantId;
@ApiModelProperty(value = "人员状态: 1正常,2异常")
private Integer personnelStatus = 1;
@ApiModelProperty(value = "机构名称")
private String orgName;
}

View File

@ -22,7 +22,7 @@ public class OrgPersonnelPageQuery extends BasePageQuery {
@ApiModelProperty(value = "岗位id")
private Long postId;
@ApiModelProperty(value = "用户名称/姓名")
@ApiModelProperty(value = "用户名称/姓名/评价师名称")
private String userName;
@ApiModelProperty(value = "账号")
@ -36,4 +36,10 @@ public class OrgPersonnelPageQuery extends BasePageQuery {
@ApiModelProperty(value = "是否员工变更管理页面")
private Boolean employeeChange = false;
@ApiModelProperty(value = "是否注册安全工程师(1是2否)")
private Integer registerEngineerFlag;
@ApiModelProperty(value = "评价师列表")
private Boolean evaluatorList = false;
}

View File

@ -4,6 +4,8 @@ import org.qinan.safetyeval.domain.entity.EvalProjectEntity;
import org.qinan.safetyeval.domain.query.EvalProjectQuery;
import org.qinan.safetyeval.domain.query.PageResult;
import java.util.List;
public interface EvalProjectGateway {
EvalProjectEntity save(EvalProjectEntity entity);
@ -25,4 +27,12 @@ public interface EvalProjectGateway {
void editProjectNode(Long projectId, String val);
EvalProjectEntity findByControlledNumber(String controlledNumber);
/**
* idproject_nodeplan_end_datearchive_flagis_statutory
*
* @param orgId id
* @return
*/
List<EvalProjectEntity> listNodeStatFieldsByOrgId(Long orgId);
}

View File

@ -1,5 +1,6 @@
package org.qinan.safetyeval.domain.query;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
@ -42,4 +43,9 @@ public class OrgPersonnelQuery {
/** 人员 ID 列表(离职审核状态筛选) */
private java.util.List<Long> personnelIds;
@ApiModelProperty(value = "是否注册安全工程师(1是2否)")
private Integer registerEngineerFlag;
@ApiModelProperty(value = "评价师列表")
private Boolean evaluatorList = false;
}

View File

@ -142,6 +142,21 @@ public class EvalProjectGatewayImpl implements EvalProjectGateway {
return dataObject == null ? null : evalProjectDoConvertor.convertDoToE(dataObject);
}
@Override
public List<EvalProjectEntity> listNodeStatFieldsByOrgId(Long orgId) {
LambdaQueryWrapper<EvalProjectDO> wrapper = new LambdaQueryWrapper<>();
// 只取统计所需最小字段,减少查询与转换开销
wrapper.select(EvalProjectDO::getId, EvalProjectDO::getProjectNode, EvalProjectDO::getPlanEndDate,
EvalProjectDO::getArchiveFlag, EvalProjectDO::getIsStatutory)
.eq(EvalProjectDO::getDeleteEnum, "false");
if (orgId != null) {
wrapper.eq(EvalProjectDO::getOrgId, orgId);
}
return evalProjectMapper.selectList(wrapper).stream()
.map(evalProjectDoConvertor::convertDoToE)
.collect(Collectors.toList());
}
@Override
public void editProjectNode(Long projectId, String val) {
EvalProjectDO evalProjectDO = evalProjectMapper.selectById(projectId);

View File

@ -153,6 +153,13 @@ public class OrgPersonnelGatewayImpl implements OrgPersonnelGateway {
if (query.getEmploymentStatusCode() != null) {
wrapper.eq(OrgPersonnelDO::getEmploymentStatusCode, query.getEmploymentStatusCode());
}
if (query.getRegisterEngineerFlag() != null) {
wrapper.eq(OrgPersonnelDO::getRegisterEngineerFlag, query.getRegisterEngineerFlag());
}
if (query.getEvaluatorList()) {
// 查看有能力,专职人员
wrapper.isNotNull(OrgPersonnelDO::getCapabilityAssessment);
}
if (query.getPersonnelIds() != null) {
if (query.getPersonnelIds().isEmpty()) {
wrapper.eq(OrgPersonnelDO::getId, -1L);

View File

@ -1,6 +1,9 @@
package org.qinan.safetyeval.infrastructure.support;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.qinan.safetyeval.infrastructure.dataobject.OrgInfoDO;
import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDO;
import org.qinan.safetyeval.infrastructure.mapper.OrgInfoMapper;
import org.qinan.safetyeval.infrastructure.mapper.OrgPersonnelMapper;
import org.springframework.stereotype.Component;
@ -32,6 +35,9 @@ public class UserOrgIdResolver {
@Resource
private OrgPersonnelMapper orgPersonnelMapper;
@Resource
private OrgInfoMapper orgInfoMapper;
private final Map<Long, CacheEntry> cache = new ConcurrentHashMap<>();
/**
@ -72,7 +78,25 @@ public class UserOrgIdResolver {
private Long queryOrgIdByUserId(Long userId) {
OrgPersonnelDO personnel = orgPersonnelMapper.selectById(userId);
return personnel == null ? null : personnel.getOrgId();
if (personnel != null) {
return personnel.getOrgId();
}
// 兜底用户可能是机构注册人org_info.create_id = userId取其创建的机构
return queryOrgIdByCreator(userId);
}
/**
* id orgId
*
* @param userId idorg_info.create_id
* @return orgId null
*/
private Long queryOrgIdByCreator(Long userId) {
OrgInfoDO orgInfo = orgInfoMapper.selectOne(new LambdaQueryWrapper<OrgInfoDO>()
.select(OrgInfoDO::getId)
.eq(OrgInfoDO::getCreateId, userId)
.last("limit 1"));
return orgInfo == null ? null : orgInfo.getId();
}
private static class CacheEntry {