Преглед на файлове

feat(hr): 完善优秀生测评逻辑

- 新增 RankMapFunction 类,按评价活动维度进行排名计算
- 新增 UnitRankMapFunction 类,按评价活动和单位维度进行排名计算
wyc преди 4 седмици
родител
ревизия
e3d5a3d8a3
променени са 29 файла, в които са добавени 2409 реда и са изтрити 323 реда
  1. 21 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/constant/FormConstant.java
  2. 0 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/.gitkeep
  3. 39 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/enums/AppraisalResultEnum.java
  4. 53 0
      code/base/nckd-jxccl-base-common/src/main/java/nckd/jxccl/base/common/utils/ConvertUtil.java
  5. 1 1
      code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/entity/helper/EntityHelper.java
  6. 5 4
      code/base/nckd-jxccl-base-helper/src/main/java/nckd/jxccl/base/org/helper/AdminOrgHelper.java
  7. 13 13
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/CreateEvalQuestService.java
  8. 56 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/algo/RankMapFunction.java
  9. 59 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/algo/UnitRankMapFunction.java
  10. 0 11
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/helper/EvalQuestHelper.java
  11. 795 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/business/helper/HonorStudentHelper.java
  12. 22 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/common/HonorStudentConstant.java
  13. 367 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/common/bo/EvalQuestResultBO.java
  14. 25 65
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/CreateEvalQuestFormPlugin.java
  15. 15 6
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestFormPlugin.java
  16. 35 203
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestListPlugin.java
  17. 0 6
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestSelectOrg.java
  18. 40 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalResultFormPlugin.java
  19. 0 12
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvaluationRuleListPlugin.java
  20. 0 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/.gitkeep
  21. 96 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/CreateQvalQuestAffirmOperationPlugin.java
  22. 138 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestBeginEvalOperationPlugin.java
  23. 116 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestEndEvalOperationPlugin.java
  24. 281 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestGenerateQuestOperationPlugin.java
  25. 33 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalQuestGetScoreOperationPlugin.java
  26. 81 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalResultAuditOperationPlugin.java
  27. 65 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/EvalResultUnAuditOperationPlugin.java
  28. 52 0
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/operate/validate/EvalResultPerfScoreValidate.java
  29. 1 2
      code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/task/CreateEvalQuestTask.java

+ 21 - 0
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*/
@@ -115,4 +123,17 @@ public class FormConstant {
     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;
+    }
+}

+ 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];
+    }
+
 }

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

@@ -37,7 +37,7 @@ public class EntityHelper {
      * @param entityName 实体标识
      * @param org 组织id
      * @param currUser 当前用户
-     * @return: kd.bos.dataentity.entity.DynamicObject 新创建的基础资料实体,状态已设置为可用(数据状态:已审核、使用状态:可用),并设置创建时间、创建人、创建组织、业务单元
+     * @return: kd.bos.dataentity.entity.DynamicObject 新创建的基础资料实体,状态已设置为可用(数据状态:已审核、使用状态:可用),并设置创建时间
      * @author W.Y.C
      * @date: 2025/07/17 20:13
      */

+ 5 - 4
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;
 
@@ -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");

+ 13 - 13
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;
@@ -23,6 +21,7 @@ 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;
@@ -32,9 +31,9 @@ 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.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -66,7 +65,7 @@ public class CreateEvalQuestService {
      * @date: 2025/07/02 17:24
      */
     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());
+        logger.info("【优秀生考评】-生成综合评测问卷-参数: evalQuestTplId={},selectedEvalRule={} ,selectedPersonSize={}", evalQuestTpl.getLong(FormConstant.ID_KEY), selectedEvalRule.getLong(FormConstant.ID_KEY),selectedPerson.size());
         try {
             // 获取当前用户ID和主组织ID(创建组织)
             Long currUserId = userId;
@@ -108,9 +107,10 @@ public class CreateEvalQuestService {
             //同级评分人下限人数
             ruleColum.add(HonorStudentConstant.NCKD_LOWER);
             //查询评价规则
-            selectedEvalRule = BusinessDataServiceHelper.loadSingle(selectedEvalRule.getLong(HonorStudentConstant.ID_KEY),HonorStudentConstant.EVALUATIONRULE_ENTITYID);
+            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);
@@ -119,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=其他同级评分人下限人数)
@@ -137,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());
@@ -148,7 +148,7 @@ public class CreateEvalQuestService {
                 }
 
                 if (personId == null) {
-                    logger.warn("【优秀生考评】-跳过人员ID为空的数据,索引:{}", i);
+                    logger.warn("【优秀生考评】-生成综合评测问卷-跳过人员ID为空的数据,索引:{}", i);
                     continue;
                 }
 
@@ -161,7 +161,7 @@ public class CreateEvalQuestService {
                 //分录构建
                 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);
@@ -172,7 +172,7 @@ public class CreateEvalQuestService {
                     callback.onProgress(i);
                 }
             }
-
+            logger.info("【优秀生考评】-生成综合评测问卷-完成");
         }catch (KDBizException e){
             logger.error("【优秀生考评】-生成综合评测问卷-业务异常",e);
             throw e;
@@ -180,7 +180,7 @@ public class CreateEvalQuestService {
             logger.error("【优秀生考评】-生成综合评测问卷-系统异常",e);
             throw e;
         }
-        logger.info("【优秀生考评】-生成综合评测问卷-结束");
+
     }
 
     /**

+ 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;
+        }
+    }
+}

+ 22 - 0
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/common/HonorStudentConstant.java

@@ -152,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";
     /** 所在单位排名 */
@@ -174,6 +176,12 @@ public class HonorStudentConstant extends FormConstant {
     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";
     /** 选择组织范围(可选)*/
@@ -195,6 +203,8 @@ public class HonorStudentConstant extends FormConstant {
     /** 综合测评问卷模板分录 */
     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";
@@ -208,6 +218,18 @@ public class HonorStudentConstant extends FormConstant {
     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 + "]";
+    }
+}

+ 25 - 65
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/CreateEvalQuestFormPlugin.java

@@ -8,9 +8,13 @@ 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;
@@ -34,6 +38,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.StringJoiner;
+import java.util.stream.Collectors;
 
 /**
 * 生成评价对象(弹窗)表单插件
@@ -43,6 +48,8 @@ import java.util.StringJoiner;
 */
 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);
@@ -55,58 +62,21 @@ public class CreateEvalQuestFormPlugin extends AbstractFormPlugin implements Plu
         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) {
-            //批量新增综合测评问卷对话框确认事件
-            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);
-            //------------ 校验是否已生成过问卷(校验规则:评价对象是否已经有对应的评价规则或模板问卷) 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,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")));
-                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());
@@ -141,24 +111,14 @@ public class CreateEvalQuestFormPlugin extends AbstractFormPlugin implements Plu
 
                 // 3. 发布任务并显示进度界面
                 JobForm.dispatch(formInfo, this.getView().getParentView());
-
                 this.getView().close();
-            } else {
-                try {
-                    CreateEvalQuestService.batchGenerateEvalQuest(evalQuestTpl, selectedEvalRule, selectedPerson, null, null, null);
-                    this.getView().getParentView().invokeOperation(FormConstant.REFRESH);
-                    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();
-    }
 }

+ 15 - 6
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestFormPlugin.java

@@ -14,7 +14,10 @@ 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;
@@ -64,12 +67,18 @@ public class EvalQuestFormPlugin extends AbstractFormPlugin implements Plugin {
     }
 
     @Override
-    public void afterDoOperation(AfterDoOperationEventArgs e) {
-        String operateKey = e.getOperateKey();
-        if(HonorStudentConstant.OP_REFRESH_PEERS.equalsIgnoreCase(operateKey)){
-            //刷新同级人员
-
+    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);
             //弹出选择组织窗口
@@ -81,10 +90,10 @@ public class EvalQuestFormPlugin extends AbstractFormPlugin implements Plugin {
             showParameter.setCaption("同级评分人组织范围选择");
             this.getView().showForm(showParameter);
         }
+        System.out.println();
     }
 
 
-
     @Override
     public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
         String actionId = closedCallBackEvent.getActionId();

+ 35 - 203
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/plugin/form/EvalQuestListPlugin.java

@@ -1,6 +1,5 @@
 package nckd.jxccl.hr.hstu.plugin.form;
 
-import kd.bos.common.enums.EnableEnum;
 import kd.bos.context.RequestContext;
 import kd.bos.dataentity.OperateOption;
 import kd.bos.dataentity.entity.DynamicObject;
@@ -21,6 +20,7 @@ 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;
@@ -46,12 +46,15 @@ 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.Date;
+import java.util.EventObject;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -71,9 +74,16 @@ public class EvalQuestListPlugin extends AbstractListPlugin implements Plugin {
     private static final Log logger = LogFactory.getLog(EvalQuestListPlugin.class);
 
     @Override
-    public void afterDoOperation(AfterDoOperationEventArgs e) {
-        String operateKey = e.getOperateKey();
-        if(HonorStudentConstant.OP_CREATEEVAL.equalsIgnoreCase(operateKey)){
+    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();
@@ -82,173 +92,34 @@ public class EvalQuestListPlugin extends AbstractListPlugin implements Plugin {
             showParameter.setCloseCallBack(new CloseCallBack(this, HonorStudentConstant.NCKD_CREATEEVALQUEST_ENTITYID));
             showParameter.setCaption("生成综合测评问卷");
             this.getView().showForm(showParameter);
-        }else if(HonorStudentConstant.OP_GENERATE_QUEST.equalsIgnoreCase(operateKey)){
-            //--------------- 生成问卷(答卷) begin ---------------
-            ListSelectedRowCollection selectedRows = this.getSelectedRows();
-            List<Long> selectedRowIds = this.getSelectedRows().stream()
-                    .map(selectedRow -> ConvertUtil.toLong(selectedRow.getPrimaryKeyValue()))
-                    .collect(Collectors.toList());
-
-            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){
-                throw new ValidationException(errorJoin.toString());
-            }
-
-            // 2.校验打分人是否有领导和上级
-            validateEvaluatorRoles(evalQuestArray);
-
-            // 3.构建并保存答卷
-            buildAndSaveEvalResult(evalQuestArray);
-            // 4.刷新列表
-            this.getView().invokeOperation(FormConstant.REFRESH);
-            this.getView().showSuccessNotification("生成问卷成功");
-
-            //--------------- 生成问卷(答卷) end ---------------
         }
     }
 
-    /**
-     * 构建并保存答卷
-     * @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(evalQuest, 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);
+    @Override
+    public void afterDoOperation(AfterDoOperationEventArgs e) {
+        String operateKey = e.getOperateKey();
+        boolean success = e.getOperationResult() != null && e.getOperationResult().isSuccess();
 
-                    }
-                }
-                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());
-                    }
-                    throw new ValidationException(errorMsg.toString());
-                }
-                //修改问卷状态
-                for (DynamicObject evalQuest : evalQuestArray) {
-                    //问卷修改为就绪状态
-                    evalQuest.set(HonorStudentConstant.NCKD_PERIODSTATE,"3");
-                }
-                SaveServiceHelper.update(evalQuestArray);
-            } catch (Throwable e) {
-                // 异常回滚
-                t.markRollback();
-                throw e;
-            }
+        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("更新考评结果成功");
         }
 
     }
 
-    private static void buildEvalResult(DynamicObject evalQuest, 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_PERFPLANSTATE, "0");
-    }
-
     @Override
     public void closedCallBack(ClosedCallBackEvent closedCallBackEvent) {
         String actionId = closedCallBackEvent.getActionId();
@@ -284,43 +155,4 @@ public class EvalQuestListPlugin extends AbstractListPlugin implements Plugin {
         super.setFilter(e);
         e.setOrderBy("createtime asc");
     }
-
-
-    /**
-     * 校验评分人是否有领导和上级评分人
-     * @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){
-            throw new ValidationException(errorMsg.toString());
-        }
-    }
 }

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

@@ -1,18 +1,12 @@
 package nckd.jxccl.hr.hstu.plugin.form;
 
-import kd.bos.dataentity.entity.DynamicObject;
 import kd.bos.dataentity.entity.DynamicObjectCollection;
-import kd.bos.form.ConfirmCallBackListener;
-import kd.bos.form.MessageBoxOptions;
 import kd.bos.form.control.Control;
 import kd.bos.form.plugin.AbstractFormPlugin;
 import kd.sdk.plugin.Plugin;
-import nckd.jxccl.base.common.utils.ConvertUtil;
 import nckd.jxccl.hr.hstu.common.HonorStudentConstant;
 
 import java.util.EventObject;
-import java.util.HashMap;
-import java.util.Map;
 
 /**
 * 同级评分人组织范围选择(弹窗)插件

+ 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));
+                    }
+                }
+            }
+        }
+    }
+}

+ 1 - 2
code/hr/nckd-jxccl-hr/src/main/java/nckd/jxccl/hr/hstu/task/CreateEvalQuestTask.java

@@ -20,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;
 
 /**
  * 生成评价对象异步任务
@@ -58,7 +57,7 @@ public class CreateEvalQuestTask extends AbstractTask implements ProgressCallbac
 
             feedbackProgress(100, "任务完成", null);
         } catch (Exception e) {
-            logger.error("【优秀生考评】-生成综合评测问卷-异常,异常信息:{}",e.getMessage());
+            logger.error("【优秀生考评】-生成综合评测问卷-系统异常:{}",e);
             throw new KDBizException("任务执行失败:" + e.getMessage());
         }
     }