Przeglądaj źródła

feat(hr): 新增子企业负责人任职情况相关功能

- 新增人员附表实体常量:企业负责人信息、党政职务变更履历、法人单位任职信息
- 新增操作执行结果显示工具类 ShowOperExecuteResult,支持成功/失败信息展示
- 完善绩效管理保存操作插件,增强归档数据修改校验逻辑
- 优化考核结果计算逻辑,增加对不同年份考核结果的处理
- 新增子企业负责人任职情况相关常量类和插件实现
- 调整操作提示类型,将部分警告信息改为错误提示
- 修复部分实体字段重复定义问题,优化代码结构
wyc 5 dni temu
rodzic
commit
32debe00f8
16 zmienionych plików z 611 dodań i 21 usunięć
  1. 7 3
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java
  2. 117 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/ShowOperExecuteResult.java
  3. 1 1
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/PerfRankMgmtSaveOpPlugin.java
  4. 0 1
      code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/cycle/CycleGenerateOpPlugin.java
  5. 42 13
      code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/cycle/PerfManagerSaveOpPlugin.java
  6. 2 2
      code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/result/PerfArchiveOrUnArchiveOpPlugin.java
  7. 4 1
      code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/salary/SalaryAdjOpPlugin.java
  8. 0 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/business/.gitkeep
  9. 80 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/common/SubCoHeadServiceConstant.java
  10. 0 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/mservice/.gitkeep
  11. 302 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/form/empmgt/SubCoHeadServiceListPlugin.java
  12. 56 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/operate/SubCoHeadServiceOpPlugin.java
  13. 0 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/other/.gitkeep
  14. 0 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/report/.gitkeep
  15. 0 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/workflow/.gitkeep
  16. 0 0
      code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/webapi/.gitkeep

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

@@ -62,7 +62,12 @@ public class FormConstant {
     public static final String BOS_ORG_ENTITY = "bos_org";
     /** HR组织 */
     public static final String HAOS_ADMINORGHRF7_ENTITY = "haos_adminorghrf7";
-
+    /** 人员附表-企业负责人信息-实体 */
+    public static final String NCKD_HRPI_ENTHEAD = "nckd_hrpi_enthead";
+    /** 人员附表-党政职务变更履历-实体 */
+    public static final String NCKD_HRPI_PARTYPOSH = "nckd_hrpi_partyposh";
+    /** 人员附表-法人单位任职信息-实体 */
+    public static final String NCKD_HRPI_LEGALPOST = "nckd_hrpi_legalpost";
 
     //====================================== 标品op ======================================
     /** 确认框确认按钮 */
@@ -273,8 +278,6 @@ public class FormConstant {
     public static final String POSTYPE = "postype";
     /** 任职状态分类*/
     public static final String POST_STATE_CLS = "poststatecls";
-    /** 党政职务变更履历*/
-    public static final String NCKD_HRPI_PARTYPOSH = "nckd_hrpi_partyposh";
     /** 职位级别*/
     public static final String NCKD_POSGRADE = "nckd_posgrade";
     /** 排序号*/
@@ -310,4 +313,5 @@ public class FormConstant {
     public static final String NCKD_ORG = "nckd_org";
 
 
+
 }

+ 117 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/ShowOperExecuteResult.java

@@ -0,0 +1,117 @@
+package nckd.jxccl.base.common.utils;
+
+import kd.bos.dataentity.resource.ResManager;
+import kd.bos.dataentity.serialization.DataEntitySerializer;
+import kd.bos.dataentity.serialization.DataEntitySerializerOption;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.IPageCache;
+import kd.bos.form.ShowType;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * 操作执行结果显示工具类
+ * 用于生成操作执行结果的表单显示参数,支持显示操作成功和失败的信息
+ * 当错误项较多时可以使用表格方式显示,避免信息被截断
+ *
+ * @author W.Y.C
+ * @date 2025/11/28 14:49
+ * @version 1.0
+ */
+public class ShowOperExecuteResult {
+
+    /**
+     * 获取操作结果表单显示参数(重载方法1)
+     * 
+     * @param operateName 操作名称
+     * @param successMap 成功记录映射关系(成功的数据需要显示时需要在op自定义参数中添加:this.getOperationResult().getCustomData().put("成功的id","需要显示的消息");)
+     * @param pageCache 页面缓存对象
+     * @param operationResult 操作结果对象
+     * @return 表单显示参数
+     */
+    public static FormShowParameter getOperResultForm(String operateName, Map<Object, Object> successMap, IPageCache pageCache, OperationResult operationResult) {
+        return getOperResultForm(null, operateName, successMap, pageCache, operationResult);
+    }
+
+    /**
+     * 获取操作结果表单显示参数(重载方法2)
+     * 
+     * @param operateName 操作名称
+     * @param pageCache 页面缓存对象
+     * @param operationResult 操作结果对象
+     * @return 表单显示参数
+     */
+    public static FormShowParameter getOperResultForm(String operateName, IPageCache pageCache,  OperationResult operationResult) {
+        return getOperResultForm(null, operateName, null, pageCache, operationResult);
+    }
+
+    /**
+     * 获取操作结果表单显示参数(核心方法)
+     * 构造并返回一个包含操作执行结果信息的表单显示参数对象
+     * 
+     * @param title 自定义标题,如果为空则根据成功/失败数量自动生成标题
+     * @param operateName 操作名称
+     * @param successMap 成功记录映射关系
+     * @param pageCache 页面缓存对象,用于存储操作结果序列化后的数据
+     * @param operationResult 操作结果对象,包含详细的成功/失败信息
+     * @return 表单显示参数对象
+     */
+    public static FormShowParameter getOperResultForm(String title, String operateName, Map<Object, Object> successMap, IPageCache pageCache, OperationResult operationResult) {
+
+        // 收集所有错误或验证信息
+        StringJoiner errorMsgJoiner = new StringJoiner(StrFormatter.LINE_SEPARATOR);
+        for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
+            errorMsgJoiner.add(error.getMessage());
+        }
+        String errorMsg = errorMsgJoiner.toString();
+        
+        // 如果没有具体的错误详情,则使用操作结果中的通用消息
+        if (StringUtils.isBlank(errorMsg)) {
+            errorMsg = operationResult.getMessage();
+        }
+
+        // 将操作结果序列化后存入页面缓存
+        DataEntitySerializerOption option = new DataEntitySerializerOption();
+        option.setIncludeComplexProperty(true);
+        pageCache.put("operationresult", DataEntitySerializer.serializerToString(operationResult, option));
+        
+        // 构建自定义参数
+        Map<String, Object> customParam = new HashMap(2);
+        customParam.put("operateName", operateName);
+        
+        // 设置标题:如果有自定义标题则使用,否则根据成功/失败数量自动生成
+        if (StringUtils.isNotBlank(title)) {
+            customParam.put("title", title);
+        } else {
+            int billCount = operationResult.getBillCount();
+            int successCount = operationResult.getSuccessPkIds().size();
+            int validError = billCount - successCount;
+            customParam.put("title", ResManager.loadKDString("成功数量:%1$s,失败数量:%2$s", "AbstractFormView_8", "bos-form-metadata", new Object[]{successCount, validError}));
+        }
+        
+        // 添加其他参数
+        customParam.put("hasMore", true);
+        customParam.put("errorMsg", errorMsg);
+        
+        // 如果有成功记录映射关系,则添加到参数中
+        if (successMap != null && !successMap.isEmpty()) {
+            // 成功消息
+            customParam.put("pkNumbers", successMap);
+        }
+        
+        // 构造表单显示参数对象
+        FormShowParameter parameter = new FormShowParameter();
+        parameter.setFormId("bos_operationresult"); // 设置表单ID
+        parameter.getOpenStyle().setShowType(ShowType.Modal); // 设置显示类型
+        parameter.getCustomParams().putAll(customParam); // 添加自定义参数
+        parameter.setShowTitle(false); // 不显示默认标题
+        
+        return parameter;
+    }
+
+}

+ 1 - 1
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/psms/plugin/operate/performance/PerfRankMgmtSaveOpPlugin.java

@@ -204,7 +204,7 @@ public class PerfRankMgmtSaveOpPlugin extends AbstractOperationServicePlugIn imp
                     if(StringUtils.isBlank(errorMsg)){
                         errorMsg = operationResult.getMessage();
                     }
-                    throw new ValidationException("同步考核周期失败,原因:"+errorMsg);
+                    throw new ValidationException("保存失败,原因:同步考核周期结果失败。\r\n"+errorMsg);
                 }
             }
         }

+ 0 - 1
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/cycle/CycleGenerateOpPlugin.java

@@ -52,7 +52,6 @@ import java.util.Set;
 import java.util.StringJoiner;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
 * 周期生成

+ 42 - 13
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/cycle/PerfManagerSaveOpPlugin.java

@@ -23,6 +23,7 @@ import kd.bos.servicehelper.QueryServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
 import kd.sdk.plugin.Plugin;
 import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.AppraisalResultEnum;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
@@ -161,6 +162,7 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
                 Map<Long,String> entryResultMap = new HashMap<>();
                 if(!archivedPersonIds.isEmpty() && !entryIds.isEmpty()){
                     QueryFieldBuilder perfManagerEntryQueryFieldBuilder = QueryFieldBuilder.create()
+                            .add(PerfManagerFormConstant.NCKD_SALARYADJUSTGENFLAG)
                             .add(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY,FormConstant.ID_KEY)
                             .addIdNumberName(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY,PerfManagerFormConstant.NCKD_APPRAISALRESULT);
                     QFilter perfManagerEntryFilter = new QFilter(String.join( ".",PerfManagerFormConstant.NCKD_PERFMANAGERENTRY,FormConstant.ID_KEY), QCP.in, entryIds);
@@ -172,6 +174,20 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
                             ));
 
                 }
+                Map<Long, DynamicObject> dbMap = new HashMap<>();
+                if(isUpdate){
+                    //如果是更新则查询数据库中是否生成调档
+                    QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+                            .add(FormConstant.ID_KEY)
+                            .add(PerfManagerFormConstant.NCKD_SALARYADJUSTGENFLAG);
+                    QFilter filter = new QFilter(FormConstant.ID_KEY, QCP.in, ids);
+                    DynamicObjectCollection query = QueryServiceHelper.query(PerfManagerFormConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+                    dbMap = query.stream()
+                            .collect(Collectors.toMap(
+                                    dynamicObject -> dynamicObject.getLong(FormConstant.ID_KEY),
+                                    dynamicObject -> dynamicObject
+                            ));
+                }
 
 
                 QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
@@ -192,6 +208,7 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
                         ));
                 for (ExtendedDataEntity rowDataEntity : getDataEntities()) {
                     DynamicObject data = rowDataEntity.getDataEntity();
+                    long id = data.getLong(FormConstant.ID_KEY);
                     DynamicObject person = data.getDynamicObject(FormConstant.NCKD_PERSON);
                     person = person == null ? data.getDynamicObject(FormConstant.NCKD_EMPPOSORGREL).getDynamicObject(FormConstant.EMPLOYEE_KEY) : person;
                     long personId = person.getLong(FormConstant.ID_KEY);
@@ -278,22 +295,34 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
                         }
 
                         //如果是更新则需要校验是否更改已归档的考核结果
-                        if(isUpdate && !entryIds.isEmpty() && !entryResultMap.isEmpty()) {
-                            for (DynamicObject entry : entrys) {
-                                long entryId = entry.getLong(FormConstant.ID_KEY);
-                                if(entryId > 0) {
-                                    DynamicObject appraisalResult = entry.getDynamicObject(PerfManagerFormConstant.NCKD_APPRAISALRESULT);
-                                    LocalDateTime appraisalYear = DateUtil.toLocalDateTime(entry.getDate(PerfManagerFormConstant.NCKD_APPRAISALYEAR));
-                                    String appraisalResultNumber = appraisalResult != null ? appraisalResult.getString(FormConstant.NUMBER_KEY) : null;
-                                    String dbAppraisalResultNumber = entryResultMap.get(entryId);
-                                    if (!Objects.equals(appraisalResultNumber, dbAppraisalResultNumber)) {
-                                        addFatalErrorMessage(rowDataEntity,
-                                                StrFormatter.format("人员【{}】考核周期已归档,不能修改【{}】年的考核结果。",
-                                                        personName,
-                                                        appraisalYear.getYear()));
+                        if(isUpdate) {
+                            if(!entryIds.isEmpty() && !entryResultMap.isEmpty()) {
+                                for (DynamicObject entry : entrys) {
+                                    long entryId = entry.getLong(FormConstant.ID_KEY);
+                                    if (entryId > 0) {
+                                        DynamicObject appraisalResult = entry.getDynamicObject(PerfManagerFormConstant.NCKD_APPRAISALRESULT);
+                                        LocalDateTime appraisalYear = DateUtil.toLocalDateTime(entry.getDate(PerfManagerFormConstant.NCKD_APPRAISALYEAR));
+                                        String appraisalResultNumber = appraisalResult != null ? appraisalResult.getString(FormConstant.NUMBER_KEY) : null;
+                                        String dbAppraisalResultNumber = entryResultMap.get(entryId);
+                                        String appraisalResultName = StringUtils.isNotBlank(dbAppraisalResultNumber) ? AppraisalResultEnum.getByCode(dbAppraisalResultNumber).getName() : "空";
+                                        if (!Objects.equals(appraisalResultNumber, dbAppraisalResultNumber) && archivedPersonIds.contains(personId)) {
+                                            addFatalErrorMessage(rowDataEntity,
+                                                    StrFormatter.format("人员【{}】考核周期已归档,不能修改【{}】年的考核结果,修改前考核结果【{}】。",
+                                                            personName,
+                                                            appraisalYear.getYear(),
+                                                            appraisalResultName));
+                                        }
                                     }
                                 }
                             }
+                            if(!dbMap.isEmpty()){
+                                DynamicObject dbPerManager = dbMap.get(id);
+                                boolean salaryAdjustGenFlag = dbPerManager.getBoolean(PerfManagerFormConstant.NCKD_SALARYADJUSTGENFLAG);
+                                if(salaryAdjustGenFlag){
+                                    addFatalErrorMessage(rowDataEntity,
+                                            StrFormatter.format("人员【{}】已生成调档,不能修改。",personName));
+                                }
+                            }
                         }
 
                     }

+ 2 - 2
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/result/PerfArchiveOrUnArchiveOpPlugin.java

@@ -72,7 +72,7 @@ public class PerfArchiveOrUnArchiveOpPlugin extends AbstractOperationServicePlug
                     for (DynamicObject dynamicObject : perfArchiveRecordQuery) {
                         String personName = dynamicObject.getString(String.join( ".",FormConstant.NCKD_PERSON,FormConstant.NAME_KEY));
                         long personId = dynamicObject.getLong(String.join( ".",FormConstant.NCKD_PERSON,FormConstant.ID_KEY));
-                        this.addWarningMessage(getDataEntities()[personMap.get(personId)], StrFormatter.format("【{}】已归档,忽略此次处理;", personName));
+                        this.addErrorMessage(getDataEntities()[personMap.get(personId)], StrFormatter.format("【{}】已归档,忽略此次处理;", personName));
                     }
                 }
                 // 处理撤销归档操作
@@ -87,7 +87,7 @@ public class PerfArchiveOrUnArchiveOpPlugin extends AbstractOperationServicePlug
                                 DynamicObject data = getDataEntities()[dataIndex].getDataEntity();
                                 DynamicObject person = data.getDynamicObject(FormConstant.NCKD_PERSON);
                                 String personName = person.getString(FormConstant.NAME_KEY);
-                                this.addWarningMessage(getDataEntities()[dataIndex], StrFormatter.format("【{}】未归档无需撤销,忽略此次处理;", personName));
+                                this.addErrorMessage(getDataEntities()[dataIndex], StrFormatter.format("【{}】未归档无需撤销,忽略此次处理;", personName));
                             });
                 }
             }

+ 4 - 1
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/salary/SalaryAdjOpPlugin.java

@@ -452,10 +452,13 @@ public class SalaryAdjOpPlugin extends AbstractOperationServicePlugIn implements
                     }
                     AppraisalResultEnum thirdYearResult = AppraisalResultEnum.getByCode(thirdYearResultNumber);
 
+                    //根据年份考核结果计算实际结束年份
                     LocalDateTime actEndYear = null;
                     if (isAppraisalResult(firstYearResult) && isAppraisalResult(secondYearResult) && !isAppraisalResult(thirdYearResult)) {
                         actEndYear = DateUtil.minusYears(endDate, 1);
-                    } else {
+                    } else if (isAppraisalResult(firstYearResult) && !isAppraisalResult(secondYearResult) && !isAppraisalResult(thirdYearResult)) {
+                        actEndYear = DateUtil.minusYears(endDate, 2);
+                    }else {
                         actEndYear = endDate;
                     }
                     perfManager.set(PerfManagerFormConstant.NCKD_ACTENDYEAR, DateUtil.toDate(actEndYear));

+ 0 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/business/.gitkeep


+ 80 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/common/SubCoHeadServiceConstant.java

@@ -0,0 +1,80 @@
+package nckd.jxccl.swc.mas.common;
+
+import nckd.jxccl.base.common.constant.FormConstant;
+
+/**
+ * 子企业负责人任职情况常量类
+ *
+ * @author W.Y.C
+ * @version 1.0
+ * @date 2025-11-27 18:37:26
+ */
+public class SubCoHeadServiceConstant extends FormConstant {
+    /** 子企业负责人任职情况-实体标识 */
+    public static final String SUBCOHEADSERVICE_ENTITYID = "nckd_subcoheadservice";
+    /** 年度 */
+    public static final String NCKD_YEAR = "nckd_year";
+    /** 所属二级单位 */
+    public static final String NCKD_PAYUNIT = "nckd_payunit";
+    /** 法人单位 */
+    public static final String NCKD_LAWENTITY = "nckd_lawentity";
+    /** 员工 */
+    public static final String NCKD_EMPLOYEE = "nckd_employee";
+    /** 职务 */
+    public static final String NCKD_POSNAME = "nckd_posname";
+    /** 任职开始时间 */
+    public static final String NCKD_STARTDATE = "nckd_startdate";
+    /** 任职结束时间 */
+    public static final String NCKD_ENDDATE = "nckd_enddate";
+    /** 本年任职月数 */
+    public static final String NCKD_SERVICEMONTHS = "nckd_servicemonths";
+    /** 是否直管干部 */
+    public static final String NCKD_ISDIRCADRE = "nckd_isdircadre";
+    /** 是否职业经理人 */
+    public static final String NCKD_ISPROFMAN = "nckd_isprofman";
+    /** 是否经理层成员 */
+    public static final String NCKD_ISMANAGER = "nckd_ismanager";
+    /** 薪酬是否一人一议 */
+    public static final String NCKD_SALNEGOT = "nckd_salnegot";
+    /** 岗位管理层级 */
+    public static final String NCKD_POSTLEVEL = "nckd_postlevel";
+    /** 法人岗位层级 */
+    public static final String NCKD_LEGPOSTLV = "nckd_legpostlv";
+    /** 薪酬核算岗位 */
+    public static final String NCKD_SALCALCPOST = "nckd_salcalcpost";
+    /** 载入党政职务履历 */
+    public static final String LOADPARTYPOSITION_OP = "loadpartyposition";
+    /** 是否高管*/
+    public static final String NCKD_ISEXEC = "nckd_isexec";
+
+
+    /*-------------------------------------- 企业负责人信息常量类 begin --------------------------------------*/
+    /** 企业负责人类型 */
+    public static final String NCKD_HEADTYPE = "nckd_headtype";
+    /** 职业经理人类型 */
+    public static final String NCKD_PROFMANTYP = "nckd_profmantyp";
+    /** 任期 */
+    public static final String NCKD_TERM = "nckd_term";
+    /** 是否实行任期制和契约化管理 */
+    public static final String NCKD_TERMCONT = "nckd_termcont";
+    /*-------------------------------------- 企业负责人信息常量类 end --------------------------------------*/
+
+    /*-------------------------------------- 党政职务变更履历常量类 begin --------------------------------------*/
+    /** 变动时间 */
+    public static final String NCKD_CHANGETIME = "nckd_changetime";
+    /** 职务变动类别 */
+    public static final String NCKD_POSCHTP = "nckd_poschtp";
+    /** 职务层次 */
+    public static final String NCKD_POSLEVEL = "nckd_poslevel";
+    /** 职务级别 */
+    public static final String NCKD_POSGRADE = "nckd_posgrade";
+    /** 任免方式 */
+    public static final String NCKD_APPRWAY = "nckd_apprway";
+    /** 任职部门 */
+    public static final String NCKD_OFFICEDEPT = "nckd_officedept";
+    /** 任免职文号 */
+    public static final String NCKD_APPRDOCNO = "nckd_apprdocno";
+    /** 原职务级别 */
+    public static final String NCKD_ORGPOSGRD = "nckd_orgposgrd";
+    /*-------------------------------------- 党政职务变更履历常量类 end --------------------------------------*/
+}

+ 0 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/mservice/.gitkeep


+ 302 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/form/empmgt/SubCoHeadServiceListPlugin.java

@@ -0,0 +1,302 @@
+package nckd.jxccl.swc.mas.plugin.form.empmgt;
+
+import kd.bos.common.enums.EnableEnum;
+import kd.bos.consts.PermItemConst;
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.OperateOption;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.entity.MainEntityType;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.form.IFormView;
+import kd.bos.form.IPageCache;
+import kd.bos.form.MessageBoxOptions;
+import kd.bos.form.ShowType;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.list.plugin.AbstractListPlugin;
+import kd.bos.mvc.SessionManager;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.basedata.BaseDataServiceHelper;
+import kd.bos.servicehelper.operation.OperationServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.hr.hbp.common.model.AuthorizedOrgResultWithSub;
+import kd.sdk.hr.hbp.business.helper.permission.HRPermissionServiceHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.utils.DateUtil;
+import nckd.jxccl.base.common.utils.QueryFieldBuilder;
+import nckd.jxccl.base.common.utils.ShowOperExecuteResult;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.entity.helper.EntityHelper;
+import nckd.jxccl.base.hrpi.helper.EmpPosOrgRelHelper;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.swc.mas.common.SubCoHeadServiceConstant;
+
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+* 子企业负责人任职情况-列表插件
+* 实体标识:nckd_subcoheadservice
+* @author W.Y.C
+* @date 2025/11/27 18:36
+* @version 1.0
+*/
+public class SubCoHeadServiceListPlugin extends AbstractListPlugin implements Plugin {
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs e) {
+        String operateKey = e.getOperateKey();
+        if(e.getOperationResult() != null && e.getOperationResult().isSuccess()){
+            if(SubCoHeadServiceConstant.LOADPARTYPOSITION_OP.equals(operateKey)){
+                //载入党政职务履历
+                loadParTyPosition();
+            }
+        }
+    }
+    
+    /**
+     * 载入党政职务履历
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/11/27 18:40
+     */
+    private void loadParTyPosition(){
+        /*假设今年是2025年,那么符合查询条件的数据应该满足:
+        开始日期 <= 2025-12-31 且 结束日期 >= 2025-01-01
+       符合条件的例子:
+            开始日期: 2025-03-01, 结束日期: 2025-09-30
+            在今年范围内开始和结束
+
+            开始日期: 2024-06-01, 结束日期: 2025-06-01
+            跨年度,但在今年有有效期
+
+            开始日期: 2025-08-01, 结束日期: 2026-07-31
+            从今年开始延续到明年
+
+            开始日期: 2020-01-01, 结束日期: 2030-12-31
+            长期有效,覆盖今年全年
+         */
+        LocalDateTime now = DateUtil.now();
+
+        LocalDateTime beginYear = DateUtil.beginOfYear(now);
+        LocalDateTime endYear = DateUtil.endOfYear(now);
+
+        Date startOfYear = DateUtil.toDate(DateUtil.beginOfYear(now));
+        Date endOfYear = DateUtil.toDate(DateUtil.endOfYear(now));
+
+        // 只处理权限范围内的人员
+        Long currUserId = RequestContext.get().getCurrUserId();
+        AuthorizedOrgResultWithSub userAdminOrgWithSub = HRPermissionServiceHelper.getUserAdminOrgsWithSub(
+                currUserId, "nckd_pm", SubCoHeadServiceConstant.SUBCOHEADSERVICE_ENTITYID,
+                PermItemConst.ITEM_VIEW, "nckd_employee.hsbs_empposorgrel.adminorg", new HashMap<>());
+        QueryFieldBuilder subCoHeadServiceFieldBuilder = QueryFieldBuilder.create()
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_EMPLOYEE);
+        //查询当年已生成子企业负责人任职情况的人员
+        QFilter subCoHeadServiceFilter = new QFilter(SubCoHeadServiceConstant.NCKD_YEAR, QCP.large_equals, startOfYear)
+                .and(SubCoHeadServiceConstant.NCKD_YEAR, QCP.less_equals, endOfYear);
+        DynamicObjectCollection subCoHeadServiceFilterQuery = QueryServiceHelper.query(SubCoHeadServiceConstant.SUBCOHEADSERVICE_ENTITYID, subCoHeadServiceFieldBuilder.buildSelect(), new QFilter[]{subCoHeadServiceFilter});
+        List<Long> employeeIds = subCoHeadServiceFilterQuery.stream()
+                .map(dynamicObject -> dynamicObject.getLong(String.join(".", SubCoHeadServiceConstant.NCKD_EMPLOYEE, FormConstant.ID_KEY)))
+                .collect(Collectors.toList());
+
+        //查询党政履历
+//        nckd_hrpi_partyposh
+        QueryFieldBuilder partyPoshFieldBuilder = QueryFieldBuilder.create()
+                .add(SubCoHeadServiceConstant.STARTDATE)
+                .add(SubCoHeadServiceConstant.ENDDATE)
+                .add(SubCoHeadServiceConstant.NCKD_PAYUNIT)
+                //变动时间
+                .add(SubCoHeadServiceConstant.NCKD_CHANGETIME)
+                .add(SubCoHeadServiceConstant.NCKD_POSNAME)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_POSCHTP)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_POSLEVEL)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_POSGRADE)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_APPRWAY)
+                .add(SubCoHeadServiceConstant.NCKD_OFFICEDEPT)
+                .add(SubCoHeadServiceConstant.NCKD_APPRDOCNO)
+                .add(SubCoHeadServiceConstant.NCKD_ISDIRCADRE)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_ORGPOSGRD)
+                .addIdNumberName(SubCoHeadServiceConstant.EMPLOYEE_KEY)
+                .orderDesc(SubCoHeadServiceConstant.STARTDATE,SubCoHeadServiceConstant.ENDDATE);
+        QFilter partyPoshFilter = new QFilter(SubCoHeadServiceConstant.STARTDATE, QCP.less_equals, endOfYear)
+                .and(new QFilter(SubCoHeadServiceConstant.ENDDATE, QCP.is_null,null)
+                        .or(SubCoHeadServiceConstant.ENDDATE, QCP.large_equals, startOfYear))
+                //TODO 法人岗位层级为高管
+                .and(FormConstant.EMPLOYEE_KEY, QCP.not_in, employeeIds);
+        DynamicObjectCollection partyPoshQuery = QueryServiceHelper.query(FormConstant.NCKD_HRPI_PARTYPOSH, partyPoshFieldBuilder.buildSelect(), new QFilter[]{partyPoshFilter});
+        //按员工ID分组
+        Map<Long, DynamicObject> latestPartyPoshRecordMap = partyPoshQuery.stream()
+                .collect(Collectors.toMap(obj -> obj.getLong(String.join(".", FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)), Function.identity(), BinaryOperator.maxBy(Comparator.comparing(
+                        // 按 STARTDATE 字段比较
+                        obj -> obj.getDate(SubCoHeadServiceConstant.STARTDATE)
+                ))));
+
+        //查询企业负责人信息
+        QueryFieldBuilder entHeadFieldBuilder = QueryFieldBuilder.create()
+                .add(SubCoHeadServiceConstant.STARTDATE)
+                .add(SubCoHeadServiceConstant.ENDDATE)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_HEADTYPE)
+                .add(SubCoHeadServiceConstant.NCKD_ISPROFMAN)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_PROFMANTYP)
+                .add(SubCoHeadServiceConstant.NCKD_ISMANAGER)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_SALCALCPOST)
+                .add(SubCoHeadServiceConstant.NCKD_SALNEGOT)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_TERM)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_POSTLEVEL)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_LEGPOSTLV)
+                .addIdNumberName(SubCoHeadServiceConstant.EMPLOYEE_KEY)
+                .add(SubCoHeadServiceConstant.NCKD_TERMCONT)
+                .orderDesc(SubCoHeadServiceConstant.STARTDATE,SubCoHeadServiceConstant.ENDDATE);
+        QFilter entHeadFilter = new QFilter(SubCoHeadServiceConstant.STARTDATE, QCP.less_equals, endOfYear)
+                .and(new QFilter(SubCoHeadServiceConstant.ENDDATE, QCP.is_null,null)
+                        .or(SubCoHeadServiceConstant.ENDDATE, QCP.large_equals, startOfYear))
+                .and(FormConstant.EMPLOYEE_KEY,QCP.not_in, employeeIds)
+                //法人岗位层级为高管
+                .and(String.join(".", SubCoHeadServiceConstant.NCKD_LEGPOSTLV, SubCoHeadServiceConstant.NCKD_ISEXEC),QCP.equals, EnableEnum.YES.getCode());
+        DynamicObjectCollection entHeadQuery = QueryServiceHelper.query(FormConstant.NCKD_HRPI_ENTHEAD, entHeadFieldBuilder.buildSelect(), new QFilter[]{entHeadFilter});
+        Map<Long, DynamicObject> entHeadRecordMap = entHeadQuery.stream()
+                .collect(Collectors.toMap(obj -> obj.getLong(String.join(".", FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)), Function.identity(), BinaryOperator.maxBy(Comparator.comparing(
+                        // 按 STARTDATE 字段比较
+                        obj -> obj.getDate(SubCoHeadServiceConstant.STARTDATE)
+                ))));
+
+        //查询人员最新任职经历
+        DynamicObject[] empPosOrgRelArray = EmpPosOrgRelHelper.queryEmpPosOrgRelByEmployees(entHeadRecordMap.keySet());
+        List<Long> empPosOrgRelIds = Arrays.stream(empPosOrgRelArray).map(empPosOrgRel -> empPosOrgRel.getLong(FormConstant.ID_KEY)).collect(Collectors.toList());
+        //查询人员法人单位
+        QueryFieldBuilder legalPostFieldBuilder = QueryFieldBuilder.create()
+                .add(SubCoHeadServiceConstant.STARTDATE)
+                .add(SubCoHeadServiceConstant.ENDDATE)
+                .addIdNumberName(FormConstant.NCKD_EMPPOSORGREL,FormConstant.EMPLOYEE_KEY)
+                .addIdNumberName(SubCoHeadServiceConstant.NCKD_LAWENTITY);
+        QFilter legalPostFilter = QFilterCommonHelper.getValidDateFilter(SubCoHeadServiceConstant.STARTDATE,SubCoHeadServiceConstant.ENDDATE)
+                .and(FormConstant.NCKD_EMPPOSORGREL,QCP.in, empPosOrgRelIds);
+        DynamicObjectCollection legalPostQuery = QueryServiceHelper.query(FormConstant.NCKD_HRPI_LEGALPOST, legalPostFieldBuilder.buildSelect(), new QFilter[]{legalPostFilter});
+        Map<Long, DynamicObject> legalPostMap = legalPostQuery.stream()
+                .collect(Collectors.toMap(obj -> obj.getLong(String.join(".",FormConstant.NCKD_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY, FormConstant.ID_KEY)), Function.identity(), BinaryOperator.maxBy(Comparator.comparing(
+                        // 按 STARTDATE 字段比较
+                        obj -> obj.getDate(SubCoHeadServiceConstant.STARTDATE)
+                ))));
+
+
+        List<Long> createOrgList = BaseDataServiceHelper.getCreateOrgList(SubCoHeadServiceConstant.SUBCOHEADSERVICE_ENTITYID);
+        MainEntityType bosOrgEntityType = EntityMetadataCache.getDataEntityType(FormConstant.BOS_ORG);
+        DynamicObject org = new DynamicObject(bosOrgEntityType);
+        if (!createOrgList.isEmpty()) {
+            org.set(FormConstant.ID_KEY, createOrgList.get(0));
+        }
+        String ctrlStrategy = BaseDataServiceHelper.getBdCtrlStrgy(SubCoHeadServiceConstant.SUBCOHEADSERVICE_ENTITYID,org.getLong(FormConstant.ID_KEY)+"");
+        //构建子企业负责人任职情况实体
+        List<DynamicObject> saveSubCoHeadServiceList = new ArrayList<>();
+        for (Map.Entry<Long, DynamicObject> entHeadRecordEntry : entHeadRecordMap.entrySet()) {
+            //企业负责人信息
+            DynamicObject entHead = entHeadRecordEntry.getValue();
+            //党政履历
+            DynamicObject partyPosh = latestPartyPoshRecordMap.get(entHeadRecordEntry.getKey());
+            DynamicObject newSubCoHeadService = EntityHelper.newEntity(SubCoHeadServiceConstant.SUBCOHEADSERVICE_ENTITYID);
+            newSubCoHeadService.set(FormConstant.CREATEORG_KEY,org);
+            newSubCoHeadService.set(FormConstant.CTRLSTRATEGY_KEY,ctrlStrategy);
+            newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_YEAR,DateUtil.toDate(beginYear));
+            newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_EMPLOYEE,entHeadRecordEntry.getKey());
+            if(partyPosh != null) {
+                //所属二级单位
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_PAYUNIT, partyPosh.getString(SubCoHeadServiceConstant.NCKD_PAYUNIT));
+                //职务
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_POSNAME,partyPosh.getString(SubCoHeadServiceConstant.NCKD_POSNAME));
+                //是否直管干部
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_ISDIRCADRE,partyPosh.getString(SubCoHeadServiceConstant.NCKD_ISDIRCADRE));
+                //任职开始时间(变动日期)
+                Date changeTime = entHead.getDate(SubCoHeadServiceConstant.NCKD_CHANGETIME);
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_STARTDATE,changeTime);
+                //TODO 任职结束时间(下一段的开始日期)
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_ENDDATE,null);
+                if(changeTime != null){
+                    //【变动时间】的次月到当年年底的月数
+                    LocalDateTime newMonths = DateUtil.addMonths(DateUtil.toLocalDateTime(changeTime), 1);
+                    long between = DateUtil.between(newMonths, endYear, ChronoUnit.MONTHS);
+                    newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_SERVICEMONTHS,between);
+                }
+
+            }
+            DynamicObject legalPost = legalPostMap.get(entHeadRecordEntry.getKey());
+            if(legalPost != null){
+                long lawEntityId = legalPost.getLong(String.join(".", SubCoHeadServiceConstant.NCKD_LAWENTITY, FormConstant.ID_KEY));
+                //法人单位
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_LAWENTITY,lawEntityId);
+            }
+            if(entHead != null){
+
+                //是否职业经理人
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_ISPROFMAN,entHead.getString(SubCoHeadServiceConstant.NCKD_ISPROFMAN));
+                //是否经理层成员
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_ISMANAGER,entHead.getString(SubCoHeadServiceConstant.NCKD_ISMANAGER));
+                //薪酬核算岗位
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_SALCALCPOST,entHead.getLong(String.join(".", SubCoHeadServiceConstant.NCKD_SALCALCPOST,FormConstant.ID_KEY)));
+                //薪酬是否一人一议
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_SALNEGOT,entHead.getString(SubCoHeadServiceConstant.NCKD_SALNEGOT));
+                //TODO 当前取的是岗位管理层级,可能要改为岗位管理层级细项
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_POSTLEVEL,entHead.getLong(String.join(".", SubCoHeadServiceConstant.NCKD_POSTLEVEL,FormConstant.ID_KEY)));
+                //法人岗位层级
+                newSubCoHeadService.set(SubCoHeadServiceConstant.NCKD_LEGPOSTLV,entHead.getLong(String.join(".", SubCoHeadServiceConstant.NCKD_LEGPOSTLV,FormConstant.ID_KEY)));
+
+            }
+            saveSubCoHeadServiceList.add(newSubCoHeadService);
+
+        }
+        if(!saveSubCoHeadServiceList.isEmpty()) {
+            //调用save op
+            OperateOption option = OperateOption.create();
+            option.setVariableValue("action", "load");
+            OperationResult operationResult = SaveServiceHelper.saveOperate(SubCoHeadServiceConstant.SUBCOHEADSERVICE_ENTITYID, saveSubCoHeadServiceList.toArray(new DynamicObject[0]), option);
+            if (!operationResult.isSuccess()) {
+                String parentPageId = this.getView().getFormShowParameter().getPageId();
+                IFormView parentView = SessionManager.getCurrent().getViewNoPlugin(parentPageId);
+                IPageCache pageCache = (IPageCache) parentView.getService(IPageCache.class);
+                Map<String, String> customData = operationResult.getCustomData();
+                //成功的记录
+                Map<Object, Object> successMap = new HashMap<>();
+                for (Object successPkId : operationResult.getSuccessPkIds()) {
+                    successMap.put(successPkId, customData.get(successPkId.toString()));
+                }
+                int billCount = operationResult.getBillCount();
+                int successCount = operationResult.getSuccessPkIds().size();
+                int validError = billCount - successCount;
+                String title = StrFormatter.format("载入人数:{},成功数量:{},失败数量:{}。", billCount, successCount, validError);
+                this.getView().showForm(ShowOperExecuteResult.getOperResultForm(title, "载入党政职务履历", successMap, pageCache, operationResult));
+            } else {
+                //刷新列表
+                Map<String, String> customData = operationResult.getCustomData();
+                Map<Object, Object> successMap = new HashMap<>();
+                for (Object successPkId : operationResult.getSuccessPkIds()) {
+                    successMap.put(successPkId, customData.get(successPkId.toString()));
+                }
+                if (!successMap.isEmpty()) {
+                    String parentPageId = this.getView().getFormShowParameter().getPageId();
+                    IFormView parentView = SessionManager.getCurrent().getViewNoPlugin(parentPageId);
+                    IPageCache pageCache = (IPageCache) parentView.getService(IPageCache.class);
+                    this.getView().showForm(ShowOperExecuteResult.getOperResultForm("载入党政职务履历", successMap, pageCache, operationResult));
+                } else {
+                    this.getView().invokeOperation(FormConstant.REFRESH_OP);
+                    this.getView().showConfirm("提示", operationResult.getMessage(), MessageBoxOptions.OK, null, null, null, null);
+                }
+            }
+        }else {
+            this.getView().showTipNotification("没有需要载入的数据!");
+        }
+
+    }
+}

+ 56 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/operate/SubCoHeadServiceOpPlugin.java

@@ -0,0 +1,56 @@
+package nckd.jxccl.swc.mas.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
+import kd.bos.entity.validate.AbstractValidator;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.swc.mas.common.SubCoHeadServiceConstant;
+
+import java.util.Date;
+
+/**
+* 子企业负责人任职情况-保存插件
+* 实体标识:nckd_subcoheadservice
+* @author W.Y.C
+* @date 2025/11/27 22:25
+* @version 1.0
+*/
+public class SubCoHeadServiceOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+
+        e.addValidator(new AbstractValidator() {
+
+            @Override
+            public void validate() {
+                String operateKey = this.getOperateKey();
+                for (ExtendedDataEntity dataEntity : this.getDataEntities()) {
+                    DynamicObject data = dataEntity.getDataEntity();
+                    Date startDate = data.getDate(SubCoHeadServiceConstant.NCKD_STARTDATE);
+                    /*if(startDate == null){
+                        this.addWarningMessage(dataEntity,"");
+                    }
+                    for (int i = 0; i < 20;i++){
+                        this.addErrorMessage(dataEntity,"错误"+i);
+                    }*/
+
+                }
+
+            }
+
+        });
+    }
+
+
+    @Override
+    public void endOperationTransaction(EndOperationTransactionArgs e) {
+        String operationKey = e.getOperationKey();
+        super.endOperationTransaction(e);
+
+        this.getOperationResult().getCustomData().put("成功的id","成功的消息");
+    }
+}

+ 0 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/other/.gitkeep


+ 0 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/report/.gitkeep


+ 0 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/plugin/workflow/.gitkeep


+ 0 - 0
code/swc/nckd-jxccl-swc/src/main/java/nckd/jxccl/swc/mas/webapi/.gitkeep