Sfoglia il codice sorgente

feat(opmc): 实现年度全排名功能及相关逻辑优化

- 新增年度全排名相关常量定义,包括实体标识、单据体、是否参与排名等字段
- 实现根据人员和日期查询全排名结果的方法
- 优化考核周期查询逻辑,支持根据日期范围查询符合条件的考核周期
- 完善考核周期生成逻辑,区分手动/导入新增周期与周期生成功能
- 修复考核周期保存操作中的事务处理逻辑,确保数据一致性
- 增加对快速过滤和自定义过滤条件的支持,提升报表查询灵活性
- 重构代码结构,提取公共查询字段构建方法,提高代码复用性
- 优化注释和文档说明,增强代码可读性和维护性
wyc 1 settimana fa
parent
commit
f1e9407657

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

@@ -4,7 +4,6 @@ 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.entity.ExtendedDataEntity;
 import kd.bos.entity.MainEntityType;
 import kd.bos.entity.operate.OperateOptionConst;
 import kd.bos.entity.operate.result.IOperateInfo;
@@ -19,7 +18,6 @@ import kd.bos.orm.query.QFilter;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.MetadataServiceHelper;
 import kd.bos.servicehelper.QueryServiceHelper;
-import kd.bos.servicehelper.operation.OperationServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
 import kd.sdk.plugin.Plugin;
 import nckd.jxccl.base.common.constant.FormConstant;
@@ -28,18 +26,13 @@ import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.common.utils.StrFormatter;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
-import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
 import nckd.jxccl.hr.psms.common.PerfRankMgmtConstant;
 import nckd.jxccl.hr.psms.plugin.operate.performance.validate.PerfRankMgmtSaveValidate;
 import org.apache.commons.lang3.StringUtils;
 
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.StringJoiner;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**

+ 6 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/common/PerfManagerFormConstant.java

@@ -54,8 +54,14 @@ public class PerfManagerFormConstant extends FormConstant {
     /** 批量新增考核周期(弹窗)-实体标识 */
     public static final String BATCHEVALCYCLE_ENTITYID = "nckd_batchevalcycle";
 
+    /*-------------------------------------- 年度全排名 begin --------------------------------------*/
     /** 年度 */
     public static final String NCKD_THEYEAR = "nckd_theyear";
     /** 年度绩效排名管理-实体标识 */
     public static final String NCKD_PERFRANKMGMT_ENTITYID = "nckd_perfrankmgmt";
+    /** 单据体 */
+    public static final String NCKD_PERFRANKMGMTENTRY = "nckd_perfrankmgmtentry";
+    /** 是否参与排名 */
+    public static final String NCKD_ISRANKING = "nckd_isranking";
+    /*-------------------------------------- 年度全排名 end --------------------------------------*/
 }

+ 166 - 108
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/helper/PerfManagerHelper.java

@@ -2,13 +2,17 @@ package nckd.jxccl.opmc.pm.helper;
 
 import kd.bos.common.enums.EnableEnum;
 import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
 import kd.bos.entity.MainEntityType;
 import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.bos.servicehelper.MetadataServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
 import kd.bos.servicehelper.operation.SaveServiceHelper;
 import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.AppraisalResultEnum;
+import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.QueryFieldBuilder;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
 import nckd.jxccl.opmc.pm.common.PerfManagerFormConstant;
@@ -21,176 +25,203 @@ import java.util.List;
 import java.util.Map;
 
 /**
-* 考核周期帮助类
-* @author W.Y.C
-* @date 2025/11/4 17:06
-* @version 1.0
-*/
+ * 考核周期帮助类
+ *
+ * @author W.Y.C
+ * @date 2025/11/4 17:06
+ * @version 1.0
+ */
 public class PerfManagerHelper {
 
 
     /**
-     * 获取当前人员所有考核周期
-     * @param personIds
-     * @param otherFilter
-     * @return: kd.bos.dataentity.entity.DynamicObject[]
+     * 根据人员和日期查询全排名结果
+     * @param date 日期
+     * @param personIds 人员id
+     * @return: java.util.Map<java.lang.Long, nckd.jxccl.base.common.enums.AppraisalResultEnum>
      * @author W.Y.C
-     * @date: 2025/11/13 22:16
+     * @date: 2025/11/15 22:40
      */
-    public static DynamicObject[] getByPersonId(Collection<Long> personIds,QFilter otherFilter) {
+    public static Map<Long, AppraisalResultEnum> getPerfRankResult(Date date, Collection<Long> personIds) {
+
+        QFilter filter = new QFilter(PerfManagerFormConstant.NCKD_THEYEAR, QCP.equals, DateUtil.getYear(date))
+                .and(String.join(".", PerfManagerFormConstant.NCKD_PERFRANKMGMTENTRY, FormConstant.NCKD_PERSON), QCP.in, personIds)
+                .and(String.join(".", PerfManagerFormConstant.NCKD_PERFRANKMGMTENTRY, PerfManagerFormConstant.NCKD_ISRANKING), QCP.equals, EnableEnum.YES.getCode());
         QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
-                .add(FormConstant.ID_KEY)
-                .addIdNumberName(FormConstant.NCKD_EMPPOSORGREL)
-                .addIdNumberName(FormConstant.NCKD_PERSON)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_FIRSTYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_SECONDYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_THIRDYEARRESULT)
-                .add(PerfManagerFormConstant.NCKD_BEGINYEAR)
-                .add(PerfManagerFormConstant.NCKD_ENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_ACTENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_WHYEND)
-                .add(PerfManagerFormConstant.NCKD_THESTATUS)
-                .add(PerfManagerFormConstant.NCKD_ISCURRENTNEWEST)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY,PerfManagerFormConstant.NCKD_APPRAISALRESULT)
-                .addGroup(new String[]{PerfManagerFormConstant.NCKD_PERFMANAGERENTRY},PerfManagerFormConstant.NCKD_APPRAISALRESULT,PerfManagerFormConstant.NCKD_APPRAISALYEAR,PerfManagerFormConstant.NCKD_ISALLRANKSOURCE)
+                .addIdNumberName(PerfManagerFormConstant.NCKD_PERFRANKMGMTENTRY, PerfManagerFormConstant.NCKD_APPRAISALRESULT)
+                .addIdNumberName(PerfManagerFormConstant.NCKD_PERFRANKMGMTENTRY, PerfManagerFormConstant.NCKD_PERSON);
+        DynamicObjectCollection query = QueryServiceHelper.query(PerfManagerFormConstant.NCKD_PERFRANKMGMT_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+        Map<Long, AppraisalResultEnum> resultMap = new HashMap<>();
+        for (DynamicObject obj : query) {
+            long personId = obj.getLong(String.join(".", PerfManagerFormConstant.NCKD_PERFRANKMGMTENTRY, PerfManagerFormConstant.NCKD_PERSON, FormConstant.ID_KEY));
+            String resultNumber = obj.getString(String.join(".", PerfManagerFormConstant.NCKD_PERFRANKMGMTENTRY, PerfManagerFormConstant.NCKD_APPRAISALRESULT, FormConstant.NUMBER_KEY));
+            AppraisalResultEnum resultEnum = AppraisalResultEnum.getByCode(resultNumber);
+            if (resultEnum != null) {
+                resultMap.put(personId, resultEnum);
+            }
+
+        }
+
+        return resultMap;
+    }
+
+
+    /**
+     * 根据日期查询范围内的考核周期
+     * 查询逻辑说明:
+     * 1. 开始时间条件:考核周期的开始年份(NCKD_BEGINYEAR)必须小于等于指定日期
+     * 2. 结束时间条件:优先使用实际结束年份(NCKD_ACTENDYEAR),如果为空则使用计划结束年份(NCKD_ENDYEAR)
+     * 3. 结束时间必须大于等于指定日期
+     * 4. 即查找满足 "NCKD_BEGINYEAR <= date <= (NCKD_ACTENDYEAR为空时取NCKD_ENDYEAR)" 条件的考核周期
+     *
+     * @param date      指定查询日期
+     * @param personIds 人员ID集合
+     * @return 符合条件的考核周期数组
+     * @author W.Y.C
+     * @date 2025/11/4 17:06
+     */
+    public static DynamicObject[] getByDate(Date date, Collection<Long> personIds) {
+        QueryFieldBuilder queryFieldBuilder = createDefaultQueryFieldBuilder();
+
+        // 构造查询条件:日期在[NCKD_BEGINYEAR, NCKD_ENDYEAR]范围内
+        // 考虑到NCKD_ACTENDYEAR可能为空,优先使用NCKD_ACTENDYEAR作为结束时间
+        QFilter filter = new QFilter(PerfManagerFormConstant.NCKD_BEGINYEAR, QCP.less_equals, date)
+                .and(new QFilter(PerfManagerFormConstant.NCKD_PERSON, QCP.in, personIds));
+
+        // 添加结束时间判断逻辑
+        QFilter endDateFilter = new QFilter(PerfManagerFormConstant.NCKD_ACTENDYEAR, QCP.large_equals, date)
+                .or(new QFilter(PerfManagerFormConstant.NCKD_ACTENDYEAR, QCP.is_null, null)
+                        .and(new QFilter(PerfManagerFormConstant.NCKD_ENDYEAR, QCP.large_equals, date)));
+
+        filter.and(endDateFilter);
+
+        return BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID,
+                queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+    }
+
+    /**
+     * 获取当前人员所有考核周期
+     *
+     * @param personIds   人员ID集合
+     * @param otherFilter 其他过滤条件
+     * @return 符合条件的考核周期数组
+     * @author W.Y.C
+     * @date 2025/11/13 22:16
+     */
+    public static DynamicObject[] getByPersonId(Collection<Long> personIds, QFilter otherFilter) {
+        QueryFieldBuilder queryFieldBuilder = createDefaultQueryFieldBuilder()
                 .orderDesc(PerfManagerFormConstant.NCKD_BEGINYEAR);
 
         QFilter filter = new QFilter(PerfManagerFormConstant.NCKD_PERSON, QCP.in, personIds);
-        if(otherFilter != null) {
+        if (otherFilter != null) {
             filter.and(otherFilter);
         }
-        return BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+        return BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID,
+                queryFieldBuilder.buildSelect(), new QFilter[]{filter});
     }
 
     /**
      * 查询开始时间之前的考核周期
-     * @param beginYear
-     * @param personIds
-     * @param otherFilter
-     * @return: kd.bos.dataentity.entity.DynamicObject[]
+     *
+     * @param beginYear   开始年份
+     * @param personIds   人员ID集合
+     * @param otherFilter 其他过滤条件
+     * @return 符合条件的考核周期数组
      * @author W.Y.C
-     * @date: 2025/11/13 22:16
+     * @date 2025/11/13 22:16
      */
-    public static DynamicObject[] getBeforeBeginYear(Date beginYear,Collection<Long> personIds,QFilter otherFilter) {
-        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
-                .add(FormConstant.ID_KEY)
-                .addIdNumberName(FormConstant.NCKD_EMPPOSORGREL)
-                .addIdNumberName(FormConstant.NCKD_PERSON)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_FIRSTYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_SECONDYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_THIRDYEARRESULT)
-                .add(PerfManagerFormConstant.NCKD_BEGINYEAR)
-                .add(PerfManagerFormConstant.NCKD_ENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_ACTENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_WHYEND)
-                .add(PerfManagerFormConstant.NCKD_THESTATUS)
-                .add(PerfManagerFormConstant.NCKD_ISCURRENTNEWEST)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY,PerfManagerFormConstant.NCKD_APPRAISALRESULT)
-                .addGroup(new String[]{PerfManagerFormConstant.NCKD_PERFMANAGERENTRY},PerfManagerFormConstant.NCKD_APPRAISALRESULT,PerfManagerFormConstant.NCKD_APPRAISALYEAR,PerfManagerFormConstant.NCKD_ISALLRANKSOURCE);
+    public static DynamicObject[] getBeforeBeginYear(Date beginYear, Collection<Long> personIds, QFilter otherFilter) {
+        QueryFieldBuilder queryFieldBuilder = createDefaultQueryFieldBuilder();
 
         QFilter filter = new QFilter(PerfManagerFormConstant.NCKD_BEGINYEAR, QCP.less_equals, beginYear)
                 .and(new QFilter(PerfManagerFormConstant.NCKD_THESTATUS, QCP.equals, EnableEnum.YES.getCode()))
                 .and(new QFilter(PerfManagerFormConstant.NCKD_PERSON, QCP.in, personIds));
-        if(otherFilter != null) {
+        if (otherFilter != null) {
             filter.and(otherFilter);
         }
 
-        return BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+        return BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID,
+                queryFieldBuilder.buildSelect(), new QFilter[]{filter});
     }
 
     /**
      * 根据人员获取当前最新的考核周期
+     *
      * @param personIds 人员ID
-     * @return: kd.bos.dataentity.entity.DynamicObject[]
+     * @return 符合条件的考核周期数组
      * @author W.Y.C
-     * @date: 2025/11/04 17:31
+     * @date 2025/11/04 17:31
      */
     public static DynamicObject[] getNewestPerfManagerByPerson(Collection<Long> personIds) {
-        return getNewestPerfManagerByPerson(personIds,null);
+        return getNewestPerfManagerByPerson(personIds, null);
     }
 
+    /**
+     * 根据ID获取考核周期
+     *
+     * @param ids ID集合
+     * @return 考核周期数组
+     */
     public static DynamicObject[] getById(Collection<Long> ids) {
         QFilter filter = QFilterCommonHelper.getIdInFilter(ids);
         MainEntityType dataEntityType = MetadataServiceHelper.getDataEntityType(PerfManagerFormConstant.PERFMANAGER_ENTITYID);
 
-        return BusinessDataServiceHelper.load(ids.toArray(new Long[0]),dataEntityType);
+        return BusinessDataServiceHelper.load(ids.toArray(new Long[0]), dataEntityType);
     }
 
-
     /**
-     * 根据人员获取当前最新的考核周期(“是否当前最新记录 = true” 并且  “周期状态 = 1”)
-     * @param personIds 人员ID
+     * 根据人员获取当前最新的考核周期("是否当前最新记录 = true" 并且 "周期状态 = 1")
+     *
+     * @param personIds   人员ID
      * @param otherFilter 其他过滤条件
-     * @return: kd.bos.dataentity.entity.DynamicObject[]
+     * @return 符合条件的考核周期数组
      * @author W.Y.C
-     * @date: 2025/11/04 17:30
+     * @date 2025/11/04 17:30
      */
-    public static DynamicObject[] getNewestPerfManagerByPerson(Collection<Long> personIds,QFilter otherFilter) {
-        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
-                .add(FormConstant.ID_KEY)
-                .addIdNumberName(FormConstant.NCKD_EMPPOSORGREL)
-                .addIdNumberName(FormConstant.NCKD_PERSON)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_FIRSTYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_SECONDYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_THIRDYEARRESULT)
-                .add(PerfManagerFormConstant.NCKD_BEGINYEAR)
-                .add(PerfManagerFormConstant.NCKD_ENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_ACTENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_WHYEND)
-                .add(PerfManagerFormConstant.NCKD_THESTATUS)
-                .add(PerfManagerFormConstant.NCKD_ISCURRENTNEWEST)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY,PerfManagerFormConstant.NCKD_APPRAISALRESULT)
-                .addGroup(new String[]{PerfManagerFormConstant.NCKD_PERFMANAGERENTRY},PerfManagerFormConstant.NCKD_APPRAISALRESULT,PerfManagerFormConstant.NCKD_APPRAISALYEAR,PerfManagerFormConstant.NCKD_ISALLRANKSOURCE);
+    public static DynamicObject[] getNewestPerfManagerByPerson(Collection<Long> personIds, QFilter otherFilter) {
+        QueryFieldBuilder queryFieldBuilder = createDefaultQueryFieldBuilder();
 
         QFilter filter = new QFilter(PerfManagerFormConstant.NCKD_ISCURRENTNEWEST, QCP.equals, EnableEnum.YES.getCode())
                 .and(new QFilter(PerfManagerFormConstant.NCKD_THESTATUS, QCP.equals, EnableEnum.YES.getCode()))
                 .and(new QFilter(PerfManagerFormConstant.NCKD_PERSON, QCP.in, personIds));
-        if(otherFilter != null) {
+        if (otherFilter != null) {
             filter.and(otherFilter);
         }
 
-        return BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter});
+        return BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID,
+                queryFieldBuilder.buildSelect(), new QFilter[]{filter});
     }
 
     /**
-     * 根据人员获取当前最新的考核周期(根据“周期开始时间”)
-     * @param personIds 人员ID
+     * 根据人员获取当前最新的考核周期(根据"周期开始时间")
+     *
+     * @param personIds   人员ID
      * @param otherFilter 其他过滤条件
-     * @return: kd.bos.dataentity.entity.DynamicObject[]
+     * @return 符合条件的考核周期列表
      * @author W.Y.C
-     * @date: 2025/11/04 17:30
+     * @date 2025/11/04 17:30
      */
-    public static List<DynamicObject> getNewestPerfManagerByPersonAndBeginYear(Collection<Long> personIds,QFilter otherFilter) {
-        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
-                .add(FormConstant.ID_KEY)
-                .addIdNumberName(FormConstant.NCKD_PERSON)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_FIRSTYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_SECONDYEARRESULT)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_THIRDYEARRESULT)
-                .add(PerfManagerFormConstant.NCKD_BEGINYEAR)
-                .add(PerfManagerFormConstant.NCKD_ENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_ACTENDYEAR)
-                .add(PerfManagerFormConstant.NCKD_WHYEND)
-                .add(PerfManagerFormConstant.NCKD_THESTATUS)
-                .add(PerfManagerFormConstant.NCKD_ISCURRENTNEWEST)
+    public static List<DynamicObject> getNewestPerfManagerByPersonAndBeginYear(Collection<Long> personIds, QFilter otherFilter) {
+        QueryFieldBuilder queryFieldBuilder = createDefaultQueryFieldBuilder()
                 .add(PerfManagerFormConstant.CREATE_TIME_KEY)
-                .addIdNumberName(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY,PerfManagerFormConstant.NCKD_APPRAISALRESULT)
-                .addGroup(new String[]{PerfManagerFormConstant.NCKD_PERFMANAGERENTRY},PerfManagerFormConstant.NCKD_APPRAISALRESULT,PerfManagerFormConstant.NCKD_APPRAISALYEAR,PerfManagerFormConstant.NCKD_ISALLRANKSOURCE)
                 .orderDesc(PerfManagerFormConstant.NCKD_BEGINYEAR);
 
         QFilter filter = new QFilter(PerfManagerFormConstant.NCKD_PERSON, QCP.in, personIds);
-        if(otherFilter != null) {
+        if (otherFilter != null) {
             filter.and(otherFilter);
         }
-        DynamicObject[] load = BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{filter}, queryFieldBuilder.buildOrder());
 
-        //只取每个人员最新记录(先按NCKD_BEGINYEAR,再按CREATE_TIME_KEY)
+        DynamicObject[] load = BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID,
+                queryFieldBuilder.buildSelect(), new QFilter[]{filter}, queryFieldBuilder.buildOrder());
+
+        // 只取每个人员最新记录(先按NCKD_BEGINYEAR,再按CREATE_TIME_KEY)
         Map<Long, DynamicObject> latestRecordMap = new HashMap<>();
         for (DynamicObject dynamicObject : load) {
             DynamicObject person = dynamicObject.getDynamicObject(FormConstant.NCKD_PERSON);
             Date beginDate = dynamicObject.getDate(PerfManagerFormConstant.NCKD_BEGINYEAR);
             Date createTime = dynamicObject.getDate(PerfManagerFormConstant.CREATE_TIME_KEY);
             long personId = person.getLong(FormConstant.ID_KEY);
+
             // 如果map中没有该personId的记录,或者当前记录的beginDate更晚,
             // 或者beginDate相同但createTime更晚,则更新记录
             if (!latestRecordMap.containsKey(personId)) {
@@ -210,20 +241,20 @@ public class PerfManagerHelper {
         return new ArrayList<>(latestRecordMap.values());
     }
 
-
     /**
      * 根据人员将所有IsCurrentNewest更新为非最新的
+     *
      * @param personId 人员ID(可传多个)
-     * @return: void
      * @author W.Y.C
-     * @date: 2025/09/28 21:18
+     * @date 2025/09/28 21:18
      */
     public static void markAsNotCurrentNewest(Long... personId) {
         QFilter filter = new QFilter(String.join(".", FormConstant.NCKD_PERSON, FormConstant.ID_KEY), QCP.in, personId);
         QueryFieldBuilder queryField = QueryFieldBuilder.create()
                 .add(FormConstant.ID_KEY)
                 .add(FormConstant.NCKD_ISCURRENTNEWEST);
-        DynamicObject[] personPosFileColl = BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID,queryField.buildSelect(), new QFilter[]{filter});
+        DynamicObject[] personPosFileColl = BusinessDataServiceHelper.load(PerfManagerFormConstant.PERFMANAGER_ENTITYID,
+                queryField.buildSelect(), new QFilter[]{filter});
         for (DynamicObject personPosFile : personPosFileColl) {
             personPosFile.set(FormConstant.NCKD_ISCURRENTNEWEST, Boolean.FALSE);
         }
@@ -232,14 +263,14 @@ public class PerfManagerHelper {
 
     /**
      * 将人员最新考核周期标记为最新的
-     * @param personIds 人员ID(可传多个)
+     *
+     * @param personIds   人员ID(可传多个)
      * @param otherFilter 其他条件
-     * @return: void
      * @author W.Y.C
-     * @date: 2025/09/28 21:18
+     * @date 2025/09/28 21:18
      */
-    public static void markAsCurrentNewest(Collection personIds,QFilter otherFilter) {
-        List<DynamicObject> perfManagerColl = getNewestPerfManagerByPersonAndBeginYear(personIds,otherFilter);
+    public static void markAsCurrentNewest(Collection personIds, QFilter otherFilter) {
+        List<DynamicObject> perfManagerColl = getNewestPerfManagerByPersonAndBeginYear(personIds, otherFilter);
         DynamicObject[] updatePerfManagerColl = new DynamicObject[perfManagerColl.size()];
         for (int i = 0; i < perfManagerColl.size(); i++) {
             DynamicObject dynamicObject = perfManagerColl.get(i);
@@ -248,4 +279,31 @@ public class PerfManagerHelper {
         }
         SaveServiceHelper.update(updatePerfManagerColl);
     }
+
+    /**
+     * 创建默认的查询字段构建器
+     *
+     * @return QueryFieldBuilder实例
+     */
+    private static QueryFieldBuilder createDefaultQueryFieldBuilder() {
+        return QueryFieldBuilder.create()
+                .add(FormConstant.ID_KEY)
+                .addIdNumberName(FormConstant.NCKD_EMPPOSORGREL)
+                .addIdNumberName(FormConstant.NCKD_PERSON)
+                .addIdNumberName(PerfManagerFormConstant.NCKD_FIRSTYEARRESULT)
+                .addIdNumberName(PerfManagerFormConstant.NCKD_SECONDYEARRESULT)
+                .addIdNumberName(PerfManagerFormConstant.NCKD_THIRDYEARRESULT)
+                .add(PerfManagerFormConstant.NCKD_BEGINYEAR)
+                .add(PerfManagerFormConstant.NCKD_ENDYEAR)
+                .add(PerfManagerFormConstant.NCKD_ACTENDYEAR)
+                .add(PerfManagerFormConstant.NCKD_WHYEND)
+                .add(PerfManagerFormConstant.NCKD_THESTATUS)
+                .add(PerfManagerFormConstant.NCKD_ISCURRENTNEWEST)
+                .add(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY)
+                .addIdNumberName(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY, PerfManagerFormConstant.NCKD_APPRAISALRESULT)
+                .addGroup(new String[]{PerfManagerFormConstant.NCKD_PERFMANAGERENTRY},
+                        PerfManagerFormConstant.NCKD_APPRAISALRESULT,
+                        PerfManagerFormConstant.NCKD_APPRAISALYEAR,
+                        PerfManagerFormConstant.NCKD_ISALLRANKSOURCE);
+    }
 }

+ 39 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/result/AnnualPerfDetailFormPlugin.java

@@ -0,0 +1,39 @@
+package nckd.jxccl.opmc.pm.plugin.form.result;
+
+import kd.bos.entity.datamodel.ListSelectedRowCollection;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.ShowType;
+import kd.bos.form.StyleCss;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.opmc.pm.common.PerfManagerFormConstant;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+* 年度绩效结果明细-插件
+* 实体标识:nckd_annualperfdetail
+* @author W.Y.C
+* @date 2025/11/15 21:51
+* @version 1.0
+*/
+public class AnnualPerfDetailFormPlugin extends AbstractFormPlugin implements Plugin {
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs e) {
+        if(e.getOperationResult() != null && e.getOperationResult().isSuccess()) {
+            String operateKey = e.getOperateKey();
+            if ("deemedresult".equals(operateKey)) {
+
+                FormShowParameter showParameter = new FormShowParameter();
+                showParameter.setFormId("nckd_updateresult");
+                showParameter.getOpenStyle().setShowType(ShowType.Modal);
+                this.getView().showForm(showParameter);
+            }
+        }
+    }
+}

+ 90 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/form/result/AnnualPerfDetailReportListDataPlugin.java

@@ -1,16 +1,19 @@
 package nckd.jxccl.opmc.pm.plugin.form.result;
 
 import kd.bos.algo.DataSet;
+import kd.bos.common.enums.EnableEnum;
 import kd.bos.dataentity.entity.LocaleString;
 import kd.bos.entity.EntityMetadataCache;
 import kd.bos.entity.QueryEntityType;
 import kd.bos.entity.report.AbstractReportColumn;
 import kd.bos.entity.report.AbstractReportListDataPlugin;
+import kd.bos.entity.report.FastFilter;
 import kd.bos.entity.report.ReportColumn;
 import kd.bos.entity.report.ReportQueryParam;
 import kd.bos.ext.hr.service.query.QueryEntityHelper;
 import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.QueryServiceHelper;
 import kd.sdk.plugin.Plugin;
 import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.utils.DateUtil;
@@ -20,6 +23,7 @@ import nckd.jxccl.opmc.pm.common.PerfManagerFormConstant;
 import java.time.LocalDate;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
 * 年度绩效结果明细-报表取数插件
@@ -32,6 +36,7 @@ public class AnnualPerfDetailReportListDataPlugin extends AbstractReportListData
 
     @Override
     public DataSet query(ReportQueryParam reportQueryParam, Object o) throws Throwable {
+
         // 构建查询字段
         QueryFieldBuilder queryFieldBuilder = buildQueryFieldBuilder();
 
@@ -46,6 +51,12 @@ public class AnnualPerfDetailReportListDataPlugin extends AbstractReportListData
         QFilter qFilter = new QFilter(String.join(".", PerfManagerFormConstant.PERFMANAGERENTRY, PerfManagerFormConstant.NCKD_APPRAISALYEAR), QCP.large_equals, beginDate);
         qFilter.and(String.join(".", PerfManagerFormConstant.PERFMANAGERENTRY, PerfManagerFormConstant.NCKD_APPRAISALYEAR), QCP.less_equals, endDate);
 
+        // 处理快速过滤条件
+        processFastFilter(reportQueryParam, qFilter);
+
+        //其他过滤条件
+        processFilter(reportQueryParam, qFilter);
+
         // 执行基础查询
         QueryEntityType queryEntityType = (QueryEntityType) EntityMetadataCache.getDataEntityType("annualperfdetailquery");
         DataSet dataSet = QueryEntityHelper.getInstance().getQueryDataSet(queryEntityType,queryFieldBuilder.buildSelect(), new QFilter[]{qFilter}, null);
@@ -142,4 +153,83 @@ public class AnnualPerfDetailReportListDataPlugin extends AbstractReportListData
                         PerfManagerFormConstant.NCKD_ENDYEAR);
 
     }
+
+    /**
+     * 处理过滤条件
+     */
+    private void processFilter(ReportQueryParam reportQueryParam, QFilter qFilter) {
+        List<QFilter> qFilters = reportQueryParam.getFilter().getQFilters();
+            for (QFilter filter : qFilters) {
+            //由于页面命名限制不允许配置对应数据库字段(例如:position.id的格式),这里只能手动转换为数据库实际的字段
+            String property = filter.getProperty();
+            if ("nckd_posstatus.id".equalsIgnoreCase(property)){
+                qFilter.and(new QFilter(String.join(".", FormConstant.HRPI_EMPPOSORGREL,FormConstant.POS_STATUS,FormConstant.ID_KEY),filter.getCP(),filter.getValue()));
+            }else if("nckd_beginyearfilter".equalsIgnoreCase(property)){
+                qFilter.and(new QFilter("last_perfmanager."+PerfManagerFormConstant.NCKD_BEGINYEAR,filter.getCP(),filter.getValue()));
+            }else if("nckd_endyearfilter".equalsIgnoreCase(property)){
+                qFilter.and(new QFilter("last_perfmanager."+PerfManagerFormConstant.NCKD_ENDYEAR,filter.getCP(),filter.getValue()));
+            }
+        }
+    }
+
+    /**
+     * 处理快速过滤条件
+     */
+    private void processFastFilter(ReportQueryParam reportQueryParam, QFilter qFilter) {
+        FastFilter fastFilter = reportQueryParam.getFilter().getFastFilter();
+        if (fastFilter != null) {
+            List<Map<String, List<Object>>> fastFilterList = fastFilter.getFastFilter();
+            for (Map<String, List<Object>> stringListMap : fastFilterList) {
+                //nckd_empnumfastfilter转为employee.empnumber,nckd_namefastfilter转换为employee.name,转换后添加到fields中
+                List<Object> fieldList = stringListMap.get("FieldName");
+                List<Object> valueList = stringListMap.get("Value");
+                String[] fields = new String[fieldList.size()];
+                for (int i = 0; i < fieldList.size(); i++) {
+                    fields[i] = fieldList.get(i).toString()
+                            .replace("nckd_empnumfastfilter", String.join(".", FormConstant.HRPI_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY,FormConstant.EMP_NUMBER_KEY))
+                            .replace("nckd_namefastfilter", String.join(".", FormConstant.HRPI_EMPPOSORGREL, FormConstant.EMPLOYEE_KEY,FormConstant.NAME_KEY));
+                }
+                //valueList转到values
+                String[] values = new String[valueList.size()];
+                for (int i = 0; i < valueList.size(); i++) {
+                    values[i] = valueList.get(i).toString();
+                }
+                QFilter orFilter = null;
+                for (String field : fields) {
+                    for (String value : values) {
+                        if (orFilter == null) {
+                            orFilter = new QFilter(field, QCP.like, "%" + value + "%");
+                        } else {
+                            orFilter = orFilter.or(field, QCP.like, "%" + value + "%");
+                        }
+                    }
+
+                }
+
+               if(orFilter != null) {
+                   qFilter.and(orFilter);
+               }
+            }
+        }
+    }
+
+    /**
+     * 处理过滤条件
+     */
+   /* private void processFilter(ReportQueryParam reportQueryParam, QFilter qFilter) {
+        List<QFilter> qFilters = reportQueryParam.getFilter().getQFilters();
+        for (QFilter filter : qFilters) {
+            //由于页面命名限制不允许配置对应数据库字段(例如:position.id的格式),这里只能手动转换为数据库实际的字段
+            String property = filter.getProperty();
+            if ("nckd_positionfilter.id".equalsIgnoreCase(property)){
+                qFilter.and(new QFilter(String.join(".", FormConstant.POSITION_KEY, FormConstant.ID_KEY),filter.getCP(),filter.getValue()));
+            }else if("nckd_orgfilter.id".equalsIgnoreCase(property)){
+                qFilter.and(new QFilter(String.join(".", FormConstant.COMPANY_KEY, FormConstant.ID_KEY),filter.getCP(),filter.getValue()));
+            }else if("nckd_joblevelhrffilter.id".equalsIgnoreCase(property)){
+                qFilter.and(new QFilter(String.join(".", PositionStructureConstant.PERSONPOSFILE_ENTITYID, PositionStructureConstant.NCKD_JOBLEVELHR,FormConstant.ID_KEY),filter.getCP(),filter.getValue()));
+            }else if("nckd_begindatefilter".equalsIgnoreCase(property)){
+                qFilter.and(new QFilter(String.join(".", PositionStructureConstant.PERSONPOSFILE_ENTITYID, PositionStructureConstant.NCKD_BEGINDATE),filter.getCP(),filter.getValue()));
+            }
+        }
+    }*/
 }

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

@@ -70,7 +70,7 @@ public class CycleGenerateOpPlugin extends AbstractOperationServicePlugIn implem
                 .filter(Objects::nonNull)
                 .collect(Collectors.toList());
         //先结束当前周期
-        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
+       /* QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create()
                 .add(FormConstant.ID_KEY)
                 .add(PerfManagerFormConstant.NCKD_WHYEND)
                 .add(PerfManagerFormConstant.NCKD_WAGEEXPLAIN)
@@ -89,7 +89,7 @@ public class CycleGenerateOpPlugin extends AbstractOperationServicePlugIn implem
             //实际结束时间(如果endYear大于当前时间(年)则使用endYear否则使用当前时间(年))
             dbPerfManager.set(PerfManagerFormConstant.NCKD_ACTENDYEAR,DateUtil.toDate(personPerfInfo.getActEndYear()));
         }
-        SaveServiceHelper.update(dbPerfManagerArray);
+        SaveServiceHelper.update(dbPerfManagerArray);*/
 
 
         //调用save-op
@@ -114,6 +114,7 @@ public class CycleGenerateOpPlugin extends AbstractOperationServicePlugIn implem
         }else {
             OperateOption option = OperateOption.create();
             option.setVariableValue(OperateOptionConst.IGNOREINTERACTION, Boolean.TRUE + "");
+            option.setVariableValue("cyclegenerate", Boolean.TRUE + "");
             OperationResult operationResult = OperationServiceHelper.executeOperate(FormConstant.SAVE_OP, PerfManagerFormConstant.PERFMANAGER_ENTITYID, savePerfManager.toArray(new DynamicObject[0]), option);
 
             if (!operationResult.isSuccess()) {

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

@@ -263,10 +263,12 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
 
     }
     @Override
-        public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
         //事务开始之后将其他考核周期设置为非最新
         PerfManagerHelper.markAsNotCurrentNewest(personBeginYearMap.keySet().toArray(new Long[0]));
 
+        Boolean isCycleGenerate = ConvertUtil.toBoolean(this.getOption().getVariableValue("cyclegenerate",StringUtils.EMPTY),Boolean.FALSE);
+        Boolean isUpdate = ConvertUtil.toBoolean(this.getOption().getVariableValue("isUpdate",StringUtils.EMPTY),Boolean.FALSE);
         List<DynamicObject> updatePerManager = new ArrayList<>();
         for (DynamicObject dataEntity : e.getDataEntities()) {
             long id = dataEntity.getLong(FormConstant.ID_KEY);
@@ -284,47 +286,50 @@ public class PerfManagerSaveOpPlugin extends AbstractOperationServicePlugIn impl
                 dataEntity.set(FormConstant.NAME_KEY, StrFormatter.format("【{}】{}~{}的考核周期",personName,beginYear.getYear(),endYear.getYear()));
             }
             //上一周期标记为“已结束”并设置“实际结束时间” begin
-            //找出当前周期前还未结束的考核周期
-            QFilter filter = null;
-            if (id > 0) {
-                filter = new QFilter(FormConstant.ID_KEY, QCP.not_in, id);
-            }
-            DynamicObject[] beforeBeginYear = PerfManagerHelper.getBeforeBeginYear(DateUtil.toDate(beginYear), Collections.singletonList(personId), filter);
-            if(beforeBeginYear != null && beforeBeginYear.length > 0) {
-                DynamicObject[] allPerfManagerArray = PerfManagerHelper.getByPersonId(Collections.singletonList(personId), filter);
-                List<DynamicObject> allPerfManagerList = new ArrayList<>(Arrays.asList(allPerfManagerArray));
-                allPerfManagerList.add(dataEntity);
-                for (DynamicObject lastPerfManager : beforeBeginYear) {
-                    lastPerfManager.set(PerfManagerFormConstant.NCKD_THESTATUS, "3");
-                    //找到当前周期的下一周期
-                    Date currentBeginYear = lastPerfManager.getDate(PerfManagerFormConstant.NCKD_BEGINYEAR);
-                    Date currentEndYear = lastPerfManager.getDate(PerfManagerFormConstant.NCKD_ENDYEAR);
-
-                    DynamicObject nextCycle = findNextCycle(allPerfManagerList, currentBeginYear);
-                    if (nextCycle != null) {
-                        // 获取下一周期的开始年份
-                        Date nextBeginYear = nextCycle.getDate(PerfManagerFormConstant.NCKD_BEGINYEAR);
-                        LocalDateTime nextBeginLocalDateTime = DateUtil.toLocalDateTime(nextBeginYear);
-                        // 计算预期的实际结束年份:下一周期开始时间-1年
-                        LocalDateTime expectedActEndYear = DateUtil.minusYears(nextBeginLocalDateTime, 1);
-                        LocalDateTime currentEndLocalDateTime = DateUtil.toLocalDateTime(currentEndYear);
-                        // 如果预期结束时间大于等于当前周期的结束时间,说明中间有断层
-                        // 则实际结束时间设置为当前周期的结束时间
-                        // 否则设置为预期的实际结束时间(下一周期开始时间-1年)
-                        LocalDateTime actEndYear = expectedActEndYear.isAfter(currentEndLocalDateTime) ?
-                                currentEndLocalDateTime : expectedActEndYear;
-                        lastPerfManager.set(PerfManagerFormConstant.NCKD_ACTENDYEAR, DateUtil.toDate(actEndYear));
-                    } else {
-                        // 如果没有找到下一周期,则实际结束时间设置为当前周期的结束时间
-                        lastPerfManager.set(PerfManagerFormConstant.NCKD_ACTENDYEAR, currentEndYear);
-                    }
-                    lastPerfManager.set(PerfManagerFormConstant.NCKD_WHYEND, StrFormatter.format("新增周期({}~{}),系统自动结束前周期",beginYear.getYear(), endYear.getYear()));
-                    updatePerManager.add(lastPerfManager);
+            if(!isUpdate) {
+                //找出当前周期前还未结束的考核周期
+                QFilter filter = null;
+                if (id > 0) {
+                    filter = new QFilter(FormConstant.ID_KEY, QCP.not_in, id);
                 }
-                //找到当前周期的上一周期
-                DynamicObject previousCycle = findPreviousCycle(allPerfManagerList, DateUtil.toDate(beginYear));
-                if(previousCycle != null) {
-                    dataEntity.set(PerfManagerFormConstant.NCKD_LASTPERFMANAGER, previousCycle);
+                DynamicObject[] beforeBeginYear = PerfManagerHelper.getBeforeBeginYear(DateUtil.toDate(beginYear), Collections.singletonList(personId), filter);
+                if (beforeBeginYear != null && beforeBeginYear.length > 0) {
+                    DynamicObject[] allPerfManagerArray = PerfManagerHelper.getByPersonId(Collections.singletonList(personId), filter);
+                    List<DynamicObject> allPerfManagerList = new ArrayList<>(Arrays.asList(allPerfManagerArray));
+                    allPerfManagerList.add(dataEntity);
+                    for (DynamicObject lastPerfManager : beforeBeginYear) {
+                        lastPerfManager.set(PerfManagerFormConstant.NCKD_THESTATUS, "3");
+                        //找到当前周期的下一周期
+                        Date currentBeginYear = lastPerfManager.getDate(PerfManagerFormConstant.NCKD_BEGINYEAR);
+                        Date currentEndYear = lastPerfManager.getDate(PerfManagerFormConstant.NCKD_ENDYEAR);
+
+                        DynamicObject nextCycle = findNextCycle(allPerfManagerList, currentBeginYear);
+                        if (nextCycle != null) {
+                            // 获取下一周期的开始年份
+                            Date nextBeginYear = nextCycle.getDate(PerfManagerFormConstant.NCKD_BEGINYEAR);
+                            LocalDateTime nextBeginLocalDateTime = DateUtil.toLocalDateTime(nextBeginYear);
+                            // 计算预期的实际结束年份:下一周期开始时间-1年
+                            LocalDateTime expectedActEndYear = DateUtil.minusYears(nextBeginLocalDateTime, 1);
+                            LocalDateTime currentEndLocalDateTime = DateUtil.toLocalDateTime(currentEndYear);
+                            // 如果预期结束时间大于等于当前周期的结束时间,说明中间有断层
+                            // 则实际结束时间设置为当前周期的结束时间
+                            // 否则设置为预期的实际结束时间(下一周期开始时间-1年)
+                            LocalDateTime actEndYear = expectedActEndYear.isAfter(currentEndLocalDateTime) ?
+                                    currentEndLocalDateTime : expectedActEndYear;
+                            lastPerfManager.set(PerfManagerFormConstant.NCKD_ACTENDYEAR, DateUtil.toDate(actEndYear));
+                        } else {
+                            // 如果没有找到下一周期,则实际结束时间设置为当前周期的结束时间
+                            lastPerfManager.set(PerfManagerFormConstant.NCKD_ACTENDYEAR, currentEndYear);
+                        }
+                        String str = isCycleGenerate ? "周期生成" : "手动/导入新增周期";
+                        lastPerfManager.set(PerfManagerFormConstant.NCKD_WHYEND, StrFormatter.format("{}({}~{}),系统自动结束前周期", str, beginYear.getYear(), endYear.getYear()));
+                        updatePerManager.add(lastPerfManager);
+                    }
+                    //找到当前周期的上一周期
+                    DynamicObject previousCycle = findPreviousCycle(allPerfManagerList, DateUtil.toDate(beginYear));
+                    if (previousCycle != null) {
+                        dataEntity.set(PerfManagerFormConstant.NCKD_LASTPERFMANAGER, previousCycle);
+                    }
                 }
             }
             //上一周期标记为“已结束”并设置“实际结束时间” end

+ 186 - 0
code/opmc/nckd-jxccl-opmc/src/main/java/nckd/jxccl/opmc/pm/plugin/operate/result/UpdateResultOpPlugin.java

@@ -0,0 +1,186 @@
+package nckd.jxccl.opmc.pm.plugin.operate.result;
+
+import kd.bos.dataentity.OperateOption;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.operate.OperateOptionConst;
+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.entity.validate.AbstractValidator;
+import kd.bos.servicehelper.operation.OperationServiceHelper;
+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.DateUtil;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.opmc.pm.common.PerfManagerFormConstant;
+import nckd.jxccl.opmc.pm.helper.PerfManagerHelper;
+
+import java.time.LocalDateTime;
+import java.util.*;
+
+/**
+* 视同合格/优秀/无结果
+* 实体标识:nckd_updateresult
+* @author W.Y.C
+* @date 2025/11/14 16:50
+* @version 1.0
+*/
+public class UpdateResultOpPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    //缓存需要修改的数据,key:考核周期ID
+    Map<Long, List<PendingUpdate>> pendingUpdateMap = new java.util.HashMap<>();
+
+    private class PendingUpdate {
+
+        Long entryId;
+        Date appraisalYear;
+        DynamicObject appraisalResult;
+
+        public PendingUpdate(Long entryId,Date appraisalYear,DynamicObject appraisalResult) {
+            this.entryId = entryId;
+            this.appraisalResult = appraisalResult;
+            this.appraisalYear = appraisalYear;
+        }
+    }
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+
+        e.addValidator(new AbstractValidator() {
+            @Override
+            public void validate() {
+                if(getOperationResult() != null && getOperationResult().isSuccess()) {
+                    for (ExtendedDataEntity rowDataEntity : getDataEntities()) {
+                        DynamicObject data = rowDataEntity.getDataEntity();
+                        DynamicObjectCollection entryColl = data.getDynamicObjectCollection(FormConstant.NCKD_ENTRYENTITY);
+                        for (DynamicObject entry : entryColl) {
+                            DynamicObject empPosOrgRel = entry.getDynamicObject(FormConstant.NCKD_EMPPOSORGREL);
+                            DynamicObject employee = empPosOrgRel.getDynamicObject(FormConstant.EMPLOYEE_KEY);
+                            long personId = employee.getLong(FormConstant.ID_KEY);
+                            Date appraisalYear = entry.getDate(PerfManagerFormConstant.NCKD_APPRAISALYEAR);
+                            LocalDateTime appraisalYearLocalDateTime = DateUtil.toLocalDateTime(appraisalYear);
+                            DynamicObject appraisalResult = entry.getDynamicObject(PerfManagerFormConstant.NCKD_APPRAISALRESULT);
+
+                            DynamicObject[] dbPerfManagerArray = PerfManagerHelper.getByDate(appraisalYear, Collections.singletonList(personId));
+                            if (dbPerfManagerArray == null || dbPerfManagerArray.length == 0) {
+                                this.addFatalErrorMessage(rowDataEntity, StrFormatter.format("员工【{}】没有【{}】年的考核周期", employee.getString(FormConstant.NAME_KEY), DateUtil.getYear(appraisalYear)));
+                            }else{
+                                for (DynamicObject dbPerfManager : dbPerfManagerArray) {
+                                    long dbId = dbPerfManager.getLong(FormConstant.ID_KEY);
+                                    Date dbBeginYear = dbPerfManager.getDate(PerfManagerFormConstant.NCKD_BEGINYEAR);
+                                    Date dbEndYear = dbPerfManager.getDate(PerfManagerFormConstant.NCKD_ENDYEAR);
+                                    if(dbPerfManager.getDate(PerfManagerFormConstant.NCKD_ACTENDYEAR) != null){
+                                        //如果有实际结束周期则结束时间为实际结束周期
+                                        dbEndYear = dbPerfManager.getDate(PerfManagerFormConstant.NCKD_ACTENDYEAR);
+                                    }
+                                    DynamicObjectCollection dbEntryColl = dbPerfManager.getDynamicObjectCollection(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY);
+                                    boolean isExist = false;
+                                    for (DynamicObject dbEntry : dbEntryColl) {
+                                        long entryId = dbEntry.getLong(FormConstant.ID_KEY);
+                                        LocalDateTime dbAppraisalYear = DateUtil.toLocalDateTime(dbEntry.getDate(PerfManagerFormConstant.NCKD_APPRAISALYEAR));
+                                        //只取年份在考核周期内的数据
+
+                                        if(dbAppraisalYear.getYear() >= DateUtil.getYear(dbBeginYear) &&  dbAppraisalYear.getYear()  <= DateUtil.getYear(dbEndYear)){
+                                            if(dbAppraisalYear.getYear() == appraisalYearLocalDateTime.getYear()) {
+                                                isExist = true;
+                                                DynamicObject dbAppraisalResult = dbEntry.getDynamicObject(PerfManagerFormConstant.NCKD_APPRAISALRESULT);
+                                                boolean dbIsAllRankSource = dbEntry.getBoolean(PerfManagerFormConstant.NCKD_ISALLRANKSOURCE);
+                                                if (dbAppraisalResult != null) {
+                                                    if (dbIsAllRankSource) {
+                                                        this.addFatalErrorMessage(rowDataEntity, StrFormatter.format("员工【{}】已存在【{}】年的考核结果【{}】,并且结果来源于全排名。", employee.getString(FormConstant.NAME_KEY), DateUtil.getYear(appraisalYear), dbAppraisalResult.getString(FormConstant.NAME_KEY)));
+                                                    } else {
+                                                        String dbAppraisalResultNumber = dbAppraisalResult.getString(FormConstant.NUMBER_KEY);
+                                                        if (!AppraisalResultEnum.NONE.getCode().equalsIgnoreCase(dbAppraisalResultNumber)) {
+                                                            if (!Objects.equals(dbAppraisalResult.getLong(FormConstant.ID_KEY), appraisalResult.getLong(FormConstant.ID_KEY))) {
+                                                                this.addFatalErrorMessage(rowDataEntity, StrFormatter.format("员工【{}】已存在【{}】年的考核结果【{}】,不能修改。", employee.getString(FormConstant.NAME_KEY), DateUtil.getYear(appraisalYear), dbAppraisalResult.getString(FormConstant.NAME_KEY)));
+                                                            } else {
+                                                                //原绩效跟要更新的绩效一样,忽略
+                                                            }
+                                                        } else {
+                                                            //原绩效结果等于"无",又不是来源于全排名。可以修改
+                                                            List<PendingUpdate> pendingUpdateList = pendingUpdateMap.computeIfAbsent(dbId, k -> new ArrayList<>());
+                                                            PendingUpdate pendingUpdate = new PendingUpdate(entryId, appraisalYear, appraisalResult);
+                                                            pendingUpdateList.add(pendingUpdate);
+                                                            pendingUpdateMap.put(dbId, pendingUpdateList);
+                                                        }
+                                                    }
+                                                } else {
+                                                    //原绩效结果为空。可以修改
+                                                    List<PendingUpdate> pendingUpdateList = pendingUpdateMap.computeIfAbsent(dbId, k -> new ArrayList<>());
+                                                    PendingUpdate pendingUpdate = new PendingUpdate(entryId, appraisalYear, appraisalResult);
+                                                    pendingUpdateList.add(pendingUpdate);
+                                                    pendingUpdateMap.put(dbId, pendingUpdateList);
+                                                }
+                                            }
+                                        }
+                                    }
+                                    if(!isExist){
+                                        //考核周期分录没有该年份的数据
+                                        //检查全排名是否存在
+                                        Map<Long, AppraisalResultEnum> perfRankResult = PerfManagerHelper.getPerfRankResult(appraisalYear, Collections.singletonList(personId));
+                                        boolean isPass = true;
+                                        if(!perfRankResult.isEmpty()){
+                                            AppraisalResultEnum appraisalResultEnum = perfRankResult.get(personId);
+                                            if(appraisalResultEnum != null){
+                                                this.addFatalErrorMessage(rowDataEntity, StrFormatter.format("【{}】【{}】年的考核结果已在全排名中产生【{}】,不能修改。", employee.getString(FormConstant.NAME_KEY), DateUtil.getYear(appraisalYear), appraisalResultEnum.getName()));
+                                                isPass = false;
+                                            }
+                                        }
+                                        if(isPass) {
+                                            List<PendingUpdate> pendingUpdateList = pendingUpdateMap.computeIfAbsent(dbId, k -> new ArrayList<>());
+                                            PendingUpdate pendingUpdate = new PendingUpdate(null, appraisalYear, appraisalResult);
+                                            pendingUpdateList.add(pendingUpdate);
+                                            pendingUpdateMap.put(dbId, pendingUpdateList);
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+
+        if(!pendingUpdateMap.isEmpty()){
+            DynamicObject[] updatePerfManagerArray = PerfManagerHelper.getById(pendingUpdateMap.keySet());
+            for (DynamicObject updatePerfManager : updatePerfManagerArray) {
+                long id = updatePerfManager.getLong(FormConstant.ID_KEY);
+                List<PendingUpdate> pendingUpdateList = pendingUpdateMap.get(id);
+                DynamicObjectCollection updatePerfManagerEntryColl = updatePerfManager.getDynamicObjectCollection(PerfManagerFormConstant.NCKD_PERFMANAGERENTRY);
+                for (PendingUpdate pendingUpdate : pendingUpdateList) {
+                    if(pendingUpdate.entryId != null) {
+                        for (DynamicObject updatePerfManagerEntry : updatePerfManagerEntryColl) {
+                            long entryId = updatePerfManagerEntry.getLong(FormConstant.ID_KEY);
+                            if (Objects.equals(entryId, pendingUpdate.entryId)) {
+                                updatePerfManagerEntry.set(PerfManagerFormConstant.NCKD_APPRAISALRESULT, pendingUpdate.appraisalResult);
+                                updatePerfManagerEntry.set(PerfManagerFormConstant.NCKD_ISALLRANKSOURCE, false);
+                            }
+                        }
+                    }else{
+                        DynamicObject newEntry = updatePerfManagerEntryColl.addNew();
+                        newEntry.set(PerfManagerFormConstant.NCKD_APPRAISALYEAR,pendingUpdate.appraisalYear);
+                        newEntry.set(PerfManagerFormConstant.NCKD_APPRAISALRESULT, pendingUpdate.appraisalResult);
+                        newEntry.set(PerfManagerFormConstant.NCKD_ISALLRANKSOURCE, false);
+                    }
+                }
+
+            }
+
+            OperateOption option = OperateOption.create();
+            option.setVariableValue(OperateOptionConst.IGNOREINTERACTION, Boolean.TRUE + "");
+            //告诉OP此次操作类型
+            option.setVariableValue("isUpdate", Boolean.TRUE+"");
+            OperationResult operationResult = OperationServiceHelper.executeOperate(FormConstant.SAVE_OP, PerfManagerFormConstant.PERFMANAGER_ENTITYID, updatePerfManagerArray, option);
+        }
+
+    }
+}