Эх сурвалжийг харах

feat(hr): 优化职级计算逻辑并新增字段支持

- 在 FormConstant 中新增 NCKD_ALIAS 和 NCKD_ISPARTICIPATE 常量
- 重构 JobLevelCalculatorService 中的查询方法,移除冗余参数
- 新增 getJobLevelByJobSeqAndQualAndScore 方法用于更精确的职级匹配
- 修改 queryJobLevels 查询条件,增加对 NCKD_ISPARTICIPATE 字段的过滤
- 调整绩效管理保存验证逻辑,改进人员映射结构为分组方式
- 优化多个方法中的判空和数据处理逻辑,提升代码健壮性
wyc 5 цаг өмнө
parent
commit
de7f351994

+ 4 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java

@@ -423,5 +423,9 @@ public class FormConstant {
 
     /** 变动操作 */
     public static final String AFFACTION_KEY = "affaction";
+    /** 别名 */
+    public static final String NCKD_ALIAS = "nckd_alias";
+    /** 别名 */
+    public static final String NCKD_ISPARTICIPATE = "nckd_isparticipate";
 
 }

+ 91 - 31
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/JobLevelCalculatorService.java

@@ -35,6 +35,7 @@ import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.time.LocalDateTime;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -1624,8 +1625,7 @@ public class JobLevelCalculatorService {
      * @date: 2025/09/20 16:52
      */
     public static DynamicObject getNonJobLevel(DynamicObject jobSeq){
-        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), null, 0,
-                null, String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ));
+        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), null, 0, String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ));
         DynamicObject jobLevel = !jobLevels.isEmpty() ? jobLevels.get(0) : null;
         if( jobLevel != null) {
             long jobLevelId = jobLevel.getLong(String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.ID_KEY));
@@ -1644,7 +1644,7 @@ public class JobLevelCalculatorService {
      */
     public static DynamicObject getLowestJobLevel(DynamicObject jobSeq) {
 
-        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), null, null,
+        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), null,
                 null, String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ));
         DynamicObject jobLevel = !jobLevels.isEmpty() ? jobLevels.get(0) : null;
         if( jobLevel != null) {
@@ -1663,7 +1663,7 @@ public class JobLevelCalculatorService {
      * @date: 2025/09/20 16:52
      */
     public static DynamicObject getMaxJobLevel(DynamicObject jobSeq,BigDecimal score) {
-        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), score, null,
+        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), score,
                 null, String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ +" desc"));
         DynamicObject jobLevel = !jobLevels.isEmpty() ? jobLevels.get(0) : null;
         if( jobLevel != null) {
@@ -1719,15 +1719,15 @@ public class JobLevelCalculatorService {
             System.out.println("非技能序列使用职称等级,编码【" + likenumber + "】");
         }
 
-        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), score, null,
+        DynamicObject jobLevels = getJobLevelByJobSeqAndQualAndScore(jobSeq.getString(FormConstant.NUMBER_KEY), score, null,
                 likenumber, String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ + " desc"));
 
-        if(!jobLevels.isEmpty()){
+        if(jobLevels != null){
             if(downgradeNum != null && downgradeNum > 0) {
                 //降级
                 Map<Integer, DynamicObject> jobLevelMap = getJobLevelByJobSeqMap(jobSeq);
                 //当前分数能达到的最大职级减去需降级数
-                int maxJobLevelSeq = jobLevels.get(0).getInt(FormConstant.JOBLEVELSEQ);
+                int maxJobLevelSeq = jobLevels.getInt(FormConstant.JOBLEVELSEQ);
                 DynamicObject jobLevel = jobLevelMap.get(maxJobLevelSeq - downgradeNum);
                 if (jobLevel == null) {
                     //降级数超出则返回最低职级
@@ -1735,7 +1735,7 @@ public class JobLevelCalculatorService {
                 }
                 return jobLevel;
             }
-            long jobLevelId = jobLevels.get(0).getLong(String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.ID_KEY));
+            long jobLevelId = jobLevels.getLong(String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.ID_KEY));
             return BusinessDataServiceHelper.loadSingle(jobLevelId, FormConstant.HBJM_JOBLEVELHR);
         }else{
             //没有获取到预期的职级则返回最低职级
@@ -1773,7 +1773,7 @@ public class JobLevelCalculatorService {
      * @date: 2025/09/20 16:52
      */
     public static DynamicObject[] getJobLevelByJobSeq(DynamicObject jobSeq) {
-        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), null, null,
+        DynamicObjectCollection jobLevels = queryJobLevels(jobSeq.getString(FormConstant.NUMBER_KEY), null,
                 null, String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ));
         List<Long> jobLevelIds = jobLevels.stream().map(dynamicObject -> dynamicObject.getLong(String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.ID_KEY))).collect(Collectors.toList());
         QFilter idInFilter = QFilterCommonHelper.getIdInFilter(jobLevelIds);
@@ -1798,13 +1798,12 @@ public class JobLevelCalculatorService {
      * @param jobSeqNumber 职位序列编码
      * @param score 积分
      * @param jobLevelSeq 职级序号
-     * @param jobLevelNumber 资格编码
      * @param orderBy 排序
      * @return: kd.bos.dataentity.entity.DynamicObjectCollection
      * @author W.Y.C
      * @date: 2025/09/27 13:49
      */
-    private static DynamicObjectCollection queryJobLevels(String jobSeqNumber, BigDecimal score, Integer jobLevelSeq, String jobLevelNumber, String orderBy) {
+    private static DynamicObjectCollection queryJobLevels(String jobSeqNumber, BigDecimal score, Integer jobLevelSeq, String orderBy) {
 
         QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
                 .addIdNumberNameWithExtras(
@@ -1819,7 +1818,8 @@ public class JobLevelCalculatorService {
                 .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
                 .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBLEVELHR,FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
                 .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBLEVELHR,FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()))
-                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ), QCP.is_notnull, null));
+                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ), QCP.is_notnull, null))
+                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.NCKD_ISPARTICIPATE), QCP.equals, EnableEnum.YES.getCode()));
         if(score != null){
             filter.and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.NCKD_SCORE), QCP.less_equals, score));
         }
@@ -1831,32 +1831,92 @@ public class JobLevelCalculatorService {
         }
 
         DynamicObjectCollection query = null;
-        if(StringUtils.isBlank(jobLevelNumber)){
             //根据职位序列查询
             filter.and(new QFilter(String.join(".",FormConstant.NCKD_JOBSEQ,FormConstant.NUMBER_KEY), QCP.equals, jobSeqNumber))
                     .and(new QFilter(String.join(".",FormConstant.NCKD_JOBSEQ, FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
                     .and(new QFilter(String.join( ".",FormConstant.NCKD_JOBSEQ,FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
                     .and(new QFilter(String.join( ".",FormConstant.NCKD_JOBSEQ,FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()));
-            query = QueryServiceHelper.query(PositionStructureConstant.GETLEVELBYJOBSEQ_QUERY,
-                    queryFieldBuilder.buildSelect(),
-                    new QFilter[]{filter},
-                    orderBy);
+        return QueryServiceHelper.query(PositionStructureConstant.GETLEVELBYJOBSEQ_QUERY,
+                queryFieldBuilder.buildSelect(),
+                new QFilter[]{filter},
+                orderBy);
+    }
+
+    //根据职位序列、资格级别和分数获取符合条件的职级
+    public static DynamicObject getJobLevelByJobSeqAndQualAndScore(String jobSeqNumber, BigDecimal score, Integer jobLevelSeq, String jobLevelNumber, String orderBy) {
+        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+                .addIdNumberNameWithExtras(
+                        new String[]{FormConstant.HBJM_JOBLEVELHR},
+                        FormConstant.JOBLEVELSEQ,
+                        FormConstant.NCKD_COEFFICIENT,
+                        FormConstant.NCKD_SCORE
+                );
+
+        QFilter filter = new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR,FormConstant.NCKD_SCORE), QCP.is_notnull, null)
+                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBLEVELHR,FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBLEVELHR,FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()))
+                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ), QCP.is_notnull, null))
+                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.NCKD_ISPARTICIPATE), QCP.equals, EnableEnum.YES.getCode()));
+        if(jobLevelSeq != null){
+            filter.and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ), QCP.less_equals, jobLevelSeq));
         }else{
-            //根据职位序列和资格条件查询
-            filter.and(new QFilter(String.join(".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ,FormConstant.NUMBER_KEY), QCP.equals, jobSeqNumber))
-                    .and(new QFilter(String.join(".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ, FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
-                    .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ,FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
-                    .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ,FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()))
-                    .and(new QFilter(String.join(".",FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
-                    .and(new QFilter(String.join( ".",FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
-                    .and(new QFilter(String.join( ".",FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()));
-            filter.and(new QFilter(FormConstant.NCKD_JOBLEVELNUMBER, QCP.like, "%"+jobLevelNumber+"%"));
-            query = QueryServiceHelper.query(PositionStructureConstant.GETLEVELBYJOBSEQQUERYANDQUAL_QUERY,
-                    queryFieldBuilder.buildSelect(),
-                    new QFilter[]{filter},
-                    orderBy);
+            //只查询有效的序号(无职级是-1,避免查出来)
+            filter.and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ), QCP.large_than, 0));
         }
-        return query;
+
+        QFilter filter1 = filter.copy();
+        filter1.and(new QFilter(String.join(".",FormConstant.NCKD_JOBSEQ,FormConstant.NUMBER_KEY), QCP.equals, jobSeqNumber))
+                .and(new QFilter(String.join(".",FormConstant.NCKD_JOBSEQ, FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.NCKD_JOBSEQ,FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.NCKD_JOBSEQ,FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()))
+                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBLEVELHR, FormConstant.NCKD_SCORE), QCP.less_equals, score));
+        //获取分数可以达到的职级列表
+        DynamicObjectCollection query1 = QueryServiceHelper.query(PositionStructureConstant.GETLEVELBYJOBSEQ_QUERY,
+                queryFieldBuilder.buildSelect(),
+                new QFilter[]{filter1},
+                orderBy);
+        Map<Integer, List<DynamicObject>> resultMap = query1.stream()
+                .collect(Collectors.groupingBy(
+                        obj -> obj.getInt(String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ)),
+                        LinkedHashMap::new,
+                        Collectors.toList()
+                ))
+                .entrySet()
+                .stream()
+                .sorted(Map.Entry.<Integer, List<DynamicObject>>comparingByKey().reversed())
+                .collect(Collectors.toMap(
+                        Map.Entry::getKey,
+                        Map.Entry::getValue,
+                        (existing, replacement) -> existing,
+                        LinkedHashMap::new
+                ));
+
+        //获取职称级别/技能级别可以达到的最大职级
+        filter.and(new QFilter(String.join(".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ,FormConstant.NUMBER_KEY), QCP.equals, jobSeqNumber))
+                .and(new QFilter(String.join(".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ, FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ,FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.HBJM_JOBGRADESCMHR,FormConstant.NCKD_JOBSEQ,FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()))
+                .and(new QFilter(String.join(".",FormConstant.IS_CURRENT_VERSION), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.ENABLE), QCP.equals, EnableEnum.YES.getCode()))
+                .and(new QFilter(String.join( ".",FormConstant.STATUS), QCP.equals, StatusEnum.C.toString()));
+        filter.and(new QFilter(FormConstant.NCKD_JOBLEVELNUMBER, QCP.like, "%"+jobLevelNumber+"%"));
+        DynamicObjectCollection query = QueryServiceHelper.query(PositionStructureConstant.GETLEVELBYJOBSEQQUERYANDQUAL_QUERY,
+                queryFieldBuilder.buildSelect(),
+                new QFilter[]{filter},
+                orderBy);
+        if(!query.isEmpty()){
+            int max = query.get(0).getInt(String.join(".", FormConstant.HBJM_JOBLEVELHR, FormConstant.JOBLEVELSEQ));
+            //找到 resultMap 中最接近 max 值的职级
+            DynamicObject closestObject = resultMap.entrySet().stream()
+                    .min(Comparator.comparingInt(entry -> Math.abs(entry.getKey() - max)))
+                    .map(Map.Entry::getValue)
+                    .filter(list -> !list.isEmpty())
+                    .map(list -> list.get(0))
+                    .orElse(null);
+            return closestObject;
+        }
+        return null;
     }
 
     // 辅助类定义

+ 3 - 4
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/validate/PerfRankMgmtSaveValidate.java

@@ -239,11 +239,10 @@ public class PerfRankMgmtSaveValidate extends AbstractValidator {
         QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
                 .addIdNumberName(PerfRankMgmtConstant.NCKD_PERSON);
         DynamicObjectCollection query = QueryServiceHelper.query(PerfRankMgmtConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
-        Map<Long, DynamicObject> personMap = query.stream()
+        Map<Long, List<DynamicObject>> personMap = query.stream()
                 .filter(obj -> obj.getLong(String.join(".", PerfRankMgmtConstant.NCKD_PERSON, FormConstant.ID_KEY)) > 0)
-                .collect(Collectors.toMap(
-                        obj -> obj.getLong(String.join(".", PerfRankMgmtConstant.NCKD_PERSON, FormConstant.ID_KEY)),
-                        obj -> obj
+                .collect(Collectors.groupingBy(
+                        obj -> obj.getLong(String.join(".", PerfRankMgmtConstant.NCKD_PERSON, FormConstant.ID_KEY))
                 ));
 //        StringJoiner msgJoiner = new StringJoiner(StrFormatter.LINE_SEPARATOR);
         for (DynamicObject entry : entries) {