|
|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
package org.qinan.safetyeval.infrastructure.utils;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.lang.Pair;
|
|
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
|
import cn.hutool.extra.spring.SpringUtil;
|
|
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
@ -8,6 +9,7 @@ import lombok.experimental.UtilityClass;
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.qinan.safetyeval.client.co.IndustryProfessionalPersonCo;
|
|
|
|
|
import org.qinan.safetyeval.client.co.OrgPersonnelCertCapabilityComplianceCheckCO;
|
|
|
|
|
import org.qinan.safetyeval.client.co.PersonnelCertFilingCheckCO;
|
|
|
|
|
import org.qinan.safetyeval.client.co.QualFilingComplianceCheckResultCO;
|
|
|
|
|
import org.qinan.safetyeval.client.dto.*;
|
|
|
|
|
import org.qinan.safetyeval.domain.constant.*;
|
|
|
|
|
@ -191,9 +193,32 @@ public class ComplianceCheckUtil {
|
|
|
|
|
.collect(Collectors.joining(CommonUtil.COMMA));
|
|
|
|
|
throw new BizException(ErrorCode.UNKNOWN_ERROR, "人员信息不存在" + collect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setPersonnelCert(result);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* setPersonnelCert
|
|
|
|
|
*
|
|
|
|
|
* @param result result
|
|
|
|
|
*/
|
|
|
|
|
private static void setPersonnelCert(List<QualFilingPersonnelFilingCheckDTO> result) {
|
|
|
|
|
List<Long> personnelIds = result.stream()
|
|
|
|
|
.map(QualFilingPersonnelFilingCheckDTO::getId)
|
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
|
.distinct()
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
|
|
|
|
|
List<PersonnelCertFilingCheckCO> certList = SpringUtil.getBean(OrgPersonnelCertMapper.class)
|
|
|
|
|
.selectCertByPersonnelIds(personnelIds);
|
|
|
|
|
Map<Long, List<PersonnelCertFilingCheckCO>> certMap = certList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(PersonnelCertFilingCheckCO::getPersonnelId));
|
|
|
|
|
for (QualFilingPersonnelFilingCheckDTO dto : result) {
|
|
|
|
|
dto.setPersonnelCertFilingCheckCOList(certMap.getOrDefault(dto.getId(), Collections.emptyList()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将人员备案检查数据中的职称信息回填到备案人员列表。
|
|
|
|
|
*
|
|
|
|
|
@ -232,7 +257,7 @@ public class ComplianceCheckUtil {
|
|
|
|
|
boolean pass = filing.getFixedAssetAmount() != null
|
|
|
|
|
&& filing.getFixedAssetAmount() >= 800L;
|
|
|
|
|
String currentValue = filing.getFixedAssetAmount() != null
|
|
|
|
|
? filing.getFixedAssetAmount() + " 万元" : "未填写" ;
|
|
|
|
|
? filing.getFixedAssetAmount() + " 万元" : "未填写";
|
|
|
|
|
return buildResult(QualFilingComplianceCheckEnum.FIXED_AMOUNT,
|
|
|
|
|
pass ? QualFilingComplianceCheckEnum.STATUS_PASS : QualFilingComplianceCheckEnum.STATUS_FAIL,
|
|
|
|
|
currentValue);
|
|
|
|
|
@ -245,9 +270,9 @@ public class ComplianceCheckUtil {
|
|
|
|
|
boolean pass = filing.getWorkplaceArea() != null
|
|
|
|
|
&& filing.getWorkplaceArea()
|
|
|
|
|
.compareTo(new BigDecimal(QualFilingComplianceCheckEnum.WORKPLACE_LOWER)) >= 0;
|
|
|
|
|
String workplace = filing.getWorkplaceArea() != null ? filing.getWorkplaceArea().toPlainString() : "未填写" ;
|
|
|
|
|
String archive = filing.getArchiveRoomArea() != null ? filing.getArchiveRoomArea().toPlainString() : "未填写" ;
|
|
|
|
|
String currentValue = "工作场所 " + workplace + " 平方米,档案室 " + archive + " 平方米" ;
|
|
|
|
|
String workplace = filing.getWorkplaceArea() != null ? filing.getWorkplaceArea().toPlainString() : "未填写";
|
|
|
|
|
String archive = filing.getArchiveRoomArea() != null ? filing.getArchiveRoomArea().toPlainString() : "未填写";
|
|
|
|
|
String currentValue = "工作场所 " + workplace + " 平方米,档案室 " + archive + " 平方米";
|
|
|
|
|
return buildResult(QualFilingComplianceCheckEnum.WORKPLACE,
|
|
|
|
|
pass ? QualFilingComplianceCheckEnum.STATUS_PASS : QualFilingComplianceCheckEnum.STATUS_FAIL,
|
|
|
|
|
currentValue);
|
|
|
|
|
@ -260,7 +285,7 @@ public class ComplianceCheckUtil {
|
|
|
|
|
int scopeCount = filing.getBusinessScope() != null ? filing.getBusinessScope().size() : 0;
|
|
|
|
|
int total = personnelList == null ? 0 : personnelList.size();
|
|
|
|
|
boolean pass = total >= QualFilingComplianceCheckEnum.PERSONNEL_COUNT_LOWER + (scopeCount - 1) * 5;
|
|
|
|
|
String currentValue = scopeCount + " 个业务范围," + total + " 人" ;
|
|
|
|
|
String currentValue = scopeCount + " 个业务范围," + total + " 人";
|
|
|
|
|
return buildResult(QualFilingComplianceCheckEnum.PERSONNEL_COUNT,
|
|
|
|
|
pass ? QualFilingComplianceCheckEnum.STATUS_PASS : QualFilingComplianceCheckEnum.STATUS_FAIL,
|
|
|
|
|
currentValue);
|
|
|
|
|
@ -277,16 +302,22 @@ public class ComplianceCheckUtil {
|
|
|
|
|
QualFilingComplianceCheckEnum.STATUS_FAIL, "无人员数据");
|
|
|
|
|
}
|
|
|
|
|
int total = personnelList.size();
|
|
|
|
|
String code = CertTypeCodeEnum.REGISTERED_SAFETY_ENGINEER.getCode();
|
|
|
|
|
|
|
|
|
|
// 中/高 级注册安全工程师
|
|
|
|
|
Set<Long> engineerSet = personnelCertCoList.stream()
|
|
|
|
|
// .filter(p -> CertTypeCodeEnum.REGISTERED_SAFETY_ENGINEER
|
|
|
|
|
// .getCode().equals(p.getCertTypeCode()) && !CertLevelEnum.JUNIOR.getCode().equals(p.getCertLevel()))
|
|
|
|
|
.map(QualFilingPersonnelFilingCheckDTO::getId)
|
|
|
|
|
.flatMap(it -> it.getPersonnelCertFilingCheckCOList().stream())
|
|
|
|
|
.filter(it -> code.equals(it.getCertTypeCode()))
|
|
|
|
|
.map(PersonnelCertFilingCheckCO::getPersonnelId)
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
|
|
// 高级职称人员
|
|
|
|
|
Set<Long> seniorTitleSet = personnelList.stream()
|
|
|
|
|
.filter(p -> p.getTitleCodeArr() != null && p.getTitleCodeArr().stream()
|
|
|
|
|
.anyMatch(t -> QualificationLevelEnum.SENIOR.getCode().equals(t.getTitleCode())))
|
|
|
|
|
.map(QualFilingPersonnelAddCmd::getSourcePersonnelId)
|
|
|
|
|
.collect(Collectors.toSet());
|
|
|
|
|
|
|
|
|
|
long engineerRate = engineerSet.size() * 100L / total;
|
|
|
|
|
long seniorTitleRate = seniorTitleSet.size() * 100L / total;
|
|
|
|
|
engineerSet.addAll(seniorTitleSet);
|
|
|
|
|
@ -294,24 +325,14 @@ public class ComplianceCheckUtil {
|
|
|
|
|
boolean pass = engineerRate >= QualFilingComplianceCheckEnum.PERSONNEL_RATE
|
|
|
|
|
&& seniorTitleRate >= QualFilingComplianceCheckEnum.PERSONNEL_RATE
|
|
|
|
|
&& sumRate >= 60;
|
|
|
|
|
String currentValue = "注册安工程师 " + engineerRate + "%,高级职称 " + seniorTitleRate + "%,合计 " + sumRate + "%" ;
|
|
|
|
|
String currentValue = "注册安工程师 " + engineerRate + "%,高级职称 " + seniorTitleRate + "%,合计 " + sumRate + "%";
|
|
|
|
|
if (!pass && throwException) {
|
|
|
|
|
throw new BizException(PERSON_NOT_ENOUGH, currentValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据人员id查询专业能力code并设置到CO中
|
|
|
|
|
List<Long> sourcePersonnelIds = personnelList.stream()
|
|
|
|
|
.map(QualFilingPersonnelAddCmd::getSourcePersonnelId)
|
|
|
|
|
.distinct()
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
List<IndustryProfessionalPersonCo> personnelCoList = SpringUtil.getBean(OrgPersonnelMapper.class)
|
|
|
|
|
.selectProfessionalCapabilityByPersonnelIds(sourcePersonnelIds);
|
|
|
|
|
Pair<Boolean, String> booleanStringPair = industryProfessionalStandardsValid(
|
|
|
|
|
businessScope, personnelCoList, null);
|
|
|
|
|
|
|
|
|
|
/*Pair<Boolean, String> booleanStringPair = industryProfessionalStandardsValid(
|
|
|
|
|
businessScope, personnelCoList, personnelCertCoList);*/
|
|
|
|
|
|
|
|
|
|
// 安全评价机构业务范围与专业能力配备标准 校验
|
|
|
|
|
Pair<Boolean, String> booleanStringPair =
|
|
|
|
|
industryProfessionalStandardsPersonValid(businessScope, personnelCertCoList);
|
|
|
|
|
boolean personPassed = Boolean.TRUE.equals(booleanStringPair.getKey());
|
|
|
|
|
if (!personPassed && throwException) {
|
|
|
|
|
throw new BizException(PERSON_NOT_ENOUGH, booleanStringPair.getValue());
|
|
|
|
|
@ -375,7 +396,7 @@ public class ComplianceCheckUtil {
|
|
|
|
|
if (industryEnum != null) {
|
|
|
|
|
scope = industryEnum.getValue();
|
|
|
|
|
} else {
|
|
|
|
|
scope = "未知行业范围" ;
|
|
|
|
|
scope = "未知行业范围";
|
|
|
|
|
}
|
|
|
|
|
currentValue.append("业务[").append(scope).append("] 技术负责人 ")
|
|
|
|
|
.append(technicalDirectorCount).append("/1,过程控制负责人 ")
|
|
|
|
|
@ -413,7 +434,7 @@ public class ComplianceCheckUtil {
|
|
|
|
|
&& m.getUploadStatusCode() == QualFilingMaterialUploadStatusEnum.UPLOADED.getCode()
|
|
|
|
|
&& m.getMaterialType() != null
|
|
|
|
|
&& m.getMaterialType() == MaterialTypeEnum.NO_VIOLATION_RECORD.getCode());
|
|
|
|
|
String currentValue = hasRecord ? "未命中重大违法失信记录" : "命中重大违法失信记录" ;
|
|
|
|
|
String currentValue = hasRecord ? "未命中重大违法失信记录" : "命中重大违法失信记录";
|
|
|
|
|
return buildResult(QualFilingComplianceCheckEnum.CREDIT_RECORD,
|
|
|
|
|
hasRecord ? QualFilingComplianceCheckEnum.STATUS_PASS : QualFilingComplianceCheckEnum.STATUS_FAIL,
|
|
|
|
|
currentValue);
|
|
|
|
|
@ -439,19 +460,15 @@ public class ComplianceCheckUtil {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* industryProfessionalStandardsValid
|
|
|
|
|
* 安全评价机构业务范围与专业能力配备标准 校验
|
|
|
|
|
*
|
|
|
|
|
* @param industryCodeList industryCodeList
|
|
|
|
|
* @param personnelCoList industryProfessionalPersonCos
|
|
|
|
|
* @param personnelCertCoList certCapabilityList
|
|
|
|
|
* @return Pair<Boolean, String> key 是否通过 ,value 失败消息(通过时为 null)
|
|
|
|
|
*/
|
|
|
|
|
public static Pair<Boolean, String> industryProfessionalStandardsValid(List<String> industryCodeList
|
|
|
|
|
, List<IndustryProfessionalPersonCo> personnelCoList
|
|
|
|
|
, List<OrgPersonnelCertCapabilityComplianceCheckCO> personnelCertCoList) {
|
|
|
|
|
if (CollectionUtils.isEmpty(industryCodeList)) {
|
|
|
|
|
return Pair.of(false, "没有业务范围");
|
|
|
|
|
}
|
|
|
|
|
public static Pair<Boolean, String> industryProfessionalStandardsPersonValid(List<String> industryCodeList
|
|
|
|
|
, List<QualFilingPersonnelFilingCheckDTO> personnelCertCoList) {
|
|
|
|
|
|
|
|
|
|
// 通过 SpringUtil 获取 Mapper,根据 industryCodeList 查询专业能力配备标准
|
|
|
|
|
IndustryProfessionalStandardsMapper mapper = SpringUtil.getBean(IndustryProfessionalStandardsMapper.class);
|
|
|
|
|
LambdaQueryWrapper<IndustryProfessionalStandardsDO> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
@ -460,29 +477,145 @@ public class ComplianceCheckUtil {
|
|
|
|
|
List<IndustryProfessionalStandardsDO> standardsDOList = mapper.selectList(queryWrapper);
|
|
|
|
|
|
|
|
|
|
if (CollectionUtils.isEmpty(standardsDOList)) {
|
|
|
|
|
log.warn("没有配置标准");
|
|
|
|
|
return Pair.of(true, null);
|
|
|
|
|
log.warn("务范围与专业能力配备标准未开启");
|
|
|
|
|
return Pair.of(false, "务范围与专业能力配备标准未开启");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 按 industryCode 分组后循环调用 doIndustryProfessionalStandardsValid
|
|
|
|
|
Map<String, List<IndustryProfessionalStandardsDO>> standardsGroupByIndustry = standardsDOList.stream()
|
|
|
|
|
.collect(Collectors.groupingBy(IndustryProfessionalStandardsDO::getIndustryCode));
|
|
|
|
|
String notExistIndustryCodeList = industryCodeList.stream().filter(it -> !standardsGroupByIndustry.containsKey(it))
|
|
|
|
|
.map(IndustryEnum::getValueByCode)
|
|
|
|
|
.collect(Collectors.joining(CommonUtil.COMMA));
|
|
|
|
|
if (StrUtil.isNotBlank(notExistIndustryCodeList)) {
|
|
|
|
|
return Pair.of(false, "务范围 " + notExistIndustryCodeList + "与专业能力配备标准未开启");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<IndustryProfessionalPersonCo> personnelCoCopyList = new ArrayList<>(personnelCoList);
|
|
|
|
|
|
|
|
|
|
Map<String, List<OrgPersonnelCertCapabilityComplianceCheckCO>> personnelCertCoGroupByIndustry =
|
|
|
|
|
personnelCertCoList.stream().collect(
|
|
|
|
|
Collectors.groupingBy(OrgPersonnelCertCapabilityComplianceCheckCO::getBusinessScope));
|
|
|
|
|
return doIndustryProfessionalStandardsValid(standardsGroupByIndustry, personnelCertCoList);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StringJoiner failureMsg = new StringJoiner(";");
|
|
|
|
|
for (Map.Entry<String, List<IndustryProfessionalStandardsDO>> entry : standardsGroupByIndustry.entrySet()) {
|
|
|
|
|
Pair<Boolean, String> result = doIndustryProfessionalStandardsValid(entry.getValue(), personnelCoCopyList
|
|
|
|
|
, personnelCertCoGroupByIndustry.getOrDefault(entry.getKey(), new ArrayList<>()));
|
|
|
|
|
if (Boolean.FALSE.equals(result.getKey()) && result.getValue() != null) {
|
|
|
|
|
failureMsg.add(result.getValue());
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 安全评价机构业务范围与专业能力配备标准 校验
|
|
|
|
|
* <p>
|
|
|
|
|
* 核心约束:一人只能代表一个专业,申请多个业务范围时人员不能重复计算。
|
|
|
|
|
* 分两阶段校验:
|
|
|
|
|
* <ul>
|
|
|
|
|
* <li>阶段一(逐行业计数):逐个行业检查所需要的能力人员是否充足,不足即记录错误并提前返回。</li>
|
|
|
|
|
* <li>阶段二(全局最优分配):所有行业都通过后,使用最大流算法(Dinic)在
|
|
|
|
|
* "一人一专业、多业务范围不重复计算" 的约束下,判断是否存在全局分配方案满足所有需求。</li>
|
|
|
|
|
* </ul>
|
|
|
|
|
*
|
|
|
|
|
* @param standardsGroupByIndustryMap 是标准的行业要求 枚举类 IndustryEnum
|
|
|
|
|
* @param personnelCertCoList 人员的能力在 capabilityAssessment.professionalCapabilityCode
|
|
|
|
|
* @return Pair<Boolean, String> key 是否通过 ,value 失败消息(通过时为 null)
|
|
|
|
|
*/
|
|
|
|
|
public static Pair<Boolean, String> doIndustryProfessionalStandardsValid(
|
|
|
|
|
Map<String, List<IndustryProfessionalStandardsDO>> standardsGroupByIndustryMap
|
|
|
|
|
, List<QualFilingPersonnelFilingCheckDTO> personnelCertCoList) {
|
|
|
|
|
|
|
|
|
|
// 1. 收集人员 → 具备的专业能力code集合(来源于能力认定)
|
|
|
|
|
Map<Long, Set<String>> personCapabilityMap = personnelCertCoList.stream()
|
|
|
|
|
.filter(p -> !CollectionUtils.isEmpty(p.getCapabilityAssessment()))
|
|
|
|
|
.collect(Collectors.toMap(
|
|
|
|
|
QualFilingPersonnelFilingCheckDTO::getId,
|
|
|
|
|
p -> p.getCapabilityAssessment().stream()
|
|
|
|
|
.map(CapabilityAssessmentDTO::getProfessionalCapabilityCode)
|
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
|
.collect(Collectors.toSet()),
|
|
|
|
|
(a, b) -> a));
|
|
|
|
|
|
|
|
|
|
StringBuilder failureMsg = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
// 2. 阶段一:逐行业简单计数校验(行业内本身人员是否充足),不通过直接返回
|
|
|
|
|
for (Map.Entry<String, List<IndustryProfessionalStandardsDO>> entry : standardsGroupByIndustryMap.entrySet()) {
|
|
|
|
|
appendPhaseOneFailures(entry.getKey(), entry.getValue(), personCapabilityMap, failureMsg);
|
|
|
|
|
}
|
|
|
|
|
if (failureMsg.length() > 0) {
|
|
|
|
|
return Pair.of(false, failureMsg.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 阶段二:全局最优分配校验(一人一专业,多业务范围不重复计算)
|
|
|
|
|
// 构建需求(复合键 industryCode::capCode)和 能力→需求键 映射
|
|
|
|
|
Map<String, Long> demandMap = new LinkedHashMap<>();
|
|
|
|
|
Map<String, List<String>> capToDemandKeys = new HashMap<>();
|
|
|
|
|
for (Map.Entry<String, List<IndustryProfessionalStandardsDO>> entry : standardsGroupByIndustryMap.entrySet()) {
|
|
|
|
|
String industryCode = entry.getKey();
|
|
|
|
|
for (IndustryProfessionalStandardsDO standard : entry.getValue()) {
|
|
|
|
|
String capCode = standard.getProfessionalCapabilityCode();
|
|
|
|
|
String demandKey = industryCode + "::" + capCode;
|
|
|
|
|
demandMap.put(demandKey, standard.getPersonNum() == null ? 0L : standard.getPersonNum());
|
|
|
|
|
capToDemandKeys.computeIfAbsent(capCode, k -> new ArrayList<>()).add(demandKey);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return failureMsg.length() > 1 ? Pair.of(false, failureMsg.toString()) : Pair.of(true, null);
|
|
|
|
|
|
|
|
|
|
// 构建人员 → 需求键集合
|
|
|
|
|
Map<Long, Set<String>> personDemandMap = new HashMap<>();
|
|
|
|
|
for (Map.Entry<Long, Set<String>> entry : personCapabilityMap.entrySet()) {
|
|
|
|
|
Set<String> demandKeys = new HashSet<>();
|
|
|
|
|
for (String cap : entry.getValue()) {
|
|
|
|
|
List<String> keys = capToDemandKeys.get(cap);
|
|
|
|
|
if (keys != null) {
|
|
|
|
|
demandKeys.addAll(keys);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!demandKeys.isEmpty()) {
|
|
|
|
|
personDemandMap.put(entry.getKey(), demandKeys);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Map<String, Long> assignedMap = canFullyAssign(personDemandMap, demandMap);
|
|
|
|
|
|
|
|
|
|
// 比对分配结果,生成失败明细
|
|
|
|
|
for (Map.Entry<String, List<IndustryProfessionalStandardsDO>> entry : standardsGroupByIndustryMap.entrySet()) {
|
|
|
|
|
String industryCode = entry.getKey();
|
|
|
|
|
for (IndustryProfessionalStandardsDO standard : entry.getValue()) {
|
|
|
|
|
String capCode = standard.getProfessionalCapabilityCode();
|
|
|
|
|
long required = standard.getPersonNum() == null ? 0L : standard.getPersonNum();
|
|
|
|
|
long assigned = assignedMap.getOrDefault(industryCode + "::" + capCode, 0L);
|
|
|
|
|
appendIfShort(industryCode, capCode, required, assigned, failureMsg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return failureMsg.length() > 0 ? Pair.of(false, failureMsg.toString()) : Pair.of(true, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 阶段一:统计某项专业能力的可用人数(具备该能力的人员总数),不足则追加失败明细
|
|
|
|
|
*/
|
|
|
|
|
private static void appendPhaseOneFailures(String industryCode, List<IndustryProfessionalStandardsDO> standards
|
|
|
|
|
, Map<Long, Set<String>> personCapabilityMap, StringBuilder failureMsg) {
|
|
|
|
|
String industryName = IndustryEnum.getValueByCode(industryCode);
|
|
|
|
|
for (IndustryProfessionalStandardsDO standard : standards) {
|
|
|
|
|
String capCode = standard.getProfessionalCapabilityCode();
|
|
|
|
|
long required = standard.getPersonNum() == null ? 0L : standard.getPersonNum();
|
|
|
|
|
long available = personCapabilityMap.values().stream()
|
|
|
|
|
.filter(caps -> caps.contains(capCode))
|
|
|
|
|
.count();
|
|
|
|
|
appendIfShort(industryName, capCode, required, available, failureMsg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 当实际人数小于需求时,追加一条失败明细
|
|
|
|
|
*/
|
|
|
|
|
private static void appendIfShort(String industryOrCode, String capCode, long required
|
|
|
|
|
, long available, StringBuilder failureMsg) {
|
|
|
|
|
if (available >= required) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
IndustryEnum industryEnum = IndustryEnum.ofCode(industryOrCode);
|
|
|
|
|
String industryName = industryEnum != null ? industryEnum.getValue() : industryOrCode;
|
|
|
|
|
ProfessionalCapabilityEnum capEnum = ProfessionalCapabilityEnum.ofCode(capCode);
|
|
|
|
|
String capName = capEnum != null ? capEnum.getValue() : capCode;
|
|
|
|
|
failureMsg.append(industryName)
|
|
|
|
|
.append(CommonUtil.COLON)
|
|
|
|
|
.append(capName)
|
|
|
|
|
.append(" 需要")
|
|
|
|
|
.append(required)
|
|
|
|
|
.append("人,当前可用")
|
|
|
|
|
.append(available)
|
|
|
|
|
.append("人;");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|