浏览代码

Merge branch 'refs/heads/master' into feat-swc-mas_1.0

wyc 19 小时之前
父节点
当前提交
a649ec68fc
共有 16 个文件被更改,包括 502 次插入342 次删除
  1. 4 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java
  2. 91 31
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/business/JobLevelCalculatorService.java
  3. 34 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/other/ManagerAllowanceListPlugin.java
  4. 47 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/performance/PerfRankMgmtFormPlugin.java
  5. 51 34
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/validate/PerfRankMgmtSaveValidate.java
  6. 2 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/sdm/common/SanDingConstant.java
  7. 32 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/sdm/plugin/form/SanDingTaskFormPlugin.java
  8. 12 27
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/business/hr/PositionBillService.java
  9. 44 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/hr/MultiLangEnum.java
  10. 39 123
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/hr/PositionBillConstant.java
  11. 6 5
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PosBillEntryAddFormPlugin.java
  12. 15 4
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PositionBillEntryFormPlugin.java
  13. 10 10
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PositionBillFormPlugin.java
  14. 86 71
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/PosBillEntryAddSaveOpPlugin.java
  15. 28 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/PositionBillEntrySaveOpPlugin.java
  16. 1 36
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/validator/PositionBillEntryValidator.java

+ 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;
     }
 
     // 辅助类定义

+ 34 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/other/ManagerAllowanceListPlugin.java

@@ -0,0 +1,34 @@
+package nckd.jxccl.hr.psms.plugin.form.other;
+
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.list.plugin.AbstractListPlugin;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+
+/**
+* 配置有职位津贴的管理人员
+* 实体标识:nckd_managerallowance
+* @author W.Y.C
+* @date 2025/12/18 21:32
+* @version 1.0
+*/
+public class ManagerAllowanceListPlugin extends AbstractListPlugin implements Plugin {
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs afterDoOperationEventArgs) {
+        if(afterDoOperationEventArgs.getOperationResult() != null){
+            String operateKey = afterDoOperationEventArgs.getOperateKey();
+            if(FormConstant.SUBMIT_OP.equalsIgnoreCase(operateKey)){
+                if(!afterDoOperationEventArgs.getOperationResult().isSuccess()){
+                    for (IOperateInfo iOperateInfo : afterDoOperationEventArgs.getOperationResult().getAllErrorOrValidateInfo()) {
+                        if(iOperateInfo.getMessage().equalsIgnoreCase("只有暂存的数据才允许提交。")){
+                            afterDoOperationEventArgs.getOperationResult().setShowMessage(false);
+                            this.getView().showTipNotification("只有未确认的数据才允许确认。");
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 47 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/form/performance/PerfRankMgmtFormPlugin.java

@@ -59,6 +59,8 @@ import nckd.jxccl.hr.psms.common.PositionStructureConstant;
 import nckd.jxccl.hr.psms.helper.PositionFileHelper;
 import org.apache.commons.lang3.StringUtils;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
@@ -185,11 +187,55 @@ public class PerfRankMgmtFormPlugin extends AbstractFormPlugin implements Wizard
                 this.getModel().setValue(PerfRankMgmtConstant.NCKD_POSTALLOWANCE, hasAllowance,changeSet[0].getRowIndex());
                 this.getView().updateView(PerfRankMgmtConstant.NCKD_POSTALLOWANCE,changeSet[0].getRowIndex());
             }
-
+        }else if(PerfRankMgmtConstant.NCKD_TOPRANKS.equalsIgnoreCase(name)){
+            //输入总排名
+            ChangeData[] changeSet = e.getChangeSet();
+            Object newValue = changeSet[0].getNewValue();
+            Object oldValue = changeSet[0].getOldValue();
+//            优秀人数、基本合格人数、不合格人数
+            if(!Objects.equals(newValue, oldValue)) {
+                QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+                        .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY}, PerfRankMgmtConstant.NCKD_RATIO)
+                        .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY, PositionStructureConstant.NCKD_APPRAISALRESULT}, FormConstant.NUMBER_KEY);
+                DynamicObjectCollection query = QueryServiceHelper.query(PerfRankMgmtConstant.RANKRATIOCONF_ENTITYID, queryFieldBuilder.buildSelect(), null);
+                Map<String, BigDecimal> appraisalResultRatioMap = new HashMap<>();
+                query.forEach(dynamicObject -> {
+                    String key = dynamicObject.getString(String.join(".", FormConstant.NCKD_ENTRYENTITY, PositionStructureConstant.NCKD_APPRAISALRESULT, FormConstant.NUMBER_KEY));
+                    BigDecimal value = dynamicObject.getBigDecimal(String.join(".", FormConstant.NCKD_ENTRYENTITY, PerfRankMgmtConstant.NCKD_RATIO));
+                    appraisalResultRatioMap.put(key, value);
+                });
+
+                // 获取配置比例
+                BigDecimal excellentRatio = appraisalResultRatioMap.get(AppraisalResultEnum.EXCELLENT.getCode());
+                BigDecimal qualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.QUALIFIED.getCode());
+                BigDecimal basicallyQualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.BASICALLY_QUALIFIED.getCode());
+                BigDecimal unQualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.UN_QUALIFIED.getCode());
+
+                // 计算各等级的理论人数(四舍五入)
+                int expectedExcellent = calculateExpectedCount(ConvertUtil.toInt(newValue, 0), excellentRatio);
+                int expectedQualified = calculateExpectedCount(ConvertUtil.toInt(newValue, 0), qualifiedRatio);
+                int expectedBasic = calculateExpectedCount(ConvertUtil.toInt(newValue, 0), basicallyQualifiedRatio);
+                int expectedFail = calculateExpectedCount(ConvertUtil.toInt(newValue, 0), unQualifiedRatio);
+
+                this.getModel().setValue(PerfRankMgmtConstant.NCKD_EXCELLENTS, expectedExcellent);
+//                this.getModel().setValue(PerfRankMgmtConstant.NCKD_BASICS, expectedQualified);
+                this.getModel().setValue(PerfRankMgmtConstant.NCKD_BASICS, expectedBasic);
+                this.getModel().setValue(PerfRankMgmtConstant.NCKD_FAILS, expectedFail);
+            }
         }
 
     }
 
+    /**
+     * 计算理论人数(四舍五入)
+     */
+    private int calculateExpectedCount(int totalCount, BigDecimal ratio) {
+        // 将百分比转换为小数进行计算
+        BigDecimal decimalRatio = ratio.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
+        BigDecimal expected = decimalRatio.multiply(BigDecimal.valueOf(totalCount));
+        return expected.setScale(0, RoundingMode.HALF_UP).intValue();
+    }
+
     @Override
     public void beforeImportEntry(BeforeImportEntryEventArgs e) {
         super.beforeImportEntry(e);

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

@@ -1,5 +1,6 @@
 package nckd.jxccl.hr.psms.plugin.operate.performance.validate;
 
+import akka.routing.FromConfig;
 import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
 import kd.bos.entity.ExtendedDataEntity;
@@ -113,25 +114,38 @@ public class PerfRankMgmtSaveValidate extends AbstractValidator {
         // 不合格人数
         int failCount = context.failCount;
 
-        // 获取配置比例
+      /*  // 获取配置比例
         BigDecimal excellentRatio = appraisalResultRatioMap.get(AppraisalResultEnum.EXCELLENT.getCode());
         BigDecimal qualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.QUALIFIED.getCode());
         BigDecimal basicallyQualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.BASICALLY_QUALIFIED.getCode());
-        BigDecimal unQualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.UN_QUALIFIED.getCode());
+        BigDecimal unQualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.UN_QUALIFIED.getCode());*/
 
         // 计算各等级的理论人数(四舍五入)
-        int expectedExcellent = calculateExpectedCount(totalRankCount, excellentRatio);
+       /* int expectedExcellent = calculateExpectedCount(totalRankCount, excellentRatio);
         int expectedQualified = calculateExpectedCount(totalRankCount, qualifiedRatio);
         int expectedBasic = calculateExpectedCount(totalRankCount, basicallyQualifiedRatio);
-        int expectedFail = calculateExpectedCount(totalRankCount, unQualifiedRatio);
-
+        int expectedFail = calculateExpectedCount(totalRankCount, unQualifiedRatio);*/
 
+        DynamicObject data = rowDataEntity.getDataEntity();
+        int topRanks = data.getInt(PerfRankMgmtConstant.NCKD_TOPRANKS);
+        int expectedExcellent = data.getInt(PerfRankMgmtConstant.NCKD_EXCELLENTS);
+        int expectedBasic = data.getInt(PerfRankMgmtConstant.NCKD_BASICS);
+        int expectedFail = data.getInt(PerfRankMgmtConstant.NCKD_FAILS);
+        int expectedQualified = topRanks - expectedExcellent - expectedBasic - expectedFail;
+
+
+
+        // 集团本部不校验
+        DynamicObject adminOrg = data.getDynamicObject(FormConstant.NCKD_ADMINORG);
+        DynamicObject secondOrg = adminOrg.getDynamicObject(FormConstant.NCKD_SECONDORG);
+        if(secondOrg == null || !secondOrg.getString(FormConstant.NUMBER_KEY).contains("0101")){
+            // 校验各等级人数是否在合理范围内(允许±1的差异)
+            /*validateCountRange(AppraisalResultEnum.EXCELLENT.getName(), excellentCount, expectedExcellent, totalRankCount,rowDataEntity);
+            validateCountRange(AppraisalResultEnum.QUALIFIED.getName(), qualifiedCount, expectedQualified, totalRankCount,rowDataEntity);
+            validateCountRange(AppraisalResultEnum.BASICALLY_QUALIFIED.getName(), basicCount, expectedBasic, totalRankCount,rowDataEntity);
+            validateCountRange(AppraisalResultEnum.UN_QUALIFIED.getName(), failCount, expectedFail, totalRankCount,rowDataEntity);*/
+        }
 
-        // 校验各等级人数是否在合理范围内(允许±1的差异)
-        validateCountRange(AppraisalResultEnum.EXCELLENT.getName(), excellentCount, expectedExcellent, totalRankCount,rowDataEntity);
-        validateCountRange(AppraisalResultEnum.QUALIFIED.getName(), qualifiedCount, expectedQualified, totalRankCount,rowDataEntity);
-        validateCountRange(AppraisalResultEnum.BASICALLY_QUALIFIED.getName(), basicCount, expectedBasic, totalRankCount,rowDataEntity);
-        validateCountRange(AppraisalResultEnum.UN_QUALIFIED.getName(), failCount, expectedFail, totalRankCount,rowDataEntity);
 
     }
 
@@ -239,11 +253,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) {
@@ -366,26 +379,30 @@ public class PerfRankMgmtSaveValidate extends AbstractValidator {
      */
     private void checkCountConsistency(DynamicObject data, ValidationContext context,
                                        ExtendedDataEntity rowDataEntity) {
-        int topRanks = data.getInt(PerfRankMgmtConstant.NCKD_TOPRANKS);
-        int allowanceRanks = data.getInt(PerfRankMgmtConstant.NCKD_ALLOWANCERANKS);
-        int fails = data.getInt(PerfRankMgmtConstant.NCKD_FAILS);
-        int basics = data.getInt(PerfRankMgmtConstant.NCKD_BASICS);
-        int excellents = data.getInt(PerfRankMgmtConstant.NCKD_EXCELLENTS);
-
-        if (topRanks != context.totalRankCount) {
-            this.addFatalErrorMessage(rowDataEntity, "总排名人数与实际录入数据不一致;\n");
-        }
-        if (allowanceRanks != context.allowanceRankCount) {
-            this.addFatalErrorMessage(rowDataEntity, "R排名人数与实际录入数据不一致;\n");
-        }
-        if (fails != context.failCount) {
-            this.addFatalErrorMessage(rowDataEntity, "不合格人数与实际录入数据不一致;\n");
-        }
-        if (basics != context.basicCount) {
-            this.addFatalErrorMessage(rowDataEntity, "基本人数与实际录入数据不一致;\n");
-        }
-        if (excellents != context.excellentCount) {
-            this.addFatalErrorMessage(rowDataEntity, "优秀人数与实际录入数据不一致;\n");
+        DynamicObject adminOrg = data.getDynamicObject(FormConstant.NCKD_ADMINORG);
+        DynamicObject secondOrg = adminOrg.getDynamicObject(FormConstant.NCKD_SECONDORG);
+        if(secondOrg == null || !secondOrg.getString(FormConstant.NUMBER_KEY).contains("0101")) {
+            int topRanks = data.getInt(PerfRankMgmtConstant.NCKD_TOPRANKS);
+            int allowanceRanks = data.getInt(PerfRankMgmtConstant.NCKD_ALLOWANCERANKS);
+            int fails = data.getInt(PerfRankMgmtConstant.NCKD_FAILS);
+            int basics = data.getInt(PerfRankMgmtConstant.NCKD_BASICS);
+            int excellents = data.getInt(PerfRankMgmtConstant.NCKD_EXCELLENTS);
+
+            if (topRanks != context.totalRankCount) {
+                this.addFatalErrorMessage(rowDataEntity, "总排名人数与实际录入数据不一致;\n");
+            }
+            if (allowanceRanks != context.allowanceRankCount) {
+                this.addFatalErrorMessage(rowDataEntity, "R排名人数与实际录入数据不一致;\n");
+            }
+            if (fails != context.failCount) {
+                this.addFatalErrorMessage(rowDataEntity, "不合格人数与实际录入数据不一致;\n");
+            }
+            if (basics != context.basicCount) {
+                this.addFatalErrorMessage(rowDataEntity, "基本人数与实际录入数据不一致;\n");
+            }
+            if (excellents != context.excellentCount) {
+                this.addFatalErrorMessage(rowDataEntity, "优秀人数与实际录入数据不一致;\n");
+            }
         }
     }
 

+ 2 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/sdm/common/SanDingConstant.java

@@ -69,6 +69,8 @@ public class SanDingConstant extends FormConstant {
     public static final String NCKD_AUTHORIZEDSTRENGTH_KEY = "nckd_authorizedstrength";
     /** 缺编人数 */
     public static final String NCKD_STAFFINGSHORTFALL_KEY = "nckd_staffingshortfall";
+    /** 附件 */
+    public static final String ATTACHMENTPANEL_KEY = "attachmentpanel";
 
     /** 行政组织.ID */
     public static final String HAOS_ADMINORGHR_ID = "haos_adminorghr.id";

+ 32 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/sdm/plugin/form/SanDingTaskFormPlugin.java

@@ -0,0 +1,32 @@
+package nckd.jxccl.hr.sdm.plugin.form;
+
+import kd.bos.form.control.AttachmentPanel;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.hr.hbp.common.util.HRStringUtils;
+import nckd.jxccl.hr.sdm.common.SanDingConstant;
+
+/**
+ * 三定任务表单插件
+ * @entity: nckd_sandingtask
+ * @author: jtd
+ * @date: 2025/12/18 20:12
+ */
+public class SanDingTaskFormPlugin extends AbstractFormPlugin {
+
+    @Override
+    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
+        super.beforeDoOperation(args);
+
+        FormOperate formOperate = (FormOperate)args.getSource();
+        String operateKey = formOperate.getOperateKey();
+        if (HRStringUtils.equals(SanDingConstant.SUBMIT_OP, operateKey)) {
+            AttachmentPanel attachmentPanel = getControl(SanDingConstant.ATTACHMENTPANEL_KEY);
+            if (attachmentPanel.getAttachmentData().isEmpty()) {
+                getView().showTipNotification("请按要求上传附件。");
+                args.setCancel(true);
+            }
+        }
+    }
+}

+ 12 - 27
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/business/hr/PositionBillService.java

@@ -18,6 +18,7 @@ import kd.bos.servicehelper.MetadataServiceHelper;
 import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
 import kd.hr.hbp.common.util.HRDateTimeUtils;
 import kd.hr.hbp.common.util.HRStringUtils;
+import kd.sdk.hr.hdm.common.enums.reg.RegBillStatusEnum;
 import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
 
 import java.util.Date;
@@ -32,19 +33,9 @@ public class PositionBillService {
 
     private static final Map<String, String> changeTypeToLocaleMap = Maps.newHashMapWithExpectedSize(2);
 
-    private static final Map<String, String> billStatusToLocaleMap = Maps.newHashMapWithExpectedSize(7);
-
     static {
         changeTypeToLocaleMap.put("add", "新增岗位");
         changeTypeToLocaleMap.put("change", "变更信息");
-
-        billStatusToLocaleMap.put("B", "已提交");
-        billStatusToLocaleMap.put("D", "审批中");
-        billStatusToLocaleMap.put("C", "审批通过");
-        billStatusToLocaleMap.put("E", "审批不通过");
-        billStatusToLocaleMap.put("F", "已废弃");
-        billStatusToLocaleMap.put("G", "待重新提交");
-        billStatusToLocaleMap.put("LD", "已删除");
     }
 
     /**
@@ -69,47 +60,41 @@ public class PositionBillService {
      * @param iFormView
      * @param operation
      * @param pluginName
-     * @param filter
      */
-    public static void openViewForm(IFormView iFormView, String operation, String pluginName, QFilter filter) {
+    public static void openViewForm(IFormView iFormView, String operation, String pluginName) {
         if (iFormView.getModel().getValue("org") == null) {// 179
             iFormView.showTipNotification("请先填写组织体系管理组织。");
         } else {
-            HRBaseServiceHelper orgBatchChgBillHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILL);
-            QFilter idFilter = new QFilter("id", "=", iFormView.getModel().getDataEntity().getLong("id"));
-            DynamicObject dynamicObject = orgBatchChgBillHelper.loadDynamicObject(idFilter);
+            HRBaseServiceHelper positionBillHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILL);
+            QFilter idFilter = new QFilter(PositionBillConstant.ID_KEY, "=", iFormView.getModel().getDataEntity().getLong(PositionBillConstant.ID_KEY));
+            DynamicObject dynamicObject = positionBillHelper.loadDynamicObject(idFilter);
             if (dynamicObject != null) {
                 String billStatus = dynamicObject.getString(PositionBillConstant.BILL_STATUS_KEY);
-                if (!billStatus.equals("A") && !billStatus.equals("G") && !billStatus.equals("D") && (!billStatus.equals("B") || !StringUtils.equals(iFormView.getFormShowParameter().getAppId(), "wftask"))) {
+                if (!billStatus.equals(RegBillStatusEnum.TEMPSTORAGE.getCode()) && !billStatus.equals(RegBillStatusEnum.WAITRESUBMIT.getCode()) && !billStatus.equals(RegBillStatusEnum.APPROVING.getCode()) && (!billStatus.equals(RegBillStatusEnum.ALREADYSUBMIT.getCode()) || !StringUtils.equals(iFormView.getFormShowParameter().getAppId(), "wftask"))) {
                     String operateLocaleName = changeTypeToLocaleMap.get(operation);
-                    String auditstatusName = billStatusToLocaleMap.get(dynamicObject.getString(PositionBillConstant.BILL_STATUS_KEY));
-                    iFormView.showErrorNotification(String.format("“%1$s”的单据不能“%2$s”。", new Object[]{auditstatusName, operateLocaleName}));
+                    String auditstatusName = RegBillStatusEnum.getName(dynamicObject.getString(PositionBillConstant.BILL_STATUS_KEY));
+                    iFormView.showErrorNotification(String.format("“%1$s”的单据不能“%2$s”。", auditstatusName, operateLocaleName));
                     return;
                 }
             }
 
-            ListShowParameter listShowParameter = new ListShowParameter();
-            if (filter != null) {// 202
-                listShowParameter.getListFilterParameter().getQFilters().add(filter);
-            }
-
             BillShowParameter formShowParameter = new BillShowParameter();
-
             switch (operation) {
                 case PositionBillConstant.NEWENTRY_ADD:
                     formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYADD);
                     break;
                 case PositionBillConstant.NEWENTRY_CHANGE:
                     formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYCHANGE);
-                    break;
             }
-
             formShowParameter.setCustomParam("position_bsed", iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT) == null ? HRDateTimeUtils.getNowDateTime().getTime() : ((Date)iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT)).getTime());
             formShowParameter.getOpenStyle().setShowType(ShowType.Modal);
             formShowParameter.setCustomParam("billid", iFormView.getModel().getDataEntity().getLong(PositionBillConstant.ID_KEY));
             formShowParameter.setCustomParam("billBsed", iFormView.getModel().getDataEntity().getDate(PositionBillConstant.NCKD_EFFDT));
             formShowParameter.setCloseCallBack(new CloseCallBack(pluginName, operation));
-            formShowParameter.setCustomParam("org", iFormView.getModel().getDataEntity().getLong("org.id"));
+            if (HRStringUtils.equals(iFormView.getFormShowParameter().getAppId(), "wftask")) {
+                formShowParameter.setHasRight(true);
+            }
+            formShowParameter.setCustomParam("org", iFormView.getModel().getDataEntity().getLong(String.join(".", PositionBillConstant.ORG_KEY, PositionBillConstant.ID_KEY)));
             int sequence = getEntrySeq(iFormView.getModel(), PositionBillConstant.CHANGE_TYPE_ADD);
             formShowParameter.setCustomParam("sequence", sequence);
             iFormView.showForm(formShowParameter);

+ 44 - 0
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/hr/MultiLangEnum.java

@@ -0,0 +1,44 @@
+package nckd.jxccl.hrmp.hbpm.common.hr;
+
+import kd.bos.coderule.util.MultiLangEnumBridge;
+
+/**
+ * 多语言枚举
+ * @author: jtd
+ * @date: 2025/12/17 21:52
+ */
+public enum MultiLangEnum {
+    CHINES_SIMP("zh_CN", new MultiLangEnumBridge("简体中文", "MultiLangEnum_0", "hrmp-haos-common")),
+    CHINES_TRAD("zh_TW", new MultiLangEnumBridge("繁体中文", "MultiLangEnum_1", "hrmp-haos-common")),
+    ENGLISH("en_US", new MultiLangEnumBridge("英文", "MultiLangEnum_2", "hrmp-haos-common"));
+
+    private String code;
+    private MultiLangEnumBridge bridge = null;
+
+    private MultiLangEnum(String code, MultiLangEnumBridge bridge) {
+        this.code = code;
+        this.bridge = bridge;
+    }
+
+    public static String getName(String code) {
+        if (code == null) {
+            return null;
+        } else {
+            for(MultiLangEnum se : values()) {
+                if (code.equals(se.getCode())) {
+                    return se.getName();
+                }
+            }
+
+            return null;
+        }
+    }
+
+    public String getCode() {
+        return this.code;
+    }
+
+    public String getName() {
+        return this.bridge.loadKDString();
+    }
+}

+ 39 - 123
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/hr/PositionBillConstant.java

@@ -6,164 +6,80 @@ import java.util.HashMap;
 import java.util.Map;
 
 /**
- * 岗位常量
+ * 岗位申请常量
  * @author: jtd
  * @date: 2025-10-20 16:29
  */
 public class PositionBillConstant extends FormConstant {
 
-    /**
-     * 岗位F7组织树(去时间)
-     */
-    public static final String NCKD_NOTIME_POSTREELISTF7 = "nckd_notime_postreelistf7";
+    /** 岗位/标岗F7组织树(自定义)实体标识 */
+    public static final String NCKD_HBPM_POSORGTREELISTF_ENTITY = "nckd_hbpm_posorgtreelistf";
+    /** 岗位信息键值转换实体标识 */
+    public static final String NCKD_POSITION_TRANSKEY_ENTITY = "nckd_position_transkey";
 
-    /**
-     * 行政组织树表单ID
-     */
+    /** 行政组织树表单ID */
     public static final String HAOS_ORGTREELISTF7 = "haos_orgtreelistf7";
-
-    /**
-     * 岗位变动类型表单ID
-     */
+    /** 岗位变动类型表单ID */
     public static final String NCKD_POSITION_CHANGETYPE = "nckd_position_changetype";
-
-    /**
-     * 变动类型
-     */
+    /** 变动类型 */
     public static final String NCKD_CHANGETYPE = "nckd_changetype";
-
-    /**
-     * 变动类型-岗位新设
-     */
+    /** 变动类型-岗位新设 */
     public static final Long CHANGE_TYPE_ADD = 1010L;
-
-    /**
-     * 变动类型-岗位变更
-     */
+    /** 变动类型-岗位变更 */
     public static final Long CHANGE_TYPE_CHANGE = 1020L;
-
-    /**
-     * 变动类型Map
-     */
+    /** 变动类型Map */
     public static final Map<String, Long> CHANGE_TYPE_MAP = new HashMap(){{
         put("add", CHANGE_TYPE_ADD);
         put("change", CHANGE_TYPE_CHANGE);
     }};
-
-    /**
-     * 岗位信息维护表单ID
-     */
+    /** 岗位信息维护表单ID */
     public static final String HBPM_POSITIONHR = "hbpm_positionhr";
-
-
-    /**
-     * 岗位申请单表单ID
-     */
+    /** 岗位申请单表单ID */
     public static final String NCKD_POSITIONBILL = "nckd_positionbill";
-
-    /**
-     * 岗位申请单分录表单ID
-     */
+    /** 岗位申请单分录表单ID */
     public static final String NCKD_POSITIONBILLENTRY = "nckd_positionbillentry";
-
-    /**
-     * 岗位申请-新增岗位表单ID
-     */
+    /** 岗位申请-新增岗位表单ID */
     public static final String NCKD_POSBILLENTRYADD = "nckd_posbillentryadd";
-
-    /**
-     * 岗位申请-变更信息表单ID
-     */
+    /** 岗位申请-变更信息表单ID */
     public static final String NCKD_POSBILLENTRYCHANGE = "nckd_posbillentrychange";
-
-    /**
-     * 岗位职责分录ID
-     */
+    /** 岗位职责分录ID */
     public static final String NCKD_POSDUTYENTRYENTITY = "nckd_posdutyentryentity";
-
-    /**
-     * 新增分录-岗位新设OP
-     */
+    /** 新增分录-岗位新设OP */
     public static final String NEWENTRY_ADD = "newentry_add";
-
-    /**
-     * 新增分录-岗位变更OP
-     */
+    /** 新增分录-岗位变更OP */
     public static final String NEWENTRY_CHANGE = "newentry_change";
-
-    /**
-     * 删除分录-岗位新设OP
-     */
+    /** 删除分录-岗位新设OP */
     public static final String DELETEENTRY_ADD = "deleteentry_add";
-
-    /**
-     * 删除分录-岗位变更OP
-     */
+    /** 删除分录-岗位变更OP */
     public static final String DELETEENTRY_CHANGE = "deleteentry_change";
-
-    /**
-     * 编辑-岗位新设OP
-     */
+    /** 编辑-岗位新设OP */
     public static final String EDIT_ADD = "edit_add";
-
-    /**
-     * 编辑-岗位变更OP
-     */
+    /** 编辑-岗位变更OP */
     public static final String EDIT_CHANGE = "edit_change";
-
-    /**
-     * 岗位申请单内码
-     */
+    /** 岗位申请单内码 */
     public static final String NCKD_BILLID = "nckd_billid";
-
-    /**
-     * 生效日期
-     */
+    /** 生效日期 */
     public static final String NCKD_EFFDT = "nckd_effdt";
-
-    /**
-     * 设立日期
-     */
+    /** 设立日期 */
     public static final String NCKD_ESTDATE = "nckd_estdate";
-
-    /**
-     * 设立日期
-     */
+    /** 设立日期 */
     public static final String ESTABLISHMENTDATE_KEY = "establishmentdate";
-
-    /**
-     * 分录顺序号
-     */
+    /** 分录顺序号 */
     public static final String NCKD_SEQUENCE = "nckd_sequence";
-
-    /**
-     * 行政组织
-     */
+    /** 行政组织 */
     public static final String NCKD_ADMINORG = "nckd_adminorg";
-
-    /**
-     * 岗位
-     */
+    /** 岗位 */
     public static final String NCKD_POSITION = "nckd_position";
-
-    /**
-     * 上级岗位
-     */
+    /** 上级岗位 */
     public static final String NCKD_PARENT = "nckd_parent";
-
-    /**
-     * 上级岗位
-     */
+    /** 上级岗位 */
     public static final String PARENT_KEY = "parent";
-
-    /**
-     * 组织体系管理组织
-     */
+    /** 组织体系管理组织 */
     public static final String NCKD_ORG = "nckd_org";
-
-    /**
-     * 生效日期
-     */
+    /** 生效日期 */
     public static final String NCKD_BSED = "nckd_bsed";
-
-}
+    /** 行政组织业务ID */
+    public static final String NCKD_ADMINORGBOID_KEY = "nckd_adminorgboid";
+    /** 岗位业务ID */
+    public static final String NCKD_POSITIONBOID_KEY = "nckd_positionboid";
+}

+ 6 - 5
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PosBillEntryAddFormPlugin.java

@@ -50,7 +50,6 @@ public class PosBillEntryAddFormPlugin extends AbstractFormPlugin {
     public void beforeBindData(EventObject e) {
         super.beforeBindData(e);
 
-        getPageCache().put("paramsChangeSetNumber", Boolean.FALSE.toString());
         // 如果是新增
         long entityId = getModel().getDataEntity().getLong(PositionBillConstant.ID_KEY);
         if (entityId == 0L) {
@@ -70,7 +69,6 @@ public class PosBillEntryAddFormPlugin extends AbstractFormPlugin {
         } else {
             setPositionNumberEnable();
         }
-        getPageCache().put("paramsChangeSetNumber", Boolean.TRUE.toString());
 
         // 新增的时候生成岗位ID
         String positionIdKey = String.format("%s_id", PositionBillConstant.NCKD_POSITION);
@@ -96,14 +94,15 @@ public class PosBillEntryAddFormPlugin extends AbstractFormPlugin {
     }
 
     private void setPositionNumber(DynamicObject positionHrDy) {
+        DynamicObject dataEntity = getModel().getDataEntity();// 157
         // 组织体系管理组织
-        DynamicObject org = getModel().getDataEntity().getDynamicObject(PositionBillConstant.NCKD_ORG);
+        DynamicObject org = dataEntity.getDynamicObject(PositionBillConstant.NCKD_ORG);
         if (org == null) {
             getView().setEnable(Boolean.FALSE, PositionBillConstant.NUMBER_KEY);
             return;
         }
 
-        String number = getModel().getDataEntity().getString(PositionBillConstant.NUMBER_KEY);
+        String number = dataEntity.getString(PositionBillConstant.NUMBER_KEY);
         if (HRStringUtils.isNotEmpty(number) && !HRStringUtils.equals(number, getView().getPageCache().get(CODERULE_NUMBER))) {
             return;
         }
@@ -111,7 +110,9 @@ public class PosBillEntryAddFormPlugin extends AbstractFormPlugin {
         long orgid = org.getLong(PositionBillConstant.ID_KEY);
         boolean cudeRule = CodeRuleServiceHelper.isExist(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(orgid));
         if (cudeRule) {
-            if (CodeRuleServiceHelper.isModifiable(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(org.getLong(PositionBillConstant.ID_KEY)))) {
+            boolean fromDatabase = dataEntity.getDataEntityState().getFromDatabase();
+            boolean modifiable = CodeRuleServiceHelper.isModifiable(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(org.getLong(PositionBillConstant.ID_KEY)));
+            if (modifiable || fromDatabase) {
                 String positionNumber = CodeRuleServiceHelper.getNumber(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(org.getLong(PositionBillConstant.ID_KEY)));
                 HRBaseServiceHelper hrBaseServiceHelper = new HRBaseServiceHelper(PositionBillConstant.HBPM_POSITIONHR);
                 QFilter qFilter = new QFilter(PositionBillConstant.NUMBER_KEY, QCP.equals, positionNumber);

+ 15 - 4
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PositionBillEntryFormPlugin.java

@@ -1,6 +1,7 @@
 package nckd.jxccl.hrmp.hbpm.plugin.form.hr;
 
 import kd.bos.bill.OperationStatus;
+import kd.bos.common.enums.EnableEnum;
 import kd.bos.form.FormShowParameter;
 import kd.bos.form.events.BeforeDoOperationEventArgs;
 import kd.bos.form.field.BasedataEdit;
@@ -11,7 +12,6 @@ import kd.bos.list.ListShowParameter;
 import kd.hr.hbp.common.util.HRStringUtils;
 import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
 
-import java.math.BigInteger;
 import java.util.EventObject;
 
 /**
@@ -41,6 +41,7 @@ public class PositionBillEntryFormPlugin extends AbstractFormPlugin implements B
 
         FormShowParameter formShowParameter = getView().getFormShowParameter();
         setOrg();
+        setDefaultValue();
         if (formShowParameter.getCustomParam("sequence") != null && getModel().getDataEntity(true).getInt(PositionBillConstant.NCKD_SEQUENCE) == 0) {
             getModel().setValue(PositionBillConstant.NCKD_SEQUENCE, formShowParameter.getCustomParam("sequence"));
         }
@@ -58,11 +59,21 @@ public class PositionBillEntryFormPlugin extends AbstractFormPlugin implements B
                 getModel().beginInit();
                 getModel().setValue(PositionBillConstant.NCKD_ORG, orgParam);
                 getModel().endInit();
-                getPageCache().put("isInit", BigInteger.ONE.toString());
+                getPageCache().put("isInit", EnableEnum.YES.getCode());
             }
         }
     }
 
+    /**
+     * 设置单头ID
+     */
+    private void setDefaultValue() {
+        Object billId = getView().getFormShowParameter().getCustomParam("billid");
+        if (billId != null) {// 135
+            getModel().setValue(PositionBillConstant.NCKD_BILLID, Long.parseLong(String.valueOf(billId)));
+        }
+    }
+
     public void afterBindData(EventObject e) {
         super.afterBindData(e);
 
@@ -86,14 +97,14 @@ public class PositionBillEntryFormPlugin extends AbstractFormPlugin implements B
         // 替换岗位F7模板
         if (PositionBillConstant.NCKD_POSITION.equals(fieldKey)) {
             ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
-            showParameter.setFormId(PositionBillConstant.NCKD_NOTIME_POSTREELISTF7);
+            showParameter.setFormId(PositionBillConstant.NCKD_HBPM_POSORGTREELISTF_ENTITY);
             showParameter.setCaption("岗位");
         }
 
         // 替换上级岗位F7模板
         if (PositionBillConstant.NCKD_PARENT.equals(fieldKey)) {
             ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
-            showParameter.setFormId(PositionBillConstant.NCKD_NOTIME_POSTREELISTF7);
+            showParameter.setFormId(PositionBillConstant.NCKD_HBPM_POSORGTREELISTF_ENTITY);
             showParameter.setCaption("上级岗位");
         }
     }

+ 10 - 10
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PositionBillFormPlugin.java

@@ -92,22 +92,22 @@ public class PositionBillFormPlugin extends AbstractFormPlugin {
         String opKey = afterDoOperationEventArgs.getOperateKey();
         switch (opKey) {
             case PositionBillConstant.NEWENTRY_ADD:
-                PositionBillService.openViewForm(this.getView(), opKey, this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), opKey, this.getPluginName());
                 break;
-            case "newentry_change":
-                PositionBillService.openViewForm(this.getView(), opKey, this.getPluginName(), null);
+            case PositionBillConstant.NEWENTRY_CHANGE:
+                PositionBillService.openViewForm(this.getView(), opKey, this.getPluginName());
                 break;
             case "deleteentry_add":
-                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName());
                 break;
             case "deleteentry_change":
-                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName());
                 break;
             case "edit_add":
-                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName());
                 break;
             case "edit_change":
-                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName());
                 break;
         }
     }
@@ -118,13 +118,13 @@ public class PositionBillFormPlugin extends AbstractFormPlugin {
 
         switch (closedCallBackEvent.getActionId()) {
             case "add":
-                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName());
                 break;
             case "change":
-                PositionBillService.openViewForm(this.getView(), "change", this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), "change", this.getPluginName());
                 break;
             case "delete":
-                PositionBillService.openViewForm(this.getView(), "delete", this.getPluginName(), null);
+                PositionBillService.openViewForm(this.getView(), "delete", this.getPluginName());
                 break;
             case "edit":
         }

+ 86 - 71
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/PosBillEntryAddSaveOpPlugin.java

@@ -5,48 +5,39 @@ import com.google.common.collect.Maps;
 import kd.bos.common.enums.EnableEnum;
 import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.entity.DynamicObject;
-import kd.bos.dataentity.entity.DynamicObjectCollection;
-import kd.bos.dataentity.metadata.IDataEntityProperty;
-import kd.bos.dataentity.metadata.clr.DataEntityPropertyCollection;
-import kd.bos.entity.EntityMetadataCache;
 import kd.bos.entity.constant.StatusEnum;
 import kd.bos.entity.operate.OperateOptionConst;
 import kd.bos.entity.operate.result.IOperateInfo;
 import kd.bos.entity.operate.result.OperationResult;
 import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
-import kd.bos.entity.plugin.AddValidatorsEventArgs;
 import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
 import kd.bos.exception.KDBizException;
 import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.bos.service.operation.OperationServiceImpl;
-import kd.bos.servicehelper.BusinessDataServiceHelper;
-import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
+import kd.hr.hbp.common.constants.history.HisModelDataStatusEnum;
 import kd.hr.hbp.common.util.HRDynamicObjectUtils;
 import kd.hr.hbp.common.util.HRStringUtils;
+import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
-import nckd.jxccl.hrmp.hbpm.plugin.operate.hr.validator.PositionBillEntryValidator;
 
-import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * 岗位申请-新增岗位保存OP
+ * @entity: nckd_posbillentryadd
  * @author: jtd
  * @date: 2025-11-08 15:30
  */
 public class PosBillEntryAddSaveOpPlugin extends AbstractOperationServicePlugIn {
 
-    private static final String FIELD_PREFIX = "nckd_";
-
-    @Override
-    public void onAddValidators(AddValidatorsEventArgs e) {
-        super.onAddValidators(e);
-
-        e.addValidator(new PositionBillEntryValidator());
-    }
+    private static final String PAGECACHE_KEY_BILLNO_FROM_INIT_VALUE_OF_OPERATION = "coderule_billno_from_init_value_of_operation";
 
     @Override
     public void beginOperationTransaction(BeginOperationTransactionArgs e) {
@@ -59,68 +50,75 @@ public class PosBillEntryAddSaveOpPlugin extends AbstractOperationServicePlugIn
 
         // 获取岗位和上级岗位的业务ID
         List<Long> positionBoIds = Lists.newArrayListWithExpectedSize(positionEntities.length);
-        for (DynamicObject orgEntity : positionEntities) {
-            positionBoIds.add(orgEntity.getLong(String.format("%s_id", PositionBillConstant.NCKD_POSITION)));
-
+        // 获取 行政组织业务ID
+        List<Long> adminorgBoIds = Lists.newArrayListWithExpectedSize(positionEntities.length);
+        for (DynamicObject positionEntity : positionEntities) {
+            positionBoIds.add(positionEntity.getLong(String.join("_", PositionBillConstant.NCKD_POSITION, PositionBillConstant.ID_KEY)));
+            adminorgBoIds.add(positionEntity.getLong(PositionBillConstant.NCKD_ADMINORGBOID_KEY));
             // 获取上级岗位
-            DynamicObject parentPositionVersionDy = orgEntity.getDynamicObject(PositionBillConstant.NCKD_PARENT);
+            DynamicObject parentPositionVersionDy = positionEntity.getDynamicObject(PositionBillConstant.NCKD_PARENT);
             if (parentPositionVersionDy != null) {
                 long parentOrgBoId = parentPositionVersionDy.getLong(PositionBillConstant.BOID_KEY);
                 positionBoIds.add(parentOrgBoId);
-                //orgEntity.set("adminorgboid", Long.valueOf(parentOrgBoId));
             }
         }
 
-        // 根据岗位业务ID从数据库中获取岗位信息
-        DynamicObjectCollection positionQueryDyColl = QueryServiceHelper.query(PositionBillConstant.HBPM_POSITIONHR, PositionBillConstant.ID_KEY, new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, positionBoIds)});
-        List<Object> listIds = new ArrayList<Object>();
-        positionQueryDyColl.forEach(row -> listIds.add(row.getLong(PositionBillConstant.ID_KEY)));
-        DynamicObject[] dbPositionDys = BusinessDataServiceHelper.load(listIds.toArray(), EntityMetadataCache.getDataEntityType(PositionBillConstant.HBPM_POSITIONHR));
-        Map<Long, DynamicObject> dbPositionMap = Maps.newHashMapWithExpectedSize(dbPositionDys.length);
-        for (DynamicObject dbPositionDy : dbPositionDys) {
-            dbPositionMap.put(dbPositionDy.getLong(PositionBillConstant.ID_KEY), dbPositionDy);
+        // 根据岗位ID从数据库中获取岗位信息
+        HRBaseServiceHelper positionServiceHelper = HRBaseServiceHelper.create(PositionBillConstant.HBPM_POSITIONHR);
+        DynamicObject[] positionDyos = positionServiceHelper.loadDynamicObjectArray(new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, positionBoIds)});
+        Map<Long, DynamicObject> dbPositionMap = Maps.newHashMapWithExpectedSize(positionDyos.length);
+        for (DynamicObject positionDyo : positionDyos) {
+            dbPositionMap.put(positionDyo.getLong(PositionBillConstant.ID_KEY), positionDyo);
         }
-
-        // 准备岗位保存数据
+        // 根据组织BOID从数据库中获取组织信息
+        DynamicObject[] adminOrgDyos = HRBaseServiceHelper.create(PositionBillConstant.ADMINORGHR_ENTITYID).loadDynamicObjectArray(new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, adminorgBoIds)});
+        Map<Long, DynamicObject> dbAdminOrgMap = Maps.newHashMapWithExpectedSize(adminOrgDyos.length);
+        for (DynamicObject adminOrgDyo : adminOrgDyos) {
+            dbAdminOrgMap.put(adminOrgDyo.getLong(PositionBillConstant.BOID_KEY), adminOrgDyo);
+        }
+        // 构建岗位对象
         OperateOption operateOption = OperateOption.create();
         List<DynamicObject> positionList = Lists.newArrayListWithExpectedSize(positionEntities.length);
-        for (DynamicObject positionEntity : positionEntities) {
-            long positionId = positionEntity.getLong(String.format("%s_id", PositionBillConstant.NCKD_POSITION));
+        // 查询需要转换的键值
+        String selectFields = QueryFieldBuilder.create().add(PositionBillConstant.NUMBER_KEY).add(PositionBillConstant.NAME_KEY).buildSelect();
+        DynamicObject[] transKeyDyos = HRBaseServiceHelper.create(PositionBillConstant.NCKD_POSITION_TRANSKEY_ENTITY).queryOriginalArray(selectFields, null);
+        // key->目标字段 value->源字段
+        Map<String, String> transKeyMap = Arrays.stream(transKeyDyos).map(Function.identity()).collect(Collectors.toMap(transKeyDyo -> transKeyDyo.getString(PositionBillConstant.NAME_KEY), transKeyDyo -> transKeyDyo.getString(PositionBillConstant.NUMBER_KEY), (oldValue, newValue) -> newValue));
 
+        for (DynamicObject positionEntity : positionEntities) {
+            long positionId = positionEntity.getLong(String.join("_", PositionBillConstant.NCKD_POSITION, PositionBillConstant.ID_KEY));
             // 如果数据库存在则用数据库的岗位对象
-            DynamicObject positionDy = dbPositionMap.get(positionId);
+            DynamicObject positionDyo = dbPositionMap.get(positionId);
             // 不存在则创建一个
-            if (positionDy == null) {
-                positionDy = BusinessDataServiceHelper.newDynamicObject(PositionBillConstant.HBPM_POSITIONHR);
-            }
-
-            // 键值转换
-            Map<String, String> transKeyMap = new HashMap<String, String>();
-            DataEntityPropertyCollection properties = positionDy.getDataEntityType().getProperties();
-            for (IDataEntityProperty property : properties) {
-                String name = property.getName();
-                if (name.startsWith(FIELD_PREFIX)) {
-                    transKeyMap.put(name.substring(name.indexOf(FIELD_PREFIX)), name);
-                }
+            if (positionDyo == null) {
+                positionDyo = positionServiceHelper.generateEmptyDynamicObject();
             }
-            // 设立日期单独处理
-            transKeyMap.put(PositionBillConstant.ESTABLISHMENTDATE_KEY, PositionBillConstant.NCKD_ESTDATE);
-
             // 将表单中的信息赋值到岗位信息中
-            HRDynamicObjectUtils.copy(positionEntity, positionDy);
-            positionDy.set(PositionBillConstant.ID_KEY, positionId);
+            HRDynamicObjectUtils.copy(positionEntity, positionDyo, transKeyMap);
+            // 设置 行政组织
+            positionDyo.set(PositionBillConstant.ADMINORG, dbAdminOrgMap.get(positionEntity.getLong(PositionBillConstant.NCKD_ADMINORGBOID_KEY)));
+             // 设置ID
+            positionDyo.set(PositionBillConstant.ID_KEY, positionId);
+            // 设置 上级岗位
             DynamicObject parentPositionVersionDy = positionEntity.getDynamicObject(PositionBillConstant.NCKD_PARENT);
             if (parentPositionVersionDy != null) {
-                positionDy.set(PositionBillConstant.PARENT_KEY, dbPositionMap.get(parentPositionVersionDy.getLong(PositionBillConstant.BOID_KEY)));
+                positionDyo.set(PositionBillConstant.PARENT_KEY, dbPositionMap.get(parentPositionVersionDy.getLong(PositionBillConstant.BOID_KEY)));
             } else {
-                positionDy.set(PositionBillConstant.PARENT_KEY, null);
+                positionDyo.set(PositionBillConstant.PARENT_KEY, null);
             }
-            positionDy.set(PositionBillConstant.STATUS, StatusEnum.A);
-            positionDy.set(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());
-            positionList.add(positionDy);
-            String number = positionDy.getString("number");
+            // 设置 数据状态
+            positionDyo.set(PositionBillConstant.STATUS, StatusEnum.A);
+            // 设置 业务状态
+            positionDyo.set(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());
+            // 设置 是否标准岗位
+            positionDyo.set(PositionBillConstant.ISSTANDARDPOS_KEY, EnableEnum.NO.getCode());
+            // 设置 数据版本状态
+            //positionDyo.set(PositionBillConstant.DATA_STATUS, HisModelDataStatusEnum.TEMP.getStatus());
+            positionList.add(positionDyo);
+            String number = positionDyo.getString("number");
+            // 设置 编码为已变更
             if (HRStringUtils.isNotEmpty(number)) {
-                operateOption.setVariableValue(positionId + "coderule_billno_from_initAbstractCodeRule", "coderule_billno_from_init_value_of_operation");
+                operateOption.setVariableValue(positionId + "coderule_billno_from_initAbstractCodeRule", PAGECACHE_KEY_BILLNO_FROM_INIT_VALUE_OF_OPERATION);
             }
         }
         // 跳过功能权限校验
@@ -128,27 +126,44 @@ public class PosBillEntryAddSaveOpPlugin extends AbstractOperationServicePlugIn
         // 跳过数据权限校验
         operateOption.setVariableValue(OperateOptionConst.SKIPCHECKPERMISSION, Boolean.TRUE.toString());
         StringBuilder errorMsg = new StringBuilder();
-        for (int index = 0; index < positionList.size(); index++) {
-            DynamicObject positionDy = positionList.get(index);
+        List<String> errorMsgList = Lists.newArrayList();
+        List successPkIds = Lists.newArrayList();
+        for (int index = 0; index < positionList.size(); ++index) {
+            DynamicObject positionDyo = positionList.get(index);
             OperationServiceImpl opImpl = new OperationServiceImpl();
-            OperationResult saveResult = opImpl.localInvokeOperation(PositionBillConstant.SAVE_OP, new DynamicObject[] { positionDy }, operateOption);
+            OperationResult saveResult = opImpl.localInvokeOperation(PositionBillConstant.SAVE_OP, new DynamicObject[]{positionDyo}, operateOption);
             if (!saveResult.isSuccess()) {
-                List<IOperateInfo> errorOrValidateInfo = saveResult.getAllErrorOrValidateInfo();
-                for (IOperateInfo operateInfo : errorOrValidateInfo) {
-                    errorMsg.append(operateInfo.getMessage());
+                for(IOperateInfo operateInfo : saveResult.getAllErrorOrValidateInfo()) {
+                    errorMsgList.add(operateInfo.getMessage());
                 }
             } else {
-                //DynamicObject[] dbPositionEntityDys = OrgRepository.getInstance().queryOrgDys(String.join(",", PositionBillConstant.ID_KEY, PositionBillConstant.NUMBER_KEY), new QFilter(PositionBillConstant.ID_KEY, QCP.in, saveResult.getSuccessPkIds()));
-                DynamicObject[] dbPositionEntityDys = null;
+                successPkIds.addAll(saveResult.getSuccessPkIds());
+                DynamicObject[] dbPositionEntityDys = positionServiceHelper.loadDynamicObjectArray(new QFilter[]{new QFilter(PositionBillConstant.ID_KEY, QCP.in, saveResult.getSuccessPkIds())});
                 DynamicObject dbPositionEntityDy = dbPositionEntityDys[0];
                 DynamicObject positionEntity = positionEntities[index];
-                positionEntity.set(String.format("%s_id", PositionBillConstant.NCKD_POSITION), dbPositionEntityDy.get(PositionBillConstant.ID_KEY));
+                positionEntity.set(String.join("_", PositionBillConstant.NCKD_POSITION, PositionBillConstant.ID_KEY), dbPositionEntityDy.get(PositionBillConstant.ID_KEY));
                 positionEntity.set(PositionBillConstant.NUMBER_KEY, dbPositionEntityDy.getString(PositionBillConstant.NUMBER_KEY));
             }
         }
-        if (errorMsg.length() > 0) {
-            throw new KDBizException(errorMsg.toString());
+        if (!errorMsgList.isEmpty()) {
+            throw new KDBizException(String.join(System.lineSeparator(), errorMsgList));
+        } else {
+            // 由于标品会强制设置值,所以需要后置更新
+            updatePositionDataStatus(successPkIds);
+        }
+    }
+
+    /**
+     * 更新岗位数据版本状态
+     * @param successPkIds
+     */
+    private void updatePositionDataStatus(List successPkIds) {
+        HRBaseServiceHelper positionServiceHelper = HRBaseServiceHelper.create(PositionBillConstant.HBPM_POSITIONHR);
+        DynamicObject[] positionDys = positionServiceHelper.loadDynamicObjectArray(new QFilter[]{new QFilter(PositionBillConstant.BOID_KEY, QCP.in, successPkIds)});
+        for (DynamicObject positionDy : positionDys) {
+            positionDy.set(PositionBillConstant.DATA_STATUS, HisModelDataStatusEnum.TEMP.getStatus());
         }
+        SaveServiceHelper.save(positionDys);
     }
 
 }

+ 28 - 0
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/PositionBillEntrySaveOpPlugin.java

@@ -0,0 +1,28 @@
+package nckd.jxccl.hrmp.hbpm.plugin.operate.hr;
+
+import kd.bos.dataentity.OperateOption;
+import kd.bos.entity.operate.OperateOptionConst;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.hr.homs.opplugin.web.orgbatch.validator.OrgAddSaveValidator;
+import nckd.jxccl.hrmp.hbpm.plugin.operate.hr.validator.PositionBillEntryValidator;
+
+/**
+ * 岗位申请单分录保存操作插件
+ * @entity: nckd_positionbillentry
+ * @author: jtd
+ * @date: 2025/12/18 09:57
+ */
+public class PositionBillEntrySaveOpPlugin extends AbstractOperationServicePlugIn {
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        super.onAddValidators(e);
+
+        OperateOption option = this.getOption();
+        String onlyValidate = option.getVariableValue(OperateOptionConst.ONLY_VALIDATE, Boolean.FALSE.toString());// 22
+        if (Boolean.TRUE.toString().equals(onlyValidate)) {
+            e.addValidator(new PositionBillEntryValidator());
+        }
+    }
+}

+ 1 - 36
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/validator/PositionBillEntryValidator.java

@@ -9,6 +9,7 @@ import kd.bos.dataentity.entity.ILocaleString;
 import kd.bos.entity.ExtendedDataEntity;
 import kd.bos.entity.validate.AbstractValidator;
 import kd.hr.hbp.common.util.HRStringUtils;
+import nckd.jxccl.hrmp.hbpm.common.hr.MultiLangEnum;
 import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
 
 import java.util.Map;
@@ -20,42 +21,6 @@ import java.util.Map;
  */
 public class PositionBillEntryValidator extends AbstractValidator {
 
-    private enum MultiLangEnum {
-        CHINES_SIMP("zh_CN", new MultiLangEnumBridge("简体中文", "MultiLangEnum_0", "hrmp-haos-common")),
-        CHINES_TRAD("zh_TW", new MultiLangEnumBridge("繁体中文", "MultiLangEnum_1", "hrmp-haos-common")),
-        ENGLISH("en_US", new MultiLangEnumBridge("英文", "MultiLangEnum_2", "hrmp-haos-common"));
-
-        private String code;
-        private MultiLangEnumBridge bridge = null;
-
-        private MultiLangEnum(String code, MultiLangEnumBridge bridge) {
-            this.code = code;
-            this.bridge = bridge;
-        }
-
-        public static String getName(String code) {
-            if (code == null) {
-                return null;
-            } else {
-                for(MultiLangEnum se : values()) {
-                    if (code.equals(se.getCode())) {
-                        return se.getName();
-                    }
-                }
-
-                return null;
-            }
-        }
-
-        public String getCode() {
-            return this.code;
-        }
-
-        public String getName() {
-            return this.bridge.loadKDString();
-        }
-    }
-
     @Override
     public void validate() {
         // 获取Op参数 校验岗位编码重复和岗位名称重复