| 
					
				 | 
			
			
				@@ -0,0 +1,538 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+package nckd.jxccl.hr.psms.plugin.operate.performance.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 kd.bos.orm.query.QFilter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import kd.bos.servicehelper.QueryServiceHelper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.base.common.constant.FormConstant; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.base.common.enums.AppraisalResultEnum; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.base.common.utils.DateUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.base.common.utils.QueryFieldBuilder; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.base.common.utils.StrFormatter; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.base.orm.helper.QFilterCommonHelper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.hr.psms.common.PerfRankMgmtConstant; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import nckd.jxccl.hr.psms.common.PositionStructureConstant; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.math.BigDecimal; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.math.RoundingMode; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.ArrayList; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Collections; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.HashMap; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.HashSet; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.List; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Map; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Set; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* 绩效排名管理保存验证插件 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* @date 2025/10/21 22:39 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+* @version 1.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+*/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class PerfRankMgmtSaveValidate extends AbstractValidator { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private final Map<String, BigDecimal> appraisalResultRatioMap = new HashMap<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public void validate() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        QueryFieldBuilder queryFieldBuilder = QueryFieldBuilder.create() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY}, PerfRankMgmtConstant.NCKD_RATIO) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .addGroup(new String[]{FormConstant.NCKD_ENTRYENTITY, PositionStructureConstant.NCKD_APPRAISALRESULT}, FormConstant.NUMBER_KEY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        DynamicObjectCollection query = QueryServiceHelper.query(PerfRankMgmtConstant.RANKRATIOCONF_ENTITYID, queryFieldBuilder.buildSelect(), new QFilter[]{QFilterCommonHelper.getEnableFilter()}); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        query.forEach(dynamicObject -> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            String key = dynamicObject.getString(String.join(".",FormConstant.NCKD_ENTRYENTITY, PositionStructureConstant.NCKD_APPRAISALRESULT, FormConstant.NUMBER_KEY)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BigDecimal value = dynamicObject.getBigDecimal(String.join(".",FormConstant.NCKD_ENTRYENTITY, PerfRankMgmtConstant.NCKD_RATIO)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            appraisalResultRatioMap.put(key, value); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (ExtendedDataEntity rowDataEntity : getDataEntities()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(appraisalResultRatioMap.isEmpty()){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                this.addMessage(rowDataEntity, "没有配置【排名考核结果比例】"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DynamicObject data = rowDataEntity.getDataEntity(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 年份校验 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (validateYear(data, rowDataEntity)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 获取明细数据并验证是否为空 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                DynamicObjectCollection entries = data.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (entries.isEmpty()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    this.addMessage(rowDataEntity, "请添加排名名单"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    continue; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 验证明细数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                ValidationContext context = validateEntries(entries, rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 验证统计数据一致性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                validateDataConsistency(data, context, rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //校验考核结果人数比例 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateRatio(ValidationContext context, ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 总人数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int totalRankCount = context.totalRankCount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 优秀人数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int excellentCount = context.excellentCount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 合格人数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int qualifiedCount = context.qualifiedCount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 基本合格人数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int basicCount = context.basicCount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 不合格人数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int failCount = context.failCount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 获取配置比例 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal excellentRatio = appraisalResultRatioMap.get(AppraisalResultEnum.EXCELLENT.getCode()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal qualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.QUALIFIED.getCode()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal basicallyQualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.BASICALLY_QUALIFIED.getCode()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal unQualifiedRatio = appraisalResultRatioMap.get(AppraisalResultEnum.UN_QUALIFIED.getCode()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 计算各等级的理论人数(四舍五入) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int expectedExcellent = calculateExpectedCount(totalRankCount, excellentRatio); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int expectedQualified = calculateExpectedCount(totalRankCount, qualifiedRatio); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int expectedBasic = calculateExpectedCount(totalRankCount, basicallyQualifiedRatio); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int expectedFail = calculateExpectedCount(totalRankCount, unQualifiedRatio); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 校验各等级人数是否在合理范围内(允许±1的差异) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateCountRange(AppraisalResultEnum.EXCELLENT.getName(), excellentCount, expectedExcellent, totalRankCount,rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateCountRange(AppraisalResultEnum.QUALIFIED.getName(), qualifiedCount, expectedQualified, totalRankCount,rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateCountRange(AppraisalResultEnum.BASICALLY_QUALIFIED.getName(), basicCount, expectedBasic, totalRankCount,rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateCountRange(AppraisalResultEnum.UN_QUALIFIED.getName(), failCount, expectedFail, totalRankCount,rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 计算理论人数(四舍五入) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private int calculateExpectedCount(int totalCount, BigDecimal ratio) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 将百分比转换为小数进行计算 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal decimalRatio = ratio.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        BigDecimal expected = decimalRatio.multiply(BigDecimal.valueOf(totalCount)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return expected.setScale(0, RoundingMode.HALF_UP).intValue(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 校验人数范围(允许±1的差异) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateCountRange(String levelName, int actualCount, int expectedCount, int totalCount,ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int difference = Math.abs(actualCount - expectedCount); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 允许的差异阈值,可以根据总人数动态调整 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int allowedDifference = Math.max(1, totalCount / 100); // 至少允许1人差异,或总人数的1% 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (difference > allowedDifference) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    StrFormatter.format("{}人数与配置比例不符,应为{}人,实际为{}人", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            levelName, expectedCount,actualCount)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证年份字段有效性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param data 数据对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:40 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private boolean validateYear(DynamicObject data, ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int theYear = data.getInt(PerfRankMgmtConstant.NCKD_THEYEAR); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int currentYear = DateUtil.now().getYear(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (theYear < 1900 || theYear > currentYear) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, "年份不合法或超过当前年份"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证明细数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param entries 分录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: nckd.jxccl.hr.psms.plugin.operate.performance.validate.PerfRankMgmtSaveValidate.ValidationContext 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:40 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private ValidationContext validateEntries(DynamicObjectCollection entries, ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ValidationContext context = new ValidationContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Set<Long> personIds = new HashSet<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (int i = 0; i < entries.size(); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DynamicObject entry = entries.get(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            validateEntry(entry, rowDataEntity, i + 1, personIds, context); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证单条明细数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param entry 分录 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowIndex 行索引 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param personIds 已处理人员ID集合(用于去重检查) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param context 验证上下文 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:41 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateEntry(DynamicObject entry, ExtendedDataEntity rowDataEntity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                               int rowIndex, Set<Long> personIds, ValidationContext context) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        DynamicObject person = entry.getDynamicObject(PerfRankMgmtConstant.NCKD_PERSON); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (person == null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, StrFormatter.format("第{}行,请选择人员\n", rowIndex)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 人员重复校验 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            long personId = person.getLong(FormConstant.ID_KEY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (personIds.contains(personId)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                this.addMessage(rowDataEntity, StrFormatter.format("第{}行,人员【{}】重复;\n", rowIndex, person.getString(FormConstant.NAME_KEY))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                personIds.add(personId); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 统计各类人数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            boolean isRanking = entry.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            boolean postAllowance = entry.getBoolean(PerfRankMgmtConstant.NCKD_POSTALLOWANCE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DynamicObject appraisalResult = entry.getDynamicObject(PerfRankMgmtConstant.NCKD_APPRAISALRESULT); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (isRanking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                context.totalRankCount++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (postAllowance) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    context.allowanceRankCount++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (appraisalResult != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                String appraisalResultNumber = appraisalResult.getString(FormConstant.NUMBER_KEY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                AppraisalResultEnum appraisalResultEnum = AppraisalResultEnum.getByCode(appraisalResultNumber); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (appraisalResultEnum != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    switch (appraisalResultEnum) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case EXCELLENT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            context.excellentCount++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case BASICALLY_QUALIFIED: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            context.basicCount++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case UN_QUALIFIED: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            context.failCount++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        case QUALIFIED: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            context.qualifiedCount++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证数据一致性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param data 数据对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param context 验证上下文 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:41 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateDataConsistency(DynamicObject data, ValidationContext context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                         ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 各类人数一致性校验 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        checkCountConsistency(data, context, rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 排名范围校验 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateRankRanges(data.getDynamicObjectCollection(PerfRankMgmtConstant.NCKD_PERFRANKMGMTENTRY), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                data.getInt(PerfRankMgmtConstant.NCKD_TOPRANKS), rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateRatio(context, rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 检查统计数据一致性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param data 数据对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param context 验证上下文 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:42 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void checkCountConsistency(DynamicObject data, ValidationContext context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int topRanks = data.getInt(PerfRankMgmtConstant.NCKD_TOPRANKS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int allowanceRanks = data.getInt(PerfRankMgmtConstant.NCKD_ALLOWANCERANKS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int fails = data.getInt(PerfRankMgmtConstant.NCKD_FAILS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int basics = data.getInt(PerfRankMgmtConstant.NCKD_BASICS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int excellents = data.getInt(PerfRankMgmtConstant.NCKD_EXCELLENTS); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (topRanks != context.totalRankCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, "总排名人数与实际录入数据不一致;\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (allowanceRanks != context.allowanceRankCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, "R排名人数与实际录入数据不一致;\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (fails != context.failCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, "不合格人数与实际录入数据不一致;\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (basics != context.basicCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, "基本人数与实际录入数据不一致;\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (excellents != context.excellentCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, "优秀人数与实际录入数据不一致;\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证排名范围和重复情况 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param entries 分录集合 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param totalRankCount 总排名数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:42 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateRankRanges(DynamicObjectCollection entries, int totalRankCount, ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ValidationContext context = new ValidationContext(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 统计每个排名出现的次数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (int i = 0; i < entries.size(); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DynamicObject entry = entries.get(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DynamicObject person = entry.getDynamicObject(PerfRankMgmtConstant.NCKD_PERSON); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (person != null) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                String personName = person.getString(FormConstant.NAME_KEY); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                boolean isRanking = entry.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                boolean postAllowance = entry.getBoolean(PerfRankMgmtConstant.NCKD_POSTALLOWANCE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (isRanking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    validateAndRecordRank(entry, PerfRankMgmtConstant.NCKD_TOPRANK, "参与排名","排名", personName, rowDataEntity, context.rankCountMap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (postAllowance) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        validateAndRecordRank(entry, PerfRankMgmtConstant.NCKD_ALLOWANCERANK, "享受职位津贴","R排名", personName, rowDataEntity, context.rankRCountMap); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 找出重复的排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        findDuplicateRanks(context.rankCountMap, context.duplicateRanks); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        findDuplicateRanks(context.rankRCountMap, context.duplicateRRanks); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 检查排名范围和重复率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       for (int i = 0; i < entries.size(); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            DynamicObject entry = entries.get(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            boolean isRanking = entry.getBoolean(PerfRankMgmtConstant.NCKD_ISRANKING); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            boolean postAllowance = entry.getBoolean(PerfRankMgmtConstant.NCKD_POSTALLOWANCE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (isRanking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 检查排名字段是否在有效范围内 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                int topRank = entry.getInt(PerfRankMgmtConstant.NCKD_TOPRANK); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (topRank < 1 || topRank > totalRankCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    this.addMessage(rowDataEntity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            StrFormatter.format("第{}行,排名{}超出有效范围[1-{}]\n", i + 1, topRank, totalRankCount)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                if (postAllowance) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    // 检查R排名字段是否在有效范围内 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    int allowanceRank = entry.getInt(PerfRankMgmtConstant.NCKD_ALLOWANCERANK); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    if (allowanceRank < 1 || allowanceRank > totalRankCount) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        this.addMessage(rowDataEntity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                StrFormatter.format("第{}行,R排名{}超出有效范围[1-{}]\n", i + 1, allowanceRank, totalRankCount)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 验证排名重复率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateRankDuplicateRate(context, totalRankCount, rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 特殊排名组合校验 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateSpecialRankCombination(context, rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证并记录排名值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param entry 分录对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankField 排名字段名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankType 排名类型描述 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param personName 人员姓名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankCountMap 排名计数映射 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateAndRecordRank(DynamicObject entry, String rankField,String type, String rankType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       String personName, ExtendedDataEntity rowDataEntity, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                       Map<Integer, Integer> rankCountMap) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int rankValue = entry.getInt(rankField); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (rankValue < 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, StrFormatter.format("人员【{}】已勾选{},{}数不能小于1或为空", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    personName, type, rankType)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            rankCountMap.put(rankValue, rankCountMap.getOrDefault(rankValue, 0) + 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 查找重复的排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankCountMap 排名计数映射 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param duplicateRanks 重复排名集合 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void findDuplicateRanks(Map<Integer, Integer> rankCountMap, Set<Integer> duplicateRanks) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (Map.Entry<Integer, Integer> entry : rankCountMap.entrySet()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (entry.getValue() > 1) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                duplicateRanks.add(entry.getKey()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 特殊排名组合校验 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 当相同排名重复出现时,其连续序列结束位置不能被其他排名占用 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param context 上下文 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:43 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateSpecialRankCombination(ValidationContext context, ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 校验普通排名的特殊组合 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<String> invalidCombinations = new ArrayList<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 校验普通排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateSpecialRankCombinationForType(context.rankCountMap, context.duplicateRanks, "排名", invalidCombinations); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 校验R排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateSpecialRankCombinationForType(context.rankRCountMap, context.duplicateRRanks, "R排名", invalidCombinations); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 如果有不合规的组合,添加详细的错误信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!invalidCombinations.isEmpty()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            StringBuilder errorMsg = new StringBuilder("排名设置不符合规范!\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("【校验规则】\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("当相同排名重复出现时,其连续序列结束位置不能被其他排名占用。\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("【问题详情】\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            for (int i = 0; i < invalidCombinations.size(); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                errorMsg.append(StrFormatter.format("{}. {}\n", i + 1, invalidCombinations.get(i))); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("【示例说明】\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("❌ 不合规示例:[1,2,2,2,4] - 排名2重复3次,结束位置应为2+3-1=4,但4已在列表中\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("✅ 合规示例:[1,1,1,4] - 排名1重复3次,结束位置应为1+3-1=3,3不在列表中\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("【解决建议】\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            errorMsg.append("请调整重复排名的数值或移除冲突的排名,确保连续序列结束位置未被占用;\n\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            this.addMessage(rowDataEntity, errorMsg.toString()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 针对特定类型排名校验特殊组合规则 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankCountMap 排名计数映射 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param duplicateRanks 重复排名集合 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankType 排名类型(如"排名"、"R排名") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param invalidCombinations 不合规组合列表 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateSpecialRankCombinationForType(Map<Integer, Integer> rankCountMap, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                       Set<Integer> duplicateRanks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                       String rankType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                       List<String> invalidCombinations) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 遍历所有重复的排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        for (Integer rank : duplicateRanks) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int count = rankCountMap.get(rank); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 计算连续序列结束值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            int mark = rank + count - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 检查结束值是否在列表中存在 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (rankCountMap.containsKey(mark) && mark != rank) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                invalidCombinations.add(StrFormatter.format( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        "{}{}重复{}次,结束位置{}被占用", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                        rankType, rank, count, mark)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证排名重复率是否超过阈值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param context 上下文 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param totalRankCount 总排名数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return: void 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date: 2025/10/21 22:44 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateRankDuplicateRate(ValidationContext context, int totalRankCount, ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 验证普通排名重复率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateRankDuplicateRateForType(context.rankCountMap, context.duplicateRanks, totalRankCount, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "排名", rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        // 验证R排名重复率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        validateRankDuplicateRateForType(context.rankRCountMap, context.duplicateRRanks, totalRankCount, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "R排名", rowDataEntity); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 针对特定类型排名验证重复率 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankCountMap 排名计数映射 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param duplicateRanks 重复排名集合 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param totalRankCount 总排名数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rankType 排名类型 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param rowDataEntity 行数据实体 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateRankDuplicateRateForType(Map<Integer, Integer> rankCountMap, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  Set<Integer> duplicateRanks, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  int totalRankCount, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  String rankType, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                  ExtendedDataEntity rowDataEntity) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (totalRankCount > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            double duplicateRate = (double) duplicateRanks.size() / totalRankCount; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (duplicateRate > 0.3) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                // 构建重复排名详情信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                StringBuilder detailMessage = new StringBuilder(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                detailMessage.append(rankType).append("重复率超过30%,当前重复率: "); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                detailMessage.append(String.format("%.1f", duplicateRate * 100)).append("%,"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                detailMessage.append("具体重复的排名有: "); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                List<Integer> sortedDuplicateRanks = new ArrayList<>(duplicateRanks); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                Collections.sort(sortedDuplicateRanks); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                for (int i = 0; i < sortedDuplicateRanks.size(); i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    int rank = sortedDuplicateRanks.get(i); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    int count = rankCountMap.get(rank); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    detailMessage.append(StrFormatter.format("{}【{}】出现{}次;", rankType, rank, count)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                detailMessage.append("\n"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                this.addMessage(rowDataEntity, detailMessage.toString()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private void validateUserUniqueAcrossUnits() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证上下文对象,用于存储验证过程中的统计数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @author W.Y.C 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @date 2025/10/21 22:45 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @version 1.0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static class ValidationContext { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int totalRankCount = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int allowanceRankCount = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int failCount = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int basicCount = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int excellentCount = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        int qualifiedCount = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Set<Integer> rankSet = new HashSet<>();  // 记录已出现的排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Set<Integer> duplicateRanks = new HashSet<>();  // 记录普通排名中重复的排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Set<Integer> duplicateRRanks = new HashSet<>();  // 记录R排名中重复的排名 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<Integer, Integer> rankCountMap = new HashMap<>();  // 记录每个普通排名出现的次数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Map<Integer, Integer> rankRCountMap = new HashMap<>();  // 记录每个R排名出现的次数 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |