Procházet zdrojové kódy

feat(hr): 新增岗位申请相关功能模块

- 新增岗位申请单服务类 PositionBillService 及其常量类 PositionBillConstant
- 实现岗位申请-新增岗位表单插件 PosBillEntryAddFormPlugin- 添加上级岗位列表插件 ParentPositionListPlugin- 更新组织批次相关常量类包路径并调整引用
- 修改岗位相关常量字段命名规范统一为小写
- 调整组织结构字段名称以适配新规范
- 优化组织调整申请界面插件逻辑处理流程
-修复岗位申请单据状态判断逻辑问题
- 完善岗位编码生成及回收机制处理逻辑- 增加岗位变动类型映射关系及相关操作标识定义
jtd před 1 týdnem
rodič
revize
ca27cb9f11
37 změnil soubory, kde provedl 1161 přidání a 91 odebrání
  1. 5 3
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java
  2. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/business/.gitkeep
  3. 1 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/common/AppflgConstant.java
  4. 1 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/common/orgbatch/OrgBatchConstant.java
  5. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/mservice/.gitkeep
  6. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/form/.gitkeep
  7. 2 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/form/orgbatch/AdminOrgCopyDialogFormPlugin.java
  8. 13 13
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/form/orgbatch/OrgBatchChgBillListPlugin.java
  9. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/operate/.gitkeep
  10. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/other/.gitkeep
  11. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/report/.gitkeep
  12. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/workflow/.gitkeep
  13. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/webapi/.gitkeep
  14. 1 1
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/haos/common/adminorg/AdminOrgConstant.java
  15. 7 5
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/haos/plugin/operate/adminorg/AdminOrgDetailConfirmChangeOpPlugin.java
  16. 191 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/business/hr/PositionBillService.java
  17. 169 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/hr/PositionBillConstant.java
  18. 0 22
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/position/PositionConstant.java
  19. 38 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/ParentPositionListPlugin.java
  20. 264 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PosBillEntryAddFormPlugin.java
  21. 107 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PositionBillEntryFormPlugin.java
  22. 134 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/PositionBillFormPlugin.java
  23. 0 29
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/list/position/PositionListPlugin.java
  24. 154 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/PosBillEntryAddSaveOpPlugin.java
  25. 74 0
      code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/operate/hr/validator/PositionBillEntryValidator.java
  26. 0 14
      code/odc/nckd-jxccl-odc/build.gradle
  27. 0 0
      code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/workflow/.gitkeep
  28. 0 0
      code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/webapi/.gitkeep
  29. 0 0
      code/odc/nckd-jxccl-odc/src/main/java/resources/.gitkeep
  30. 0 0
      code/odc/nckd-jxccl-odc/src/main/resources/.gitkeep
  31. 0 0
      code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/business/test/.gitkeep
  32. 0 0
      code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/common/test/.gitkeep
  33. 0 0
      code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/mservice/test/.gitkeep
  34. 0 0
      code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/plugin/test/.gitkeep
  35. 0 0
      code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/report/test/.gitkeep
  36. 0 0
      code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/webapi/test/.gitkeep
  37. 0 0
      code/odc/nckd-jxccl-odc/src/test/resources/.gitkeep

+ 5 - 3
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java

@@ -66,6 +66,8 @@ public class FormConstant {
     public static final String AFFIRM_OP = "affirm";
     /** 保存按钮标识 */
     public static final String SAVE_OP = "save";
+    /** 保存并新增按钮标识 */
+    public static final String SAVE_AND_NEW_OP = "saveandnew";
     /** 退出按钮 */
     public static final String CLOSE_OP = "tblclose";
     /** 审核操作标识 */
@@ -142,7 +144,7 @@ public class FormConstant {
     /** 初始状态 */
     public static final String INIT_STATUS = "initstatus";
     /** 组织 */
-    public static final String ORG_KEY = "ORG";
+    public static final String ORG_KEY = "org";
     /** 创建组织*/
     public static final String CREATEORG_KEY = "createorg";
     /** 原创建组织*/
@@ -152,13 +154,13 @@ public class FormConstant {
     /** 控制策略*/
     public static final String CTRLSTRATEGY_KEY = "ctrlstrategy";
     /** 分录行号 */
-    public static final String SEQ_KEY = "SEQ";
+    public static final String SEQ_KEY = "seq";
     /** 排序 */
     public static final String INDEX_KEY = "index";
     /** 编号标识 */
     public static final String EMP_NUMBER_KEY = "empnumber";
     /**人员*/
-    public static final String PERSON = "PERSON";
+    public static final String PERSON = "person";
     /** 组织*/
     public static final String ADMINORG = "adminorg";
     /** 所属公司*/

+ 0 - 0
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/list/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/business/.gitkeep


+ 1 - 1
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/common/AppflgConstant.java → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/common/AppflgConstant.java

@@ -5,7 +5,7 @@
  * Author: liebin.zheng
  * Generate Date: 2025-05-26 16:28:10
  */
-package nckd.jxccl.odc.homs.common;
+package nckd.jxccl.hr.homs.common;
 
 /**
  * hr云init应用-通用常量类<br>

+ 1 - 1
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/common/orgbatch/OrgBatchConstant.java → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/common/orgbatch/OrgBatchConstant.java

@@ -5,7 +5,7 @@
  * Author: liebin.zheng
  * Generate Date: 2025-05-26 16:28:10
  */
-package nckd.jxccl.odc.homs.common.orgbatch;
+package nckd.jxccl.hr.homs.common.orgbatch;
 
 import nckd.jxccl.base.common.constant.FormConstant;
 

+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/business/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/mservice/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/mservice/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/form/.gitkeep


+ 2 - 2
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/form/orgbatch/AdminOrgCopyDialogFormPlugin.java → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/form/orgbatch/AdminOrgCopyDialogFormPlugin.java

@@ -1,11 +1,11 @@
-package nckd.jxccl.odc.homs.plugin.form.orgbatch;
+package nckd.jxccl.hr.homs.plugin.form.orgbatch;
 
 import kd.bos.form.FormShowParameter;
 import kd.bos.form.ShowType;
 import kd.bos.form.events.AfterDoOperationEventArgs;
 import kd.bos.form.field.BasedataEdit;
 import kd.bos.form.plugin.AbstractFormPlugin;
-import nckd.jxccl.odc.homs.common.orgbatch.OrgBatchConstant;
+import nckd.jxccl.hr.homs.common.orgbatch.OrgBatchConstant;
 
 import java.util.EventObject;
 

+ 13 - 13
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/list/orgbatch/OrgBatchChgBillListPlugin.java → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/form/orgbatch/OrgBatchChgBillListPlugin.java

@@ -1,6 +1,5 @@
-package nckd.jxccl.odc.homs.plugin.list.orgbatch;
+package nckd.jxccl.hr.homs.plugin.form.orgbatch;
 
-import kd.bos.entity.datamodel.ListSelectedRow;
 import kd.bos.entity.datamodel.ListSelectedRowCollection;
 import kd.bos.form.CloseCallBack;
 import kd.bos.form.FormShowParameter;
@@ -12,7 +11,7 @@ import kd.bos.form.operate.AbstractOperate;
 import kd.bos.list.ListShowParameter;
 import kd.bos.list.plugin.AbstractListPlugin;
 import kd.hr.haos.business.domain.adminorg.service.impl.AdminOrgDetailHelper;
-import nckd.jxccl.odc.homs.common.orgbatch.OrgBatchConstant;
+import nckd.jxccl.hr.homs.common.orgbatch.OrgBatchConstant;
 
 /**
  * 组织调整申请界面插件
@@ -25,13 +24,16 @@ public class OrgBatchChgBillListPlugin extends AbstractListPlugin {
     public void beforeDoOperation(BeforeDoOperationEventArgs args) {
         super.beforeDoOperation(args);
 
-        boolean rootInit = (new AdminOrgDetailHelper()).checkRootInit(this.getView());
-        if (!rootInit) {
-            args.setCancel(true);
-        } else {
-            AbstractOperate operate = (AbstractOperate)args.getSource();
-            String operateKey = operate.getOperateKey();
-            openOperationPage(operateKey, args);
+        AbstractOperate operate = (AbstractOperate)args.getSource();
+        String operateKey = operate.getOperateKey();
+        if (OrgBatchConstant.SHOW_CHARGE_PERSON_OP.equals(operateKey)) {
+            // 使用标品校验逻辑
+            boolean rootInit = (new AdminOrgDetailHelper()).checkRootInit(getView());
+            if (!rootInit) {
+                args.setCancel(true);
+            } else {
+                openOperationPage(operateKey, args);
+            }
         }
     }
 
@@ -87,9 +89,7 @@ public class OrgBatchChgBillListPlugin extends AbstractListPlugin {
 
         // 设置部门负责人回调
         if (OrgBatchConstant.CHARGE_PERSON_DIALOG.equals(actionId)) {
-            ListSelectedRow listSelectedRow = returnData.get(0);
-            // 跳转到部门负责人设置界面
-            (new AdminOrgDetailHelper()).showDeptLeaderSet(this, (Long) listSelectedRow.getPrimaryKeyValue());
+            (new AdminOrgDetailHelper()).showDeptLeaderSet(this, (Long) returnData.get(0).getPrimaryKeyValue());
         }
     }
 }

+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/form/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/operate/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/list/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/other/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/operate/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/report/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/other/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/plugin/workflow/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/report/.gitkeep → code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/homs/webapi/.gitkeep


+ 1 - 1
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/haos/common/adminorg/AdminOrgConstant.java

@@ -12,7 +12,7 @@ public class AdminOrgConstant extends FormConstant {
     /**
      * 组织结构字段
      */
-    public static final String[] ADMINORG_STRUCT_FIELDS = {"nckd_firstdep","nckd_seconddep","nckd_thirddep","nckd_fourthdep","nckd_fifthdep","nckd_sixthdep"};
+    public static final String[] ADMINORG_STRUCT_FIELDS = {"nckd_firstorg","nckd_secondorg","nckd_thirdorg","nckd_fourthorg","nckd_fifthorg","nckd_sixthorg"};
 
     /**
      * 物理层级

+ 7 - 5
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/haos/plugin/operate/adminorg/AdminOrgDetailConfirmChangeOpPlugin.java

@@ -36,8 +36,8 @@ public class AdminOrgDetailConfirmChangeOpPlugin extends AbstractOperationServic
         }
 
         DynamicObject data = dataEntities[0];
-        // 非上级调整或未来生效
-        if (!"1020_S".equals(data.getDynamicObject(AdminOrgConstant.CHANGETYPE).getString(AdminOrgConstant.NUMBER_KEY)) || HRDateTimeUtils.dayAfter(data.getDate(AdminOrgConstant.BSED), HRDateTimeUtils.getNowDate())) {
+        // 非(上级调整或变更信息)或未来生效
+        if (!("1020_S".equals(data.getDynamicObject(AdminOrgConstant.CHANGETYPE).getString(AdminOrgConstant.NUMBER_KEY)) || "1030_S".equals(data.getDynamicObject(AdminOrgConstant.CHANGETYPE).getString(AdminOrgConstant.NUMBER_KEY))) || HRDateTimeUtils.dayAfter(data.getDate(AdminOrgConstant.BSED), HRDateTimeUtils.getNowDate())) {
             return false;
         }
 
@@ -54,7 +54,7 @@ public class AdminOrgDetailConfirmChangeOpPlugin extends AbstractOperationServic
         }
 
         // 获取组织及下级组织(旧数据)
-        QFilter qFilter = QFilter.of("1!=1", new Object[0]);
+        QFilter qFilter = QFilter.of("1!=1");
         Arrays.stream(dataEntities).map(dataEntity -> dataEntity.getString(AdminOrgConstant.STRUCTLONGNUMBER)+"%").forEach(structlongnumber -> {
             qFilter.or(QFilter.like(AdminOrgConstant.STRUCTLONGNUMBER, structlongnumber));
         });
@@ -72,13 +72,15 @@ public class AdminOrgDetailConfirmChangeOpPlugin extends AbstractOperationServic
 
         // 获取组织及下级组织(新数据)含历史版本
         List<Long> adminOrgBoIds = adminOrgOldDyColl.stream().map(adminOrg -> adminOrg.getLong(AdminOrgConstant.BOID_KEY)).collect(Collectors.toList());
-        DynamicObject[] adminOrgDys = BusinessDataServiceHelper.load(AdminOrgConstant.ADMINORGHR_ENTITYID, String.join(",", AdminOrgConstant.BOID_KEY, AdminOrgConstant.STRUCTLONGNUMBER, AdminOrgConstant.LEVEL, String.join(",", AdminOrgConstant.ADMINORG_STRUCT_FIELDS)), new QFilter[]{QFilter.isNotNull(AdminOrgConstant.STRUCTLONGNUMBER).and(new QFilter(AdminOrgConstant.STRUCTLONGNUMBER, QCP.not_equals, "")).and(new QFilter(AdminOrgConstant.BOID_KEY, QCP.in, adminOrgBoIds))}, AdminOrgConstant.BOID_KEY);
+        String selectProperties = String.join(",", AdminOrgConstant.BOID_KEY, AdminOrgConstant.STRUCTLONGNUMBER, AdminOrgConstant.LEVEL, String.join(",", AdminOrgConstant.ADMINORG_STRUCT_FIELDS));
+        QFilter qFilter = QFilter.isNotNull(AdminOrgConstant.STRUCTLONGNUMBER).and(new QFilter(AdminOrgConstant.STRUCTLONGNUMBER, QCP.not_equals, "")).and(new QFilter(AdminOrgConstant.BOID_KEY, QCP.in, adminOrgBoIds));
+        DynamicObject[] adminOrgDys = BusinessDataServiceHelper.load(AdminOrgConstant.ADMINORGHR_ENTITYID, selectProperties, new QFilter[]{qFilter}, AdminOrgConstant.BOID_KEY);
         // 遍历获取结构编码
         Map<String, String> structMap = Arrays.stream(adminOrgDys)
                 .map(adminOrgDy -> adminOrgDy.getString(AdminOrgConstant.STRUCTLONGNUMBER))
                 .flatMap(structNumber -> Arrays.stream(structNumber.split("!")))
                 .collect(Collectors.toMap(
-                        Function.identity(), // key就是遍历值 这里简写了 等价于 structNumber -> structNumber
+                        Function.identity(), // 等价于 structNumber -> structNumber
                         structNumber -> "", // value为空
                         (existing, replacement) -> existing // 重复key处理 保留旧值或新值都可以 这里随便挑一个
                 ));

+ 191 - 0
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/business/hr/PositionBillService.java

@@ -0,0 +1,191 @@
+package nckd.jxccl.hrmp.hbpm.business.hr;
+
+import com.google.common.collect.Maps;
+import com.kingdee.util.StringUtils;
+import kd.bos.bill.BillShowParameter;
+import kd.bos.bill.OperationStatus;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.datamodel.IDataModel;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.IFormView;
+import kd.bos.form.ShowType;
+import kd.bos.form.control.EntryGrid;
+import kd.bos.list.ListShowParameter;
+import kd.bos.org.utils.DynamicObjectUtils;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+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 nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 岗位申请单服务类
+ * @author: jtd
+ * @date: 2025-10-31 14:33
+ */
+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", "已删除");
+    }
+
+    /**
+     * 获取分录序号
+     * @param iDataModel
+     * @param changeType
+     * @return
+     */
+    public static int getEntrySeq(IDataModel iDataModel, Long changeType) {
+        Long billId = iDataModel.getDataEntity().getLong(PositionBillConstant.ID_KEY);
+        HRBaseServiceHelper hrBaseServiceHelper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY);
+        QFilter qFilter = new QFilter(PositionBillConstant.NCKD_BILLID, QCP.equals, billId);
+        qFilter.and(PositionBillConstant.NCKD_CHANGETYPE, QCP.equals, changeType);
+        String selectProps = String.join(",", new String[]{PositionBillConstant.ID_KEY, PositionBillConstant.NCKD_SEQUENCE});
+        String order = String.format("%s desc", PositionBillConstant.NCKD_SEQUENCE);
+        DynamicObject dynamicObject = hrBaseServiceHelper.queryOne(selectProps, qFilter.toArray(), order);
+        return dynamicObject == null ? 1 : dynamicObject.getInt(PositionBillConstant.NCKD_SEQUENCE) + 1;
+    }
+
+    /**
+     * 打开表单界面
+     * @param iFormView
+     * @param operation
+     * @param pluginName
+     * @param filter
+     */
+    public static void openViewForm(IFormView iFormView, String operation, String pluginName, QFilter filter) {
+        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);
+            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"))) {
+                    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}));
+                    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"));
+            int sequence = getEntrySeq(iFormView.getModel(), PositionBillConstant.CHANGE_TYPE_ADD);
+            formShowParameter.setCustomParam("sequence", sequence);
+            iFormView.showForm(formShowParameter);
+        }
+    }
+
+    public static void entryEntityMore(IDataModel iDataModel, IFormView iFormView, String tag, OperationStatus status, String pluginName) {
+        /*EntryGrid entryEntity = iFormView.getControl(ENTRY_ENTITY_PREFIX + tag);
+        int row = entryEntity.getEntryState().getFocusRow();
+        DynamicObject dynamicObject = iDataModel.getDataEntity(true).getDynamicObjectCollection(ENTRY_ENTITY_PREFIX + tag).get(row);
+        Map map = HRDynamicObjectUtils.convertDynamicObjectToMap(dynamicObject);
+        long id = dynamicObject.getLong("id");
+        BillShowParameter formShowParameter = new BillShowParameter();
+        if ("add".equals(tag)) {
+            formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYADD);
+        } else if ("change".equals(tag)) {
+            formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYCHANGE);
+        }
+
+        HRBaseServiceHelper helper = new HRBaseServiceHelper(PositionBillConstant.NCKD_POSITIONBILLENTRY);
+        boolean exists = helper.isExists(id);
+        if (exists) {
+            formShowParameter.setPkId(id);
+        }
+        formShowParameter.setStatus(status);
+        formShowParameter.setCustomParam("id", id);
+        formShowParameter.getOpenStyle().setShowType(ShowType.Modal);
+        formShowParameter.setCustomParam("selectObject", SerializationUtils.toJsonString(map));
+        formShowParameter.setCustomParam("billid", iDataModel.getValue(PositionBillConstant.ID_KEY));
+        formShowParameter.setCustomParam("iscard", "isCardFalse");
+        formShowParameter.setCustomParam("org_bsed", iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT) == null ? HRDateTimeUtils.getNowDateTime().getTime() : ((Date)iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT)).getTime());
+        formShowParameter.setCustomParam("org", iDataModel.getDataEntity().getLong("org.id"));
+        formShowParameter.setCustomParam("billstatus", iDataModel.getDataEntity().get(PositionBillConstant.BILL_STATUS_KEY));
+        int sequence = getEntrySeq(iDataModel, PositionBillConstant.CHANGE_TYPE_MAP.get(tag));
+        formShowParameter.setCustomParam("sequence", sequence);
+        formShowParameter.setCloseCallBack(new CloseCallBack(pluginName, ENTRY_ENTITY_PREFIX + tag));
+        iFormView.showForm(formShowParameter);*/
+
+        String entryEntityId = "nckd_entryentity_" + tag;
+        EntryGrid strategyEntryGrid = iFormView.getControl(entryEntityId);
+        int row = strategyEntryGrid.getEntryState().getFocusRow();
+        DynamicObject dynamicObject = iDataModel.getDataEntity(true).getDynamicObjectCollection(entryEntityId).get(row);
+        Long id = dynamicObject.getLong(PositionBillConstant.ID_KEY);
+        BillShowParameter formShowParameter = new BillShowParameter();
+        formShowParameter.setCustomParam("position_bsed", iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT) == null ? HRDateTimeUtils.getNowDateTime().getTime() : ((Date)iFormView.getModel().getValue(PositionBillConstant.NCKD_EFFDT)).getTime());
+        if ("add".equals(tag)) {
+            formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYADD);
+        } else if ("change".equals(tag)) {
+            formShowParameter.setFormId(PositionBillConstant.NCKD_POSBILLENTRYCHANGE);
+        }
+        formShowParameter.setPkId(id);
+        formShowParameter.setStatus(status);
+        if (HRStringUtils.equals(iFormView.getFormShowParameter().getAppId(), "wftask")) {
+            formShowParameter.setHasRight(true);
+        }
+
+        if (!status.equals(OperationStatus.VIEW)) {
+            formShowParameter.setCloseCallBack(new CloseCallBack(pluginName, entryEntityId));
+        }
+        formShowParameter.getOpenStyle().setShowType(ShowType.Modal);
+        iFormView.showForm(formShowParameter);
+    }
+
+
+    /**
+     * 获取岗位信息维护对象
+     * @param addDy
+     * @return
+     */
+    public static DynamicObject getPositionHrDy(DynamicObject addDy) {
+        DynamicObject positionHrDy = new DynamicObject(MetadataServiceHelper.getDataEntityType(PositionBillConstant.HBPM_POSITIONHR));
+        DynamicObjectUtils.copy(addDy, positionHrDy);
+        positionHrDy.set("id", addDy.getLong(PositionBillConstant.ID_KEY));
+        positionHrDy.set("parent", addDy.get(PositionBillConstant.NCKD_PARENT));
+        positionHrDy.set("adminorg", addDy.get(PositionBillConstant.NCKD_ADMINORG));
+        return positionHrDy;
+    }
+
+}

+ 169 - 0
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/hr/PositionBillConstant.java

@@ -0,0 +1,169 @@
+package nckd.jxccl.hrmp.hbpm.common.hr;
+
+import nckd.jxccl.base.common.constant.FormConstant;
+
+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";
+
+    /**
+     * 行政组织树表单ID
+     */
+    public static final String HAOS_ORGTREELISTF7 = "haos_orgtreelistf7";
+
+    /**
+     * 岗位变动类型表单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
+     */
+    public static final Map<String, Long> CHANGE_TYPE_MAP = new HashMap(){{
+        put("add", CHANGE_TYPE_ADD);
+        put("change", CHANGE_TYPE_CHANGE);
+    }};
+
+    /**
+     * 岗位信息维护表单ID
+     */
+    public static final String HBPM_POSITIONHR = "hbpm_positionhr";
+
+
+    /**
+     * 岗位申请单表单ID
+     */
+    public static final String NCKD_POSITIONBILL = "nckd_positionbill";
+
+    /**
+     * 岗位申请单分录表单ID
+     */
+    public static final String NCKD_POSITIONBILLENTRY = "nckd_positionbillentry";
+
+    /**
+     * 岗位申请-新增岗位表单ID
+     */
+    public static final String NCKD_POSBILLENTRYADD = "nckd_posbillentryadd";
+
+    /**
+     * 岗位申请-变更信息表单ID
+     */
+    public static final String NCKD_POSBILLENTRYCHANGE = "nckd_posbillentrychange";
+
+    /**
+     * 岗位职责分录ID
+     */
+    public static final String NCKD_POSDUTYENTRYENTITY = "nckd_posdutyentryentity";
+
+    /**
+     * 新增分录-岗位新设OP
+     */
+    public static final String NEWENTRY_ADD = "newentry_add";
+
+    /**
+     * 新增分录-岗位变更OP
+     */
+    public static final String NEWENTRY_CHANGE = "newentry_change";
+
+    /**
+     * 删除分录-岗位新设OP
+     */
+    public static final String DELETEENTRY_ADD = "deleteentry_add";
+
+    /**
+     * 删除分录-岗位变更OP
+     */
+    public static final String DELETEENTRY_CHANGE = "deleteentry_change";
+
+    /**
+     * 编辑-岗位新设OP
+     */
+    public static final String EDIT_ADD = "edit_add";
+
+    /**
+     * 编辑-岗位变更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";
+
+}

+ 0 - 22
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/common/position/PositionConstant.java

@@ -1,22 +0,0 @@
-package nckd.jxccl.hrmp.hbpm.common.position;
-
-import nckd.jxccl.base.common.constant.FormConstant;
-
-/**
- * 岗位常量
- * @author: jtd
- * @date: 2025-10-20 16:29
- */
-public class PositionConstant extends FormConstant {
-
-    /**
-     * 是否来自工作流
-     */
-    public static final String NCKD_ISFROMWF = "nckd_isfromwf";
-
-    /**
-     * 是否生效
-     */
-    public static final String NCKD_ISEFFECT = "nckd_iseffect";
-
-}

+ 38 - 0
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/form/hr/ParentPositionListPlugin.java

@@ -0,0 +1,38 @@
+package nckd.jxccl.hrmp.hbpm.plugin.form.hr;
+
+import kd.bos.form.control.SplitContainer;
+import kd.bos.form.control.SplitDirection;
+import kd.bos.form.events.PreOpenFormEventArgs;
+import kd.bos.list.plugin.AbstractListPlugin;
+
+import java.util.EventObject;
+import java.util.Map;
+
+
+/**
+ * 上级岗位列表插件
+ * @author: jtd
+ * @date: 2025-10-24 10:24
+ */
+public class ParentPositionListPlugin extends AbstractListPlugin {
+
+    @Override
+    public void preOpenForm(PreOpenFormEventArgs e) {
+        super.preOpenForm(e);
+
+        // 指定显示岗位数据
+        Map<String, Object> customParams = e.getFormShowParameter().getCustomParams();
+        customParams.put("showBasedata", "0");
+    }
+
+    @Override
+    public void beforeBindData(EventObject e) {
+        super.beforeBindData(e);
+
+        // 默认隐藏左树
+        SplitContainer splitContainer = (SplitContainer)this.getView().getControl("splitcontainerap");
+        if (splitContainer != null) {
+            splitContainer.hidePanel(SplitDirection.left, true);
+        }
+    }
+}

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

@@ -0,0 +1,264 @@
+package nckd.jxccl.hrmp.hbpm.plugin.form.hr;
+
+import kd.bos.common.enums.EnableEnum;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.utils.ObjectUtils;
+import kd.bos.dataentity.utils.StringUtils;
+import kd.bos.entity.datamodel.events.PropertyChangedArgs;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.form.ConfirmCallBackListener;
+import kd.bos.form.ConfirmTypes;
+import kd.bos.form.IPageCache;
+import kd.bos.form.MessageBoxOptions;
+import kd.bos.form.MessageBoxResult;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.BeforeClosedEvent;
+import kd.bos.form.events.MessageBoxClosedEvent;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.orm.ORM;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.coderule.CodeRuleServiceHelper;
+import kd.hr.hbp.business.servicehelper.HRBaseServiceHelper;
+import kd.hr.hbp.common.util.HRStringUtils;
+import nckd.jxccl.hrmp.hbpm.business.hr.PositionBillService;
+import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
+
+import java.util.Date;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 岗位申请-新增岗位表单插件
+ * @author: jtd
+ * @date: 2025-11-05 15:32
+ */
+public class PosBillEntryAddFormPlugin extends AbstractFormPlugin {
+
+    /**
+     * 编码规则的编码
+     */
+    private static final String CODERULE_NUMBER = "codeRuleNumber";
+
+    /**
+     * 保存结果标识
+     */
+    private static final String SAVE_RESULT = "saveResult";
+
+    @Override
+    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) {
+            Long billId = getView().getFormShowParameter().getCustomParam("billid");
+            getModel().setValue(PositionBillConstant.NCKD_BILLID, billId);
+            getPageCache().put("initFlag", Boolean.TRUE.toString());
+        }
+
+        // 设置生效时间
+        long positionBsedTime = getView().getFormShowParameter().getCustomParam("position_bsed");
+        getModel().setValue(PositionBillConstant.NCKD_BSED, new Date(positionBsedTime));
+        getModel().setValue(PositionBillConstant.ENABLE, EnableEnum.YES.getCode());
+
+        // 设置岗位编码
+        if (HRStringUtils.isEmpty(getModel().getDataEntity().getString(PositionBillConstant.NUMBER_KEY))) {
+            setPositionNumber(PositionBillService.getPositionHrDy(getModel().getDataEntity()));
+        } else {
+            setPositionNumberEnable();
+        }
+        getPageCache().put("paramsChangeSetNumber", Boolean.TRUE.toString());
+
+        // 新增的时候生成岗位ID
+        String positionIdKey = String.format("%s_id", PositionBillConstant.NCKD_POSITION);
+        long positionId = getModel().getDataEntity().getLong(positionIdKey);
+        if (positionId == 0L) {
+            positionId = ORM.create().genLongId(PositionBillConstant.HBPM_POSITIONHR);
+            getModel().setValue(positionIdKey, positionId);
+        }
+    }
+
+    private void setPositionNumberEnable() {
+        DynamicObject org = getModel().getDataEntity().getDynamicObject(PositionBillConstant.NCKD_ORG);
+        if (org == null) {
+            getView().setEnable(Boolean.valueOf(false), PositionBillConstant.NUMBER_KEY);
+            return;
+        }
+        long orgid = org.getLong(PositionBillConstant.ID_KEY);
+        DynamicObject positionHrDy = PositionBillService.getPositionHrDy(getModel().getDataEntity());
+        boolean cudeRule = CodeRuleServiceHelper.isExist(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(orgid));
+        if (cudeRule && !CodeRuleServiceHelper.isModifiable(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(org.getLong(PositionBillConstant.ID_KEY)))) {
+            getView().setEnable(Boolean.valueOf(false), PositionBillConstant.NUMBER_KEY);
+        }
+    }
+
+    private void setPositionNumber(DynamicObject positionHrDy) {
+        // 组织体系管理组织
+        DynamicObject org = getModel().getDataEntity().getDynamicObject(PositionBillConstant.NCKD_ORG);
+        if (org == null) {
+            getView().setEnable(Boolean.FALSE, PositionBillConstant.NUMBER_KEY);
+            return;
+        }
+
+        String number = getModel().getDataEntity().getString(PositionBillConstant.NUMBER_KEY);
+        if (HRStringUtils.isNotEmpty(number) && !HRStringUtils.equals(number, getView().getPageCache().get(CODERULE_NUMBER))) {
+            return;
+        }
+
+        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)))) {
+                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);
+                if (!hrBaseServiceHelper.isExists(qFilter)) {
+                    getModel().setValue(PositionBillConstant.NUMBER_KEY, positionNumber);
+                    getView().getPageCache().put(CODERULE_NUMBER, positionNumber);
+                } else {
+                    setPositionNumber(positionHrDy);
+                }
+            } else {
+                getView().setEnable(Boolean.FALSE, PositionBillConstant.NUMBER_KEY);
+            }
+        } else {
+            getModel().setValue(PositionBillConstant.NUMBER_KEY, null);
+            getView().getPageCache().put(CODERULE_NUMBER, "");
+            getView().setEnable(Boolean.TRUE, PositionBillConstant.NUMBER_KEY);
+        }
+    }
+
+    @Override
+    public void afterBindData(EventObject e) {
+        super.afterBindData(e);
+
+        // 设置岗位ID
+        long positionId = getModel().getDataEntity().getLong(PositionBillConstant.ID_KEY);
+        if (positionId == 0L) {
+            getModel().setValue(PositionBillConstant.ID_KEY, ORM.create().genLongId(PositionBillConstant.HBPM_POSITIONHR));
+        }
+
+        // 设置上级岗位变更前的数据到页面缓存中
+        DynamicObject parentPosition = getModel().getDataEntity().getDynamicObject(PositionBillConstant.NCKD_PARENT);
+        if (parentPosition != null) {
+            getView().getPageCache().put("beforeParentPositionId", parentPosition.getString(PositionBillConstant.ID_KEY));
+        }
+
+        // 取消变更提示
+        getModel().setDataChanged(false);
+    }
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs eventArgs) {
+        super.afterDoOperation(eventArgs);
+        OperationResult result = eventArgs.getOperationResult();
+        if (!ObjectUtils.isEmpty(result) && !result.isSuccess()) {
+            return;
+        }
+        IPageCache parentPageCache = getView().getParentView().getPageCache();
+        String operateKey = eventArgs.getOperateKey();
+        if (HRStringUtils.equals(operateKey, PositionBillConstant.SAVE_AND_NEW_OP) || HRStringUtils.equals(operateKey, PositionBillConstant.SAVE_OP)) {
+            String beforeParentPositionId = getView().getPageCache().get("beforeParentPositionId");
+            String addPositionParentChange = Boolean.FALSE.toString();
+            DynamicObject parentPosition = getModel().getDataEntity().getDynamicObject(PositionBillConstant.NCKD_PARENT);
+            if (parentPosition != null) {
+                String afterParentOrgId = parentPosition.getString(PositionBillConstant.ID_KEY);
+                if (!HRStringUtils.equals(beforeParentPositionId, afterParentOrgId)) {
+                    addPositionParentChange = Boolean.TRUE.toString();
+                }
+                parentPageCache.put("addPositionParentChange", addPositionParentChange);
+                parentPageCache.put("parentId", afterParentOrgId);
+            }
+            Map<String, String> map = new HashMap<>();
+            DynamicObject dataEntity = getModel().getDataEntity();
+            map.put("positionId", dataEntity.getString(String.format("%s_id", PositionBillConstant.NCKD_POSITION)));
+            map.put("name", dataEntity.getString(PositionBillConstant.NAME_KEY));
+            map.put("id", dataEntity.getString(PositionBillConstant.ID_KEY));
+            getView().getPageCache().put("saveResult", Boolean.TRUE.toString());
+            getView().returnDataToParent(map);
+        }
+    }
+
+    @Override
+    public void beforeClosed(BeforeClosedEvent event) {
+        super.beforeClosed(event);
+
+        String isCancelOverFlag = getView().getPageCache().get("isclose");
+        if (HRStringUtils.isNotEmpty(isCancelOverFlag) && Boolean.TRUE.toString().equals(isCancelOverFlag)) {
+            getModel().setDataChanged(false);
+            getView().getPageCache().put("isclose", Boolean.FALSE.toString());
+            return;
+        }
+
+        boolean dataChanged = getModel().getDataChanged();
+        if (dataChanged) {
+            event.setCancel(true);
+            ConfirmCallBackListener confirmCallBacks = new ConfirmCallBackListener("close_addbill", this);
+            Map<Integer, String> btnNameMaps = new HashMap<>();
+            btnNameMaps.put(MessageBoxResult.Cancel.getValue(), "返回编辑");
+            btnNameMaps.put(MessageBoxResult.Yes.getValue(), "直接退出");
+            MessageBoxOptions options = MessageBoxOptions.OKCancel;
+            String msg = "检测到您有更改内容,是否不保存直接退出?若不保存,将丢失这些更改。";
+            getView().showConfirm(msg, getModel().getChangeDesc(), options, ConfirmTypes.Save, confirmCallBacks, btnNameMaps);
+        } else {
+            String codeRuleNumber = getView().getPageCache().get(CODERULE_NUMBER);
+            if (!StringUtils.isEmpty(codeRuleNumber)) {
+                DynamicObject org = getModel().getDataEntity().getDynamicObject(PositionBillConstant.ORG_KEY);
+                if (org == null) {
+                    return;
+                }
+                String saveResult = getView().getPageCache().get(SAVE_RESULT);
+                if (!Boolean.TRUE.toString().equals(saveResult)) {
+                    long orgId = org.getLong(PositionBillConstant.ID_KEY);
+                    DynamicObject positionHrDy = PositionBillService.getPositionHrDy(getModel().getDataEntity());
+                    CodeRuleServiceHelper.recycleNumber(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(orgId), codeRuleNumber);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void confirmCallBack(MessageBoxClosedEvent event) {
+        super.confirmCallBack(event);
+        if ("close_addbill".equals(event.getCallBackId()) && event.getResult() != MessageBoxResult.Cancel) {
+            String codeRuleNumber = getView().getPageCache().get(CODERULE_NUMBER);
+            if (!StringUtils.isEmpty(codeRuleNumber)) {
+                DynamicObject org = getModel().getDataEntity().getDynamicObject(PositionBillConstant.ORG_KEY);
+                if (org == null) {
+                    return;
+                }
+                String saveResult = getView().getPageCache().get(SAVE_RESULT);
+                if (!Boolean.TRUE.toString().equals(saveResult)) {
+                    long orgId = org.getLong(PositionBillConstant.ID_KEY);
+                    DynamicObject positionHrDy = PositionBillService.getPositionHrDy(getModel().getDataEntity());
+                    CodeRuleServiceHelper.recycleNumber(PositionBillConstant.HBPM_POSITIONHR, positionHrDy, String.valueOf(orgId), codeRuleNumber);
+                }
+            }
+            getView().getPageCache().put("isclose", Boolean.TRUE.toString());
+            getView().invokeOperation("close");
+        }
+    }
+
+    @Override
+    public void propertyChanged(PropertyChangedArgs changedArgs) {
+        String fieldKey = changedArgs.getProperty().getName();
+        boolean isGetNumber = true;
+        if (PositionBillConstant.NCKD_ESTDATE.equals(fieldKey)) {
+            setEstablishmentDateToBsed((Date)changedArgs.getChangeSet()[0].getNewValue());
+        }
+    }
+
+    /**
+     * 设置设立日期到生效日期
+     * @param date
+     */
+    private void setEstablishmentDateToBsed(Date date) {
+        if (date != null) {
+            getModel().setValue(PositionBillConstant.NCKD_BSED, date);
+        }
+    }
+
+}

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

@@ -0,0 +1,107 @@
+package nckd.jxccl.hrmp.hbpm.plugin.form.hr;
+
+import kd.bos.bill.OperationStatus;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.field.BasedataEdit;
+import kd.bos.form.field.events.BeforeF7SelectEvent;
+import kd.bos.form.field.events.BeforeF7SelectListener;
+import kd.bos.form.plugin.AbstractFormPlugin;
+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;
+
+/**
+ * 岗位申请单分录表单插件
+ * @author: jtd
+ * @date: 2025-11-04 9:35
+ */
+public class PositionBillEntryFormPlugin extends AbstractFormPlugin implements BeforeF7SelectListener {
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+
+        BasedataEdit adminorg = getView().getControl(PositionBillConstant.NCKD_ADMINORG);
+        adminorg.addBeforeF7SelectListener(this);
+
+        BasedataEdit position = getView().getControl(PositionBillConstant.NCKD_POSITION);
+        position.addBeforeF7SelectListener(this);
+
+        BasedataEdit parent = getView().getControl(PositionBillConstant.NCKD_PARENT);
+        parent.addBeforeF7SelectListener(this);
+    }
+
+    @Override
+    public void beforeBindData(EventObject e) {
+        super.beforeBindData(e);
+
+        FormShowParameter formShowParameter = getView().getFormShowParameter();
+        setOrg();
+        if (formShowParameter.getCustomParam("sequence") != null && getModel().getDataEntity(true).getInt(PositionBillConstant.NCKD_SEQUENCE) == 0) {
+            getModel().setValue(PositionBillConstant.NCKD_SEQUENCE, formShowParameter.getCustomParam("sequence"));
+        }
+    }
+
+    /**
+     * 设置组织体系管理组织
+     */
+    private void setOrg() {
+        String entityId = getView().getEntityId();
+        if (PositionBillConstant.NCKD_POSBILLENTRYADD.equals(entityId) || PositionBillConstant.NCKD_POSBILLENTRYCHANGE.equals(entityId)) {
+            Object orgParam = getView().getFormShowParameter().getCustomParam(PositionBillConstant.ORG_KEY);
+            String isInit = getPageCache().get("isInit");
+            if (orgParam != null && HRStringUtils.isEmpty(isInit)) {
+                getModel().beginInit();
+                getModel().setValue(PositionBillConstant.NCKD_ORG, orgParam);
+                getModel().endInit();
+                getPageCache().put("isInit", BigInteger.ONE.toString());
+            }
+        }
+    }
+
+    public void afterBindData(EventObject e) {
+        super.afterBindData(e);
+
+        getModel().setDataChanged(false);
+        OperationStatus status = getView().getFormShowParameter().getStatus();
+        if (OperationStatus.ADDNEW.equals(status) || OperationStatus.EDIT.equals(status)) {
+            getView().setEnable(Boolean.TRUE, PositionBillConstant.ORG_KEY);
+        }
+    }
+
+    @Override
+    public void beforeF7Select(BeforeF7SelectEvent beforeF7SelectEvent) {
+        String fieldKey = beforeF7SelectEvent.getProperty().getName();
+        // 替换组织F7模板
+        if (PositionBillConstant.NCKD_ADMINORG.equals(fieldKey)) {
+            ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
+            showParameter.setFormId(PositionBillConstant.HAOS_ORGTREELISTF7);
+            //showParameter.setCaption("行政组织");
+        }
+
+        // 替换岗位F7模板
+        if (PositionBillConstant.NCKD_POSITION.equals(fieldKey)) {
+            ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
+            showParameter.setFormId(PositionBillConstant.NCKD_NOTIME_POSTREELISTF7);
+            showParameter.setCaption("岗位");
+        }
+
+        // 替换上级岗位F7模板
+        if (PositionBillConstant.NCKD_PARENT.equals(fieldKey)) {
+            ListShowParameter showParameter = (ListShowParameter) beforeF7SelectEvent.getFormShowParameter();
+            showParameter.setFormId(PositionBillConstant.NCKD_NOTIME_POSTREELISTF7);
+            showParameter.setCaption("上级岗位");
+        }
+    }
+
+    @Override
+    public void beforeDoOperation(BeforeDoOperationEventArgs args) {
+        super.beforeDoOperation(args);
+
+
+    }
+}

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

@@ -0,0 +1,134 @@
+package nckd.jxccl.hrmp.hbpm.plugin.form.hr;
+
+import kd.bos.bill.OperationStatus;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.form.ConfirmCallBackListener;
+import kd.bos.form.MessageBoxOptions;
+import kd.bos.form.MessageBoxResult;
+import kd.bos.form.control.EntryGrid;
+import kd.bos.form.control.events.ItemClickEvent;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.ClosedCallBackEvent;
+import kd.bos.form.events.MessageBoxClosedEvent;
+import kd.bos.form.field.events.BeforeF7SelectEvent;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.form.plugin.IFormPlugin;
+import kd.bos.list.ListShowParameter;
+import kd.bos.orm.ORM;
+import nckd.jxccl.hrmp.hbpm.business.hr.PositionBillService;
+import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
+
+import java.util.EventObject;
+
+/**
+ * 岗位申请单表单插件
+ * @author: jtd
+ * @date: 2025-10-25 13:38
+ */
+public class PositionBillFormPlugin extends AbstractFormPlugin {
+
+    private static final String NCKD_ENTRYENTITY_ADD = "nckd_entrtyentity_add";
+    private static final String NCKD_ENTRYENTITY_INFO = "nckd_entrtyentity_info";
+    private static final String NCKD_CHANGETYPE = "nckd_chagetype";
+
+    @Override
+    public void afterBindData(EventObject e) {
+        super.afterBindData(e);
+
+        // 生成临时单据ID
+        genBillIdIfNotExist();
+        this.getModel().setDataChanged(false);
+    }
+
+    /**
+     * 生成临时单据ID
+     */
+    private void genBillIdIfNotExist() {
+        long billId = this.getModel().getDataEntity().getLong("id");
+        if (billId == 0L) {
+            billId = ORM.create().genLongId(this.getView().getEntityId());
+            this.getModel().setValue("id", billId);
+        }
+    }
+
+    @Override
+    public void itemClick(ItemClickEvent evt) {
+        super.itemClick(evt);
+
+        if ("tb_del".equals(evt.getItemKey())) {
+            EntryGrid posdutyEntryGrid = getView().getControl(PositionBillConstant.NCKD_POSDUTYENTRYENTITY);
+            int length = (posdutyEntryGrid.getSelectRows()).length;
+            if (length > 0) {
+                ConfirmCallBackListener deleteEntryCallBackListener = new ConfirmCallBackListener("del_row", this);
+                getView().showConfirm(String.format("你已选中%s条记录,删除后将不可恢复,是否继续?", length), MessageBoxOptions.OKCancel, deleteEntryCallBackListener);
+            } else {
+                getView().showTipNotification("请选中需要操作的行。");
+            }
+        }
+    }
+
+
+
+    @Override
+    public void confirmCallBack(MessageBoxClosedEvent event) {
+        super.confirmCallBack(event);
+
+        if ("del_row".equals(event.getCallBackId()) && event.getResult().getValue() == MessageBoxResult.Yes.getValue()) {
+            EntryGrid strategyEntryGrid = (EntryGrid)getView().getControl("cooprelentryentity");
+            int[] rows = strategyEntryGrid.getSelectRows();
+            getModel().deleteEntryRows("cooprelentryentity", rows);
+        }
+    }
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs afterDoOperationEventArgs) {
+        super.afterDoOperation(afterDoOperationEventArgs);
+
+        OperationResult afterOperationResult = afterDoOperationEventArgs.getOperationResult();
+        if (!(afterOperationResult == null || afterOperationResult.isSuccess())) {
+            return;
+        }
+
+        String opKey = afterDoOperationEventArgs.getOperateKey();
+        switch (opKey) {
+            case PositionBillConstant.NEWENTRY_ADD:
+                PositionBillService.openViewForm(this.getView(), opKey, this.getPluginName(), null);
+                break;
+            case "newentry_change":
+                PositionBillService.openViewForm(this.getView(), opKey, this.getPluginName(), null);
+                break;
+            case "deleteentry_add":
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                break;
+            case "deleteentry_change":
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                break;
+            case "edit_add":
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                break;
+            case "edit_change":
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                break;
+        }
+    }
+
+    @Override
+    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
+        super.closedCallBack(closedCallBackEvent);
+
+        switch (closedCallBackEvent.getActionId()) {
+            case "add":
+                PositionBillService.openViewForm(this.getView(), "add", this.getPluginName(), null);
+                break;
+            case "change":
+                PositionBillService.openViewForm(this.getView(), "change", this.getPluginName(), null);
+                break;
+            case "delete":
+                PositionBillService.openViewForm(this.getView(), "delete", this.getPluginName(), null);
+                break;
+            case "edit":
+        }
+
+    }
+
+}

+ 0 - 29
code/hrmp/nckd-jxccl-hrmp/src/main/java/nckd/jxccl/hrmp/hbpm/plugin/list/position/PositionListPlugin.java

@@ -1,29 +0,0 @@
-package nckd.jxccl.hrmp.hbpm.plugin.list.position;
-
-import kd.bos.form.events.SetFilterEvent;
-import kd.bos.list.plugin.AbstractListPlugin;
-import kd.bos.orm.query.QCP;
-import kd.bos.orm.query.QFilter;
-import kd.occ.ocpos.common.enums.BillStatusEnum;
-import nckd.jxccl.hrmp.hbpm.common.position.PositionConstant;
-
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * 岗位信息维护列表插件
- * @author: jtd
- * @date: 2025-10-20 17:07
- */
-public class PositionListPlugin extends AbstractListPlugin {
-
-    @Override
-    public void setFilter(SetFilterEvent e) {
-        super.setFilter(e);
-
-        // 来源工作流且生效的数据或非来源工作流的数据
-        QFilter qFilter = new QFilter(PositionConstant.NCKD_ISFROMWF, QCP.equals, Boolean.TRUE).and(new QFilter(PositionConstant.NCKD_ISEFFECT, QCP.equals, Boolean.TRUE)).or(new QFilter(PositionConstant.NCKD_ISFROMWF, QCP.not_equals, Boolean.TRUE)).or(QFilter.isNull(PositionConstant.NCKD_ISFROMWF));
-        e.addCustomQFilter(qFilter);
-    }
-}

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

@@ -0,0 +1,154 @@
+package nckd.jxccl.hrmp.hbpm.plugin.operate.hr;
+
+import com.google.common.collect.Lists;
+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.hr.haos.business.domain.adminorg.service.impl.OrgRepository;
+import kd.hr.hbp.common.util.HRDynamicObjectUtils;
+import kd.hr.hbp.common.util.HRStringUtils;
+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.List;
+import java.util.Map;
+
+/**
+ * 岗位申请-新增岗位保存OP
+ * @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());
+    }
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+        super.beginOperationTransaction(e);
+
+        DynamicObject[] positionEntities = e.getDataEntities();
+        if (positionEntities.length == 0) {
+            return;
+        }
+
+        // 获取岗位和上级岗位的业务ID
+        List<Long> positionBoIds = Lists.newArrayListWithExpectedSize(positionEntities.length);
+        for (DynamicObject orgEntity : positionEntities) {
+            positionBoIds.add(orgEntity.getLong(String.format("%s_id", PositionBillConstant.NCKD_POSITION)));
+
+            // 获取上级岗位
+            DynamicObject parentPositionVersionDy = orgEntity.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);
+        }
+
+        // 准备岗位保存数据
+        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));
+
+            // 如果数据库存在则用数据库的岗位对象
+            DynamicObject positionDy = 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);
+                }
+            }
+            // 设立日期单独处理
+            transKeyMap.put(PositionBillConstant.ESTABLISHMENTDATE_KEY, PositionBillConstant.NCKD_ESTDATE);
+
+            // 将表单中的信息赋值到岗位信息中
+            HRDynamicObjectUtils.copy(positionEntity, positionDy);
+            positionDy.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)));
+            } else {
+                positionDy.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");
+            if (HRStringUtils.isNotEmpty(number)) {
+                operateOption.setVariableValue(positionId + "coderule_billno_from_initAbstractCodeRule", "coderule_billno_from_init_value_of_operation");
+            }
+        }
+        // 跳过功能权限校验
+        operateOption.setVariableValue(OperateOptionConst.ISHASRIGHT, Boolean.TRUE.toString());
+        // 跳过数据权限校验
+        operateOption.setVariableValue(OperateOptionConst.SKIPCHECKPERMISSION, Boolean.TRUE.toString());
+        StringBuilder errorMsg = new StringBuilder();
+        for (int index = 0; index < positionList.size(); index++) {
+            DynamicObject positionDy = positionList.get(index);
+            OperationServiceImpl opImpl = new OperationServiceImpl();
+            OperationResult saveResult = opImpl.localInvokeOperation(PositionBillConstant.SAVE_OP, new DynamicObject[] { positionDy }, operateOption);
+            if (!saveResult.isSuccess()) {
+                List<IOperateInfo> errorOrValidateInfo = saveResult.getAllErrorOrValidateInfo();
+                for (IOperateInfo operateInfo : errorOrValidateInfo) {
+                    errorMsg.append(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 dbPositionEntityDy = dbPositionEntityDys[0];
+                DynamicObject positionEntity = positionEntities[index];
+                positionEntity.set(String.format("%s_id", PositionBillConstant.NCKD_POSITION), dbPositionEntityDy.get(PositionBillConstant.ID_KEY));
+                positionEntity.set(PositionBillConstant.NUMBER_KEY, dbPositionEntityDy.getString(PositionBillConstant.NUMBER_KEY));
+            }
+        }
+        if (errorMsg.length() > 0) {
+            throw new KDBizException(errorMsg.toString());
+        }
+    }
+
+}

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

@@ -0,0 +1,74 @@
+package nckd.jxccl.hrmp.hbpm.plugin.operate.hr.validator;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import kd.bos.dataentity.OperateOption;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.ILocaleString;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.hr.haos.common.constants.MultiLangEnum;
+import kd.hr.hbp.common.util.HRStringUtils;
+import nckd.jxccl.hrmp.hbpm.common.hr.PositionBillConstant;
+
+import java.util.Map;
+
+/**
+ * 岗位申请单分录校验器
+ * @author: jtd
+ * @date: 2025-11-08 17:23
+ */
+public class PositionBillEntryValidator extends AbstractValidator {
+
+    @Override
+    public void validate() {
+        // 获取Op参数 校验岗位编码重复和岗位名称重复
+        OperateOption option = validateContext.getOption();
+        // 获取组织下的岗位同胞数据 {orgBoId: {id:positionid, number:positionnumber, name:positionname}}
+        String billPositionSiblingMapStr = option.getVariableValue("OP_BILL_SIBLING_MAP", "");
+        if (HRStringUtils.isNotEmpty(billPositionSiblingMapStr)) {
+            JSONObject orgBoIdToSiblingPositionMap = JSONObject.parseObject(billPositionSiblingMapStr);
+            // 遍历保存数据
+            for (ExtendedDataEntity data : getDataEntities()) {
+                // 获取单据对象
+                DynamicObject positionDy = data.getDataEntity();
+                DynamicObject orgDy = positionDy.getDynamicObject(PositionBillConstant.NCKD_ADMINORG);
+                long orgBoId = orgDy.getLong(PositionBillConstant.BOID_KEY);
+                long positionId = positionDy.getLong(String.format("%s.id", PositionBillConstant.NCKD_POSITION));
+                String positionNumber = positionDy.getString(PositionBillConstant.NUMBER_KEY);
+                ILocaleString positionNameMap = positionDy.getLocaleString(PositionBillConstant.NAME_KEY);
+                // 获取岗位同胞数据进行遍历处理
+                JSONArray siblingPositionArr = orgBoIdToSiblingPositionMap.getJSONArray(String.valueOf(orgBoId));
+                if (siblingPositionArr != null) {
+                    for (int i = 0, size = siblingPositionArr.size(); i < size; i++) {
+                        JSONObject positionObj = siblingPositionArr.getJSONObject(i);
+                        // 如果是当前岗位则跳过
+                        if (positionObj.getString(PositionBillConstant.ID_KEY).equals(positionId)) {
+                            continue;
+                        }
+
+                        // 如果编码重复
+                        if (positionObj.getString(PositionBillConstant.NUMBER_KEY).equals(positionNumber)) {
+                            addErrorMessage(data, "岗位编码在本单已存在,请修改。");
+                            continue;
+                        }
+
+                        // 如果名称重复 多语言校验
+                        for (Map.Entry<String, String> nameEntry : positionNameMap.entrySet()) {
+                            String lang = nameEntry.getKey();
+                            if ("GLang".equals(lang)) {
+                                continue;
+                            }
+
+                            String name = positionObj.getJSONObject(PositionBillConstant.NAME_KEY).getString(lang);
+                            if (name.equals(nameEntry.getValue())) {
+                                addErrorMessage(data, String.format("本单中“%1$s”下已存在%2$s名称为“%3$s”的岗位,请修改。", orgDy.getString(PositionBillConstant.NAME_KEY), MultiLangEnum.getName(lang), name));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+}

+ 0 - 14
code/odc/nckd-jxccl-odc/build.gradle

@@ -1,14 +0,0 @@
-/*
- * This is a kingdee cosmic template project that is automatically generated by the Kingdee cosmic development assistant plugin. 
- * If there are any issues during the use process, you can provide feedback to the kingdee developer community website.
- * Website: https://developer.kingdee.com/developer?productLineId=29
- * Author: liebin.zheng
- * Generate Date: 2025-09-28 14:21:58
- */
-
-dependencies {
-	api project(':nckd-jxccl-base-common')
-	api project(':nckd-jxccl-base-helper')
-} 
-
-

+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/plugin/workflow/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/nckd/jxccl/odc/homs/webapi/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/java/resources/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/main/resources/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/business/test/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/common/test/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/mservice/test/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/plugin/test/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/report/test/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/test/java/nckd/odc/homs/webapi/test/.gitkeep


+ 0 - 0
code/odc/nckd-jxccl-odc/src/test/resources/.gitkeep