2 Commits 58e84fcc9b ... e3d5a3d8a3

Auteur SHA1 Message Date
  wyc e3d5a3d8a3 feat(hr): 完善优秀生测评逻辑 il y a 1 mois
  wyc d037c3c7cd refactor(jxccl-hr): 重构优秀生综合测评问卷生成逻辑 il y a 2 mois
35 fichiers modifiés avec 3167 ajouts et 214 suppressions
  1. 7 1
      .gitignore
  2. 26 1
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java
  3. 0 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/.gitkeep
  4. 39 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/AppraisalResultEnum.java
  5. 35 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/PerfPlanRoleEnum.java
  6. 26 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/exception/ValidationException.java
  7. 53 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/ConvertUtil.java
  8. 69 0
      code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/entity/helper/EntityHelper.java
  9. 6 5
      code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/org/helper/AdminOrgHelper.java
  10. 1 1
      code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/org/helper/PersonHelper.java
  11. 167 72
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/CreateEvalQuestService.java
  12. 56 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/algo/RankMapFunction.java
  13. 59 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/algo/UnitRankMapFunction.java
  14. 0 11
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/helper/EvalQuestHelper.java
  15. 795 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/helper/HonorStudentHelper.java
  16. 64 3
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/common/HonorStudentConstant.java
  17. 367 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/common/bo/EvalQuestResultBO.java
  18. 36 68
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/CreateEvalQuestFormPlugin.java
  19. 148 5
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestFormPlugin.java
  20. 158 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestListPlugin.java
  21. 44 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestSelectOrg.java
  22. 25 20
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestTplListPlugin.java
  23. 74 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestTreeListPlugin.java
  24. 40 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalResultFormPlugin.java
  25. 0 12
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvaluationRuleListPlugin.java
  26. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/.gitkeep
  27. 96 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/CreateQvalQuestAffirmOperationPlugin.java
  28. 138 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestBeginEvalOperationPlugin.java
  29. 116 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestEndEvalOperationPlugin.java
  30. 281 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestGenerateQuestOperationPlugin.java
  31. 33 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestGetScoreOperationPlugin.java
  32. 81 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalResultAuditOperationPlugin.java
  33. 65 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalResultUnAuditOperationPlugin.java
  34. 52 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/validate/EvalResultPerfScoreValidate.java
  35. 10 15
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/task/CreateEvalQuestTask.java

+ 7 - 1
.gitignore

@@ -5,7 +5,12 @@ build/
 .idea/
 .gradle/
 .git/
+nckd-cosmic-debug/
 /nckd-cosmic-debug/
+**/nckd-cosmic-debug/
+
+out/
+**/out/
 
 
 # 忽略文件
@@ -28,4 +33,5 @@ gradle.properties
 #    git update-index --no-assume-unchanged code/nckd-cosmic-debug/src/main/java/nckd/cosmic/debug/DebugApplication.java
 #    git pull
 #    git update-index --assume-unchanged code/nckd-cosmic-debug/src/main/java/nckd/cosmic/debug/DebugApplication.java
-## -------------------- 让Git停止跟踪文件 end--------------------
+## -------------------- 让Git停止跟踪文件 end--------------------
+

+ 26 - 1
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java

@@ -24,6 +24,8 @@ public class FormConstant {
     public static final String SEARCH_DATE_KEY = "searchdate";
     /** 退出按钮 */
     public static final String CLOSE_KEY = "tblclose";
+    /** 工具栏标识 */
+    public static final String TOOLBARAP = "toolbarap";
     /**
      * 单据编号
      **/
@@ -91,6 +93,8 @@ public class FormConstant {
     /** 初始状态 */
     public static final String INIT_STATUS = "initstatus";
 
+    /**工具栏*/
+    public static final String TBMAIN = "tbmain";
     /** 确认框确认按钮 */
     public static final String OP_BTN_OK = "btnok";
     /** 提交操作 */
@@ -99,10 +103,14 @@ public class FormConstant {
     public static final String OP_ENABLE = "enable";
     /** 审核操作 */
     public static final String OP_AUDIT = "audit";
+    /** 反审核操作 */
+    public static final String OP_UNAUDIT = "unaudit";
     /** 删除操作 */
     public static final String OP_DELETE = "delete";
     /** 刷新*/
     public static final String REFRESH = "refresh";
+    /** 刷新*/
+    public static final String AFFIRM = "affirm";
     /** 多选基础资料*/
     public static final String BASEDATAID_KEY = "fbasedataid";
     /** 当前user id*/
@@ -110,5 +118,22 @@ public class FormConstant {
     /** 当前org id*/
     public static final String CURR_ORG_ID = "ORG_ID";
     /** 当前org id*/
-    public static final String DEP_EMP = "DEPEMP";
+    public static final String DEP_EMP = "depemp";
+    /** 左树右表-是否包含子部门*/
+    public static final String CHKINCLUDECHILD = "chkincludechild";
+    /**人员*/
+    public static final String PERSON = "PERSON";
+    /** 组织*/
+    public static final String ADMINORG = "adminorg";
+    /**组织上下级结构长编码*/
+    public static final String STRUCTLONGNUMBER = "structlongnumber";
+    /** HR行政组织*/
+    public static final String ADMINORGHR_ENTITYID = "haos_adminorghr";
+
+    /** 审核操作标识 */
+    public static final String OP_BAR_AUDIT = "bar_audit";
+    /** 反审核操作标识*/
+    public static final String OP_BAR_UNAUDIT = "bar_unaudit";
+    /** 反审核操作标识*/
+    public static final String NCKD_TOOLBARAP = "nckd_toolbarap";
 }

+ 0 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/.gitkeep


+ 39 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/AppraisalResultEnum.java

@@ -0,0 +1,39 @@
+package nckd.jxccl.base.common.enums;
+
+/**
+* 【人员考评】-考评结果枚举
+* @author W.Y.C
+* @date 2025/8/13 15:08
+* @version 1.0
+*/
+public enum AppraisalResultEnum {
+
+    /** 优秀 */
+    EXCELLENT("01", "优秀"),
+    /** 合格 */
+    QUALIFIED("02", "合格"),
+    /** 基本合格 */
+    BASICALLY_QUALIFIED("03", "基本合格"),
+    /** 不合格 */
+    UN_QUALIFIED("04", "不合格"),
+    /** 视同合格 */
+    DEEMED_QUALIFIED("05", "视同合格"),
+    /** 无 */
+    NONE("06", "无");
+
+    private final String code;
+    private final String name;
+
+    AppraisalResultEnum(String code, String name) {
+        this.code = code;
+        this.name = name;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

+ 35 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/PerfPlanRoleEnum.java

@@ -0,0 +1,35 @@
+package nckd.jxccl.base.common.enums;
+
+/**
+* 【优秀生】-评分人员角色枚举
+* @author W.Y.C
+* @date 2025/7/14 14:25
+* @version 1.0
+*/
+public enum PerfPlanRoleEnum {
+
+    /** 领导 */
+    LEAD("1", "领导"),
+    /** 上级 */
+    SUPERIOR("2", "上级"),
+    /** 同级 */
+    PEERS("3", "同级"),
+    /** 同级其他部门人员 */
+    OTHER_PEERS("3", "同级其他部门人员");
+
+    private final String code;
+    private final String name;
+
+    PerfPlanRoleEnum(String code, String name) {
+        this.code = code;
+        this.name = name;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

+ 26 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/exception/ValidationException.java

@@ -0,0 +1,26 @@
+package nckd.jxccl.base.common.exception;
+
+import kd.bos.exception.ErrorCode;
+import kd.bos.exception.KDBizException;
+import kd.bos.exception.KDException;
+
+/**
+ * 校验异常类
+ * @author W.Y.C
+ * @date 2025/7/16 16:24
+ * @version 1.0
+ */
+public class ValidationException extends KDBizException {
+
+    public ValidationException(String message) {
+        super(new ErrorCode("", message), new Object[0]);
+    }
+
+    public ValidationException(ErrorCode errorCode, Object... args) {
+        super(errorCode, args);
+    }
+
+    public ValidationException(Throwable cause, ErrorCode errorCode, Object... args) {
+        super(cause, errorCode, args);
+    }
+}

+ 53 - 0
code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/ConvertUtil.java

@@ -1,5 +1,7 @@
 package nckd.jxccl.base.common.utils;
 
+import kd.bos.dataentity.entity.DynamicObject;
+
 import java.lang.reflect.Array;
 import java.math.BigDecimal;
 import java.math.BigInteger;
@@ -691,6 +693,23 @@ public class ConvertUtil {
         return defaultValue;
     }
 
+    /**
+     * 将对象转换为DynamicObject类型
+     * @param value 要转换的对象
+     * @return: kd.bos.dataentity.entity.DynamicObject
+     * @author W.Y.C
+     * @date: 2025/08/04 12:05
+     */
+    public static DynamicObject toDynamicObject(Object value) {
+        if (value == null) {
+            return new DynamicObject();
+        }
+        if (value instanceof DynamicObject) {
+            return (DynamicObject) value;
+        }
+        return new DynamicObject();
+    }
+
     // =================== 集合转换 ===================
 
     /**
@@ -1081,4 +1100,38 @@ public class ConvertUtil {
         }
         return new String[0];
     }
+
+
+
+    /**
+     * 将对象转换为DynamicObject数组
+     * @param value 要转换的对象
+     * @return: kd.bos.dataentity.entity.DynamicObject[]
+     * @author W.Y.C
+     * @date: 2025/08/04 12:04
+     */
+    public static DynamicObject[] toDynamicObjectArray(Object value) {
+        if (value == null) {
+            return new DynamicObject[0];
+        }
+        if (value instanceof DynamicObject[]) {
+            return (DynamicObject[]) value;
+        }
+        if (value instanceof Object[]) {
+            Object[] array = (Object[]) value;
+            DynamicObject[] result = new DynamicObject[array.length];
+            for (int i = 0; i < array.length; i++) {
+                result[i] = array[i] != null ? toDynamicObject(array[i]) : null;
+            }
+            return result;
+        }
+        if (value instanceof List) {
+            List<?> list = (List<?>) value;
+            return list.stream()
+                    .map(item -> item != null ? toDynamicObject(item) : null)
+                    .toArray(DynamicObject[]::new);
+        }
+        return new DynamicObject[0];
+    }
+
 }

+ 69 - 0
code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/entity/helper/EntityHelper.java

@@ -0,0 +1,69 @@
+package nckd.jxccl.base.entity.helper;
+
+import kd.bos.common.enums.EnableEnum;
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.entity.MainEntityType;
+import kd.bos.entity.constant.StatusEnum;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.user.UserServiceHelper;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.org.helper.AdminOrgHelper;
+
+import java.util.Date;
+
+/**
+ * 实体(DynamicObject) 帮助类
+ * @author W.Y.C
+ * @date 2025/7/17 19:58
+ * @version 1.0
+ */
+public class EntityHelper {
+
+    /**
+     * 创建一个状态为"可用"的基础资料对象
+     * @param entityName 实体标识
+     * @return: kd.bos.dataentity.entity.DynamicObject 新创建的基础资料实体,状态已设置为可用(数据状态:已审核、使用状态:可用),并设置创建时间、创建人、创建组织、业务单元
+     * @author W.Y.C
+     * @date: 2025/07/17 20:06
+     */
+    public static DynamicObject newAvailableBasicEntity(String entityName){
+        return newAvailableBasicEntity(entityName, null, null);
+    }
+
+    /**
+     * 创建一个状态为"可用"的基础资料对象
+     * @param entityName 实体标识
+     * @param org 组织id
+     * @param currUser 当前用户
+     * @return: kd.bos.dataentity.entity.DynamicObject 新创建的基础资料实体,状态已设置为可用(数据状态:已审核、使用状态:可用),并设置创建时间
+     * @author W.Y.C
+     * @date: 2025/07/17 20:13
+     */
+    public static DynamicObject newAvailableBasicEntity(String entityName,DynamicObject org, DynamicObject currUser){
+        if(currUser == null){
+            DynamicObject buildEvalResult = BusinessDataServiceHelper.newDynamicObject(entityName);
+            Long currUserId =  RequestContext.get().getCurrUserId();
+            //当前登录用户
+            currUser = UserServiceHelper.getUserInfoByID(currUserId, FormConstant.ID_KEY);
+        }
+        if(org == null){
+            Long currOrgId =  RequestContext.get().getOrgId();
+            // 获取苍穹平台组织实体元数据
+            MainEntityType bosOrgEntityType = EntityMetadataCache.getDataEntityType(AdminOrgHelper.BOS_ORG);
+            // 基于元数据创建 DynamicObject
+            org = new DynamicObject(bosOrgEntityType);
+            org.set(FormConstant.ID_KEY,currOrgId);
+        }
+
+        DynamicObject dynamicObject = BusinessDataServiceHelper.newDynamicObject(entityName);
+        dynamicObject.set(FormConstant.CREATEORG_KEY, org);
+        dynamicObject.set(FormConstant.USEORG_KEY, org);
+        dynamicObject.set(FormConstant.CREATE_TIME_KEY, new Date());
+        dynamicObject.set(FormConstant.CREATOR_KEY, currUser);
+        dynamicObject.set(FormConstant.STATUS, StatusEnum.C.toString());
+        dynamicObject.set(FormConstant.ENABLE, EnableEnum.YES.getCode());
+        return dynamicObject;
+    }
+}

+ 6 - 5
code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/org/helper/AdminOrgHelper.java

@@ -6,6 +6,7 @@ import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.bos.servicehelper.QueryServiceHelper;
 import kd.hr.hbp.business.dao.factory.HRBaseDaoFactory;
+import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
 
@@ -20,7 +21,7 @@ import java.util.Set;
  */
 public class AdminOrgHelper {
 
-    public static final String BOS_ORG = "bos_org";
+    public static final String BOS_ORG = "BOS_ORG";
     /**
      * 获取当前组织下的所有子组织
      * @param adminOrgId 组织id
@@ -30,12 +31,12 @@ public class AdminOrgHelper {
      */
    public static Set<Long> getChildOrg(Long adminOrgId) {
        QFilter adminOrgIdFilter = new QFilter("adminorg.id", QCP.equals,adminOrgId);
-       DynamicObject structLongNumber = HRBaseDaoFactory.getInstance("haos_adminorgstruct").queryOne("structlongnumber",
+       DynamicObject structLongNumber = HRBaseDaoFactory.getInstance("haos_adminorgstruct").queryOne(FormConstant.STRUCTLONGNUMBER,
                new QFilter[]{QFilterCommonHelper.getCurrentVersionFilter(), QFilterCommonHelper.getInitStatusFinishFilter(),
                QFilterCommonHelper.getDataStatusFilter(), adminOrgIdFilter});
-       String longNumber = structLongNumber.getString("structlongnumber");
+       String longNumber = structLongNumber.getString(FormConstant.STRUCTLONGNUMBER);
 
-       QFilter structLongNumberFilter = new QFilter("structlongnumber", QCP.like, longNumber + "%");
+       QFilter structLongNumberFilter = new QFilter(FormConstant.STRUCTLONGNUMBER, QCP.like, longNumber + "%");
        DynamicObjectCollection dynamicObjects = HRBaseDaoFactory.getInstance("haos_adminorgstruct").queryColl("adminorg.id adminorg", new QFilter[]{structLongNumberFilter, QFilterCommonHelper.getCurrentVersionFilter(), QFilterCommonHelper.getInitStatusFinishFilter(),
                QFilterCommonHelper.getDataStatusFilter()}, null);
        Set<Long> ids = new HashSet<>(dynamicObjects.size());
@@ -52,7 +53,7 @@ public class AdminOrgHelper {
     */
     public static Long getParentOrg(Long adminOrgId) {
         QFilter adminOrgIdFilter = new QFilter("id", QCP.equals,adminOrgId);
-        DynamicObject parentOrg = QueryServiceHelper.queryOne("haos_adminorghr","parent.id parentId",new QFilter[]{QFilterCommonHelper.getCurrentVersionFilter(), QFilterCommonHelper.getInitStatusFinishFilter(),
+        DynamicObject parentOrg = QueryServiceHelper.queryOne(FormConstant.ADMINORGHR_ENTITYID,"parent.id parentId",new QFilter[]{QFilterCommonHelper.getCurrentVersionFilter(), QFilterCommonHelper.getInitStatusFinishFilter(),
                 QFilterCommonHelper.getDataStatusFilter(),QFilterCommonHelper.getEnableFilter(),QFilterCommonHelper.getStatusFilter(), adminOrgIdFilter});
         if(parentOrg != null) {
             return parentOrg.getLong("parentId");

+ 1 - 1
code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/org/helper/PersonHelper.java

@@ -52,7 +52,7 @@ public class PersonHelper {
 
         // 防止 selectFields 为空
         if (StringUtils.isBlank(selectFields)) {
-            selectFields = "id";
+            selectFields = FormConstant.ID_KEY;
         }
         // 执行查询并返回结果
         return QueryServiceHelper.query(DEP_EMP_ENTITY_ID, selectFields, filterList.toArray(new QFilter[0]));

+ 167 - 72
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/CreateEvalQuestService.java

@@ -1,13 +1,11 @@
 package nckd.jxccl.hr.hstu.business;
 
-import kd.bos.common.enums.EnableEnum;
 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.constant.StatusEnum;
 import kd.bos.entity.operate.OperateOptionConst;
 import kd.bos.entity.operate.result.IOperateInfo;
 import kd.bos.entity.operate.result.OperationResult;
@@ -22,10 +20,13 @@ import kd.bos.servicehelper.operation.SaveServiceHelper;
 import kd.bos.servicehelper.user.UserServiceHelper;
 import kd.hr.hbp.business.openservicehelper.hrpi.HRPIDepempServiceHelper;
 import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.PerfPlanRoleEnum;
+import nckd.jxccl.base.common.exception.ValidationException;
 import nckd.jxccl.base.common.schedule.ProgressCallback;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.common.utils.DateUtil;
 import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.entity.helper.EntityHelper;
 import nckd.jxccl.base.org.helper.AdminOrgHelper;
 import nckd.jxccl.base.org.helper.PersonHelper;
 import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
@@ -33,14 +34,16 @@ import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
 /**
- * 【优秀生】-生成评价问卷服务类
+ * 【优秀生】-生成评价问卷服务类(生成优秀生评价预计打分人员核心逻辑)
  * @author W.Y.C
  * @date 2025/7/2 16:41
  * @version 1.0
@@ -49,17 +52,20 @@ public class CreateEvalQuestService {
 
     private static final Log logger = LogFactory.getLog(CreateEvalQuestService.class);
 
+    /** 最大递归层级 */
+    private static final int MAX_RECURSION_DEPTH = 10;
+
     /**
      * 批量生成评价问卷
-     * @param evalQuestTplId 评价问卷模板Id
+     * @param selectedEvalRule 评价问卷模板
      * @param selectedEvalRule 评价规则
      * @param selectedPerson 被评价人
      * @return: void
      * @author W.Y.C
      * @date: 2025/07/02 17:24
      */
-    public static void batchGenerateEvalQuest(Long evalQuestTplId, DynamicObject selectedEvalRule, DynamicObjectCollection selectedPerson, ProgressCallback callback, Long userId,Long orgId) {
-        logger.info("【优秀生考评】-生成综合评测问卷-开始");
+    public static void batchGenerateEvalQuest(DynamicObject evalQuestTpl, DynamicObject selectedEvalRule, DynamicObjectCollection selectedPerson, ProgressCallback callback, Long userId,Long orgId) {
+        logger.info("【优秀生考评】-生成综合评测问卷-参数: evalQuestTplId={},selectedEvalRule={} ,selectedPersonSize={}", evalQuestTpl.getLong(FormConstant.ID_KEY), selectedEvalRule.getLong(FormConstant.ID_KEY),selectedPerson.size());
         try {
             // 获取当前用户ID和主组织ID(创建组织)
             Long currUserId = userId;
@@ -70,7 +76,7 @@ public class CreateEvalQuestService {
             if(currOrgId == null) {
                 currOrgId = RequestContext.get().getOrgId();
             }
-
+            //当前登录用户
             DynamicObject currUser = UserServiceHelper.getUserInfoByID(currUserId, HonorStudentConstant.ID_KEY);
 
             // 获取实体元数据
@@ -88,10 +94,9 @@ public class CreateEvalQuestService {
             //单据页面操作
             //option.setVariableValue(OperateOptionConst.ISFORMVIEWOPERATION, Boolean.TRUE.toString());
 
-            DynamicObject evalQuestTpl = QueryServiceHelper.queryOne(HonorStudentConstant.NCKD_EVALQUESTTPL, "id",new QFilter[]{QFilterCommonHelper.getIdEqFilter(evalQuestTplId)});
-            if (evalQuestTpl == null) {
-                throw new KDBizException("评价问卷模板未找到");
-            }
+            //查询模板
+            evalQuestTpl = BusinessDataServiceHelper.loadSingle(evalQuestTpl.getLong(HonorStudentConstant.ID_KEY),HonorStudentConstant.NCKD_EVALQUESTTPL_ENTITYID);
+
 
             StringJoiner ruleColum = new StringJoiner(",");
             ruleColum.add(FormConstant.ID_KEY);
@@ -101,9 +106,11 @@ public class CreateEvalQuestService {
             ruleColum.add(HonorStudentConstant.NCKD_UPPER);
             //同级评分人下限人数
             ruleColum.add(HonorStudentConstant.NCKD_LOWER);
-            selectedEvalRule = QueryServiceHelper.queryOne(HonorStudentConstant.EVALUATIONRULE_ENTITYID, ruleColum.toString(), new QFilter[]{QFilterCommonHelper.getIdEqFilter(selectedEvalRule.getLong(HonorStudentConstant.ID_KEY))});
+            //查询评价规则
+            long selectedEvalRuleId = selectedEvalRule.getLong(HonorStudentConstant.ID_KEY);
+            selectedEvalRule = BusinessDataServiceHelper.loadSingle(selectedEvalRuleId,HonorStudentConstant.EVALUATIONRULE_ENTITYID);
             if (selectedEvalRule == null) {
-                throw new KDBizException("评价规则未找到");
+                throw new ValidationException("评价规则未找到");
             }
             
             int proportion = selectedEvalRule.getInt(HonorStudentConstant.NCKD_PROPORTION);
@@ -112,10 +119,10 @@ public class CreateEvalQuestService {
             
             // 参数验证
             if (proportion < 0 || proportion > 100) {
-                throw new KDBizException("其他同级评分人比例必须在0-100之间");
+                throw new ValidationException("其他同级评分人比例必须在0-100之间");
             }
             if (lower < 0 || upper < lower) {
-                throw new KDBizException("同级评分人上限人数必须大于等于下限人数且都大于等于0");
+                throw new ValidationException("同级评分人上限人数必须大于等于下限人数且都大于等于0");
             }
             
             //根据比例计算出的其他部门同级评分人的最小人数(同级评分人下限人数*其他同级评分人比例/100=其他同级评分人下限人数)
@@ -130,7 +137,7 @@ public class CreateEvalQuestService {
                     //获取页面选择的多选基础数据可能会被存放在fbasedataid中
                     DynamicObject depEmpRow = (DynamicObject)row.getDynamicObject(FormConstant.BASEDATAID_KEY);
                     if (depEmpRow == null) {
-                        logger.warn("跳过无效的人员数据,索引:{}", i);
+                        logger.warn("【优秀生考评】-生成综合评测问卷-跳过无效的人员数据,索引:{}", i);
                         continue;
                     }
                     personId = ConvertUtil.toLong(depEmpRow.getPkValue());
@@ -141,20 +148,20 @@ public class CreateEvalQuestService {
                 }
 
                 if (personId == null) {
-                    logger.warn("跳过人员ID为空的数据,索引:{}", i);
+                    logger.warn("【优秀生考评】-生成综合评测问卷-跳过人员ID为空的数据,索引:{}", i);
                     continue;
                 }
 
-                MainEntityType depempEntityType = EntityMetadataCache.getDataEntityType(PersonHelper.DEP_EMP_ENTITY_ID);
-                DynamicObject person = new DynamicObject(depempEntityType);
+                MainEntityType depEmpEntityType = EntityMetadataCache.getDataEntityType(PersonHelper.DEP_EMP_ENTITY_ID);
+                DynamicObject person = new DynamicObject(depEmpEntityType);
                 person.set(FormConstant.ID_KEY,personId);
 
                 //表头构建
-                DynamicObject mainObj = prepareMainObject(person, org, currUser, selectedEvalRule, evalQuestTplId);
+                DynamicObject mainObj = prepareMainObject(person, org, currUser, selectedEvalRule, evalQuestTpl);
                 //分录构建
                 DynamicObjectCollection entryEntity = fetchExpectedScorers(row, proportion, upper, lower, otherLower, Boolean.TRUE);
                 if (entryEntity == null || entryEntity.isEmpty()) {
-                    logger.warn("未能获取到有效的评分人列表,人员ID:{}", personId);
+                    logger.warn("【优秀生考评】-生成综合评测问卷-未能获取到有效的评分人列表,人员ID:{}", personId);
                     continue;
                 }
                 mainObj.set(HonorStudentConstant.NCKD_EVALQUESTENTRY,entryEntity);
@@ -165,7 +172,7 @@ public class CreateEvalQuestService {
                     callback.onProgress(i);
                 }
             }
-
+            logger.info("【优秀生考评】-生成综合评测问卷-完成");
         }catch (KDBizException e){
             logger.error("【优秀生考评】-生成综合评测问卷-业务异常",e);
             throw e;
@@ -173,11 +180,20 @@ public class CreateEvalQuestService {
             logger.error("【优秀生考评】-生成综合评测问卷-系统异常",e);
             throw e;
         }
-        logger.info("【优秀生考评】-生成综合评测问卷-结束");
+
     }
 
+    /**
+     * 保存问卷
+     * @param mainObj 主单
+     * @param option 操作选项
+     * @param personName 评价对象名称
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/07/15 16:06
+     */
     private static void saveQuest(DynamicObject mainObj, OperateOption option, String personName) {
-        OperationResult operationResult = SaveServiceHelper.saveOperate(FormConstant.SAVE_KEY,HonorStudentConstant.NCKD_EVALQUEST, new DynamicObject[]{mainObj}, option);
+        OperationResult operationResult = SaveServiceHelper.saveOperate(FormConstant.SAVE_KEY,HonorStudentConstant.NCKD_EVALQUEST_ENTITYID, new DynamicObject[]{mainObj}, option);
         if (!operationResult.isSuccess()) {
             StringJoiner errorMsg = new StringJoiner(";");
             for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
@@ -194,23 +210,17 @@ public class CreateEvalQuestService {
      * @param org
      * @param currUser
      * @param selectedEvalRule
-     * @param evalQuestTplId
+     * @param evalQuestTpl
      * @return: kd.bos.dataentity.entity.DynamicObject
      * @author W.Y.C
      * @date: 2025/07/14 09:44
      */
-    private static DynamicObject prepareMainObject(DynamicObject person, DynamicObject org, DynamicObject currUser, DynamicObject selectedEvalRule, Long evalQuestTplId) {
-        DynamicObject mainObj = BusinessDataServiceHelper.newDynamicObject(HonorStudentConstant.NCKD_EVALQUEST);
+    private static DynamicObject prepareMainObject(DynamicObject person, DynamicObject org, DynamicObject currUser, DynamicObject selectedEvalRule, DynamicObject evalQuestTpl) {
+        DynamicObject mainObj = EntityHelper.newAvailableBasicEntity(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID,org,currUser);
         mainObj.set(HonorStudentConstant.NCKD_EVALPERSON, person);
-        mainObj.set(HonorStudentConstant.NCKD_PERIODSTATE, 0);
-        mainObj.set(HonorStudentConstant.NCKD_EVALUATIONRULE, selectedEvalRule.getLong(HonorStudentConstant.ID_KEY));
-        mainObj.set(HonorStudentConstant.NCKD_EVALQUESTTPL, evalQuestTplId);
-        mainObj.set(HonorStudentConstant.CREATEORG_KEY, org);
-        mainObj.set(HonorStudentConstant.USEORG_KEY, org);
-        mainObj.set(HonorStudentConstant.CREATE_TIME_KEY, new Date());
-        mainObj.set(HonorStudentConstant.CREATOR_KEY, currUser);
-        mainObj.set(HonorStudentConstant.STATUS, StatusEnum.C.toString());
-        mainObj.set(HonorStudentConstant.ENABLE, EnableEnum.YES.getCode());
+        mainObj.set(HonorStudentConstant.NCKD_PERIODSTATE, "0");
+        mainObj.set(HonorStudentConstant.NCKD_EVALUATIONRULE, selectedEvalRule);
+        mainObj.set(HonorStudentConstant.NCKD_EVALQUESTTPL, evalQuestTpl);
         return mainObj;
     }
 
@@ -227,12 +237,29 @@ public class CreateEvalQuestService {
      * @date: 2025/07/10 17:38
      */
     public static DynamicObjectCollection fetchExpectedScorers(DynamicObject person,int proportion,int upper,int lower,int otherLower,boolean isLeadAndSuperior) {
+        return fetchExpectedScorers(person, null,null, proportion, upper, lower, otherLower, isLeadAndSuperior);
+    }
+    /**
+     * 获取预计参与问卷打分的用户列表
+     * @param person 评分人员
+     * @param adminColl 需要圈定的组织范围
+     * @param excludePersonList 需要排除的人员
+     * @param proportion 其他同级评分人比例
+     * @param upper 同级评分人上限人数
+     * @param lower 同级评分人下限人数
+     * @param otherLower 根据比例计算出的其他部门同级评分人的最小人数(同级评分人下限人数*其他同级评分人比例/100=其他同级评分人下限人数)
+     * @param isLeadAndSuperior 是否获取上级和领导
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/07/10 17:38
+     */
+    public static DynamicObjectCollection fetchExpectedScorers(DynamicObject person,DynamicObjectCollection adminColl,List<Long> excludePersonList,int proportion,int upper,int lower,int otherLower,boolean isLeadAndSuperior) {
         Long personId = null;
         if(person.containsProperty(FormConstant.BASEDATAID_KEY)){
             //获取页面选择的数据可能会被存放在fbasedataid中
             DynamicObject depEmpRow = (DynamicObject)person.getDynamicObject(FormConstant.BASEDATAID_KEY);
             if (depEmpRow == null) {
-                logger.warn("获取人员信息失败,BASEDATAID_KEY为空");
+                logger.warn("【优秀生考评】-获取人员信息失败,BASEDATAID_KEY为空");
                 return new DynamicObjectCollection();
             }
             personId = ConvertUtil.toLong(depEmpRow.getPkValue());
@@ -241,13 +268,13 @@ public class CreateEvalQuestService {
         }
         
         if (personId == null) {
-            logger.warn("人员ID为空");
+            logger.warn("【优秀生考评】-人员ID为空");
             return new DynamicObjectCollection();
         }
 
         Map<String, Object> depEmp = HRPIDepempServiceHelper.getDepemp(personId);
         if (depEmp == null) {
-            logger.warn("获取人员信息失败,人员ID:{}", personId);
+            logger.warn("【优秀生考评】-获取人员信息失败,人员ID:{}", personId);
             return new DynamicObjectCollection();
         }
         
@@ -264,14 +291,24 @@ public class CreateEvalQuestService {
             DynamicObject parentParentPosition = QueryServiceHelper.queryOne("hbpm_positionhr", "parent.parent.id as parentId", new QFilter[]{QFilterCommonHelper.getIdEqFilter(positionId)});
             if (parentParentPosition != null && parentParentPosition.getLong("parentId") != 0) {
                 QFilter positionFilter = new QFilter("position.id", QCP.equals, parentParentPosition.getLong("parentId"));
-                leadColl = PersonHelper.getDepEmpEffectivePerson("id,person.name", positionFilter);
+                DynamicObjectCollection leadTempColl = PersonHelper.getDepEmpEffectivePerson("id,person.name", positionFilter);
+                Collections.shuffle(leadTempColl);
+                if(!leadTempColl.isEmpty()){
+                    DynamicObject lead = leadTempColl.get(0);
+                    leadColl.add(lead);
+                }
             }
 
             //2:获取上级(获取上级岗位中的人员作为上级)
             DynamicObject parentPosition = QueryServiceHelper.queryOne("hbpm_positionhr", "parent.id as parentId", new QFilter[]{QFilterCommonHelper.getIdEqFilter(positionId)});
             if (parentPosition != null && parentPosition.getLong("parentId") != 0) {
                 QFilter positionFilter = new QFilter("position.id", QCP.equals, parentPosition.getLong("parentId"));
-                superiorColl = PersonHelper.getDepEmpEffectivePerson("id,person.name", positionFilter);
+                DynamicObjectCollection superiorTempColl = PersonHelper.getDepEmpEffectivePerson("id,person.name", positionFilter);
+                Collections.shuffle(superiorTempColl);
+                if(!superiorTempColl.isEmpty()){
+                    DynamicObject superior = superiorTempColl.get(0);
+                    superiorColl.add(superior);
+                }
             }
         }
 
@@ -292,12 +329,25 @@ public class CreateEvalQuestService {
         */
         //3:查询当前组织内的同级员工
         Set<Long> excludePersons = new HashSet<>();
+        if(excludePersonList != null && !excludePersonList.isEmpty()){
+            excludePersons.addAll(excludePersonList);
+        }
         excludePersons.add(id);
         if(isLeadAndSuperior) {
             leadColl.forEach(dynamicObject -> excludePersons.add(dynamicObject.getLong(HonorStudentConstant.ID_KEY)));
             superiorColl.forEach(dynamicObject -> excludePersons.add(dynamicObject.getLong(HonorStudentConstant.ID_KEY)));
         }
-        DynamicObjectCollection peers = getPeers(adminOrgId,excludePersons, proportion,upper, lower, otherLower);
+        //如果有选择组织范围则查询组织范围内的人员,否则使用评价对象的组织
+        List<Long> adminOrgIds = new ArrayList<>();
+        if(adminColl != null && !adminColl.isEmpty()){
+            adminColl.forEach(map ->{
+                DynamicObject baseData = map.getDynamicObject(HonorStudentConstant.BASEDATAID_KEY);
+                adminOrgIds.add(baseData.getLong(HonorStudentConstant.ID_KEY));
+            } );
+        }else{
+            adminOrgIds.add(adminOrgId);
+        }
+        DynamicObjectCollection peers = getPeers(adminOrgIds,excludePersons, proportion,upper, lower, otherLower);
         peers.forEach(dynamicObject -> excludePersons.add(dynamicObject.getLong(HonorStudentConstant.ID_KEY)));
 
         //4:同级其他部门在职人员
@@ -308,22 +358,20 @@ public class CreateEvalQuestService {
 
 
         // 主单据创建
-        DynamicObject mainObj = BusinessDataServiceHelper.newDynamicObject(HonorStudentConstant.NCKD_EVALQUEST);
+        DynamicObject mainObj = BusinessDataServiceHelper.newDynamicObject(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID);
         //分录创建
         DynamicObjectCollection entryEntity = mainObj.getDynamicObjectCollection(HonorStudentConstant.NCKD_EVALQUESTENTRY);
         ////1:领导、2:上级、3:同级
         if(isLeadAndSuperior) {
-            builderEvalQuestEntry(leadColl, "1", entryEntity);
-            builderEvalQuestEntry(superiorColl, "2", entryEntity);
+            builderEvalQuestEntry(leadColl, PerfPlanRoleEnum.LEAD, entryEntity);
+            builderEvalQuestEntry(superiorColl, PerfPlanRoleEnum.SUPERIOR, entryEntity);
         }
-        builderEvalQuestEntry(peers, "3", entryEntity);
-        builderEvalQuestEntry(otherPeers, "3", entryEntity);
+        builderEvalQuestEntry(peers, PerfPlanRoleEnum.PEERS, entryEntity);
+        builderEvalQuestEntry(otherPeers, PerfPlanRoleEnum.OTHER_PEERS, entryEntity);
 
 
         return entryEntity;
     }
-    
-    private static final int MAX_RECURSION_DEPTH = 10;
 
     /**
      * 获取同级人员
@@ -331,13 +379,13 @@ public class CreateEvalQuestService {
      *  2.工作性质大类过滤掉编码为H01(居休)、H02(退养)、H03(随任)、H04(女工长假)、H05(长期工伤病休)、H06(长期病休)、H07(其他不在岗)、J(外派)的员工,不做为同级
      *  3.除去领导和上级
      *  4.入职超半年、职位非协理员
-     * @param adminOrgId 当前组织ID
+     * @param adminOrgIds 当前组织ID或自定义选择的组织
      * @param excludePersons 排除的ID
      * @return: kd.bos.dataentity.entity.DynamicObjectCollection
      * @author W.Y.C
      * @date: 2025/07/08 17:48
      */
-    private static DynamicObjectCollection getPeers(Long adminOrgId,Set<Long> excludePersons,int proportion,int upper,int lower,int otherLower){
+    private static DynamicObjectCollection getPeers(List<Long> adminOrgIds,Set<Long> excludePersons,int proportion,int upper,int lower,int otherLower){
         //最终的结果
         DynamicObjectCollection finalResult = new DynamicObjectCollection();
 
@@ -346,14 +394,18 @@ public class CreateEvalQuestService {
         //------ 基本条件 end------
 
         //1.查询当前组织内的同级员工
-        QFilter adminOrgFilter = new QFilter("adminorg.id", QCP.equals, adminOrgId);
+        QFilter adminOrgFilter = new QFilter("adminorg.id", QCP.in, adminOrgIds);
         DynamicObjectCollection depEmpEffectivePerson = PersonHelper.getDepEmpEffectivePerson("id,person.name", baseFilter, adminOrgFilter);
-
+        depEmpEffectivePerson.forEach(dynamicObject -> excludePersons.add(dynamicObject.getLong("id")));
         //2.当前组织人数小于下限人数,继续向上级组织查找直到 >= lower
-        if(depEmpEffectivePerson.size() < lower){
-            Integer count = recursionGetPeers(adminOrgId, depEmpEffectivePerson, baseFilter, lower, 1);
-            logger.info("【优秀生考评】-向上级组织查找次数:{}",count);
+        for (Long adminOrgId : adminOrgIds) {
+            if(depEmpEffectivePerson.size() < lower){
+                Integer count = recursionGetPeers(adminOrgId, depEmpEffectivePerson, baseFilter, lower, 1);
+                depEmpEffectivePerson.forEach(dynamicObject -> excludePersons.add(dynamicObject.getLong("id")));
+                logger.info("【优秀生考评】-向上级组织查找次数:{}",count);
+            }
         }
+
         //打乱顺序随机抽取前 upper 个
         Collections.shuffle(depEmpEffectivePerson);
         int endIndex = Math.min(depEmpEffectivePerson.size(), upper);
@@ -381,8 +433,12 @@ public class CreateEvalQuestService {
         //------ 基本条件 end------
         Long parentOrg = AdminOrgHelper.getParentOrg(adminOrgId);
         QFilter adminOrgFilter = new QFilter("adminorg.parent.id", QCP.equals, parentOrg);
+        //排除自己部门下的人员
         adminOrgFilter.and(new QFilter("adminorg.id", QCP.not_equals, adminOrgId));
         DynamicObjectCollection depEmpEffectivePerson = PersonHelper.getDepEmpEffectivePerson("id,person.name,adminorg.name", baseFilter, adminOrgFilter);
+        depEmpEffectivePerson.forEach(dynamicObject -> excludePersons.add(dynamicObject.getLong("id")));
+
+        //2.当前组织人数小于下限人数,继续向上级组织查找直到 >= lower
         if(depEmpEffectivePerson.size() < otherLower){
             Integer count = recursionGetParentPeers(parentOrg, depEmpEffectivePerson, baseFilter, otherLower, 1);
             logger.info("【优秀生考评】-向上级组织查找次数:{}",count);
@@ -407,24 +463,25 @@ public class CreateEvalQuestService {
      */
     private static Integer recursionGetPeers(Long adminOrgId,DynamicObjectCollection persons,QFilter baseFilter,int lower,Integer count){
         if(count > MAX_RECURSION_DEPTH) {
-            logger.warn("达到最大递归深度{}, 组织ID: {}", MAX_RECURSION_DEPTH, adminOrgId);
+            logger.warn("【优秀生考评】-达到最大递归深度{}。结束递归, 组织ID: {}", MAX_RECURSION_DEPTH, adminOrgId);
             return count;
         }
         
         Long parentOrg = AdminOrgHelper.getParentOrg(adminOrgId);
         if(parentOrg == null){
+            logger.warn("【优秀生考评】-达到最大递归深度或组织为空");
             return count;
         }
         // 创建一个查询条件,用于筛选属于上级组织的人员
         QFilter adminOrgFilter = new QFilter("adminorg.id", QCP.equals, parentOrg);
         DynamicObjectCollection depEmpEffectivePerson = PersonHelper.getDepEmpEffectivePerson("id,person.name,adminorg.name", baseFilter, adminOrgFilter);
         persons.addAll(depEmpEffectivePerson);
-        if(persons.size() >= lower || count > MAX_RECURSION_DEPTH){
+        if(persons.size() >= lower){
             return count;
         }else{
             count++;
             if(count == MAX_RECURSION_DEPTH) {
-                logger.warn("即将达到最大递归深度, 组织ID: {}", adminOrgId);
+                logger.warn("【优秀生考评】-即将达到最大递归深度, 组织ID: {}", adminOrgId);
             }
             return recursionGetPeers(parentOrg,persons,baseFilter,lower,count);
         }
@@ -447,24 +504,25 @@ public class CreateEvalQuestService {
      */
     private static Integer recursionGetParentPeers(Long adminOrgId,DynamicObjectCollection persons,QFilter baseFilter,int lower,Integer count){
         if(count > MAX_RECURSION_DEPTH) {
-            logger.warn("达到最大递归深度{}, 组织ID: {}", MAX_RECURSION_DEPTH, adminOrgId);
+            logger.warn("【优秀生考评】-达到最大递归深度{}。结束递归, 组织ID: {}", MAX_RECURSION_DEPTH, adminOrgId);
             return count;
         }
         
         Long parentOrg = AdminOrgHelper.getParentOrg(adminOrgId);
         if(parentOrg == null){
+            logger.warn("【优秀生考评】-达到最大递归深度或组织为空");
             return count;
         }
         // 构建用于筛选上级管理组织下有效人员的过滤条件
         QFilter adminOrgFilter = new QFilter("adminorg.parent.id", QCP.equals, parentOrg);
         DynamicObjectCollection depEmpEffectivePerson = PersonHelper.getDepEmpEffectivePerson("id,person.name,adminorg.name", baseFilter, adminOrgFilter);
         persons.addAll(depEmpEffectivePerson);
-        if(persons.size() >= lower || count > MAX_RECURSION_DEPTH){
+        if(persons.size() >= lower){
             return count;
         }else{
             count++;
             if(count == MAX_RECURSION_DEPTH) {
-                logger.warn("即将达到最大递归深度, 组织ID: {}", adminOrgId);
+                logger.warn("【优秀生考评】-即将达到最大递归深度, 组织ID: {}", adminOrgId);
             }
             return recursionGetParentPeers(parentOrg,persons,baseFilter,lower,count);
         }
@@ -479,23 +537,59 @@ public class CreateEvalQuestService {
      * @author W.Y.C
      * @date: 2025/07/13 18:52
      */
-    private static void builderEvalQuestEntry(DynamicObjectCollection persons,String perfPlanRole,DynamicObjectCollection entryEntity){
+    private static void builderEvalQuestEntry(DynamicObjectCollection persons,PerfPlanRoleEnum perfPlanRole,DynamicObjectCollection entryEntity){
+        List<Long> personIds = new ArrayList<>(persons.size());
+        persons.forEach(person -> personIds.add(person.getLong(HonorStudentConstant.ID_KEY)));
+        //获取任职经历
+        List<Map<String, Object>> empOrgRelList = HRPIDepempServiceHelper.listEmpOrgrels(personIds);
+        //根据ID分组,获取所属公司和职位
+        Map<Long, Map<String, DynamicObject>> empOrgRelMap = empOrgRelList.stream()
+                .filter(item -> item.get(FormConstant.DEP_EMP) != null)
+                .collect(Collectors.toMap(
+                        item -> ConvertUtil.toLong(item.get(FormConstant.DEP_EMP)),
+                        item -> {
+                            Map<String, DynamicObject> innerMap = new HashMap<>(2);
+                            Long companyId = ConvertUtil.toLong(item.get("company"));
+                            if(companyId != null && companyId > 0){
+                                DynamicObject company = BusinessDataServiceHelper.loadSingle(companyId, "haos_adminorghr");
+                                innerMap.put("company", company);
+                            }
+                            Long jobId = ConvertUtil.toLong(item.get("job"));
+                            if(jobId != null && jobId > 0){
+                                DynamicObject job = BusinessDataServiceHelper.loadSingle(jobId, "hbjm_jobhr");
+                                innerMap.put("job", job);
+                            }
+                            return innerMap;
+                        },
+                        (existing, replacement) -> replacement
+                ));
+        //获取人员对象
+        DynamicObject[] dbPersons = BusinessDataServiceHelper.load(PersonHelper.DEP_EMP_ENTITY_ID,
+                "id,person.id,person.name,person.number,adminorg.number,adminorg.name,position.name,position.number",
+                new QFilter[]{new QFilter(FormConstant.ID_KEY, QCP.in, personIds)});
+        Map<Long, DynamicObject> personMap = new HashMap<>(dbPersons.length);
+        for (DynamicObject obj : dbPersons) {
+            personMap.put(obj.getLong(FormConstant.ID_KEY), obj);
+        }
+
         persons.forEach(dynamicObject -> {
             DynamicObject evalQuest = entryEntity.addNew();
             long depEmpId = dynamicObject.getLong(HonorStudentConstant.ID_KEY);
-            evalQuest.set(HonorStudentConstant.NCKD_PERSON, depEmpId);
-            evalQuest.set(HonorStudentConstant.NCKD_PERFPLANROLE, perfPlanRole);
+            DynamicObject person = personMap.get(depEmpId);
+            evalQuest.set(HonorStudentConstant.NCKD_PERSON, person);
+            evalQuest.set(HonorStudentConstant.NCKD_PERFPLANROLE, perfPlanRole.getCode());
             //获取任职经历
-            Map<String, Object> empOrgRel = HRPIDepempServiceHelper.getDataEmpOrgrel(depEmpId);
-            Long companyId = ConvertUtil.toLong(empOrgRel.get("company_id"));
-            Long jobId = ConvertUtil.toLong(empOrgRel.get("job_id"));
-            evalQuest.set(HonorStudentConstant.NCKD_COMPANY, companyId);
-            evalQuest.set(HonorStudentConstant.NCKD_JOB, jobId);
+            Map<String, DynamicObject> empOrgRel = empOrgRelMap.get(depEmpId);
+            evalQuest.set(HonorStudentConstant.NCKD_COMPANY, empOrgRel.get("company"));
+            evalQuest.set(HonorStudentConstant.NCKD_JOB, empOrgRel.get("job"));
+            //备注生成人员对应的角色
+            evalQuest.set(HonorStudentConstant.NCKD_REMARK, StrFormatter.format("系统生成:{}",perfPlanRole.getName()));
+
         });
     }
 
     /**
-     * 查询人员基本条件
+     * 查询人员打分人员基本条件
      * @param excludePersons
      * @return: kd.bos.orm.query.QFilter
      * @author W.Y.C
@@ -507,6 +601,7 @@ public class CreateEvalQuestService {
         baseFilter.and(new QFilter("startdate",QCP.less_equals, DateUtil.minusMonths(DateUtil.now(),6)));
         //职位非协理员
         baseFilter.and(new QFilter("position.name", QCP.not_like, "%协理员%"));
+        // TODO 1.最新一条党政职务履历为副处级及以上人员不作为同级取数 2.工作性质大类过滤掉编码为H01(居休)、H02(退养)、H03(随任)、H04(女工长假)、H05(长期工伤病休)、H06(长期病休)、H07(其他不在岗)、J(外派)的员工,不做为同级
         return baseFilter;
     }
 }

+ 56 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/algo/RankMapFunction.java

@@ -0,0 +1,56 @@
+package nckd.jxccl.hr.hstu.business.algo;
+
+import kd.bos.algo.DataType;
+import kd.bos.algo.Field;
+import kd.bos.algo.MapFunction;
+import kd.bos.algo.Row;
+import kd.bos.algo.RowMeta;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+* 【优秀生】-综合评测排名计算(按评价活动维度排名)
+* @author W.Y.C
+* @date 2025/8/11 12:06
+* @version 1.0
+*/
+public class RankMapFunction extends MapFunction {
+    private final RowMeta rowMeta;
+
+    /**记录每个评价活动的排名*/
+    private Map<Long, AtomicInteger> rankMap = new HashMap<>();
+
+
+    public RankMapFunction(RowMeta sourceMeta) {
+        // 新增排名字段
+        Field[] fields = sourceMeta.getFields();
+        Field[] newFields = Arrays.copyOf(fields, fields.length + 1);
+        newFields[newFields.length - 1] = new Field("rank", DataType.IntegerType);
+        this.rowMeta = new RowMeta(newFields);
+    }
+    @Override
+    public Object[] map(Row row) {
+        Long evaluationRuleId = row.getLong(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+ FormConstant.ID_KEY);
+        //根据不同的评价活动维度排名
+        AtomicInteger rank = rankMap.computeIfAbsent(evaluationRuleId, k -> new AtomicInteger(1));
+
+        // 先返回当前值,然后递增
+        int currentRank = rank.getAndIncrement();
+
+        Object[] newRow = new Object[rowMeta.getFieldCount()];
+        for (int i = 0; i < rowMeta.getFieldCount() - 1; i++) {
+            newRow[i] = row.get(i);
+        }
+        newRow[newRow.length - 1] = currentRank;
+        return newRow;
+    }
+
+    @Override
+    public RowMeta getResultRowMeta() {
+        return rowMeta;
+    }
+}

+ 59 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/algo/UnitRankMapFunction.java

@@ -0,0 +1,59 @@
+package nckd.jxccl.hr.hstu.business.algo;
+
+import kd.bos.algo.DataType;
+import kd.bos.algo.Field;
+import kd.bos.algo.MapFunction;
+import kd.bos.algo.Row;
+import kd.bos.algo.RowMeta;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+* 【优秀生】-综合评测排名计算(按评价活动和单位维度排名)
+* @author W.Y.C
+* @date 2025/8/11 12:06
+* @version 1.0
+*/
+public class UnitRankMapFunction extends MapFunction {
+
+    private final RowMeta rowMeta;
+
+    /**记录每个评价活动和单位的排名。key:评价活动ID-使用单位ID*/
+    private Map<String, AtomicInteger> rankMap = new HashMap<>();
+
+
+    public UnitRankMapFunction(RowMeta sourceMeta) {
+        // 新增排名字段
+        Field[] fields = sourceMeta.getFields();
+        Field[] newFields = Arrays.copyOf(fields, fields.length + 1);
+        newFields[newFields.length - 1] = new Field("rank", DataType.IntegerType);
+        this.rowMeta = new RowMeta(newFields);
+    }
+    @Override
+    public Object[] map(Row row) {
+        Long evaluationRuleId = row.getLong(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+ FormConstant.ID_KEY);
+        Long useOrgId = row.getLong(HonorStudentConstant.USEORG_KEY+"."+FormConstant.ID_KEY);
+        //根据不同的评价活动+单位维度排名
+        AtomicInteger rank = rankMap.computeIfAbsent(evaluationRuleId+"-"+useOrgId, k -> new AtomicInteger(1));
+
+        // 先返回当前值,然后递增
+        int currentRank = rank.getAndIncrement();
+
+        Object[] newRow = new Object[rowMeta.getFieldCount()];
+        for (int i = 0; i < rowMeta.getFieldCount() - 1; i++) {
+            newRow[i] = row.get(i);
+        }
+        newRow[newRow.length - 1] = currentRank;
+        return newRow;
+    }
+
+    @Override
+    public RowMeta getResultRowMeta() {
+        return rowMeta;
+    }
+}

+ 0 - 11
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/helper/EvalQuestHelper.java

@@ -1,11 +0,0 @@
-package nckd.jxccl.hr.hstu.business.helper;
-
-/**
- * 【优秀生】- 评价问卷帮助类
- * @author W.Y.C
- * @date 2025/7/3 14:20
- * @version 1.0
- */
-public class EvalQuestHelper {
-
-}

+ 795 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/helper/HonorStudentHelper.java

@@ -0,0 +1,795 @@
+package nckd.jxccl.hr.hstu.business.helper;
+
+
+import com.alibaba.fastjson.JSON;
+import com.google.common.collect.Lists;
+import kd.bos.algo.DataSet;
+import kd.bos.algo.Row;
+import kd.bos.common.enums.EnableEnum;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.constant.StatusEnum;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+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.enums.PerfPlanRoleEnum;
+import nckd.jxccl.base.common.exception.ValidationException;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.base.common.utils.DateUtil;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.hr.hstu.business.algo.RankMapFunction;
+import nckd.jxccl.hr.hstu.business.algo.UnitRankMapFunction;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+import nckd.jxccl.hr.hstu.common.bo.EvalQuestResultBO;
+import nckd.jxccl.hr.hstu.plugin.form.EvalQuestListPlugin;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+* 优秀生帮助类
+* @author W.Y.C
+* @date 2025/7/23 16:18
+* @version 1.0
+*/
+public class HonorStudentHelper {
+
+    private static final Log logger = LogFactory.getLog(HonorStudentHelper.class);
+
+    /**
+     * 获取地区差异分(从当前组织向上找最近的一个组织)
+     * @param orgId 组织ID
+     * @return: java.lang.Integer
+     * @author W.Y.C
+     * @date: 2025/07/23 15:50
+     */
+    public static Integer getOrgDifference(Long orgId) {
+        //获取组织上下级结构长编码
+        DynamicObject adminOrgHr = BusinessDataServiceHelper.loadSingle(FormConstant.ADMINORGHR_ENTITYID, FormConstant.STRUCTLONGNUMBER, new QFilter[]{QFilterCommonHelper.getIdEqFilter(orgId)});
+        String structLongNumber = adminOrgHr.getString(FormConstant.STRUCTLONGNUMBER);
+        String[] structLongNumbers = structLongNumber.split("!");
+
+        QFilter[] filters = new QFilter[]{
+                new QFilter(HonorStudentConstant.NCKD_ORG+"."+FormConstant.STRUCTLONGNUMBER, QCP.in, Arrays.asList(structLongNumbers)),
+                new QFilter(HonorStudentConstant.NCKD_ORG+"."+FormConstant.IS_CURRENT_VERSION, QCP.equals, EnableEnum.YES.getCode()),
+                new QFilter(HonorStudentConstant.NCKD_ORG+"."+FormConstant.DATA_STATUS, QCP.equals, EnableEnum.YES.getCode()),
+                new QFilter(HonorStudentConstant.NCKD_ORG+"."+FormConstant.ENABLE, QCP.equals, EnableEnum.YES.getCode()),
+                new QFilter(HonorStudentConstant.NCKD_ORG+"."+FormConstant.STATUS, QCP.equals, StatusEnum.C.toString())
+        };
+        DynamicObject[] load = BusinessDataServiceHelper.load(HonorStudentConstant.ORGDIFFERENCE_ENTITYID, HonorStudentConstant.NCKD_DIFFERENCESCORE, filters,"nckd_org.level desc");
+        return load.length > 0 ? load[0].getInt(HonorStudentConstant.NCKD_DIFFERENCESCORE) : null;
+    }
+    /**
+     * 统计问卷已评分人数
+     * @param evalQuestId 问卷ID
+     * @return: java.lang.Integer
+     * @author W.Y.C
+     * @date: 2025/07/23 16:53
+     */
+    public static Integer getQuestScorePersonCount(Long evalQuestId) {
+        QFilter[] filters = new QFilter[]{
+                new QFilter(HonorStudentConstant.NCKD_PERFPLANSTATE, QCP.in, Lists.newArrayList("2")),
+                new QFilter(HonorStudentConstant.NCKD_EVALQUEST, QCP.equals, evalQuestId),
+        };
+        DynamicObject dynamicObject = QueryServiceHelper.queryOne(HonorStudentConstant.NCKD_EVALRESULT_ENTITYID, "count(id) as count", filters);
+        return dynamicObject.getInt("count");
+    }
+
+    /**
+     * 问卷未评分人数
+     * @param evalQuestId 问卷ID
+     * @return: java.lang.Integer
+     * @author W.Y.C
+     * @date: 2025/07/23 16:53
+     */
+    public static Integer getQuestNotScorePersonCount(Long evalQuestId) {
+        QFilter[] filters = new QFilter[]{
+                new QFilter(HonorStudentConstant.NCKD_PERFPLANSTATE, QCP.in, Lists.newArrayList("0", "1")),
+                new QFilter(HonorStudentConstant.NCKD_EVALQUEST, QCP.equals, evalQuestId),
+        };
+        DynamicObject dynamicObject = QueryServiceHelper.queryOne(HonorStudentConstant.NCKD_EVALRESULT_ENTITYID, "count(id) as count", filters);
+        return dynamicObject.getInt("count");
+    }
+
+    /**
+     * 根据问卷查询未评分人员
+     * @param evalQuestIds 问卷ID(支持多个)
+     * @return: kd.bos.dataentity.entity.DynamicObject[]
+     * @author W.Y.C
+     * @date: 2025/07/23 20:53
+     */
+    public static DynamicObject[] getQuestNotScorePerson(Long... evalQuestIds) {
+        QFilter[] filters = new QFilter[]{
+                new QFilter(HonorStudentConstant.NCKD_PERFPLANSTATE, QCP.in, Lists.newArrayList("0", "1")),
+                new QFilter(HonorStudentConstant.NCKD_EVALQUEST, QCP.in, Arrays.asList(evalQuestIds)),
+        };
+        StringJoiner fields = new StringJoiner(",");
+        fields.add(FormConstant.ID_KEY);
+        //评价对象
+        fields.add(HonorStudentConstant.NCKD_PERSON+"."+FormConstant.PERSON+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_PERSON+"."+FormConstant.PERSON+"."+FormConstant.NUMBER_KEY);
+        fields.add(HonorStudentConstant.NCKD_PERSON+"."+FormConstant.PERSON+"."+FormConstant.NAME_KEY);
+        //评分人
+        fields.add(HonorStudentConstant.NCKD_SCORER+"."+FormConstant.PERSON+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_SCORER+"."+FormConstant.PERSON+"."+FormConstant.NUMBER_KEY);
+        fields.add(HonorStudentConstant.NCKD_SCORER+"."+FormConstant.PERSON+"."+FormConstant.NAME_KEY);
+        return BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_EVALRESULT_ENTITYID, fields.toString(), filters);
+    }
+
+    /**
+     * 更新问卷测评结果(同级评分人数、上级评分人数、上级评分人数、同级评分总分、上级评分总分、领导评分总分、已评分总分、已评分人数、未评分人数、不了解人数、绩效得分、业绩贡献分、综合测评得分、更新排名、定格等级)
+     * @param evalQuestIds 问卷ID(支持多个)
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/08/07 19:48
+     */
+    public static void updateQuestResult(Long... evalQuestIds) {
+        logger.info("【优秀生考评】-更新问卷测评结果-开始,问卷ID:{}", Arrays.toString(evalQuestIds));
+        QFilter[] filters = new QFilter[]{
+                //new QFilter(HonorStudentConstant.NCKD_PERFPLANSTATE, QCP.equals, "2"),
+                new QFilter(FormConstant.ID_KEY, QCP.in, evalQuestIds),
+        };
+        StringJoiner fields = new StringJoiner(",");
+        fields.add(FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_PERFSCORESPART);
+        fields.add(HonorStudentConstant.NCKD_PEEK);
+        fields.add(HonorStudentConstant.NCKD_SUPERIOR);
+        fields.add(HonorStudentConstant.NCKD_LEAD);
+        fields.add(HonorStudentConstant.NCKD_PEEKSCORESSUM);
+        fields.add(HonorStudentConstant.NCKD_SUPERIORSCORESSUM);
+        fields.add(HonorStudentConstant.NCKD_LEADSCORESSUM);
+        fields.add(HonorStudentConstant.NCKD_SUMENTRYSCORE);
+        fields.add(HonorStudentConstant.NCKD_HAVEDO);
+        fields.add(HonorStudentConstant.NCKD_NODO);
+        fields.add(HonorStudentConstant.NCKD_UNCLEARS);
+        fields.add(HonorStudentConstant.NCKD_SUMSCORE);
+        fields.add(HonorStudentConstant.NCKD_DIFFERENCESCORE);
+        fields.add(HonorStudentConstant.NCKD_ALLYEARSCORESUM);
+        fields.add(HonorStudentConstant.NCKD_TOPRANKSCORE);
+        //获取评价对象组织
+        fields.add(HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.ADMINORG+"."+FormConstant.ID_KEY);
+        //-------------------------- 评价规则数据 begin--------------------------
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+        //所属年度
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_BIZYEAR);
+        //领导评分权重占比
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_LEADPROPORTION);
+        //上级评分权重占比
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_SUPERIORRATIO);
+        //同级评分权重占比
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_PEEKPROPORTION);
+        //综合测评权重占比
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_PERFPROPORTION);
+        //综合测评封顶分
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_PERFMAX);
+        //优秀评优排名基准(%)
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_COMMARKPERCENTAGE);
+        //所在单位评优排名基准(%)
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_HRMARKPERCENTAGE);
+        //-------------------------- 评价规则数据 end--------------------------
+        //查询需要生成结果的问卷数据
+        DynamicObject[] evalQuestArray = BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID, fields.toString(), filters);
+        //记录问卷中的评价活动(key:评价活动ID,Value:评价活动对象)
+        Map<Long,DynamicObject> evaluationRuleMap = new HashMap<>();
+        //=================================== 1.获取考评结果 ===================================
+        //同级评分人数、上级评分人数、上级评分人数、同级评分总分、上级评分总分、领导评分总分、已评分总分、已评分人数、未评分人数、不了解人数
+        Map<Long, EvalQuestResultBO> scoreResults = calculateScore(evalQuestIds);
+        logger.info("【优秀生考评】-更新问卷测评结果-同级评分人数、上级评分人数、上级评分人数、同级评分总分、上级评分总分、领导评分总分、已评分总分、已评分人数、未评分人数、不了解人数:{}", JSON.toJSONString(scoreResults));
+        for (DynamicObject evalQuest : evalQuestArray) {
+            //NOTE: 原SHR逻辑有重新更新地区差异分(本次不更新,原因:生成问卷时已经赋值)
+
+            DynamicObject evaluationRule = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE);
+            long evaluationRuleId = evaluationRule.getLong(FormConstant.ID_KEY);
+            evaluationRuleMap.put(evaluationRuleId, evaluationRule);
+
+            long evalQuestId = evalQuest.getLong(FormConstant.ID_KEY);
+            EvalQuestResultBO evalQuestResult = scoreResults.get(evalQuestId);
+            //=================================== 2.计算综合测评得分 并 更新 问卷综合测评得分 ===================================
+            double score = evalQuestResult.calculateComprehensiveScore(evaluationRule.getInt(HonorStudentConstant.NCKD_LEADPROPORTION),
+                    evaluationRule.getInt(HonorStudentConstant.NCKD_SUPERIORRATIO),
+                    evaluationRule.getInt(HonorStudentConstant.NCKD_PEEKPROPORTION),
+                    evaluationRule.getInt(HonorStudentConstant.NCKD_PERFPROPORTION),
+                    evaluationRule.getInt(HonorStudentConstant.NCKD_PERFMAX));
+            logger.info("【优秀生考评】-更新问卷测评结果-计算综合测评得分:{},问卷ID:{},规则ID:{}", score,evalQuestId,evaluationRuleId);
+            //设置综合测评得分
+            evalQuest.set(HonorStudentConstant.NCKD_PERFSCORESPART, score);
+
+            //同级评分人数
+            evalQuest.set(HonorStudentConstant.NCKD_PEEK, evalQuestResult.getPeerRatingCount());
+            //上级评分人数
+            evalQuest.set(HonorStudentConstant.NCKD_SUPERIOR, evalQuestResult.getSuperiorRatingCount());
+            //同级评分总分
+            evalQuest.set(HonorStudentConstant.NCKD_LEAD, evalQuestResult.getLeaderRatingCount());
+            //同级评分总分
+            evalQuest.set(HonorStudentConstant.NCKD_PEEKSCORESSUM, evalQuestResult.getPeerRatingTotal());
+            //上级评分总分
+            evalQuest.set(HonorStudentConstant.NCKD_SUPERIORSCORESSUM, evalQuestResult.getSuperiorRatingTotal());
+            //领导评分总分
+            evalQuest.set(HonorStudentConstant.NCKD_LEADSCORESSUM, evalQuestResult.getLeaderRatingTotal());
+            //已评分总分
+            evalQuest.set(HonorStudentConstant.NCKD_SUMENTRYSCORE, evalQuestResult.getRatedTotal());
+            //已评分人数
+            evalQuest.set(HonorStudentConstant.NCKD_HAVEDO, evalQuestResult.getRatedCount());
+            //未评分人数
+            evalQuest.set(HonorStudentConstant.NCKD_NODO, evalQuestResult.getUnratedPersonnel());
+            //不了解人数
+            evalQuest.set(HonorStudentConstant.NCKD_UNCLEARS, evalQuestResult.getNotUnderstandCount());
+
+            /*TODO 3.计算员工绩效得分(需要取绩效排名,待职位体系开发之后补充这部分逻辑),参考SHR:OrginsPerfPlanListHandler.gettoprankscore
+            影响字段:nckd_toprankscore(员工绩效得分)
+            具体计算逻辑:
+            取当前考评年上一年的绩效排名结果,计算公式:
+                1.计算该分组中的总人数
+                2.用排名除以总人数,得到排名比例
+                3.用1减去排名比例(确保排名越靠前(数字越小),得分应该越高)
+                4.乘以100得到最终得分
+                例子
+                    假设某组有10个人,某个员工排名第3:
+                    排名比例 = 3/10 = 0.3
+                    得分 = (1 - 0.3) * 100 = 70分
+             */
+
+
+            /*TODO 4.计算业绩贡献分(需要取年度贡献分,待职位体系开发之后补充这部分逻辑),参考SHR:OrginsPerfPlanListHandler.getallyearscoresum
+            影响字段:nckd_allyearscoresum(业绩贡献分)
+            取当前考评年上一年的绩效排名结果,具体计算过程:
+                按类型分组统计每类得分总和
+                对有上限的类型应用分数限制(如A类超过60分按60分计算)
+                对无上限类型保持原得分
+              第二步:特殊规则处理
+                对于有科研与创新类(A类)得分的情况,还需要根据获奖级别进行额外限制:
+                1.统计不同级别的获奖情况:
+                    国家级(gj)
+                    省部级(sb)
+                    公司级(gs)
+                2.应用特殊规则:
+                    如果只有公司级奖项且科研创新分超过20分,则限制为20分
+                    如果只有省部级奖项且科研创新分超过40分,则限制为40分
+              第三步:返回总分
+                最终得分 = 科研与创新类得分 + 其他类别总分
+
+              分数限制
+                1. **A类(科研与创新)**:上限60分
+                2. **B类(专利申报)**:上限10分
+                3. **C类(论文发表)**:上限2分
+                4. **E类(培训教材)**:上限5分
+                5. **G类(管理规范)**:上限15分
+                6. **H类(师带徒)**:上限6分
+                7. **I类(培训授课)**:上限5分
+                以下单据类型**没有**分数上限限制:
+                    - **D类(技能竞赛)**
+                    - **F类(技术标准)**
+                此外,对于A类(科研与创新)还有额外的特殊规则限制:
+                    - 如果员工只有公司级奖项,且该类得分超过20分,则限制为20分
+                    - 如果员工只有省部级奖项,且该类得分超过40分,则限制为40分
+             */
+
+            //=================================== 4.计算优秀生评价积分 ===================================
+            // 计算公式:nckd_differencescore(地区差异分)+nckd_allyearscoresum(业绩贡献分)+nckd_toprankscore(员工绩效得分)+nckd_perfscorespart(综合测评得分)
+            int differenceScore = evalQuest.getInt(HonorStudentConstant.NCKD_DIFFERENCESCORE);
+            int allYearScoreSum = evalQuest.getInt(HonorStudentConstant.NCKD_ALLYEARSCORESUM);
+            int topRankScore = evalQuest.getInt(HonorStudentConstant.NCKD_TOPRANKSCORE);
+            int perfScoresPart = evalQuest.getInt(HonorStudentConstant.NCKD_PERFSCORESPART);
+            evalQuest.set(HonorStudentConstant.NCKD_SUMSCORE, differenceScore+allYearScoreSum+topRankScore+perfScoresPart);
+            logger.info("【优秀生考评】-更新问卷测评结果-计算优秀生评价积分-问卷ID:{},规则ID:{},地区差异分:{},业绩贡献分:{},员工绩效得分:{},综合测评得分:{}", evalQuestId,evaluationRuleId,differenceScore,allYearScoreSum,topRankScore,perfScoresPart);
+
+        }
+        SaveServiceHelper.save(evalQuestArray);
+
+        //=================================== 5.《更新排名》和《定格等级》(注:全员更新,即同一个评测活动下的问卷都会更新) ===================================
+        Set<Long> evaluationRuleIds = evaluationRuleMap.keySet();
+        //获取排名结果(key:问卷ID,value:问卷排名结果  )
+        Map<Long, EvalQuestResultBO> rankingResultMap = getRankingResult(evaluationRuleIds.toArray(new Long[0]));
+        logger.info("【优秀生考评】-更新问卷测评结果-排名结果:{}",JSON.toJSONString(rankingResultMap));
+        //获取需要更新排名的问卷(按评测活动获取)
+        String join = String.join(",", FormConstant.ID_KEY,
+                HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.ID_KEY,
+                HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY,
+                HonorStudentConstant.NCKD_EVALUATIONRULE+"."+HonorStudentConstant.NCKD_BIZYEAR,
+                HonorStudentConstant.NCKD_COMPERSONS,
+                HonorStudentConstant.NCKD_HRPERSONS,
+                HonorStudentConstant.NCKD_COMRANKING,
+                HonorStudentConstant.NCKD_HRRANKING,
+                HonorStudentConstant.NCKD_RANKINGANDCOM,
+                HonorStudentConstant.NCKD_RANKINGANDHR,
+                HonorStudentConstant.NCKD_COMPERCENTAGE,
+                HonorStudentConstant.NCKD_HRPERCENTAGE,
+                HonorStudentConstant.NCKD_APPRAISALRESULT);
+        //根据评测活动获取所有问卷
+        DynamicObject[] allEvalQuestArray = BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID, join, new QFilter[]{QFilterCommonHelper.getIdInFilter(new ArrayList<>(rankingResultMap.keySet()))});
+
+        //获取考核结果基础数据(用于定格等级的基础数据)
+        DynamicObject[] appraisalResultList = BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_APPRAISALRESULT_ENTITYID,
+                String.join(",", FormConstant.ID_KEY,FormConstant.NUMBER_KEY),
+                new QFilter[]{new QFilter(FormConstant.NUMBER_KEY, QCP.in, Arrays.asList(AppraisalResultEnum.EXCELLENT.getCode(),AppraisalResultEnum.QUALIFIED.getCode(),AppraisalResultEnum.UN_QUALIFIED.getCode()))});
+        //优秀
+        DynamicObject excellent = null;
+        //合格
+        DynamicObject qualified = null;
+        //不合格
+        DynamicObject unQualified = null;
+        for (DynamicObject appraisalResult : appraisalResultList) {
+            String number = appraisalResult.getString(FormConstant.NUMBER_KEY);
+            if (AppraisalResultEnum.EXCELLENT.getCode().equals(number)) {
+                excellent = appraisalResult;
+            } else if (AppraisalResultEnum.QUALIFIED.getCode().equals(number)) {
+                qualified = appraisalResult;
+            } else if (AppraisalResultEnum.UN_QUALIFIED.getCode().equals(number)) {
+                unQualified = appraisalResult;
+            }
+        }
+        if(excellent == null || qualified == null || unQualified == null){
+            logger.warn("【优秀生考评】-更新问卷测评结果:未找到优秀、合格或不合格等级基础数据,请检查是否配置了(01:优秀,02:合格,04:不合格)考评结果");
+            throw new ValidationException("未找到优秀、合格或不合格等级基础数据,请检查是否配置了(01:优秀,02:合格,04:不合格)考评结果");
+        }
+
+        //---------------------- 获取员工上年度考核结果 ----------------------
+        //key为:"人员ID-考核年份",value:为考核结果编号
+        Map<String, String> lastYearEvaluationResult = getLastYearAssessmentResult(allEvalQuestArray);
+        logger.info("【优秀生考评】-更新问卷测评结果-上年度考核结果:{}",JSON.toJSONString(lastYearEvaluationResult));
+
+        for (DynamicObject allEvalQuest : allEvalQuestArray) {
+
+            EvalQuestResultBO evalQuestResult = rankingResultMap.get(allEvalQuest.getLong(FormConstant.ID_KEY));
+            //有积分得才排名
+            if(evalQuestResult.getSumScore() != null && evalQuestResult.getSumScore() > 0) {
+                allEvalQuest.set(HonorStudentConstant.NCKD_COMPERSONS,evalQuestResult.getComPersons());
+                allEvalQuest.set(HonorStudentConstant.NCKD_HRPERSONS,evalQuestResult.getHrPersons());
+                allEvalQuest.set(HonorStudentConstant.NCKD_COMRANKING,evalQuestResult.getComRanking());
+                allEvalQuest.set(HonorStudentConstant.NCKD_HRRANKING,evalQuestResult.getHrRanking());
+                allEvalQuest.set(HonorStudentConstant.NCKD_RANKINGANDCOM,evalQuestResult.getComRanking()+"/"+evalQuestResult.getComPersons());
+                allEvalQuest.set(HonorStudentConstant.NCKD_RANKINGANDHR,evalQuestResult.getHrRanking()+"/"+evalQuestResult.getHrPersons());
+
+                /*定格等级
+                    1.获取该员工上年度绩效考核结果,如果为【基本合格】或【不合格】定格为:不合格
+                    2.计算公司排名百分比和所在单位排名百分比
+                        公司排名百分比 = (公司排名 / 公司总人数) * 100%
+                        所在单位排名百分比 = (所在单位排名 / 所在单位总人数) * 100%
+                    3.判断是否符合排名基准
+                        如果:(评价规则.优秀评优排名基准(%) >= 公司排名百分比 并且 评价规则.所在单位评优排名基准(%) >= 所在单位排名百分比)=优秀
+                        否则:合格
+                 */
+                //公司排名百分比
+                Double comPercentage = evalQuestResult.calculateComPercentage();
+                allEvalQuest.set(HonorStudentConstant.NCKD_COMPERCENTAGE, comPercentage != 0 ? Math.round(comPercentage) + "%" : null);
+                //所在单位排名百分比
+                Double hrPercentage = evalQuestResult.calculateHrPercentage();
+                allEvalQuest.set(HonorStudentConstant.NCKD_HRPERCENTAGE, hrPercentage != 0 ? Math.round(hrPercentage) + "%" : null);
+
+                Long evaluationRuleId = evalQuestResult.getEvaluationRuleId();
+                DynamicObject evaluationRule = evaluationRuleMap.get(evaluationRuleId);
+                //优秀评优排名基准(%)
+                int commArkPercentage = evaluationRule.getInt(HonorStudentConstant.NCKD_COMMARKPERCENTAGE);
+                //所在单位评优排名基准(%)
+                int hrmArkPercentage = evaluationRule.getInt(HonorStudentConstant.NCKD_HRMARKPERCENTAGE);
+
+                //上年度绩效考核结果
+                long personId = allEvalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getLong(FormConstant.ID_KEY);
+                Date yearDate = allEvalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE).getDate(HonorStudentConstant.NCKD_BIZYEAR);
+                LocalDateTime lastYear = DateUtil.minusYears(DateUtil.toLocalDateTime(yearDate), 1);
+                int year = DateUtil.getYear(lastYear);
+                String appraisalResultNumber = lastYearEvaluationResult.get(personId + "-" + year);
+                //定格等级
+                if(StringUtils.isNotBlank(appraisalResultNumber) && StringUtils.equalsAny(appraisalResultNumber,AppraisalResultEnum.BASICALLY_QUALIFIED.getCode(),AppraisalResultEnum.UN_QUALIFIED.getCode())) {
+                    //不合格
+                    allEvalQuest.set(HonorStudentConstant.NCKD_APPRAISALRESULT, unQualified);
+                }else if (commArkPercentage >= comPercentage && hrmArkPercentage >= hrPercentage) {
+                    //优秀
+                    allEvalQuest.set(HonorStudentConstant.NCKD_APPRAISALRESULT, excellent);
+                } else {
+                    //合格
+                    allEvalQuest.set(HonorStudentConstant.NCKD_APPRAISALRESULT, qualified);
+                }
+            }else{
+                allEvalQuest.set(HonorStudentConstant.NCKD_COMPERSONS,null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_HRPERSONS,null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_COMRANKING,null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_HRRANKING,null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_RANKINGANDCOM,null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_RANKINGANDHR,null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_COMPERCENTAGE, null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_HRPERCENTAGE, null);
+                allEvalQuest.set(HonorStudentConstant.NCKD_APPRAISALRESULT, null);
+            }
+        }
+        SaveServiceHelper.save(allEvalQuestArray);
+        logger.info("【优秀生考评】-更新问卷测评结果-结束");
+    }
+
+    /**
+     * 获取上一年度考评结果
+     * @param allEvalQuestArray 需要获取年度考评的问卷
+     * @return: java.util.Map<java.lang.String, java.lang.String> key为"人员ID-考核年份",value为考核结果编号
+     * @author W.Y.C
+     * @date: 2025/08/13 16:19
+     */
+    private static Map<String, String> getLastYearAssessmentResult(DynamicObject[] allEvalQuestArray) {
+        //获取本次计算的所有评测活动和年份
+        List<Map<String, Object>> allEvaluationRuleList = Arrays.stream(allEvalQuestArray)
+                .map(dynamicObject -> {
+                    Map<String, Object> info = new HashMap<>();
+                    info.put("evalRuleId", dynamicObject.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE).getLong(FormConstant.ID_KEY));
+                    info.put("bizYear", dynamicObject.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE).getDate(HonorStudentConstant.NCKD_BIZYEAR));
+                    return info;
+                }).distinct().collect(Collectors.toList());
+        //构建查询年度绩效结果的查询条件
+        List<QFilter> perfManagerFilterList = new ArrayList<>(allEvaluationRuleList.size());
+        for (Map<String, Object> allEvaluationRule : allEvaluationRuleList) {
+            Long evalRuleId = ConvertUtil.toLong(allEvaluationRule.get("evalRuleId"));
+            Date bizYear = ConvertUtil.toDate(allEvaluationRule.get("bizYear"));
+            // 减一年获取上年度考核结果
+            Date lastYearBizYear = DateUtil.toDate(DateUtil.minusYears(DateUtil.toLocalDateTime(bizYear), 1));
+            LocalDateTime beginYear = DateUtil.beginOfYear(DateUtil.toLocalDateTime(lastYearBizYear));
+            LocalDateTime ednYear = DateUtil.endOfYear(DateUtil.toLocalDateTime(lastYearBizYear));
+
+            List<Long> personIds = Arrays.stream(allEvalQuestArray).filter(d -> d.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE).getLong(FormConstant.ID_KEY) == evalRuleId)
+                    .map(dynamicObject -> dynamicObject.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getLong(FormConstant.ID_KEY)).collect(Collectors.toList());
+            QFilter filter = new QFilter(HonorStudentConstant.NCKD_PERSON, QCP.in, personIds)
+                    .and(new QFilter(FormConstant.ENTRY_ENTITY_KEY+"."+HonorStudentConstant.NCKD_APPRAISALYEAR, QCP.large_equals, beginYear)
+                            .and(new QFilter(FormConstant.ENTRY_ENTITY_KEY+"."+HonorStudentConstant.NCKD_APPRAISALYEAR, QCP.less_equals, ednYear))
+                    );
+            perfManagerFilterList.add(filter);
+        }
+
+        QFilter perfManagerFilter = null;
+        for (QFilter filter : perfManagerFilterList) {
+            if(perfManagerFilter == null){
+                perfManagerFilter = filter;
+            }else{
+                perfManagerFilter = perfManagerFilter.or(filter);
+            }
+        }
+        DynamicObjectCollection perfManagerArray = QueryServiceHelper.query(HonorStudentConstant.NCKD_PERFMANAGER_ENTITYID,
+                String.join(",", HonorStudentConstant.NCKD_PERSON,
+                        FormConstant.ENTRY_ENTITY_KEY+"."+HonorStudentConstant.APPRAISAL_YEAR_KEY,
+                        FormConstant.ENTRY_ENTITY_KEY+"."+HonorStudentConstant.NCKD_APPRAISALRESULT,
+                        FormConstant.ENTRY_ENTITY_KEY+"."+HonorStudentConstant.NCKD_APPRAISALRESULT+"."+FormConstant.NUMBER_KEY),
+                new QFilter[]{perfManagerFilter});
+        // 创建映射关系:key为"人员ID-考核年份",value为考核结果编号
+        Map<String, String> appraisalResultMap = new HashMap<>();
+        for (DynamicObject perfManager : perfManagerArray) {
+            Long personId = perfManager.getLong(HonorStudentConstant.NCKD_PERSON);
+            String appraisalResultNumber = perfManager.getString(FormConstant.ENTRY_ENTITY_KEY+"."+HonorStudentConstant.NCKD_APPRAISALRESULT+"."+FormConstant.NUMBER_KEY);
+            Date yearDate = perfManager.getDate(FormConstant.ENTRY_ENTITY_KEY+"."+HonorStudentConstant.APPRAISAL_YEAR_KEY);
+            int year = DateUtil.getYear(yearDate);
+            if (StringUtils.isNotBlank(appraisalResultNumber)) {
+                appraisalResultMap.put(personId + "-" + year, appraisalResultNumber);
+            }
+        }
+        return appraisalResultMap;
+    }
+
+    /**
+     * 获取排名结果<br/>
+     * 1.根据评测活动获取排名人数<br/>
+     * 2.根据评测活动+单位获取排名人数<br/>
+     * 3.根据评测活动按优秀生积分确定各问卷排名<br/>
+     * 4.根据评测活动+单位按优秀生积分确定各问卷排名<br/>
+     * @param evaluationRuleIds 评价规则ID(支持多个)
+     * @return: java.util.Map<Long, EvalQuestResultBO> 返回评价活动内的所有问卷排名结果。key:问卷ID,value:问卷排名结果
+     * @author W.Y.C
+     * @date: 2025/08/09 14:46
+     */
+    public static Map<Long,EvalQuestResultBO> getRankingResult(Long... evaluationRuleIds) {
+        QFilter[] filters = new QFilter[] {
+                new QFilter(HonorStudentConstant.NCKD_EVALUATIONRULE, QCP.in, evaluationRuleIds)
+        };
+        StringJoiner fields = new StringJoiner(",");
+        fields.add(FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+        //所属单位
+        fields.add(HonorStudentConstant.USEORG_KEY+"."+FormConstant.ID_KEY);
+        //优秀生评价积分
+        fields.add(HonorStudentConstant.NCKD_SUMSCORE);
+        //测评状态
+        fields.add(HonorStudentConstant.NCKD_PERIODSTATE);
+        Map<Long, EvalQuestResultBO> resultMap = new HashMap<>();
+        //根据评价规则查询所有问卷
+        try(DataSet dataSet = QueryServiceHelper.queryDataSet(HonorStudentHelper.class.getName(), HonorStudentConstant.NCKD_EVALQUEST_ENTITYID,
+                fields.toString(), filters,
+                HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY+","+HonorStudentConstant.USEORG_KEY+"."+FormConstant.ID_KEY+","+HonorStudentConstant.NCKD_SUMSCORE + " desc")){
+
+            //获取评测活动所有问卷。key:评测活动id,value:对应问卷ID
+            Map<Long,List<Long>> evalQuestMap = new HashMap<>();
+            DataSet allDataSet = dataSet.copy();
+            while (allDataSet.hasNext()) {
+                Row row = allDataSet.next();
+                Long id = row.getLong(FormConstant.ID_KEY);
+                Long evaluationRuleId = row.getLong(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+                List<Long> evalQuestIdList = evalQuestMap.computeIfAbsent(evaluationRuleId, k -> new ArrayList<>());
+                evalQuestIdList.add(id);
+            }
+            try (DataSet dsCount = dataSet.copy()
+                    .filter(HonorStudentConstant.NCKD_PERIODSTATE+" <> '4'")
+                    .groupBy(new String[]{HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY})
+                    .count()
+                    .finish()) {
+                //获取公司(评价活动维度)总排名人数
+                while (dsCount.hasNext()) {
+                    Row row = dsCount.next();
+                    Long evaluationRuleId = row.getLong(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+                    Integer comPersons = row.getInteger("count");
+
+                    List<Long> evalQuestIdList = evalQuestMap.get(evaluationRuleId);
+                    for (Long evalQuestId : evalQuestIdList) {
+                        //设置当前评测活动所有公司排名人数
+                        EvalQuestResultBO evalQuestResult = resultMap.computeIfAbsent(evalQuestId, k -> new EvalQuestResultBO());
+                        evalQuestResult.setComPersons(comPersons);
+                        evalQuestResult.setEvaluationRuleId(evaluationRuleId);
+                    }
+                }
+            }
+            try (DataSet dsCount = dataSet.copy()
+                    .filter(HonorStudentConstant.NCKD_PERIODSTATE+" <> '4'")
+                    .groupBy(new String[]{HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY,HonorStudentConstant.USEORG_KEY+"."+FormConstant.ID_KEY})
+                    .count()
+                    .finish()) {
+                //获取单位(评价活动+单位维度)总排名人数
+                while (dsCount.hasNext()) {
+                    Row row = dsCount.next();
+                    Long evaluationRuleId = row.getLong(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+                    Long useOrg = row.getLong(HonorStudentConstant.USEORG_KEY+"."+FormConstant.ID_KEY);
+                    Integer perfScores = row.getInteger("count");
+
+                    List<Long> evalQuestIdList = evalQuestMap.get(evaluationRuleId);
+                    for (Long evalQuestId : evalQuestIdList) {
+                        //设置当前评测活动所有单位排名人数
+                        EvalQuestResultBO evalQuestResult = resultMap.computeIfAbsent(evalQuestId, k -> new EvalQuestResultBO());
+                        evalQuestResult.setHrPersons(perfScores);
+                        evalQuestResult.setEvaluationRuleId(evaluationRuleId);
+                    }
+                }
+            }
+            //按公司(评价活动维度)排名
+            DataSet rankDataSet = dataSet.copy();
+            rankDataSet = rankDataSet.map(new RankMapFunction(dataSet.getRowMeta()));
+            while (rankDataSet.hasNext()) {
+                Row row = rankDataSet.next();
+                Long id = row.getLong(FormConstant.ID_KEY);
+                long evaluationRuleId = row.getLong(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+                Integer sumScore = row.getInteger(HonorStudentConstant.NCKD_SUMSCORE);
+                Integer rank = row.getInteger("rank");
+
+                EvalQuestResultBO evalQuestResult = resultMap.computeIfAbsent(id, k -> new EvalQuestResultBO());
+                evalQuestResult.setSumScore(sumScore);
+                evalQuestResult.setComRanking(rank);
+                evalQuestResult.setEvaluationRuleId(evaluationRuleId);
+            }
+
+            //按单位(评价活动+单位维度)排名
+            DataSet unitRankDataSet = dataSet.copy();
+            unitRankDataSet = unitRankDataSet.map(new UnitRankMapFunction(dataSet.getRowMeta()));
+            while (unitRankDataSet.hasNext()) {
+                Row row = unitRankDataSet.next();
+                Long id = row.getLong(FormConstant.ID_KEY);
+                long evaluationRuleId = row.getLong(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+                Integer useOrgId = row.getInteger(HonorStudentConstant.USEORG_KEY+"."+FormConstant.ID_KEY);
+                Integer sumScore = row.getInteger(HonorStudentConstant.NCKD_SUMSCORE);
+                Integer rank = row.getInteger("rank");
+
+                EvalQuestResultBO evalQuestResult = resultMap.computeIfAbsent(id, k -> new EvalQuestResultBO());
+                evalQuestResult.setSumScore(sumScore);
+                evalQuestResult.setHrRanking(rank);
+                evalQuestResult.setEvaluationRuleId(evaluationRuleId);
+            }
+        }
+
+        return resultMap;
+
+
+
+    }
+
+    /**
+     * 计算考评结果(同级评分人数、上级评分人数、上级评分人数、同级评分总分、上级评分总分、领导评分总分、已评分总分、已评分人数、未评分人数、不了解人数)
+     * @param evalQuestIds 问卷ID(支持多个)
+     * @return: java.util.Map<Long, nckd.jxccl.hr.hstu.common.dto.EvalQuestResultDTO>
+     * @author W.Y.C
+     * @date: 2025/08/06 22:23
+     */
+    public static Map<Long, EvalQuestResultBO> calculateScore(Long... evalQuestIds) {
+        if(evalQuestIds == null || evalQuestIds.length == 0){
+            return new HashMap<>();
+        }
+        QFilter[] filters = new QFilter[]{
+                //new QFilter(HonorStudentConstant.NCKD_PERFPLANSTATE, QCP.equals, "2"),
+                new QFilter(HonorStudentConstant.NCKD_EVALQUEST, QCP.in, evalQuestIds),
+        };
+
+        StringJoiner selectFields = new StringJoiner(",");
+        //答卷ID
+        selectFields.add(FormConstant.ID_KEY);
+        //问卷ID
+        selectFields.add(HonorStudentConstant.NCKD_EVALQUEST);
+        //问卷分录ID
+        selectFields.add(HonorStudentConstant.NCKD_EVALQUESTENTRY);
+        //评分状态
+        selectFields.add(HonorStudentConstant.NCKD_PERFPLANSTATE);
+        //评分人
+        selectFields.add(HonorStudentConstant.NCKD_SCORER);
+        //不了解
+        selectFields.add(HonorStudentConstant.NCKD_UNCLEAR);
+        //评分角色
+        selectFields.add(StrFormatter.format("{}.{} as {}",HonorStudentConstant.NCKD_EVALQUESTENTRY,HonorStudentConstant.NCKD_PERFPLANROLE,HonorStudentConstant.NCKD_PERFPLANROLE));
+        //评分分数
+        selectFields.add(StrFormatter.format("{}.{} as {}",HonorStudentConstant.NCKD_EVALRESULTENTRY,HonorStudentConstant.NCKD_PERFSCORES,HonorStudentConstant.NCKD_PERFSCORES));
+        Map<Long, EvalQuestResultBO> resultMap = new HashMap<>(evalQuestIds.length);
+        try(DataSet dataSet = QueryServiceHelper.queryDataSet(HonorStudentHelper.class.getName(), HonorStudentConstant.NCKD_EVALRESULT_ENTITYID, selectFields.toString(), filters, null)){
+            //统计:同级评分人数、上级评分人数、领导评分人数。统计条件:已评分 并且 非不了解
+            try (DataSet dsCount = dataSet.copy()
+                    .filter(HonorStudentConstant.NCKD_PERFPLANSTATE+" = '2' and "+HonorStudentConstant.NCKD_UNCLEAR+" = false")
+                    .groupBy(new String[]{HonorStudentConstant.NCKD_EVALQUEST,HonorStudentConstant.NCKD_SCORER,HonorStudentConstant.NCKD_PERFPLANROLE})
+                    .count()
+                    .finish()) {
+                try(DataSet numberCount = dsCount.copy()
+                        .groupBy(new String[]{HonorStudentConstant.NCKD_EVALQUEST,HonorStudentConstant.NCKD_PERFPLANROLE})
+                        .count()
+                        .finish()){
+                    while (numberCount.hasNext()) {
+                        Row row = numberCount.next();
+                        Long evalQuestId = row.getLong(HonorStudentConstant.NCKD_EVALQUEST);
+                        String perfPlanRole = row.getString(HonorStudentConstant.NCKD_PERFPLANROLE);
+                        Integer perfScores = row.getInteger("count");
+
+                        EvalQuestResultBO evalQuestResultBO = resultMap.computeIfAbsent(evalQuestId, k -> new EvalQuestResultBO());
+                        if(perfPlanRole.equals(PerfPlanRoleEnum.PEERS.getCode())){
+                            //同级评分人数
+                            evalQuestResultBO.addPeerRatingCount(perfScores);
+                        }else if(perfPlanRole.equals(PerfPlanRoleEnum.SUPERIOR.getCode())){
+                            //上级评分人数
+                            evalQuestResultBO.addSuperiorRatingCount(perfScores);
+                        }else if(perfPlanRole.equals(PerfPlanRoleEnum.LEAD.getCode())){
+                            //领导评分人数
+                            evalQuestResultBO.addLeaderRatingCount(perfScores);
+                        }
+                    }
+                }
+
+            }
+            //统计:同级评分总分、上级评分总分、领导评分总分、已评分总分。统计条件:已评分 并且 非不了解
+            try (DataSet dsSum = dataSet.copy().select(HonorStudentConstant.NCKD_PERFPLANSTATE,HonorStudentConstant.NCKD_EVALQUEST,
+                            HonorStudentConstant.NCKD_PERFPLANROLE,HonorStudentConstant.NCKD_UNCLEAR,
+                            StrFormatter.format("cast((case when {} is null or {} = '' then '0' else {} end) as Integer) as {}",
+                                    HonorStudentConstant.NCKD_PERFSCORES,HonorStudentConstant.NCKD_PERFSCORES,HonorStudentConstant.NCKD_PERFSCORES,HonorStudentConstant.NCKD_PERFSCORES+"Num"))
+                    .filter(HonorStudentConstant.NCKD_PERFPLANSTATE+" = '2' and "+HonorStudentConstant.NCKD_UNCLEAR+" = false")
+                    .groupBy(new String[]{HonorStudentConstant.NCKD_EVALQUEST,HonorStudentConstant.NCKD_PERFPLANROLE})
+                    .sum(HonorStudentConstant.NCKD_PERFSCORES+"Num")
+                    .finish()) {
+                while (dsSum.hasNext()) {
+                    Row row = dsSum.next();
+                    Long evalQuestId = row.getLong(HonorStudentConstant.NCKD_EVALQUEST);
+                    String perfPlanRole = row.getString(HonorStudentConstant.NCKD_PERFPLANROLE);
+                    Integer perfScores = row.getInteger(HonorStudentConstant.NCKD_PERFSCORES+"Num");
+
+                    EvalQuestResultBO evalQuestResultBO = resultMap.computeIfAbsent(evalQuestId, k -> new EvalQuestResultBO());
+                    if(perfPlanRole.equals(PerfPlanRoleEnum.PEERS.getCode())){
+                        //同级评分总分
+                        evalQuestResultBO.addPeerRatingTotal(perfScores);
+                    }else if(perfPlanRole.equals(PerfPlanRoleEnum.SUPERIOR.getCode())){
+                        //上级评分总分
+                        evalQuestResultBO.addSuperiorRatingTotal(perfScores);
+
+                    }else if(perfPlanRole.equals(PerfPlanRoleEnum.LEAD.getCode())){
+                        //领导评分总分
+                        evalQuestResultBO.addLeaderRatingTotal(perfScores);
+                    }
+                }
+                for (Map.Entry<Long, EvalQuestResultBO> entry : resultMap.entrySet()) {
+                    EvalQuestResultBO evalQuestResultBO = entry.getValue();
+                    //同级评分总分+上级评分总分+领导评分总分=已评分总分
+                    int totalScore = (evalQuestResultBO.getPeerRatingTotal() == null ? 0 : evalQuestResultBO.getPeerRatingTotal()) +
+                            (evalQuestResultBO.getSuperiorRatingTotal() == null ? 0 : evalQuestResultBO.getSuperiorRatingTotal()) +
+                            (evalQuestResultBO.getLeaderRatingTotal() == null ? 0 : evalQuestResultBO.getLeaderRatingTotal());
+                    //已评分总分
+                    evalQuestResultBO.setRatedTotal(totalScore);
+                }
+            }
+            //统计:已评分人数、未评分人数。统计条件:【评分状态为含:(未开始、待评分)=未评分人数、已评分=已评分人数】
+            try (DataSet dsCount = dataSet.copy()
+                    .filter(HonorStudentConstant.NCKD_PERFPLANSTATE+" in ('0','1','2')")
+                    .groupBy(new String[]{HonorStudentConstant.NCKD_EVALQUEST,HonorStudentConstant.NCKD_SCORER,HonorStudentConstant.NCKD_PERFPLANSTATE})
+                    .count()
+                    .finish()) {
+                try (DataSet scoresDs = dsCount.groupBy(new String[]{HonorStudentConstant.NCKD_EVALQUEST, HonorStudentConstant.NCKD_PERFPLANSTATE}).count().finish()){
+                    while (scoresDs.hasNext()) {
+                        Row row = scoresDs.next();
+                        Long evalQuestId = row.getLong(HonorStudentConstant.NCKD_EVALQUEST);
+                        String perfPlanState = row.getString(HonorStudentConstant.NCKD_PERFPLANSTATE);
+                        Integer count = row.getInteger("count");
+
+                        EvalQuestResultBO evalQuestResultBO = resultMap.computeIfAbsent(evalQuestId, k -> new EvalQuestResultBO());
+                        if(perfPlanState.contains("0") || perfPlanState.contains("1")){
+                            //未评分人数
+                            evalQuestResultBO.addUnratedPersonnel(count);
+                        }else{
+                            //已评分人数
+                            evalQuestResultBO.addRatedCount(count);
+                        }
+                    }
+                }
+            }
+            //不了解人数
+            try (DataSet dsCount = dataSet.copy()
+                    .filter(HonorStudentConstant.NCKD_UNCLEAR+" = true")
+                    .groupBy(new String[]{HonorStudentConstant.NCKD_EVALQUEST,HonorStudentConstant.NCKD_SCORER,HonorStudentConstant.NCKD_UNCLEAR})
+                    .count()
+                    .finish()) {
+                try(DataSet unclearDs = dsCount
+                        .groupBy(new String[]{HonorStudentConstant.NCKD_EVALQUEST, HonorStudentConstant.NCKD_UNCLEAR})
+                        .count()
+                        .finish()){
+                    while (unclearDs.hasNext()) {
+                        Row row = unclearDs.next();
+                        Long evalQuestId = row.getLong(HonorStudentConstant.NCKD_EVALQUEST);
+                        Integer count = row.getInteger("count");
+                        EvalQuestResultBO evalQuestResultBO = resultMap.computeIfAbsent(evalQuestId, k -> new EvalQuestResultBO());
+                        evalQuestResultBO.addNotUnderstandCount(count);
+                    }
+                }
+            }
+        }
+        return resultMap;
+     }
+
+
+    /**
+     * 查询问卷信息
+     * @param
+     * @return: nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper.Result
+     * @author W.Y.C
+     * @date: 2025/07/23 21:20
+     */
+    @NotNull
+    public static HonorStudentHelper.Result getEvalQuest(List<Long> selectedRowIds) {
+
+        StringJoiner fields = new StringJoiner(",");
+        fields.add(FormConstant.ID_KEY);
+        //评测状态
+        fields.add(HonorStudentConstant.NCKD_PERIODSTATE);
+        //地区差异分
+        fields.add(HonorStudentConstant.NCKD_DIFFERENCESCORE);
+        //已评分人数
+        fields.add(HonorStudentConstant.NCKD_HAVEDO);
+        //未评分人数
+        fields.add(HonorStudentConstant.NCKD_NODO);
+        //评价规则
+        fields.add(HonorStudentConstant.NCKD_EVALUATIONRULE+"."+FormConstant.ID_KEY);
+        //被评价人
+        fields.add(HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.PERSON+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.PERSON+"."+FormConstant.NAME_KEY);
+        //被评价人部门
+        fields.add(HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.ADMINORG+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.ADMINORG+"."+FormConstant.NAME_KEY);
+        DynamicObject[] evalQuestArray = BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID,
+                fields.toString(),
+                new QFilter[]{QFilterCommonHelper.getIdInFilter(selectedRowIds)});
+        return new HonorStudentHelper.Result(selectedRowIds, evalQuestArray);
+    }
+
+    public static class Result {
+        public final List<Long> selectedRowIds;
+        public final DynamicObject[] evalQuestArray;
+
+        public Result(List<Long> selectedRowIds, DynamicObject[] evalQuestArray) {
+            this.selectedRowIds = selectedRowIds;
+            this.evalQuestArray = evalQuestArray;
+        }
+    }
+}

+ 64 - 3
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/common/HonorStudentConstant.java

@@ -80,7 +80,7 @@ public class HonorStudentConstant extends FormConstant {
     public static final String NCKD_SELECTEDEVALRULE = "NCKD_SELECTEDEVALRULE";
     /** 人员 */
     public static final String NCKD_SELECTEDPERSON = "NCKD_SELECTEDPERSON";
-    /** 优秀生综合测评模板 */
+    /** 优秀生综合测评模板ID */
     public static final String NCKD_EVALQUESTTPLID = "nckd_evalquesttplid";
     /** 生成评价对象 */
     public static final String OP_CREATEEVAL = "createeval";
@@ -101,7 +101,7 @@ public class HonorStudentConstant extends FormConstant {
     public static final String NCKD_DESCRIPTION = "NCKD_DESCRIPTION";
 
     /** 综合测评问卷-实体标识 */
-    public static final String NCKD_EVALQUEST = "nckd_evalquest";
+    public static final String NCKD_EVALQUEST_ENTITYID = "nckd_evalquest";
     /** 评测活动 */
     public static final String NCKD_EVALUATIONRULE = "NCKD_EVALUATIONRULE";
     /** 综合问卷模板 */
@@ -116,6 +116,8 @@ public class HonorStudentConstant extends FormConstant {
     public static final String NCKD_TEXTFIELD1 = "NCKD_TEXTFIELD1";
     /** 评分角色 */
     public static final String NCKD_PERFPLANROLE = "NCKD_PERFPLANROLE";
+    /** 备份 */
+    public static final String NCKD_REMARK = "NCKD_REMARK";
     /** 所属公司 */
     public static final String NCKD_COMPANY = "NCKD_COMPANY";
     /** 职位 */
@@ -150,6 +152,8 @@ public class HonorStudentConstant extends FormConstant {
     public static final String NCKD_SUMSCORE = "NCKD_SUMSCORE";
     /** 定格等级 */
     public static final String NCKD_APPRAISALRESULT = "NCKD_APPRAISALRESULT";
+    /** 考核结果 */
+    public static final String NCKD_APPRAISALRESULT_ENTITYID = "NCKD_APPRAISALRESULT";
     /** 公司排名 */
     public static final String NCKD_COMRANKING = "NCKD_COMRANKING";
     /** 所在单位排名 */
@@ -168,7 +172,64 @@ public class HonorStudentConstant extends FormConstant {
     public static final String NCKD_HRPERCENTAGE = "NCKD_HRPERCENTAGE";
     /** 评分不了解人数 */
     public static final String NCKD_UNCLEARS = "NCKD_UNCLEARS";
-
+    /** 综合测评问卷-生成问卷 */
+    public static final String OP_GENERATE_QUEST = "GENERATEQUEST";
+    /** 综合测评问卷-刷新同级人员 */
+    public static final String OP_REFRESH_PEERS = "refreshpeers";
+    /** 综合测评问卷-发起评测 */
+    public static final String OP_BEGINEVAL = "begineval";
+    /** 综合测评问卷-结束评测 */
+    public static final String OP_ENDEVAL = "endeval";
+    /** 综合测评问卷-获取评分结果 */
+    public static final String OP_GETSCORE = "getscore";
+    /** 综合测评问卷-同级评分人组织选择弹窗 */
+    public static final String NCKD_EVALQUEST_SELECTORG = "nckd_evalquest_selectorg";
+    /** 选择组织范围(可选)*/
+    public static final String NCKD_MULSELECTORG = "nckd_mulselectorg";
+
+
+
+
+    /** 综合测评答卷-实体标识 */
+    public static final String NCKD_EVALRESULT_ENTITYID = "nckd_evalresult";
+    /** 单据体 */
+    public static final String NCKD_ENTRYENTITY = "NCKD_ENTRYENTITY";
+    /** 缺省id字段 */
+    public static final String ID = "ID";
+    /** 分录行号 */
+    public static final String SEQ = "SEQ";
+    /** 综合测评答卷单据体 */
+    public static final String NCKD_EVALRESULTENTRY = "nckd_evalresultentry";
+    /** 综合测评问卷模板分录 */
+    public static final String NCKD_EVALQUESTTPLENTRY = "nckd_evalquesttplentry";
+    /** 综合测评问卷模板分录 */
+    public static final String NCKD_APPRAISALYEAR = "nckd_appraisalyear";
+    /** 综合测评问卷模板分录 */
+    public static final String NCKD_EVALQUESTTPLENTRYBAS_ENTITYID = "nckd_evalquesttplentrybas";
+    /** 评价分数 */
+    public static final String NCKD_PERFSCORES = "NCKD_PERFSCORES";
+    /** 综合测评问卷 */
+    public static final String NCKD_EVALQUEST = "NCKD_EVALQUEST";
+    /** 评分人 */
+    public static final String NCKD_SCORER = "NCKD_SCORER";
+    /** 评分状态 */
+    public static final String NCKD_PERFPLANSTATE = "NCKD_PERFPLANSTATE";
+    /** 不了解 */
+    public static final String NCKD_UNCLEAR = "NCKD_UNCLEAR";
+    /** 操作备注 */
+    public static final String NCKD_HOWDOMARK = "NCKD_HOWDOMARK";
+    /** 评分时间 */
+    public static final String NCKD_SCORETIME = "NCKD_SCORETIME";
+    /** 刷新同级人员 */
+    public static final String OP_NCKD_REFRESHPEERS = "nckd_refreshpeers";
+
+
+    //======================== 人员考评 ========================
+    /** 人员考评实体名称 */
+    public static final String NCKD_PERFMANAGER_ENTITYID = "nckd_perfmanager";
+
+    /** 分录-考核年份 */
+    public static final String APPRAISAL_YEAR_KEY = "nckd_appraisalyear";
 
 
 

+ 367 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/common/bo/EvalQuestResultBO.java

@@ -0,0 +1,367 @@
+package nckd.jxccl.hr.hstu.common.bo;
+
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
+
+/**
+* 问卷考评结果BO(Business Object)
+* @author W.Y.C
+* @date 2025/8/7 17:06
+* @version 1.0
+*/
+public class EvalQuestResultBO {
+
+    private static final Log logger = LogFactory.getLog(HonorStudentHelper.class);
+
+    // ================= 评分人数相关 =================
+    /** 同级评分人数 */
+    private  Integer peerRatingCount;
+    /** 上级评分人数 */
+    private  Integer superiorRatingCount;
+    /** 领导评分人数 */
+    private  Integer leaderRatingCount;
+    /** 选择"不了解"选项的人数 */
+    private  Integer notUnderstandCount;
+
+
+    // ================= 评分总分相关 =================
+    /** 同级评分总分 */
+    private  Integer peerRatingTotal;
+    /** 上级评分总分 */
+    private  Integer superiorRatingTotal;
+    /** 领导评分总分 */
+    private  Integer leaderRatingTotal;
+    /** 已评分总分 */
+    private  Integer ratedTotal;
+
+    // ================= 评分状态相关 =================
+    /** 未评分人员 */
+    private  Integer unratedPersonnel;
+    /** 已评分人数 */
+    private  Integer ratedCount;
+
+    /** 优秀生评价积分*/
+    private  Integer sumScore;
+    /** 活动规则ID */
+    private Long evaluationRuleId;
+
+    /** 公司排名人数*/
+    private Integer comPersons;
+    /** 所在单位排名人数*/
+    private Integer hrPersons;
+
+    /** 公司排名*/
+    private Integer comRanking;
+    /** 所在单位排名*/
+    private Integer hrRanking;
+
+
+    /**
+     * 计算综合测评得分
+     * @param leaderWeight 领导评分权重占比(百分比值,如50表示50%)
+     * @param superiorWeight 上级评分权重占比(百分比值)
+     * @param peerWeight 同级评分权重占比(百分比值)
+     * @param comprehensiveWeight 综合测评权重占比(百分比值)
+     * @param maxScore 综合测评封顶分
+     * @return 最终的综合测评得分
+     */
+    public double calculateComprehensiveScore(
+            int leaderWeight,
+            int superiorWeight,
+            int peerWeight,
+            int comprehensiveWeight,
+            int maxScore) {
+
+        /*
+         * 综合测评得分的计算方法
+         *
+         * 1.计算各角色综合评分贡献分。
+         *     公式:(各角色(领导、上级、同级)总分 / 对应角色评分人数) * 考评规则.各角色评分权重占比 * 0.01
+         *         计算各角色的平均分(总分除以评分人数) ,然后乘以该角色的权重占比,最后乘以0.01将百分比转换为小数
+         *     例如:
+         *         领导评分平均分90分,权重50%,贡献分 = 90 * 50% * 0.01 = 45分
+         *         上级评分平均分80分,权重40%,贡献分 = 80 * 40% * 0.01 = 32分
+         *         同级评分平均分70分,权重30%,贡献分 = 70 * 30% * 0.01 = 21分
+         * 2.计算最终的综合测评得分
+         *     公式:综合测评得分 = (各角色贡献分之和) * 综合测评权重占比 * 0.01
+         *     将所有角色的综合评分贡献分相加,再乘以考评规则中的综合测评权重占比,再乘以0.01:
+         * 3.封顶处理
+         *     公式:最终得分 = (综合测评得分 > 封顶分) ? 封顶分 : 综合测评得分
+         *     如果计算出的综合测评得分超过了考评规则中设定的综合测评封顶分,则最终得分取封顶分值:
+         */
+
+        logger.info("【优秀生考评】-更新问卷测评结果-计算综合测评得分-领导评分权重占比:{},上级评分权重占比:{},同级评分权重占比:{},综合测评权重占比:{},综合测评封顶分:{}", leaderWeight,superiorWeight,peerWeight,comprehensiveWeight,maxScore);
+
+        // 1. 计算各角色综合评分贡献分
+        double leaderContribution = calculateRoleContribution(leaderRatingTotal, leaderRatingCount, leaderWeight);
+        double superiorContribution = calculateRoleContribution(superiorRatingTotal, superiorRatingCount, superiorWeight);
+        double peerContribution = calculateRoleContribution(peerRatingTotal, peerRatingCount, peerWeight);
+
+        // 2. 计算综合测评得分
+        double comprehensiveScore = (leaderContribution + superiorContribution + peerContribution)
+                * comprehensiveWeight * 0.01;
+
+        // 3. 封顶处理
+        return Math.min(comprehensiveScore, maxScore);
+
+    }
+
+    /**
+     * 计算单个角色的贡献分
+     * @param totalScore 该角色评分总分
+     * @param raterCount 该角色评分人数
+     * @param weight 该角色权重占比(百分比值)
+     * @return 贡献分
+     */
+    private double calculateRoleContribution(Integer totalScore, Integer raterCount, int weight) {
+        if (totalScore == null || raterCount == null || raterCount == 0) {
+            return 0.0;
+        }
+        double averageScore = (double) totalScore / raterCount;
+        return averageScore * weight * 0.01;
+    }
+
+
+
+
+
+
+    /**
+     * 获取同级评分人数
+     * @return 同级评分人数
+     */
+    public Integer getLeaderRatingCount() {
+        return leaderRatingCount;
+    }
+    public void setLeaderRatingCount(Integer leaderRatingCount) {
+        this.leaderRatingCount = leaderRatingCount;
+    }
+    public void addLeaderRatingCount(Integer leaderRatingCount) {
+        this.leaderRatingCount = (this.leaderRatingCount == null) ? leaderRatingCount : this.leaderRatingCount + leaderRatingCount;
+    }
+
+    /**
+     * 获取上级评分人数
+     * @return 上级评分人数
+     */
+    public Integer getLeaderRatingTotal() {
+        return leaderRatingTotal;
+    }
+    public void setLeaderRatingTotal(Integer leaderRatingTotal) {
+        this.leaderRatingTotal = leaderRatingTotal;
+    }
+    public void addLeaderRatingTotal(Integer leaderRatingTotal) {
+        this.leaderRatingTotal = (this.leaderRatingTotal == null) ? leaderRatingTotal : this.leaderRatingTotal + leaderRatingTotal;
+    }
+
+    /**
+     * 获取选择"不了解"选项的人数
+     * @return 选择"不了解"选项的人数
+     */
+    public Integer getNotUnderstandCount() {
+        return notUnderstandCount;
+    }
+
+    public void setNotUnderstandCount(Integer notUnderstandCount) {
+        this.notUnderstandCount = notUnderstandCount;
+    }
+    public void addNotUnderstandCount(Integer notUnderstandCount) {
+        this.notUnderstandCount = (this.notUnderstandCount == null) ? notUnderstandCount : this.notUnderstandCount + notUnderstandCount;
+    }
+
+    /**
+     * 获取同级评分人数
+     * @return 同级评分人数
+     */
+    public Integer getPeerRatingCount() {
+        return peerRatingCount;
+    }
+    public void setPeerRatingCount(Integer peerRatingCount) {
+        this.peerRatingCount = peerRatingCount;
+    }
+
+    public void addPeerRatingCount(Integer peerRatingCount) {
+        this.peerRatingCount = (this.peerRatingCount == null) ? peerRatingCount : this.peerRatingCount + peerRatingCount;
+    }
+
+    /**
+     * 获取同级评分总分
+     * @return 同级评分总分
+     */
+    public Integer getPeerRatingTotal() {
+        return peerRatingTotal;
+    }
+    public void setPeerRatingTotal(Integer peerRatingTotal) {
+        this.peerRatingTotal = peerRatingTotal;
+    }
+    public void addPeerRatingTotal(Integer peerRatingTotal) {
+        this.peerRatingTotal = (this.peerRatingTotal == null) ? peerRatingTotal : this.peerRatingTotal + peerRatingTotal;
+    }
+
+    /**
+     * 获取已评分人数
+     * @return 已评分人数
+     */
+    public Integer getRatedCount() {
+        return ratedCount;
+    }
+    public void setRatedCount(Integer ratedCount) {
+        this.ratedCount = ratedCount;
+    }
+    public void addRatedCount(Integer ratedCount) {
+        this.ratedCount = (this.ratedCount == null) ? ratedCount : this.ratedCount + ratedCount;
+    }
+
+    /**
+     * 获取已评分总分
+     * @return 已评分总分
+     */
+    public Integer getRatedTotal() {
+        return ratedTotal;
+    }
+    public void setRatedTotal(Integer ratedTotal) {
+        this.ratedTotal = ratedTotal;
+    }
+    public void addRatedTotal(Integer ratedTotal) {
+        this.ratedTotal = (this.ratedTotal == null) ? ratedTotal : this.ratedTotal + ratedTotal;
+    }
+
+    /**
+     * 获取上级评分人数
+     * @return 上级评分人数
+     */
+    public Integer getSuperiorRatingCount() {
+        return superiorRatingCount;
+    }
+    public void setSuperiorRatingCount(Integer superiorRatingCount) {
+        this.superiorRatingCount = superiorRatingCount;
+    }
+    public void addSuperiorRatingCount(Integer superiorRatingCount) {
+        this.superiorRatingCount = (this.superiorRatingCount == null) ? superiorRatingCount : this.superiorRatingCount + superiorRatingCount;
+    }
+
+    /**
+     * 获取上级评分总分
+     * @return 上级评分总分
+     */
+    public Integer getSuperiorRatingTotal() {
+        return superiorRatingTotal;
+    }
+    public void setSuperiorRatingTotal(Integer superiorRatingTotal) {
+        this.superiorRatingTotal = superiorRatingTotal;
+    }
+    public void addSuperiorRatingTotal(Integer superiorRatingTotal) {
+        this.superiorRatingTotal = (this.superiorRatingTotal == null) ? superiorRatingTotal : this.superiorRatingTotal + superiorRatingTotal;
+    }
+
+    /**
+     * 获取未评分人员
+     * @return 未评分人员
+     */
+    public Integer getUnratedPersonnel() {
+        return unratedPersonnel;
+    }
+    public void setUnratedPersonnel(Integer unratedPersonnel) {
+        this.unratedPersonnel = unratedPersonnel;
+    }
+    public void addUnratedPersonnel(Integer unratedPersonnel) {
+        this.unratedPersonnel = (this.unratedPersonnel == null) ? unratedPersonnel : this.unratedPersonnel + unratedPersonnel;
+    }
+
+
+    public Long getEvaluationRuleId() {
+        return evaluationRuleId;
+    }
+
+    public void setEvaluationRuleId(Long evaluationRuleId) {
+        this.evaluationRuleId = evaluationRuleId;
+    }
+
+    public Integer getSumScore() {
+        return sumScore;
+    }
+
+    public void setSumScore(Integer sumScore) {
+        this.sumScore = sumScore;
+    }
+
+    public Integer getComPersons() {
+        return comPersons;
+    }
+
+    public void setComPersons(Integer comPersons) {
+        this.comPersons = comPersons;
+    }
+
+    public Integer getComRanking() {
+        return comRanking;
+    }
+
+    public void setComRanking(Integer comRanking) {
+        this.comRanking = comRanking;
+    }
+
+    public Integer getHrPersons() {
+        return hrPersons;
+    }
+
+    public void setHrPersons(Integer hrPersons) {
+        this.hrPersons = hrPersons;
+    }
+
+    public Integer getHrRanking() {
+        return hrRanking;
+    }
+
+    public void setHrRanking(Integer hrRanking) {
+        this.hrRanking = hrRanking;
+    }
+
+    /**
+     * 公司排名百分比 = (公司排名 / 公司总人数) * 100%
+     * @return: java.lang.Double
+     * @author W.Y.C
+     * @date: 2025/08/12 12:22
+     */
+    public Double calculateComPercentage(){
+        Integer comRanking = this.getComRanking();
+        Integer comPersons = this.getComPersons();
+        if (comRanking == null || comPersons == null || comPersons == 0) {
+            return 0.0;
+        }
+        double result = (double) comRanking / comPersons * 100;
+        return Double.valueOf(String.format("%.2f", result));
+    }
+
+    /**
+     * 所在单位排名百分比 = (所在单位排名 / 所在单位总人数) * 100%
+     * @return: java.lang.Double
+     * @author W.Y.C
+     * @date: 2025/08/12 12:22
+     */
+    public Double calculateHrPercentage(){
+        Integer hrRanking = this.getHrRanking();
+        Integer hrPersons = this.getHrPersons();
+        if (hrRanking == null || hrPersons == null || hrPersons == 0) {
+            return 0.0;
+        }
+        double result = (double) hrRanking / hrPersons * 100;
+        return Double.valueOf(String.format("%.2f", result));
+    }
+
+
+    @Override
+    public String toString() {
+        return "EvalQuestResultDTO [leaderRatingCount=" + leaderRatingCount
+                + ", leaderRatingTotal=" + leaderRatingTotal
+                + ", notUnderstandCount=" + notUnderstandCount
+                + ", peerRatingCount=" + peerRatingCount
+                + ", peerRatingTotal=" + peerRatingTotal
+                + ", ratedCount=" + ratedCount
+                + ", ratedTotal=" + ratedTotal
+                + ", superiorRatingCount=" + superiorRatingCount
+                + ", superiorRatingTotal=" + superiorRatingTotal
+                + ", unratedPersonnel=" + unratedPersonnel + "]";
+    }
+}

+ 36 - 68
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/CreateEvalQuestFormPlugin.java

@@ -8,9 +8,14 @@ import kd.bos.form.ConfirmCallBackListener;
 import kd.bos.form.MessageBoxOptions;
 import kd.bos.form.MessageBoxResult;
 import kd.bos.form.control.Control;
+import kd.bos.form.events.AfterDoOperationEventArgs;
 import kd.bos.form.events.ClosedCallBackEvent;
 import kd.bos.form.events.MessageBoxClosedEvent;
+import kd.bos.form.operate.FormOperate;
 import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.mvc.list.ListView;
 import kd.bos.orm.query.QCP;
 import kd.bos.orm.query.QFilter;
 import kd.bos.schedule.api.JobInfo;
@@ -33,15 +38,18 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
+import java.util.stream.Collectors;
 
 /**
-* 生成评价对象表单插件
+* 生成评价对象(弹窗)表单插件
 * @author W.Y.C
 * @date 2025/7/1 10:19
 * @version 1.0
 */
 public class CreateEvalQuestFormPlugin extends AbstractFormPlugin implements Plugin {
 
+    private static final Log logger = LogFactory.getLog(CreateEvalQuestFormPlugin.class);
+
     @Override
     public void registerListener(EventObject e) {
         this.addClickListeners(HonorStudentConstant.OP_BTN_OK);
@@ -51,66 +59,29 @@ public class CreateEvalQuestFormPlugin extends AbstractFormPlugin implements Plu
     public void afterCreateNewData(EventObject e) {
         super.afterCreateNewData(e);
         Long evalQuestTplId = ConvertUtil.toLong(this.getView().getFormShowParameter().getCustomParams().get(HonorStudentConstant.NCKD_EVALQUESTTPLID));
-        this.getModel().setValue(HonorStudentConstant.NCKD_EVALQUESTTPLID, evalQuestTplId);
+        this.getModel().setValue(HonorStudentConstant.NCKD_EVALQUESTTPL, evalQuestTplId);
     }
 
-    @Override
-    public void click(EventObject evt) {
-        Control source = (Control) evt.getSource();
-        if (HonorStudentConstant.OP_BTN_OK.equals(source.getKey())) {
-            DynamicObject selectedEvalRule = (DynamicObject)this.getModel().getValue(HonorStudentConstant.NCKD_SELECTEDEVALRULE);
-            if(selectedEvalRule == null){
-                this.getView().showTipNotification("请选择评价规则");
-                return;
-            }
-           DynamicObjectCollection selectedPerson = (DynamicObjectCollection)this.getModel().getValue(HonorStudentConstant.NCKD_SELECTEDPERSON);
-            if(selectedPerson.isEmpty()){
-                this.getView().showTipNotification("请选择评价对象");
-                return;
-            }
-
-            Map<String, Object> returnMap = new HashMap<>(2);
-            returnMap.put("selectedEvalRule", selectedEvalRule);
-            returnMap.put("selectedPerson", selectedPerson);
-            this.getView().showConfirm("是否确认生成已选人员的评测问卷?", MessageBoxOptions.YesNo, new ConfirmCallBackListener(HonorStudentConstant.SUBMIT_KEY, this));
-        }
-    }
 
     @Override
-    public void confirmCallBack(MessageBoxClosedEvent messageBoxClosedEvent) {
-        String callBackId = messageBoxClosedEvent.getCallBackId();
-        if (HonorStudentConstant.SUBMIT_KEY.equals(callBackId) && messageBoxClosedEvent.getResult() == MessageBoxResult.Yes) {
-            //批量新增综合测评问卷对话框确认事件
-            Long evalQuestTplId = ConvertUtil.toLong(this.getView().getFormShowParameter().getCustomParams().get(HonorStudentConstant.NCKD_EVALQUESTTPLID));
-            DynamicObject selectedEvalRule = (DynamicObject) this.getModel().getValue(HonorStudentConstant.NCKD_SELECTEDEVALRULE);
-            DynamicObjectCollection selectedPerson = (DynamicObjectCollection) this.getModel().getValue(HonorStudentConstant.NCKD_SELECTEDPERSON);
-            //------------ 校验是否已生成过问卷(校验规则:评价对象是否已经有对应的评价规则或模板问卷) begin ------------
-            List<Long> idList = new ArrayList<>();
-            selectedPerson.forEach(map ->{
-                DynamicObject depEmpRow = (DynamicObject)map.getDynamicObject(FormConstant.BASEDATAID_KEY);
-                idList.add(depEmpRow.getLong(HonorStudentConstant.ID_KEY));
-            });
-            QFilter filter = new QFilter(HonorStudentConstant.NCKD_EVALPERSON, QCP.in, idList);
-            filter.and(
-                    new QFilter(HonorStudentConstant.NCKD_EVALUATIONRULE,QCP.equals,selectedEvalRule.getLong(HonorStudentConstant.ID_KEY))
-                            .or(new QFilter(HonorStudentConstant.NCKD_EVALQUESTTPL,QCP.equals,evalQuestTplId))
-            );
-            DynamicObjectCollection evalQuestColl = QueryServiceHelper.query(HonorStudentConstant.NCKD_EVALQUEST,HonorStudentConstant.NCKD_EVALPERSON+".person.name",new QFilter[]{filter});
-            if(!evalQuestColl.isEmpty()){
-                StringJoiner exitsPersonName = new StringJoiner(",");
-                evalQuestColl.forEach(dynamicObject -> exitsPersonName.add(dynamicObject.getString(HonorStudentConstant.NCKD_EVALPERSON+".person.name")));
-                this.getView().showErrorNotification(StrFormatter.format("下列人员已存在问卷:{};不能重复生成,请检查!",exitsPersonName.toString()));
-                return;
-            }
-            //------------ 校验是否已生成过问卷(校验规则:评价对象是否已经有对应的评价规则或模板问卷) end ------------
+    public void afterDoOperation(AfterDoOperationEventArgs e) {
+        String operateKey = e.getOperateKey();
+        boolean success = e.getOperationResult() != null && e.getOperationResult().isSuccess();
+        if(HonorStudentConstant.AFFIRM.equalsIgnoreCase(operateKey) && success) {
+            FormOperate formOperate = (FormOperate) e.getSource();
+            // ------------------------------------- 获取评价对象开启异步生成 begin -------------------------------------
+            // 只有操作插件确认开启异步后才会开启
+            Boolean task = ConvertUtil.toBoolean(formOperate.getOption().getVariableValue("task"));
+            if(task){
+                DynamicObject evalQuestTpl = ((DynamicObject)this.getModel().getValue(HonorStudentConstant.NCKD_EVALQUESTTPL));
+                DynamicObject selectedEvalRule = (DynamicObject) this.getModel().getValue(HonorStudentConstant.NCKD_SELECTEDEVALRULE);
+                DynamicObjectCollection selectedPerson = (DynamicObjectCollection) this.getModel().getValue(HonorStudentConstant.NCKD_SELECTEDPERSON);
 
-            if (selectedPerson.size() > 10) {
-                //选择生成人员超过10人开启异步任务
                 // 1. 创建任务实例
                 JobInfo jobInfo = new JobInfo();
                 jobInfo.setTaskClassname(CreateEvalQuestTask.class.getName());
                 Map<String, Object> params = new HashMap<>();
-                params.put(HonorStudentConstant.NCKD_EVALQUESTTPLID, evalQuestTplId);
+                params.put(HonorStudentConstant.NCKD_EVALQUESTTPL, evalQuestTpl);
                 params.put(HonorStudentConstant.NCKD_SELECTEDEVALRULE, selectedEvalRule);
                 params.put(HonorStudentConstant.NCKD_SELECTEDPERSON, selectedPerson);
                 //调度任务中获取不到当前用户信息
@@ -125,7 +96,13 @@ public class CreateEvalQuestFormPlugin extends AbstractFormPlugin implements Plu
                 // 2. 配置进度界面
                 JobFormInfo formInfo = new JobFormInfo(jobInfo);
                 formInfo.setCaption("生成综合评测问卷进度");
-                formInfo.setCloseCallBack(new CloseCallBack(EvalQuestTplListPlugin.class.getName(), HonorStudentConstant.TASK_CREATEEVAL));
+
+                String billFormId = ((ListView) this.getView().getParentView()).getBillFormId();
+                if(HonorStudentConstant.NCKD_EVALQUESTTPL_ENTITYID.equals(billFormId)) {
+                    formInfo.setCloseCallBack(new CloseCallBack(EvalQuestTplListPlugin.class.getName(), HonorStudentConstant.TASK_CREATEEVAL));
+                }else if(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID.equals(billFormId)) {
+                    formInfo.setCloseCallBack(new CloseCallBack(EvalQuestListPlugin.class.getName(), HonorStudentConstant.TASK_CREATEEVAL));
+                }
                 formInfo.setClickClassName(CreateEvalQuestTaskClick.class.getName());
                 // 允许用户中途取消
                 //formInfo.setCanStop(true);
@@ -134,23 +111,14 @@ public class CreateEvalQuestFormPlugin extends AbstractFormPlugin implements Plu
 
                 // 3. 发布任务并显示进度界面
                 JobForm.dispatch(formInfo, this.getView().getParentView());
-
                 this.getView().close();
-            } else {
-                try {
-                    CreateEvalQuestService.batchGenerateEvalQuest(evalQuestTplId, selectedEvalRule, selectedPerson, null, null, null);
-                    this.getView().getParentView().showSuccessNotification("生成综合评测问卷成功,可在【查看评价列表】中查看");
-                    this.getView().close();
-                } catch (Exception e) {
-                    this.getView().showErrorNotification("生成评价问卷时出错,原因: " + e.getMessage());
-                }
+                logger.info("【优秀生考评】-生成综合评测问卷-开启异步任务");
+                // ------------------------------------- 获取评价对象开启异步生成 end -------------------------------------
+            }else{
+                this.getView().getParentView().invokeOperation(FormConstant.REFRESH);
+                this.getView().getParentView().showSuccessNotification("生成综合评测问卷成功,可在【查看评价列表】中查看");
+                this.getView().close();
             }
-
         }
     }
-
-    @Override
-    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
-        System.out.println();
-    }
 }

+ 148 - 5
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestFormPlugin.java

@@ -2,14 +2,46 @@ package nckd.jxccl.hr.hstu.plugin.form;
 
 import kd.bos.bill.BillShowParameter;
 import kd.bos.bill.OperationStatus;
+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.MainEntityType;
+import kd.bos.entity.operate.OperateOptionConst;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.entity.property.MulBasedataProp;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.FieldTip;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.ShowType;
+import kd.bos.form.control.Button;
+import kd.bos.form.control.EntryGrid;
+import kd.bos.form.control.Toolbar;
+import kd.bos.form.control.events.ItemClickEvent;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.events.ClosedCallBackEvent;
+import kd.bos.form.events.PreOpenFormEventArgs;
 import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
 import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.PerfPlanRoleEnum;
 import nckd.jxccl.base.common.utils.DateUtil;
+import nckd.jxccl.base.org.helper.PersonHelper;
+import nckd.jxccl.hr.hstu.business.CreateEvalQuestService;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
 
+import javax.naming.ldap.Control;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.EventObject;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * 综合测评问卷-表单插件
@@ -19,15 +51,126 @@ import java.util.EventObject;
  */
 public class EvalQuestFormPlugin extends AbstractFormPlugin implements Plugin {
 
+    private final static Log logger = LogFactory.getLog(EvalQuestFormPlugin.class);
+
     @Override
-    public void afterBindData(EventObject e) {
-        super.afterBindData(e);
+    public void beforeBindData(EventObject e) {
+        super.beforeBindData(e);
         BillShowParameter bsp = (BillShowParameter) this.getView().getFormShowParameter();
         if (bsp.getStatus() == OperationStatus.EDIT) {
             //查看状态下不会触发业务规则,需要手动处理业务规则的逻辑
-            DynamicObject evaluationRule = (DynamicObject)this.getModel().getValue("nckd_evaluationrule");
-            Date date = evaluationRule.getDate("NCKD_BIZYEAR");
-            this.getModel().setValue("nckd_bizyear", DateUtil.getYear(date));
+            DynamicObject evaluationRule = (DynamicObject)this.getModel().getValue(HonorStudentConstant.NCKD_EVALUATIONRULE);
+            Date date = evaluationRule.getDate(HonorStudentConstant.NCKD_BIZYEAR);
+            //initValue 方法赋值可避免触发值更新事件(例:检测到您有更改内容,是否不保存直接退出?的检测)
+            this.getModel().initValue(HonorStudentConstant.NCKD_BIZYEAR, DateUtil.getYear(date));
         }
     }
+
+    @Override
+    public void registerListener(EventObject e) {
+        super.registerListener(e);
+        Toolbar toolbar = this.getView().getControl(FormConstant.NCKD_TOOLBARAP);
+        toolbar.addItemClickListener(this);
+    }
+
+    @Override
+    public void itemClick(ItemClickEvent evt) {
+        String itemKey = evt.getItemKey();
+        String operationKey = evt.getOperationKey();
+        if(HonorStudentConstant.OP_NCKD_REFRESHPEERS.equalsIgnoreCase(itemKey)){
+            //刷新同级人员
+            DynamicObject dataEntity = this.getModel().getDataEntity();
+            DynamicObjectCollection dynamicObjectCollection = dataEntity.getDynamicObjectCollection(HonorStudentConstant.NCKD_MULSELECTORG);
+            //弹出选择组织窗口
+            FormShowParameter showParameter = new FormShowParameter();
+            showParameter.setFormId(HonorStudentConstant.NCKD_EVALQUEST_SELECTORG);
+            showParameter.getOpenStyle().setShowType(ShowType.Modal);
+            showParameter.setCloseCallBack(new CloseCallBack(this, HonorStudentConstant.NCKD_EVALQUEST_SELECTORG));
+
+            showParameter.setCaption("同级评分人组织范围选择");
+            this.getView().showForm(showParameter);
+        }
+        System.out.println();
+    }
+
+
+    @Override
+    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
+        String actionId = closedCallBackEvent.getActionId();
+        if(HonorStudentConstant.NCKD_EVALQUEST_SELECTORG.equalsIgnoreCase(actionId)){
+            //------------- 刷新同级人员 begin -------------
+            //获取子页面选择的组织范围
+            DynamicObjectCollection mulSelectOrg = (DynamicObjectCollection)closedCallBackEvent.getReturnData();
+            if(mulSelectOrg != null) {
+                //获取评价规则
+                DynamicObject dataEntity = this.getModel().getDataEntity();
+                DynamicObject evaluationRule = dataEntity.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE);
+                evaluationRule = BusinessDataServiceHelper.loadSingle(evaluationRule.getLong(HonorStudentConstant.ID_KEY), HonorStudentConstant.EVALUATIONRULE_ENTITYID);
+
+                //获取评价对象
+                DynamicObject person = dataEntity.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON);
+                int proportion = evaluationRule.getInt(HonorStudentConstant.NCKD_PROPORTION);
+                int upper = evaluationRule.getInt(HonorStudentConstant.NCKD_UPPER);
+                int lower = evaluationRule.getInt(HonorStudentConstant.NCKD_LOWER);
+                //根据比例计算出的其他部门同级评分人的最小人数(同级评分人下限人数*其他同级评分人比例/100=其他同级评分人下限人数)
+                int otherLower = (lower * proportion) / 100;
+
+                //获取当前分录的数据
+                DynamicObjectCollection entryColl = this.getModel().getEntryEntity(HonorStudentConstant.NCKD_EVALQUESTENTRY);
+                //排除当前已有的领导和上级(避免评分人员重复)
+                List<Long> excludePersonList = entryColl.stream().filter(entry -> !entry.getString(HonorStudentConstant.NCKD_PERFPLANROLE).equals(PerfPlanRoleEnum.PEERS.getCode()))
+                        .map(entry -> entry.getDynamicObject(HonorStudentConstant.NCKD_PERSON).getLong(FormConstant.ID_KEY)).collect(Collectors.toList());
+
+                //获取同级打分人员
+                DynamicObjectCollection freshPeers = CreateEvalQuestService.fetchExpectedScorers(person, mulSelectOrg, excludePersonList, proportion, upper, lower, otherLower, Boolean.FALSE);
+
+                //删除原同级人员
+                entryColl.removeIf(dynamicObject -> dynamicObject.getString(HonorStudentConstant.NCKD_PERFPLANROLE).equals(PerfPlanRoleEnum.PEERS.getCode()));
+                //添加新生成的同级人员
+                entryColl.addAll(freshPeers);
+                //将选择的组织范围持久化到表头中(可以追随从什么组织范围选定的人员)
+                Object[] mulSelectOrgIds = new Object[mulSelectOrg.size()];
+                for (int i = 0; i < mulSelectOrg.size(); i++) {
+                    DynamicObject dynamicObject = mulSelectOrg.get(i);
+                    DynamicObject baseData = dynamicObject.getDynamicObject(FormConstant.BASEDATAID_KEY);
+                    mulSelectOrgIds[i] = baseData.getLong(FormConstant.ID_KEY);
+                }
+                //多选基础资料赋值
+                this.getModel().setValue(HonorStudentConstant.NCKD_MULSELECTORG, mulSelectOrgIds);
+                this.getView().updateView(HonorStudentConstant.NCKD_MULSELECTORG);
+
+
+
+                // 提前同步缓存(平台不建议调用updateEntryCache,因为苍穹平台默认会在所有action请求结束后自动调用updateCache方法,手动调用可能会引发性能问题)。
+                // 但是这里需要提前刷新缓存,确保执行保存前(invokeOperation("save"))数据被刷新能正确保存。该分录数据量不大,出现性能问题的概率不大
+                this.getModel().updateEntryCache(entryColl);
+                //刷新前端分录数据(一定要在刷新缓存后调用,不然会出现数据不一致的问题)
+                this.getView().updateView(HonorStudentConstant.NCKD_EVALQUESTENTRY);
+
+
+                //持久化到数据库
+                OperateOption option = OperateOption.create();
+                option.setVariableValue(OperateOptionConst.ISSHOWMESSAGE, Boolean.FALSE+"");
+                OperationResult operationResult = this.getView().invokeOperation(FormConstant.SAVE_KEY,option);
+                if(operationResult.isSuccess()){
+                    this.getView().showSuccessNotification("刷新同级人员并保存成功,本次更新人员以蓝色标识");
+
+                    //选中以颜色标识,增加体验性
+                    List<Integer> selectRows = new ArrayList<>();
+                    for (int i = 0; i < entryColl.size(); i++) {
+                        DynamicObject dynamicObject = entryColl.get(i);
+                        if(dynamicObject.getLong(FormConstant.ID_KEY) < 1){
+                            selectRows.add(i);
+                        }
+                    }
+                    //更新人员以蓝色背景色标识
+                    EntryGrid entryGrid = this.getControl(HonorStudentConstant.NCKD_EVALQUESTENTRY);
+                    int[] selectedRowArray = selectRows.stream().mapToInt(Integer::intValue).toArray();
+                    entryGrid.setRowBackcolor("#add4ff", selectedRowArray);
+                }
+            }
+            //------------- 刷新同级人员 end -------------
+        }
+    }
+
 }

+ 158 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestListPlugin.java

@@ -0,0 +1,158 @@
+package nckd.jxccl.hr.hstu.plugin.form;
+
+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.db.tx.TX;
+import kd.bos.db.tx.TXHandle;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.entity.MainEntityType;
+import kd.bos.entity.constant.StatusEnum;
+import kd.bos.entity.datamodel.ListSelectedRowCollection;
+import kd.bos.entity.operate.OperateOptionConst;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.exception.KDBizException;
+import kd.bos.form.CloseCallBack;
+import kd.bos.form.ConfirmCallBackListener;
+import kd.bos.form.ConfirmTypes;
+import kd.bos.form.FormShowParameter;
+import kd.bos.form.MessageBoxOptions;
+import kd.bos.form.ShowType;
+import kd.bos.form.control.events.ItemClickEvent;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.ClosedCallBackEvent;
+import kd.bos.form.events.SetFilterEvent;
+import kd.bos.list.plugin.AbstractListPlugin;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.portal.util.SerializationUtils;
+import kd.bos.schedule.api.TaskInfo;
+import kd.bos.schedule.api.TaskStatusConstant;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.bos.servicehelper.user.UserServiceHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.PerfPlanRoleEnum;
+import nckd.jxccl.base.common.exception.ValidationException;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.entity.helper.EntityHelper;
+import nckd.jxccl.base.org.helper.AdminOrgHelper;
+import nckd.jxccl.base.org.helper.PersonHelper;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+* 【优秀生】-综合测评问卷
+* @author W.Y.C
+* @date 2025/7/14 15:39
+* @version 1.0
+*/
+public class EvalQuestListPlugin extends AbstractListPlugin implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(EvalQuestListPlugin.class);
+
+    @Override
+    public void registerListener(EventObject e) {
+        //监听工具栏
+        this.addItemClickListeners(FormConstant.TOOLBARAP);
+
+    }
+    @Override
+    public void itemClick(ItemClickEvent evt) {
+        String itemKey = evt.getItemKey();
+        String operationKey = evt.getOperationKey();
+        if(HonorStudentConstant.OP_CREATEEVAL.equalsIgnoreCase(operationKey)){
+            //获取评价对象
+            ListSelectedRowCollection selectedRows = this.getSelectedRows();
+            FormShowParameter showParameter = new FormShowParameter();
+            showParameter.setFormId(HonorStudentConstant.NCKD_CREATEEVALQUEST_ENTITYID);
+            showParameter.getOpenStyle().setShowType(ShowType.Modal);
+            showParameter.setCloseCallBack(new CloseCallBack(this, HonorStudentConstant.NCKD_CREATEEVALQUEST_ENTITYID));
+            showParameter.setCaption("生成综合测评问卷");
+            this.getView().showForm(showParameter);
+        }
+    }
+
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs e) {
+        String operateKey = e.getOperateKey();
+        boolean success = e.getOperationResult() != null && e.getOperationResult().isSuccess();
+
+        if(HonorStudentConstant.OP_GENERATE_QUEST.equalsIgnoreCase(operateKey) && success) {
+            //生成问卷(答卷) & 执行成功后刷新列表
+            this.getView().invokeOperation(FormConstant.REFRESH);
+            this.getView().showSuccessNotification("生成问卷成功");
+        }else if(HonorStudentConstant.OP_BEGINEVAL.equalsIgnoreCase(operateKey) && success) {
+            //发起评测
+            this.getView().invokeOperation(FormConstant.REFRESH);
+            this.getView().showSuccessNotification("发起评测成功");
+        }else if(HonorStudentConstant.OP_ENDEVAL.equalsIgnoreCase(operateKey) && success) {
+            //结束评测
+            this.getView().invokeOperation(FormConstant.REFRESH);
+            this.getView().showSuccessNotification("结束评测成功");
+        }else if(HonorStudentConstant.OP_GETSCORE.equalsIgnoreCase(operateKey) && success){
+            //获取并更新评分结果
+            this.getView().invokeOperation(FormConstant.REFRESH);
+            this.getView().showSuccessNotification("更新考评结果成功");
+        }
+
+    }
+
+    @Override
+    public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
+        String actionId = closedCallBackEvent.getActionId();
+        if(HonorStudentConstant.TASK_CREATEEVAL.equalsIgnoreCase(actionId)){
+            //生成评价问卷任务完成回调
+            Map<String, Object> result = (Map<String, Object>)closedCallBackEvent.getReturnData();
+            if(result != null) {
+                String taskInfoStr = (String) result.get("taskinfo");
+                if (StringUtils.isNotBlank(taskInfoStr)) {
+                    TaskInfo taskInfo = SerializationUtils.fromJsonString(taskInfoStr, TaskInfo.class);
+                    if (taskInfo.isTaskEnd()) {
+                        String status = taskInfo.getStatus();
+                        if (TaskStatusConstant.COMPLETED.equalsIgnoreCase(status)) {
+                            //刷新列表
+                            this.getView().invokeOperation(FormConstant.REFRESH);
+                            //成功提示
+                            this.getView().showConfirm(
+                                    "成功提示",
+                                    "生成综合评测问卷完成",
+                                    MessageBoxOptions.OK,
+                                    ConfirmTypes.Save,
+                                    new ConfirmCallBackListener()
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setFilter(SetFilterEvent e) {
+        super.setFilter(e);
+        e.setOrderBy("createtime asc");
+    }
+}

+ 44 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestSelectOrg.java

@@ -0,0 +1,44 @@
+package nckd.jxccl.hr.hstu.plugin.form;
+
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.form.control.Control;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+
+import java.util.EventObject;
+
+/**
+* 同级评分人组织范围选择(弹窗)插件
+* @author W.Y.C
+* @date 2025/7/15 14:45
+* @version 1.0
+*/
+public class EvalQuestSelectOrg extends AbstractFormPlugin implements Plugin {
+
+    @Override
+    public void registerListener(EventObject e) {
+        this.addClickListeners(HonorStudentConstant.OP_BTN_OK);
+    }
+
+    @Override
+    public void afterCreateNewData(EventObject e) {
+        super.afterCreateNewData(e);
+        //获取综合评测问卷已选的组织范围赋值到弹窗中
+        DynamicObjectCollection mulSelectOrg = this.getView().getParentView().getModel().getDataEntity().getDynamicObjectCollection(HonorStudentConstant.NCKD_MULSELECTORG);
+        this.getModel().setValue(HonorStudentConstant.NCKD_MULSELECTORG, mulSelectOrg);
+    }
+
+    @Override
+    public void click(EventObject evt) {
+        Control source = (Control) evt.getSource();
+        if (HonorStudentConstant.OP_BTN_OK.equals(source.getKey())) {
+            //获取选择的组织范围
+            DynamicObjectCollection mulSelectOrg = (DynamicObjectCollection)this.getModel().getValue(HonorStudentConstant.NCKD_MULSELECTORG);
+            //将选择的数据返回给父页面
+            this.getView().returnDataToParent(mulSelectOrg);
+            this.getView().close();
+        }
+    }
+
+}

+ 25 - 20
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestTplListPlugin.java

@@ -38,26 +38,28 @@ public class EvalQuestTplListPlugin extends AbstractListPlugin implements Plugin
         String operateKey = ((FormOperate) args.getSource()).getOperateKey();
         if(HonorStudentConstant.OP_CREATEEVAL.equals(operateKey)) {
             ListSelectedRowCollection selectedRows = this.getSelectedRows();
-            if (selectedRows.size() != 1) {
+            /*if (selectedRows.size() != 1) {
                 this.getView().showErrorNotification("请选择一条数据!");
                 args.setCancel(true);
                 return;
-            }
-            DynamicObject basedata = BusinessDataServiceHelper.loadSingle(
-                    selectedRows.get(0).getPrimaryKeyValue(),
-                    HonorStudentConstant.NCKD_EVALQUESTTPL_ENTITYID,
-                    HonorStudentConstant.STATUS+","+HonorStudentConstant.ENABLE
-            );
-            if (basedata != null) {
-                String status = basedata.getString(HonorStudentConstant.STATUS);
-                Boolean enable = basedata.getBoolean(HonorStudentConstant.ENABLE);
+            }*/
+            if(!selectedRows.isEmpty()) {
+                DynamicObject basedata = BusinessDataServiceHelper.loadSingle(
+                        selectedRows.get(0).getPrimaryKeyValue(),
+                        HonorStudentConstant.NCKD_EVALQUESTTPL_ENTITYID,
+                        HonorStudentConstant.STATUS + "," + HonorStudentConstant.ENABLE
+                );
+                if (basedata != null) {
+                    String status = basedata.getString(HonorStudentConstant.STATUS);
+                    Boolean enable = basedata.getBoolean(HonorStudentConstant.ENABLE);
 
-                // 是否可用
-                boolean isAvailable = StatusEnum.C.toString().equals(status) && Boolean.TRUE.equals(enable);
-                if(!isAvailable){
-                    this.getView().showErrorNotification(StrFormatter.format("【{}】该问卷模板状态不可用",selectedRows.get(0).getName()));
-                    args.setCancel(true);
-                    return;
+                    // 是否可用
+                    boolean isAvailable = StatusEnum.C.toString().equals(status) && Boolean.TRUE.equals(enable);
+                    if (!isAvailable) {
+                        this.getView().showErrorNotification(StrFormatter.format("【{}】该问卷模板状态不可用", selectedRows.get(0).getName()));
+                        args.setCancel(true);
+                        return;
+                    }
                 }
             }
         }
@@ -74,17 +76,20 @@ public class EvalQuestTplListPlugin extends AbstractListPlugin implements Plugin
             showParameter.setFormId(HonorStudentConstant.NCKD_CREATEEVALQUEST_ENTITYID);
             showParameter.getOpenStyle().setShowType(ShowType.Modal);
             showParameter.setCloseCallBack(new CloseCallBack(this, HonorStudentConstant.NCKD_CREATEEVALQUEST_ENTITYID));
-            showParameter.setCustomParam(HonorStudentConstant.NCKD_EVALQUESTTPLID,selectedRows.get(0).getPrimaryKeyValue());
-            showParameter.setCaption("批量新增综合测评问卷");
+            if(!selectedRows.isEmpty()) {
+                showParameter.setCustomParam(HonorStudentConstant.NCKD_EVALQUESTTPLID, selectedRows.get(0).getPrimaryKeyValue());
+            }
+            showParameter.setCaption("生成综合测评问卷");
             this.getView().showForm(showParameter);
         }
     }
 
+
     @Override
     public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
         String actionId = closedCallBackEvent.getActionId();
         if(HonorStudentConstant.TASK_CREATEEVAL.equals(actionId)){
-            //生成评价对象任务完成回调
+            //生成评价问卷任务完成回调
             Map<String, Object> result = (Map<String, Object>)closedCallBackEvent.getReturnData();
             if(result != null) {
                 String taskInfoStr = (String) result.get("taskinfo");
@@ -95,7 +100,7 @@ public class EvalQuestTplListPlugin extends AbstractListPlugin implements Plugin
                         String status = taskInfo.getStatus();
                         if (TaskStatusConstant.COMPLETED.equals(status)) {
                             this.getView().showConfirm(
-                                    "成功",
+                                    "成功提示",
                                     "生成综合评测问卷完成,可在【查看评价列表】中查看",
                                     MessageBoxOptions.OK,
                                     ConfirmTypes.Save,

+ 74 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestTreeListPlugin.java

@@ -0,0 +1,74 @@
+package nckd.jxccl.hr.hstu.plugin.form;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.bos.list.events.BuildTreeListFilterEvent;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.hr.hbp.business.dao.factory.HRBaseDaoFactory;
+import kd.hr.hbp.common.constants.org.OrgTreeDynEnum;
+import kd.hr.hbp.common.util.org.model.OrgTreeModel;
+import kd.hr.hbp.formplugin.web.org.template.AdminOrgTreeListTemplate;
+import kd.sdk.hr.hspm.common.utils.PropertyHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.utils.ConvertUtil;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+
+import java.util.EventObject;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+* 【优秀生】-综合测评问卷左树右表
+* @author W.Y.C
+* @date 2025/7/15 20:33
+* @version 1.0
+*/
+public class EvalQuestTreeListPlugin extends AdminOrgTreeListTemplate {
+
+    public EvalQuestTreeListPlugin() {
+        super(new OrgTreeModel(OrgTreeDynEnum.ADMIN_STRUCT.getDynEntity(), OrgTreeDynEnum.ADMIN_MAIN_ENTITY.getDynEntity(), Boolean.TRUE, Boolean.TRUE, Boolean.FALSE));
+    }
+
+    @Override
+    public void afterBindData(EventObject e) {
+        super.afterBindData(e);
+        this.getView().setVisible(false, FormConstant.SEARCH_DATE_KEY);
+    }
+
+    @Override
+    public void afterCreateNewData(EventObject e) {
+        //设置默认开启包含子部门
+        DynamicObject dynamicObject = this.getModel().getDataEntity();
+        if(PropertyHelper.existProperty(dynamicObject, FormConstant.CHKINCLUDECHILD)) {
+            this.getModel().setValue(FormConstant.CHKINCLUDECHILD, Boolean.TRUE);
+        }
+    }
+
+    @Override
+    protected QFilter buildNodeClickFilter(BuildTreeListFilterEvent buildTreeListFilterEvent) {
+        String focusNodeId = buildTreeListFilterEvent.getNodeId().toString();
+        QFilter nodeClickFilter = null;
+        if(!this.getTreeModel().getRoot().getId().equalsIgnoreCase(focusNodeId)){
+
+            QFilter focusNodeIdFilter = new QFilter("adminorg.id", QCP.equals, Long.valueOf(focusNodeId));
+            Boolean chkIncludeChild = ConvertUtil.toBoolean(this.getModel().getValue(FormConstant.CHKINCLUDECHILD));
+            //是否包含子部门
+            if(chkIncludeChild) {
+                DynamicObject structlongnumber = HRBaseDaoFactory.getInstance(this.getEntityName()).queryOne("structlongnumber", new QFilter[]{QFilterCommonHelper.getCurrentVersionFilter(), QFilterCommonHelper.getInitStatusFinishFilter(),
+                        QFilterCommonHelper.getDataStatusFilter(), focusNodeIdFilter});
+                String focusNodeLongNumber = (String) structlongnumber.get("structlongnumber");
+                QFilter filter = new QFilter("structlongnumber", QCP.like, focusNodeLongNumber + "%");
+                DynamicObjectCollection dynamicObjects = HRBaseDaoFactory.getInstance(this.getEntityName()).queryColl("adminorg.id adminorg", new QFilter[]{filter, QFilterCommonHelper.getCurrentVersionFilter(), QFilterCommonHelper.getInitStatusFinishFilter()}, null);
+                Set<Long> ids = new HashSet<>(dynamicObjects.size());
+                dynamicObjects.forEach(dynamicObject -> ids.add(dynamicObject.getLong("adminorg")));
+                nodeClickFilter = new QFilter("nckd_evalperson.adminorg.id", QCP.in, ids);
+            }else{
+                nodeClickFilter = new QFilter("nckd_evalperson.adminorg.id", QCP.in, ConvertUtil.toLong(focusNodeId));
+            }
+        }
+        return nodeClickFilter;
+    }
+}

+ 40 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalResultFormPlugin.java

@@ -0,0 +1,40 @@
+package nckd.jxccl.hr.hstu.plugin.form;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.constant.StatusEnum;
+import kd.bos.form.control.Button;
+import kd.bos.form.control.Control;
+import kd.bos.form.control.Toolbar;
+import kd.bos.form.control.events.ClickListener;
+import kd.bos.form.control.events.ItemClickEvent;
+import kd.bos.form.control.events.ItemClickListener;
+import kd.bos.form.events.AfterDoOperationEventArgs;
+import kd.bos.form.events.BeforeDoOperationEventArgs;
+import kd.bos.form.operate.FormOperate;
+import kd.bos.form.plugin.AbstractFormPlugin;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+
+import java.util.EventObject;
+
+/**
+* 【优秀生】-综合测评答卷
+* @author W.Y.C
+* @date 2025/7/31 15:05
+* @version 1.0
+*/
+public class EvalResultFormPlugin extends AbstractFormPlugin implements Plugin {
+
+
+    @Override
+    public void beforeDoOperation(BeforeDoOperationEventArgs e) {
+        String operateKey = ((FormOperate) e.getSource()).getOperateKey();
+        if(FormConstant.OP_AUDIT.equals(operateKey)){
+            DynamicObject dataEntity = this.getModel().getDataEntity();
+            DynamicObjectCollection entrys = dataEntity.getDynamicObjectCollection(HonorStudentConstant.NCKD_EVALRESULTENTRY);
+            System.out.println();
+        }
+    }
+}

+ 0 - 12
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvaluationRuleListPlugin.java

@@ -99,16 +99,4 @@ public class EvaluationRuleListPlugin extends AbstractListPlugin implements Plug
             //TODO 校验规则是否被使用
         }
     }
-
-    @Override
-    public void afterDoOperation(AfterDoOperationEventArgs e) {
-        super.afterDoOperation(e);
-        FormOperate operate = (FormOperate) e.getSource();
-        String operateKey = operate.getOperateKey();
-        if(OP_BEGIN.equals(operateKey)) {
-            //设置开始时间为当前时间
-        }else if(OP_END.equals(operateKey)){
-            //标记结束:触发->禁用,判断是否存在未评分的评价对象;设置结束时间
-        }
-    }
 }

+ 0 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/.gitkeep


+ 96 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/CreateQvalQuestAffirmOperationPlugin.java

@@ -0,0 +1,96 @@
+package nckd.jxccl.hr.hstu.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.operate.result.OperateErrorInfo;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.args.BeforeOperationArgs;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.entity.validate.ErrorLevel;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+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.exception.ValidationException;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.hr.hstu.business.CreateEvalQuestService;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+* 【优秀生】-获取评价对象插件
+* @author W.Y.C
+* @date 2025/8/15 16:11
+* @version 1.0
+*/
+public class CreateQvalQuestAffirmOperationPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(CreateQvalQuestAffirmOperationPlugin.class);
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        super.onAddValidators(e);
+    }
+
+    @Override
+    public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
+        logger.info("【优秀生考评】-生成综合评测问卷-开始");
+        DynamicObject[] data = e.getDataEntities();
+        if(data == null || data.length == 0){
+            e.setCancel(true);
+            e.setCancelMessage("请选择要获取问卷的数据");
+            return;
+        }
+        DynamicObject evalQuestTpl = data[0].getDynamicObject(HonorStudentConstant.NCKD_EVALQUESTTPL);
+        DynamicObject selectedEvalRule = data[0].getDynamicObject(HonorStudentConstant.NCKD_SELECTEDEVALRULE);
+        DynamicObjectCollection selectedPerson = data[0].getDynamicObjectCollection(HonorStudentConstant.NCKD_SELECTEDPERSON);
+        //------------ 校验是否已生成过问卷(校验规则:评价对象是否已经有对应的评价规则或模板问卷) begin ------------
+        List<Long> idList = new ArrayList<>();
+        selectedPerson.forEach(map ->{
+            DynamicObject depEmpRow = (DynamicObject)map.getDynamicObject(FormConstant.BASEDATAID_KEY);
+            idList.add(depEmpRow.getLong(HonorStudentConstant.ID_KEY));
+        });
+        logger.info("【优秀生考评】-生成综合评测问卷-选择的问卷模板ID:{}",evalQuestTpl.getLong(FormConstant.ID_KEY));
+        logger.info("【优秀生考评】-生成综合评测问卷-选择的评价规则ID:{}",selectedEvalRule.getLong(HonorStudentConstant.ID_KEY));
+        logger.info("【优秀生考评】-生成综合评测问卷-选择的人员ID:{}",idList.stream().map(String::valueOf).collect(Collectors.joining(",")));
+        QFilter filter = new QFilter(HonorStudentConstant.NCKD_EVALPERSON, QCP.in, idList);
+        filter.and(
+                new QFilter(HonorStudentConstant.NCKD_EVALUATIONRULE,QCP.equals,selectedEvalRule.getLong(HonorStudentConstant.ID_KEY))
+                        .or(new QFilter(HonorStudentConstant.NCKD_EVALQUESTTPL,QCP.equals,evalQuestTpl.getLong(FormConstant.ID_KEY)))
+        );
+        DynamicObjectCollection evalQuestColl = QueryServiceHelper.query(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID,HonorStudentConstant.NCKD_EVALPERSON+".person.name",new QFilter[]{filter});
+        if(!evalQuestColl.isEmpty()){
+            StringJoiner exitsPersonName = new StringJoiner(",");
+            evalQuestColl.forEach(dynamicObject -> exitsPersonName.add(dynamicObject.getString(HonorStudentConstant.NCKD_EVALPERSON+".person.name")));
+            String format = StrFormatter.format("下列人员已存在问卷:{};不能重复生成,请检查!", exitsPersonName.toString());
+            logger.warn("【优秀生考评】-生成综合评测问卷-业务校验异常:{}",format);
+            e.setCancel(true);
+            e.setCancelMessage( format);
+
+        }
+        //------------ 校验是否已生成过问卷(校验规则:评价对象是否已经有对应的评价规则或模板问卷) end ------------
+    }
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+
+        DynamicObject[] data = e.getDataEntities();
+        DynamicObject evalQuestTpl = data[0].getDynamicObject(HonorStudentConstant.NCKD_EVALQUESTTPL);
+        DynamicObject selectedEvalRule = data[0].getDynamicObject(HonorStudentConstant.NCKD_SELECTEDEVALRULE);
+        DynamicObjectCollection selectedPerson = data[0].getDynamicObjectCollection(HonorStudentConstant.NCKD_SELECTEDPERSON);
+        if (selectedPerson.size() > 10) {
+            // 选择生成人员超过10人开启异步任务
+            this.getOption().setVariableValue("task","true");
+        } else {
+            CreateEvalQuestService.batchGenerateEvalQuest(evalQuestTpl, selectedEvalRule, selectedPerson, null, null, null);
+        }
+    }
+}

+ 138 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestBeginEvalOperationPlugin.java

@@ -0,0 +1,138 @@
+package nckd.jxccl.hr.hstu.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.db.tx.TX;
+import kd.bos.db.tx.TXHandle;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.exception.ValidationException;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+import nckd.jxccl.hr.hstu.plugin.form.EvalQuestListPlugin;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+* 【优秀生】-综合测评问卷-发起评测操作插件
+* @author W.Y.C
+* @date 2025/8/15 16:58
+* @version 1.0
+*/
+public class EvalQuestBeginEvalOperationPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(EvalQuestBeginEvalOperationPlugin.class);
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+
+        DynamicObject[] selectedRows = e.getDataEntities();
+        if (selectedRows != null && selectedRows.length > 0) {
+            List<Long> selectedRowIds = new ArrayList<>(selectedRows.length);
+            for (DynamicObject row : selectedRows) {
+                // 获取单据ID(主键)
+                Long id = (Long) row.getPkValue();
+                selectedRowIds.add(id);
+            }
+            beginEval(selectedRowIds);
+        }
+    }
+
+
+    /**
+     * 发起评测
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/07/23 17:20
+     */
+    private void beginEval(List<Long> selectedRowIds) {
+        logger.info("【优秀生考评】-发起评测-开始");
+        //查询问卷信息
+        HonorStudentHelper.Result result = HonorStudentHelper.getEvalQuest(selectedRowIds);
+        logger.info("【优秀生考评】-发起评测-选择的问卷ID:{}",result.selectedRowIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
+        // ===================== 1.校验状态 =====================
+        StringJoiner errorJoin = new StringJoiner("\n");
+        Arrays.stream(result.evalQuestArray).forEach(evalQuest -> {
+            String periodState = evalQuest.getString(HonorStudentConstant.NCKD_PERIODSTATE);
+            if(!periodState.equals("3")){
+                DynamicObject person = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.PERSON);
+                errorJoin.add(StrFormatter.format("评价对象【{}】的测评状态非【已就绪】状态,只有【已就绪】状态的才能发起测评",person.getString(FormConstant.NAME_KEY)));
+            }
+        });
+        if(errorJoin.length() > 0){
+            logger.warn("【优秀生考评】-发起评测-业务校验异常:{}",errorJoin.toString());
+            throw new ValidationException(errorJoin.toString());
+        }
+
+        // ===================== 2.更新问卷状态 & 地区差异分(地区差异分 * 评价规则.地区差异权重占比 * 0.01) & 更新未评分人数 =====================
+        List<Long> ruleIds = Arrays.stream(result.evalQuestArray).map(evalQuest -> evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE).getLong(FormConstant.ID_KEY)).collect(Collectors.toList());
+        StringJoiner ruleColum = new StringJoiner(",");
+        ruleColum.add(FormConstant.ID_KEY);
+        //地区差异权重占比(%)
+        ruleColum.add(HonorStudentConstant.NCKD_DIFFPROPORTION);
+        //查询评价规则
+        DynamicObject[] ruleArray = BusinessDataServiceHelper.load(HonorStudentConstant.EVALUATIONRULE_ENTITYID, ruleColum.toString(), new QFilter[]{QFilterCommonHelper.getIdInFilter(ruleIds)});
+        Map<Long, Integer> ruleMap = Arrays.stream(ruleArray)
+                .collect(Collectors.toMap(
+                        rule -> rule.getLong(FormConstant.ID_KEY),
+                        rule -> rule.getInt(HonorStudentConstant.NCKD_DIFFPROPORTION),
+                        (existingValue, replacementValue) -> existingValue
+                ));
+
+        for (DynamicObject evalQuest : result.evalQuestArray) {
+            //问卷修改为进行中
+            evalQuest.set(HonorStudentConstant.NCKD_PERIODSTATE,"1");
+            //HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.PERSON+"."+FormConstant.NAME_KEY
+            Long evalPersonId = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.PERSON).getLong(FormConstant.ID_KEY);
+            String evalPersonName = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.PERSON).getString(FormConstant.NAME_KEY);
+            //地区差异分(地区差异分 * 评价规则.地区差异权重占比 * 0.01)
+            long adminId = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.ADMINORG).getLong(FormConstant.ID_KEY);
+            String adminName = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.ADMINORG).getString(FormConstant.NAME_KEY);
+            Integer orgDifference = HonorStudentHelper.getOrgDifference(adminId);
+            if(orgDifference != null){
+                long ruleId = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALUATIONRULE).getLong(HonorStudentConstant.ID_KEY);
+                Integer diffProportion = ruleMap.get(ruleId);
+                double differenceScore = orgDifference * (diffProportion == null ? 0 : diffProportion) * 0.01;
+                evalQuest.set(HonorStudentConstant.NCKD_DIFFERENCESCORE,differenceScore);
+                logger.info("【优秀生考评】-发起评测-评价对象【{}({})】-部门【{}({})】-地区差异权重占比:{},地区差异分:{},换算后:{}",evalPersonName,evalPersonId,adminName,adminId,diffProportion,orgDifference,differenceScore);
+            }else{
+                logger.info("【优秀生考评】-发起评测-评价对象【{}({})】-部门【{}({})】-无地区差异分",evalPersonName,evalPersonId,adminName,adminId);
+            }
+
+            //更新:已评分人员、未评分人数
+            long evalQuestId = evalQuest.getLong(FormConstant.ID_KEY);
+            Integer questScorePersonCount = HonorStudentHelper.getQuestScorePersonCount(evalQuestId);
+            Integer quesNotScorePersonCount = HonorStudentHelper.getQuestNotScorePersonCount(evalQuestId);
+            evalQuest.set(HonorStudentConstant.NCKD_HAVEDO,questScorePersonCount);
+            evalQuest.set(HonorStudentConstant.NCKD_NODO,quesNotScorePersonCount);
+        }
+
+
+        // ===================== 3.更新答卷状态(答卷修改为:待评分) =====================
+        DynamicObject[] evalResultArray = BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_EVALRESULT_ENTITYID,
+                "id,nckd_perfplanstate",
+                new QFilter[]{new QFilter(HonorStudentConstant.NCKD_EVALQUEST, QCP.in, result.selectedRowIds)});
+        for (DynamicObject evalResult : evalResultArray) {
+            //答卷修改为待评分
+            evalResult.set(HonorStudentConstant.NCKD_PERFPLANSTATE,"1");
+        }
+
+        SaveServiceHelper.update(result.evalQuestArray);
+        SaveServiceHelper.update(evalResultArray);
+        logger.info("【优秀生考评】-发起评测-完成");
+    }
+}

+ 116 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestEndEvalOperationPlugin.java

@@ -0,0 +1,116 @@
+package nckd.jxccl.hr.hstu.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.db.tx.TX;
+import kd.bos.db.tx.TXHandle;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.exception.ValidationException;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+* 【优秀生】-综合测评问卷-结束评测操作插件
+* @author W.Y.C
+* @date 2025/8/15 16:58
+* @version 1.0
+*/
+public class EvalQuestEndEvalOperationPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(EvalQuestEndEvalOperationPlugin.class);
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+
+        DynamicObject[] selectedRows = e.getDataEntities();
+        if (selectedRows != null && selectedRows.length > 0) {
+            List<Long> selectedRowIds = new ArrayList<>(selectedRows.length);
+            for (DynamicObject row : selectedRows) {
+                // 获取单据ID(主键)
+                Long id = (Long) row.getPkValue();
+                selectedRowIds.add(id);
+            }
+            endEval(selectedRowIds);
+        }
+    }
+
+
+    /**
+     * 结束评测
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/07/23 21:15
+     */
+    private void endEval(List<Long> selectedRowIds) {
+        logger.info("【优秀生考评】-结束评测-开始");
+        //查询问卷信息
+        HonorStudentHelper.Result result = HonorStudentHelper.getEvalQuest(selectedRowIds);
+        logger.info("【优秀生考评】-结束评测-选择的问卷ID:{}",result.selectedRowIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
+        // ===================== 1.校验状态 =====================
+        StringJoiner errorJoin = new StringJoiner("\n");
+        Arrays.stream(result.evalQuestArray).forEach(evalQuest -> {
+            String periodState = evalQuest.getString(HonorStudentConstant.NCKD_PERIODSTATE);
+            if(!periodState.equals("1")){
+                DynamicObject person = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.PERSON);
+                errorJoin.add(StrFormatter.format("评价对象【{}】的测评状态非【进行中】状态,只有【进行中】状态的才能结束测评",person.getString(FormConstant.NAME_KEY)));
+            }
+        });
+        if(errorJoin.length() > 0){
+            logger.warn("【优秀生考评】-结束评测-业务校验异常:{}",errorJoin.toString());
+            throw new ValidationException(errorJoin.toString());
+        }
+
+        //===================== 2.判断是否存在未评分的评价对象 =====================
+        DynamicObject[] questNotScorePerson = HonorStudentHelper.getQuestNotScorePerson(result.selectedRowIds.toArray(new Long[0]));
+        if(questNotScorePerson.length > 0){
+            errorJoin.add("未完成所有评分不能结束,以下评价对象未完成所有评分:");
+            Map<String, List<String>> personMap = new HashMap<>();
+            Arrays.stream(questNotScorePerson).forEach(evalResult -> {
+                String personName = evalResult.getDynamicObject(HonorStudentConstant.NCKD_PERSON).getDynamicObject(FormConstant.PERSON).getString(FormConstant.NAME_KEY);
+                String scorerName = evalResult.getDynamicObject(HonorStudentConstant.NCKD_SCORER).getDynamicObject(FormConstant.PERSON).getString(FormConstant.NAME_KEY);
+                personMap.computeIfAbsent(personName, k -> new ArrayList<>()).add(scorerName);
+            });
+            for (Map.Entry<String, List<String>> personListEntry : personMap.entrySet()) {
+                errorJoin.add(StrFormatter.format("评价对象【{}】-未完成评分人:{}",personListEntry.getKey(), StringUtils.join(personListEntry.getValue(),",")));
+            }
+            logger.warn("【优秀生考评】-结束评测-业务校验异常:{}",errorJoin.toString());
+            throw new ValidationException(errorJoin.toString());
+        }
+        //更新问卷状态为:已结束:2
+        for (DynamicObject evalQuest : result.evalQuestArray) {
+            //问卷修改为已结束
+            evalQuest.set(HonorStudentConstant.NCKD_PERIODSTATE,"2");
+        }
+
+        //===================== 3.更新答卷状态为:已结束:3 =====================
+        DynamicObject[] evalResultArray = BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_EVALRESULT_ENTITYID,
+                "id,nckd_perfplanstate",
+                new QFilter[]{new QFilter(HonorStudentConstant.NCKD_EVALQUEST, QCP.in, result.selectedRowIds)});
+        for (DynamicObject evalResult : evalResultArray) {
+            //答卷修改为已结束
+            evalResult.set(HonorStudentConstant.NCKD_PERFPLANSTATE,"3");
+        }
+        SaveServiceHelper.update(result.evalQuestArray);
+        SaveServiceHelper.update(evalResultArray);
+        logger.info("【优秀生考评】-结束评测-结束");
+    }
+}

+ 281 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestGenerateQuestOperationPlugin.java

@@ -0,0 +1,281 @@
+package nckd.jxccl.hr.hstu.plugin.operate;
+
+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.db.tx.TX;
+import kd.bos.db.tx.TXHandle;
+import kd.bos.entity.EntityMetadataCache;
+import kd.bos.entity.MainEntityType;
+import kd.bos.entity.constant.StatusEnum;
+import kd.bos.entity.operate.OperateOptionConst;
+import kd.bos.entity.operate.result.IOperateInfo;
+import kd.bos.entity.operate.result.OperationResult;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.exception.KDBizException;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.bos.orm.query.QCP;
+import kd.bos.orm.query.QFilter;
+import kd.bos.servicehelper.BusinessDataServiceHelper;
+import kd.bos.servicehelper.QueryServiceHelper;
+import kd.bos.servicehelper.operation.SaveServiceHelper;
+import kd.bos.servicehelper.user.UserServiceHelper;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.base.common.enums.PerfPlanRoleEnum;
+import nckd.jxccl.base.common.exception.ValidationException;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.base.entity.helper.EntityHelper;
+import nckd.jxccl.base.org.helper.AdminOrgHelper;
+import nckd.jxccl.base.org.helper.PersonHelper;
+import nckd.jxccl.base.orm.helper.QFilterCommonHelper;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+/**
+* 【优秀生】-综合测评问卷-生成问卷操作插件
+* @author W.Y.C
+* @date 2025/8/15 15:28
+* @version 1.0
+*/
+public class EvalQuestGenerateQuestOperationPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(EvalQuestGenerateQuestOperationPlugin.class);
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+        // 获取选中行数据(DynamicObject数组)
+        DynamicObject[] selectedRows = e.getDataEntities();
+        if (selectedRows != null && selectedRows.length > 0) {
+            List<Long> selectedRowIds = new ArrayList<>(selectedRows.length);
+            for (DynamicObject row : selectedRows) {
+                // 获取单据ID(主键)
+                Long id = (Long) row.getPkValue();
+                selectedRowIds.add(id);
+            }
+            generateQuest(selectedRowIds);
+        }
+    }
+
+    /**
+     * 生成问卷
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/07/22 11:25
+     */
+   private void generateQuest(List<Long> selectedRowIds) {
+        logger.info("【优秀生考评】-生成问卷-开始,选择的问卷ID:{}",selectedRowIds.stream().map(String::valueOf).collect(Collectors.joining(",")));
+        StringJoiner fields = new StringJoiner(",");
+        fields.add(FormConstant.ID_KEY);
+        //评测状态
+        fields.add(HonorStudentConstant.NCKD_PERIODSTATE);
+        //问卷模板
+        fields.add(HonorStudentConstant.NCKD_EVALQUESTTPL+"."+FormConstant.ID_KEY);
+        //被评价人
+        fields.add(HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.PERSON+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_EVALPERSON+"."+FormConstant.PERSON+"."+FormConstant.NAME_KEY);
+        //分录
+        fields.add(HonorStudentConstant.NCKD_EVALQUESTENTRY+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_EVALQUESTENTRY+"."+HonorStudentConstant.NCKD_PERSON+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_EVALQUESTENTRY+"."+HonorStudentConstant.NCKD_PERSON+"."+HonorStudentConstant.PERSON+"."+FormConstant.ID_KEY);
+        fields.add(HonorStudentConstant.NCKD_EVALQUESTENTRY+"."+HonorStudentConstant.NCKD_PERFPLANROLE);
+        DynamicObject[] evalQuestArray = BusinessDataServiceHelper.load(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID,
+                fields.toString(),
+                new QFilter[]{QFilterCommonHelper.getIdInFilter(selectedRowIds)});
+
+        // 1.校验状态
+        StringJoiner errorJoin = new StringJoiner("\n");
+        Arrays.stream(evalQuestArray).forEach(evalQuest -> {
+            String periodState = evalQuest.getString(HonorStudentConstant.NCKD_PERIODSTATE);
+            if(!periodState.equals("0")){
+                DynamicObject person = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.PERSON);
+                errorJoin.add(StrFormatter.format("评价对象【{}】的测评状态非【未开始】,只有【未开始】状态的才能生成问卷",person.getString(FormConstant.NAME_KEY)));
+            }
+        });
+        if(errorJoin.length() > 0){
+            logger.warn("【优秀生考评】-生成问卷-业务校验异常:{}",errorJoin.toString());
+            throw new ValidationException(errorJoin.toString());
+        }
+
+        // 2.校验打分人是否有领导和上级
+        validateEvaluatorRoles(evalQuestArray);
+
+        // 3.构建并保存答卷
+        buildAndSaveEvalResult(evalQuestArray);
+
+        logger.info("【优秀生考评】-生成问卷-完成");
+    }
+
+    /**
+     * 校验评分人是否有领导和上级评分人
+     * @param load 选择的问卷
+     * @return: java.lang.String
+     * @author W.Y.C
+     * @date: 2025/07/16 16:19
+     */
+    private static void validateEvaluatorRoles(DynamicObject[] load) throws ValidationException {
+        StringJoiner errorMsg = new StringJoiner("\n");
+        Arrays.stream(load).forEach(dynamicObject -> {
+            DynamicObject person = dynamicObject.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON).getDynamicObject(FormConstant.PERSON);
+            DynamicObjectCollection entryColl = dynamicObject.getDynamicObjectCollection(HonorStudentConstant.NCKD_EVALQUESTENTRY);
+
+            long leadCount = entryColl.stream()
+                    .filter(entry -> PerfPlanRoleEnum.LEAD.getCode().equals(entry.getString(HonorStudentConstant.NCKD_PERFPLANROLE)))
+                    .count();
+
+            long superiorCount = entryColl.stream()
+                    .filter(entry -> PerfPlanRoleEnum.SUPERIOR.getCode().equals(entry.getString(HonorStudentConstant.NCKD_PERFPLANROLE)))
+                    .count();
+
+            if (leadCount < 1) {
+                errorMsg.add(StrFormatter.format(
+                        "评价对象【{}】缺少领导评分人",
+                        person.getString(FormConstant.NAME_KEY)));
+            }
+
+            if (superiorCount < 1) {
+                errorMsg.add(StrFormatter.format(
+                        "评价对象【{}】缺少上级评分人",
+                        person.getString(FormConstant.NAME_KEY)));
+            }
+        });
+        if(errorMsg.length() > 0){
+            logger.warn("【优秀生考评】-生成问卷-业务校验异常:{}",errorMsg.toString());
+            throw new ValidationException(errorMsg.toString());
+        }
+    }
+
+    /**
+     * 构建并保存答卷
+     * @param evalQuestArray 问卷列表
+     * @return: void
+     * @author W.Y.C
+     * @date: 2025/07/16 20:38
+     */
+    private void buildAndSaveEvalResult(DynamicObject[] evalQuestArray) throws KDBizException {
+        Long currUserId =  RequestContext.get().getCurrUserId();
+        Long currOrgId =  RequestContext.get().getOrgId();
+        //当前登录用户
+        DynamicObject currUser = UserServiceHelper.getUserInfoByID(currUserId, HonorStudentConstant.ID_KEY);
+
+        // 获取苍穹平台组织实体元数据
+        MainEntityType bosOrgEntityType = EntityMetadataCache.getDataEntityType(AdminOrgHelper.BOS_ORG);
+        // 基于元数据创建 DynamicObject
+        DynamicObject org = new DynamicObject(bosOrgEntityType);
+        org.set(FormConstant.ID_KEY,currOrgId);
+
+
+        //获取所有问卷模板
+        Set<Long> evalQuestTplSet = new HashSet<>();
+        Map<Long,List<DynamicObject>> evalQuestTplMap = new HashMap<>();
+        Arrays.stream(evalQuestArray).forEach(evalQuest -> {
+            long evalQuestTplId = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALQUESTTPL).getLong(FormConstant.ID_KEY);
+            evalQuestTplSet.add(evalQuestTplId);
+        });
+        DynamicObjectCollection evalQuestTplColl = QueryServiceHelper.query(HonorStudentConstant.NCKD_EVALQUESTTPL_ENTITYID,"id,NCKD_EVALQUESTTPLENTRY.*",new QFilter[]{new QFilter(FormConstant.ID_KEY, QCP.in,evalQuestTplSet)});
+        for (DynamicObject evalQuestTpl : evalQuestTplColl) {
+            long id = evalQuestTpl.getLong(HonorStudentConstant.ID_KEY);
+            evalQuestTplMap.computeIfAbsent(id, k -> new ArrayList<>()).add(evalQuestTpl);
+        }
+
+        //构建答卷
+        MainEntityType depEmpEntityType = EntityMetadataCache.getDataEntityType(PersonHelper.DEP_EMP_ENTITY_ID);
+        MainEntityType evalQuestTplEntryEntityType = EntityMetadataCache.getDataEntityType(HonorStudentConstant.NCKD_EVALQUESTTPLENTRYBAS_ENTITYID);
+        List<DynamicObject> evalResultToSaveList = new ArrayList<>();
+        Arrays.stream(evalQuestArray).forEach(evalQuest -> {
+            //评价对象
+            DynamicObject evalPerson = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALPERSON);
+            //循环评分人
+            DynamicObjectCollection entryColl = evalQuest.getDynamicObjectCollection(HonorStudentConstant.NCKD_EVALQUESTENTRY);
+            entryColl.forEach(entry -> {
+                //获取分录数据
+                long entryId = entry.getLong(FormConstant.ID_KEY);
+                DynamicObject personDynamicObject = QueryServiceHelper.queryOne(HonorStudentConstant.NCKD_EVALQUEST_ENTITYID,
+                        HonorStudentConstant.NCKD_EVALQUESTENTRY+"."+HonorStudentConstant.NCKD_PERSON+"."+FormConstant.ID_KEY+" personId",
+                        new QFilter[]{new QFilter(HonorStudentConstant.NCKD_EVALQUESTENTRY+"."+FormConstant.ID_KEY, QCP.equals, entryId)});
+                //评分人
+                long scorerId = personDynamicObject.getLong("personId");
+
+                DynamicObject buildEvalResult = EntityHelper.newAvailableBasicEntity(HonorStudentConstant.NCKD_EVALRESULT_ENTITYID);
+                buildEvalResult.set(FormConstant.STATUS, StatusEnum.B.toString());
+                buildEvalResult(evalQuest,entry, buildEvalResult, evalPerson, depEmpEntityType, scorerId);
+
+                //构建答卷分录
+                DynamicObjectCollection entryEntity = buildEvalResult.getDynamicObjectCollection(HonorStudentConstant.NCKD_EVALRESULTENTRY);
+                long evalQuestTplId = evalQuest.getDynamicObject(HonorStudentConstant.NCKD_EVALQUESTTPL).getLong(FormConstant.ID_KEY);
+                List<DynamicObject> evalQuestTplList = evalQuestTplMap.get(evalQuestTplId);
+                if (evalQuestTplList != null) {
+                    evalQuestTplList.sort(Comparator.comparingInt(
+                            obj -> obj.getInt("nckd_evalquesttplentry.seq")
+                    ));
+                    for (DynamicObject evalQuestTpl : evalQuestTplList) {
+                        DynamicObject resultEntry = entryEntity.addNew();
+                        long evalQuestTplEntryId = evalQuestTpl.getLong("nckd_evalquesttplentry.id");
+                        DynamicObject evalQuestTplEntry = new DynamicObject(evalQuestTplEntryEntityType);
+                        evalQuestTplEntry.set(FormConstant.ID_KEY, evalQuestTplEntryId);
+                        resultEntry.set(HonorStudentConstant.NCKD_EVALQUESTTPLENTRY,evalQuestTplEntry);
+
+                    }
+                }
+                evalResultToSaveList.add(buildEvalResult);
+            });
+        });
+        OperateOption option = OperateOption.create();
+        // 忽消息提示
+        option.setVariableValue(OperateOptionConst.ISSHOWMESSAGE, Boolean.TRUE.toString());
+        //开启事务确保事务一致性
+        try (TXHandle t = TX.required(HonorStudentConstant.OP_GENERATE_QUEST)) {
+            try {
+                OperationResult operationResult = SaveServiceHelper.saveOperate(FormConstant.SAVE_KEY,HonorStudentConstant.NCKD_EVALQUEST_ENTITYID, evalResultToSaveList.toArray(new DynamicObject[0]), option);
+                if (!operationResult.isSuccess()) {
+                    StringJoiner errorMsg = new StringJoiner("\n");
+                    for (IOperateInfo error : operationResult.getAllErrorOrValidateInfo()) {
+                        errorMsg.add(error.getMessage());
+                    }
+                    logger.warn("【优秀生考评】-生成问卷-业务异常:{}",errorMsg.toString());
+                    throw new ValidationException(errorMsg.toString());
+                }
+                //修改问卷状态
+                for (DynamicObject evalQuest : evalQuestArray) {
+                    //问卷修改为就绪状态
+                    evalQuest.set(HonorStudentConstant.NCKD_PERIODSTATE,"3");
+                }
+                SaveServiceHelper.update(evalQuestArray);
+            } catch (Throwable e) {
+                logger.error("【优秀生考评】-生成问卷-系统异常:{}",e);
+                // 异常回滚
+                t.markRollback();
+                throw e;
+            }
+        }
+
+    }
+
+    private static void buildEvalResult(DynamicObject evalQuest,DynamicObject evalQuestEntry, DynamicObject mainObj, DynamicObject evalPerson, MainEntityType depEmpEntityType, long scorerId) {
+        //评价对象
+        mainObj.set(HonorStudentConstant.NCKD_PERSON, evalPerson);
+        //评分人
+        DynamicObject scorerPerson = new DynamicObject(depEmpEntityType);
+        scorerPerson.set(FormConstant.ID_KEY, scorerId);
+        mainObj.set(HonorStudentConstant.NCKD_SCORER, scorerPerson);
+        //对应问卷
+        mainObj.set(HonorStudentConstant.NCKD_EVALQUEST, evalQuest);
+        mainObj.set(HonorStudentConstant.NCKD_EVALQUESTENTRY, evalQuestEntry);
+        //评分状态
+        mainObj.set(HonorStudentConstant.NCKD_PERFPLANSTATE, "0");
+    }
+}

+ 33 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestGetScoreOperationPlugin.java

@@ -0,0 +1,33 @@
+package nckd.jxccl.hr.hstu.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* 【优秀生】-综合测评问卷-获取评分结果
+* @author W.Y.C
+* @date 2025/8/15 17:24
+* @version 1.0
+*/
+public class EvalQuestGetScoreOperationPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+        DynamicObject[] selectedRows = e.getDataEntities();
+        if (selectedRows != null && selectedRows.length > 0) {
+            List<Long> selectedRowIds = new ArrayList<>(selectedRows.length);
+            for (DynamicObject row : selectedRows) {
+                // 获取单据ID(主键)
+                Long id = (Long) row.getPkValue();
+                selectedRowIds.add(id);
+            }
+            HonorStudentHelper.updateQuestResult(selectedRowIds.toArray(new Long[0]));
+        }
+    }
+}

+ 81 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalResultAuditOperationPlugin.java

@@ -0,0 +1,81 @@
+package nckd.jxccl.hr.hstu.plugin.operate;
+
+import kd.bos.context.RequestContext;
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.AddValidatorsEventArgs;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+import nckd.jxccl.hr.hstu.plugin.operate.validate.EvalResultPerfScoreValidate;
+
+import java.util.Arrays;
+import java.util.Date;
+
+/**
+* 【优秀生】-综合测评答卷-审核操作插件
+* @author W.Y.C
+* @date 2025/8/1 17:28
+* @version 1.0
+*/
+public class EvalResultAuditOperationPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(EvalResultAuditOperationPlugin.class);
+
+    @Override
+    public void onAddValidators(AddValidatorsEventArgs e) {
+        //评价分数校验
+        e.addValidator(new EvalResultPerfScoreValidate());
+    }
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+        logger.info("【优秀生考评】-问卷提交评分-开始", Arrays.toString(e.getDataEntities()));
+        //开始事务前填充需要设置的数据
+        DynamicObject[] dataEntities = e.getDataEntities();
+        String userAgent = RequestContext.get().getUserAgent();
+        logger.info("【优秀生考评】-问卷提交评分-userAgent:{}",userAgent);
+        for (DynamicObject dataEntity : dataEntities) {
+            //审批时同步修改评分状态为:已评分
+            dataEntity.set(HonorStudentConstant.NCKD_PERFPLANSTATE, "2");
+            if(userAgent.contains("Windows")) {
+                dataEntity.set(HonorStudentConstant.NCKD_HOWDOMARK, "PC端提交评分");
+            }else{
+                dataEntity.set(HonorStudentConstant.NCKD_HOWDOMARK, "移动端提交评分");
+            }
+            //设置评分时间
+            dataEntity.set(HonorStudentConstant.NCKD_SCORETIME, new Date());
+            //选择不了解清空分数
+            boolean unclear = dataEntity.getBoolean(HonorStudentConstant.NCKD_UNCLEAR);
+            if(unclear){
+                DynamicObjectCollection dynamicObjectCollection = dataEntity.getDynamicObjectCollection(HonorStudentConstant.NCKD_EVALRESULTENTRY);
+                for (DynamicObject dynamicObject : dynamicObjectCollection) {
+                    dynamicObject.set(HonorStudentConstant.NCKD_PERFSCORES, null);
+                }
+            }
+
+        }
+    }
+
+    @Override
+    public void endOperationTransaction(EndOperationTransactionArgs e) {
+        //数据已入库但还未提交(才会包含当前保存的答卷)前计算同级评分人数、上级评分人数、上级评分人数、同级评分总分、上级评分总分、领导评分总分、已评分总分、已评分人数、未评分人数
+        DynamicObject[] dataEntities = e.getDataEntities();
+        Long[] evalQuestIds = new Long[dataEntities.length];
+        for (int i = 0; i < dataEntities.length; i++) {
+            DynamicObject dataEntity = dataEntities[i];
+            long evalQuestId = dataEntity.getDynamicObject(HonorStudentConstant.NCKD_EVALQUEST).getLong(FormConstant.ID_KEY);
+            evalQuestIds[i] = evalQuestId;
+        }
+        //更新问卷评分结果
+        //原SHR逻辑只更新:已评分总分、领导评分人数、领导评分总分、上级评分人数、上级评分总分、同级评分人数、同级评分总分、已评分总分、已评分人数(含不了解)、未评分人数
+        HonorStudentHelper.updateQuestResult(evalQuestIds);
+        logger.info("【优秀生考评】-问卷结果提交评分-结束");
+    }
+}

+ 65 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalResultUnAuditOperationPlugin.java

@@ -0,0 +1,65 @@
+package nckd.jxccl.hr.hstu.plugin.operate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.entity.constant.StatusEnum;
+import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
+import kd.bos.entity.plugin.PreparePropertysEventArgs;
+import kd.bos.entity.plugin.args.BeforeSaveAuditLogArg;
+import kd.bos.entity.plugin.args.BeginOperationTransactionArgs;
+import kd.bos.entity.plugin.args.EndOperationTransactionArgs;
+import kd.bos.logging.Log;
+import kd.bos.logging.LogFactory;
+import kd.sdk.plugin.Plugin;
+import nckd.jxccl.base.common.constant.FormConstant;
+import nckd.jxccl.hr.hstu.business.helper.HonorStudentHelper;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+
+/**
+* 【优秀生】-综合测评答卷-反审核操作插件
+* @author W.Y.C
+* @date 2025/8/1 17:28
+* @version 1.0
+*/
+public class EvalResultUnAuditOperationPlugin extends AbstractOperationServicePlugIn implements Plugin {
+
+    private static final Log logger = LogFactory.getLog(EvalResultUnAuditOperationPlugin.class);
+
+    @Override
+    public void onPreparePropertys(PreparePropertysEventArgs e) {
+        //非预置字段需要用到要到这声明才能用
+        e.getFieldKeys().add(HonorStudentConstant.NCKD_PERFPLANSTATE);
+        e.getFieldKeys().add(HonorStudentConstant.NCKD_HOWDOMARK);
+        e.getFieldKeys().add(HonorStudentConstant.NCKD_EVALQUEST);
+    }
+
+    @Override
+    public void beforeSaveAuditLog(BeforeSaveAuditLogArg e) {
+        super.beforeSaveAuditLog(e);
+    }
+
+    @Override
+    public void beginOperationTransaction(BeginOperationTransactionArgs e) {
+        DynamicObject[] dataEntities = e.getDataEntities();
+        for (DynamicObject dataEntity : dataEntities) {
+            //反审批审批时同步修改评分状态为:待评分
+            dataEntity.set(HonorStudentConstant.STATUS, StatusEnum.B.toString());
+            dataEntity.set(HonorStudentConstant.NCKD_PERFPLANSTATE, "1");
+            dataEntity.set(HonorStudentConstant.NCKD_HOWDOMARK, null);
+        }
+    }
+
+    @Override
+    public void endOperationTransaction(EndOperationTransactionArgs e) {
+        //数据已入库但还未提交(才会包含当前保存的答卷)前计算同级评分人数、上级评分人数、上级评分人数、同级评分总分、上级评分总分、领导评分总分、已评分总分、已评分人数、未评分人数
+        DynamicObject[] dataEntities = e.getDataEntities();
+        Long[] evalQuestIds = new Long[dataEntities.length];
+        for (int i = 0; i < dataEntities.length; i++) {
+            DynamicObject dataEntity = dataEntities[i];
+            long evalQuestId = dataEntity.getDynamicObject(HonorStudentConstant.NCKD_EVALQUEST).getLong(FormConstant.ID_KEY);
+            evalQuestIds[i] = evalQuestId;
+        }
+        //更新问卷评分结果
+        //原SHR逻辑只更新:已评分总分、领导评分人数、领导评分总分、上级评分人数、上级评分总分、同级评分人数、同级评分总分、已评分总分、已评分人数(含不了解)、未评分人数
+        HonorStudentHelper.updateQuestResult(evalQuestIds);
+    }
+}

+ 52 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/validate/EvalResultPerfScoreValidate.java

@@ -0,0 +1,52 @@
+package nckd.jxccl.hr.hstu.plugin.operate.validate;
+
+import kd.bos.dataentity.entity.DynamicObject;
+import kd.bos.dataentity.entity.DynamicObjectCollection;
+import kd.bos.entity.ExtendedDataEntity;
+import kd.bos.entity.validate.AbstractValidator;
+import nckd.jxccl.base.common.utils.StrFormatter;
+import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+* 【优秀生】-综合测评答卷-提交评分校验
+* @author W.Y.C
+* @date 2025/8/4 11:29
+* @version 1.0
+*/
+public class EvalResultPerfScoreValidate extends AbstractValidator {
+
+    @Override
+    public void initializeConfiguration() {
+        //this.entityKey = HonorStudentConstant.NCKD_EVALRESULTENTRY;
+    }
+
+    @Override
+    public void validate() {
+        //处理分层级单据数据的标准工具(简单理解就是把层级的实体变为平铺)
+        //RowDataModel rowDataModel = new RowDataModel(entityKey, getValidateContext().getBillEntityType());
+
+        for (ExtendedDataEntity rowDataEntity : getDataEntities()) {
+
+           /* rowDataModel.setRowContext(rowDataEntity.getDataEntity());
+            Boolean unclear = ConvertUtil.toBoolean(rowDataModel.getValue(HonorStudentConstant.NCKD_UNCLEAR));*/
+            DynamicObject dataEntity = rowDataEntity.getDataEntity();
+            String perfPlanState = dataEntity.getString(HonorStudentConstant.NCKD_PERFPLANSTATE);
+            if(!"1".equals(perfPlanState)){
+                addErrorMessage(rowDataEntity, "只有问卷评分状态为【待评分】的问卷才能评分");
+            }
+            boolean unclear = dataEntity.getBoolean(HonorStudentConstant.NCKD_UNCLEAR);
+            if(!unclear){
+                DynamicObjectCollection dynamicObjectCollection = dataEntity.getDynamicObjectCollection(HonorStudentConstant.NCKD_EVALRESULTENTRY);
+                for (DynamicObject dynamicObject : dynamicObjectCollection) {
+                    String perfScores = dynamicObject.getString(HonorStudentConstant.NCKD_PERFSCORES);
+                    if(StringUtils.isBlank(perfScores)){
+                        DynamicObject evalQuestTplEntry = dynamicObject.getDynamicObject(HonorStudentConstant.NCKD_EVALQUESTTPLENTRY);
+                        String matter = evalQuestTplEntry.getString(HonorStudentConstant.NCKD_MATTER);
+                        addErrorMessage(rowDataEntity, StrFormatter.format("评价内容【{}】没有评价分数,请评分后再提交", matter));
+                    }
+                }
+            }
+        }
+    }
+}

+ 10 - 15
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/task/CreateEvalQuestTask.java

@@ -9,6 +9,7 @@ import kd.bos.logging.LogFactory;
 import kd.bos.orm.query.QFilter;
 import kd.bos.schedule.executor.AbstractTask;
 import kd.bos.servicehelper.QueryServiceHelper;
+import nckd.jxccl.base.common.constant.FormConstant;
 import nckd.jxccl.base.common.schedule.ProgressCallback;
 import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.base.org.helper.PersonHelper;
@@ -19,7 +20,6 @@ import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
-import java.util.StringJoiner;
 
 /**
  * 生成评价对象异步任务
@@ -36,33 +36,28 @@ public class CreateEvalQuestTask extends AbstractTask implements ProgressCallbac
     @Override
     public void execute(RequestContext ctx, Map<String, Object> params) {
         try {
-            Long evalQuestTplId = ConvertUtil.toLong(params.get(HonorStudentConstant.NCKD_EVALQUESTTPLID));
-            Map<String, Object> selectedEvalRuleMap = (Map<String, Object>) params.get(HonorStudentConstant.NCKD_SELECTEDEVALRULE);
-            List<Map<String,Object>> selectedPersonList = (List<Map<String, Object>>) params.get(HonorStudentConstant.NCKD_SELECTEDPERSON);
+
+            Map<String, Object> evalQuestTplMap = ConvertUtil.toMap(params.get(HonorStudentConstant.NCKD_EVALQUESTTPL));
+            Map<String, Object> selectedEvalRuleMap = ConvertUtil.toMap(params.get(HonorStudentConstant.NCKD_SELECTEDEVALRULE));
+            List<Map<String,Object>> selectedPersonList = ConvertUtil.toList(params.get(HonorStudentConstant.NCKD_SELECTEDPERSON));
             Long crrUserId = ConvertUtil.toLong(params.get(HonorStudentConstant.KEY_CURR_USER_ID));
             Long currOrgId = ConvertUtil.toLong(params.get(HonorStudentConstant.CURR_ORG_ID));
             totalItems = selectedPersonList.size();
 
-            StringJoiner ruleColum = new StringJoiner(",");
-            ruleColum.add(HonorStudentConstant.ID_KEY);
-            //其他同级评分人比例
-            ruleColum.add(HonorStudentConstant.NCKD_PROPORTION);
-            //同级评分人上限人数
-            ruleColum.add(HonorStudentConstant.NCKD_UPPER);
-            //同级评分人下限人数
-            ruleColum.add(HonorStudentConstant.NCKD_LOWER);
-            DynamicObject selectedEvalRule = QueryServiceHelper.queryOne(HonorStudentConstant.EVALUATIONRULE_ENTITYID, ruleColum.toString(), new QFilter[]{QFilterCommonHelper.getIdEqFilter(selectedEvalRuleMap.get(HonorStudentConstant.ID_KEY))});
+
+            DynamicObject evalQuestTpl = QueryServiceHelper.queryOne(HonorStudentConstant.NCKD_EVALQUESTTPL_ENTITYID, FormConstant.ID_KEY, new QFilter[]{QFilterCommonHelper.getIdEqFilter(evalQuestTplMap.get(HonorStudentConstant.ID_KEY))});
+            DynamicObject selectedEvalRule = QueryServiceHelper.queryOne(HonorStudentConstant.EVALUATIONRULE_ENTITYID, FormConstant.ID_KEY, new QFilter[]{QFilterCommonHelper.getIdEqFilter(selectedEvalRuleMap.get(HonorStudentConstant.ID_KEY))});
             List<Long> idList = new ArrayList<>();
             selectedPersonList.forEach(map ->{
                 Map<String, Object> fbasedataid = (Map<String, Object>) map.get(HonorStudentConstant.BASEDATAID_KEY);
                 idList.add(ConvertUtil.toLong(fbasedataid.get(HonorStudentConstant.ID_KEY)));
             } );
             DynamicObjectCollection selectedPerson = QueryServiceHelper.query(PersonHelper.DEP_EMP_ENTITY_ID, "id,person.name",new QFilter[]{QFilterCommonHelper.getIdInFilter(idList)});
-            CreateEvalQuestService.batchGenerateEvalQuest(evalQuestTplId, selectedEvalRule, selectedPerson, this, crrUserId, currOrgId);
+            CreateEvalQuestService.batchGenerateEvalQuest(evalQuestTpl, selectedEvalRule, selectedPerson, this, crrUserId, currOrgId);
 
             feedbackProgress(100, "任务完成", null);
         } catch (Exception e) {
-            logger.error("【优秀生考评】-生成综合评测问卷-异常,异常信息:{}",e.getMessage());
+            logger.error("【优秀生考评】-生成综合评测问卷-系统异常:{}",e);
             throw new KDBizException("任务执行失败:" + e.getMessage());
         }
     }