package com.kingdee.eas.custom.perfweb.service; import com.kingdee.bos.BOSException; import com.kingdee.bos.Context; import com.kingdee.bos.bsf.service.app.IHRMsfService; import com.kingdee.bos.metadata.entity.EntityViewInfo; import com.kingdee.bos.metadata.entity.FilterInfo; import com.kingdee.bos.metadata.entity.FilterItemInfo; import com.kingdee.bos.metadata.entity.SelectorItemCollection; import com.kingdee.bos.metadata.entity.SelectorItemInfo; import com.kingdee.bos.metadata.query.util.CompareType; import com.kingdee.eas.basedata.org.AdminOrgUnitInfo; import com.kingdee.eas.common.EASBizException; import com.kingdee.eas.custom.perfweb.AssessmentResultDescriptionCollection; import com.kingdee.eas.custom.perfweb.AssessmentResultDescriptionFactory; import com.kingdee.eas.custom.perfweb.AssessmentResultDescriptionInfo; import com.kingdee.eas.custom.perfweb.IAssessmentResultDescription; import com.kingdee.eas.custom.perfweb.bizEnum.AutoStatusEnum; import com.kingdee.eas.custom.perfweb.utils.CenterOrgUtil; import com.kingdee.shr.perfweb.app.base.evalplan.EvaResultSummaryCollection; import com.kingdee.shr.perfweb.app.base.evalplan.EvaResultSummaryFactory; import com.kingdee.shr.perfweb.app.base.evalplan.EvaResultSummaryInfo; import com.kingdee.shr.perfweb.app.base.evalplan.IEvaResultSummary; import com.kingdee.shr.perfweb.app.base.evalplan.EvaPeriodStatusEnum; import com.kingdee.shr.perfweb.app.base.evalplan.IPerfPeriod; import com.kingdee.shr.perfweb.app.base.evalplan.PerfEvaObjectInfo; import com.kingdee.shr.perfweb.app.base.evalplan.PerfPeriodCollection; import com.kingdee.shr.perfweb.app.base.evalplan.PerfPeriodFactory; import com.kingdee.shr.perfweb.app.base.evalplan.PerfPeriodInfo; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; /** * 绩效考核结果报表 MSF/OSF 查询服务。 *

* 以「考核结果说明」({@code AssessmentResultDescription}) 为主表,一个中心组织对应一条报表数据; * 各等级推荐/实际人数从考核结果汇总按中心及其全部下级组织范围内员工统计。 * 审批、飞书推送由列表页 Handler 处理,不在本服务内实现。 *

* 入参:periodId(选填,空则取考核中最新考核周期)、orgId(选填,按组织过滤) *

* 作 者: 青梧 * 创建日期: 2026-06-17 */ public class CenterPerfStatService implements IHRMsfService { private static final Logger logger = Logger.getLogger(CenterPerfStatService.class); /** * MSF 入参:考核周期 ID */ private static final String PARAM_PERIOD_ID = "periodId"; /** * MSF 入参:行政组织 ID */ private static final String PARAM_ORG_ID = "orgId"; /** * 绩效等级顺序(与报表原型一致) */ private static final List GRADE_ORDER = Arrays.asList("S", "A+", "A", "B", "C"); /** * 各等级分布占比(%):S=5, A+=25, A=45, B=20, C=5。 * A 等级标准人数不直接按比例四舍五入,见 {@link #calcStandardRecommendCounts(int)}。 */ private static final Map GRADE_PERCENT = new LinkedHashMap<>(); /** * S/A+/B/C 按占比四舍五入取标准人数;A 用剩余人数兜底 */ private static final List ROUNDED_GRADE_ORDER = Arrays.asList("S", "A+", "B", "C"); /** * 考核状态枚举值 → 单据字段展示名 */ private static final Map AUTO_STATUS_LABELS = new LinkedHashMap<>(); /** * 考核状态 → 报表「单据状态」列展示名(未提交 / 审批中 / 已通过) */ private static final Map BILL_STATUS_LABELS = new LinkedHashMap<>(); static { GRADE_PERCENT.put("S", 5); GRADE_PERCENT.put("A+", 25); GRADE_PERCENT.put("A", 45); GRADE_PERCENT.put("B", 20); GRADE_PERCENT.put("C", 5); AUTO_STATUS_LABELS.put(AutoStatusEnum.WFQ_VALUE, "未发起"); AUTO_STATUS_LABELS.put(AutoStatusEnum.ZJSPZ_VALUE, "总监审批中"); AUTO_STATUS_LABELS.put(AutoStatusEnum.ZJLSPZ_VALUE, "总经理审批中"); AUTO_STATUS_LABELS.put(AutoStatusEnum.SPTG_VALUE, "审批通过"); BILL_STATUS_LABELS.put(AutoStatusEnum.WFQ_VALUE, "未提交"); BILL_STATUS_LABELS.put(AutoStatusEnum.ZJSPZ_VALUE, "审批中"); BILL_STATUS_LABELS.put(AutoStatusEnum.ZJLSPZ_VALUE, "审批中"); BILL_STATUS_LABELS.put(AutoStatusEnum.SPTG_VALUE, "已通过"); } public CenterPerfStatService() { } /** * MSF 统一入口:按 periodId、orgId 查询报表 JSON。 */ @Override public Object process(Context context, Map params) throws EASBizException, BOSException { if (params == null) { params = new HashMap<>(); } String periodId = getStringParam(params, PARAM_PERIOD_ID); String orgId = getStringParam(params, PARAM_ORG_ID); logger.info("CenterPerfStatService.process periodId=" + periodId + ",orgId=" + orgId); return queryReport(context, periodId, orgId); } /** * 查询绩效考核结果报表:主表为考核结果说明,一组织一行。 * * @param ctx 上下文 * @param periodId 考核周期 ID(选填,空则取默认周期) * @param orgId 行政组织 ID(选填,快速过滤手工选择) */ public static Map queryReport(Context ctx, String periodId, String orgId) { return queryReport(ctx, periodId, orgId, null); } /** * 查询绩效考核结果报表:主表为考核结果说明,一组织一行。 * * @param ctx 上下文 * @param periodId 考核周期 ID(选填,空则取默认周期) * @param orgId 行政组织 ID(选填,快速过滤手工选择) * @param adminOrgRangeIds 当前用户行政组织范围(未选手工组织时由 Handler 传入,对标品 getCurrentRequestAdminOrgRangeIdSet) */ public static Map queryReport(Context ctx, String periodId, String orgId, Set adminOrgRangeIds) { Map result = baseResult(); try { if (StringUtils.isBlank(periodId)) { periodId = resolveDefaultPeriodId(ctx); } if (StringUtils.isBlank(periodId)) { return fail(result, "未找到状态为考核中的考核周期"); } PerfPeriodInfo period = loadPeriod(ctx, periodId); if (period == null) { return fail(result, "未找到考核周期,periodId=" + periodId); } // 主表:考核结果说明;orgId 选手工过滤,否则按 adminOrgRangeIds 系统组织范围过滤 AssessmentResultDescriptionCollection collection = loadDescriptionByPeriod(ctx, periodId); List centerContexts = buildCenterContexts(ctx, collection, orgId, adminOrgRangeIds); // 按中心组织树汇总各等级人数(中心 + 全部下级部门员工) Map gradeAggMap = aggregateGradeByCenter(ctx, periodId, centerContexts); List> rows = new ArrayList<>(); for (CenterOrgContext centerCtx : centerContexts) { OrgGradeAgg gradeAgg = gradeAggMap.get(centerCtx.orgId); if (gradeAgg == null) { gradeAgg = new OrgGradeAgg(); } rows.add(buildReportRow(centerCtx.description, gradeAgg, period)); } Map data = new LinkedHashMap<>(); data.put("periodId", periodId); data.put("periodName", StringUtils.defaultString(period.getName(), "")); data.put("orgId", StringUtils.defaultString(orgId, "")); data.put("gradePercents", copyGradePercents()); data.put("rows", rows); result.put("code", "200"); result.put("msg", "success"); result.put("data", data); return result; } catch (Exception e) { logger.error("queryReport failed, periodId=" + periodId + ", orgId=" + orgId, e); return fail(result, "查询失败:" + e.getMessage()); } } /** * 发送飞书公示前校验:指定考核周期下全部「考核结果说明」须已审批通过(autoStatus = SPTG)。 * * @return 可发送时返回 null;不可发送时返回前端提示文案 */ public static String validateAllDescriptionApprovedForNotify(Context ctx, String periodId) throws BOSException { if (StringUtils.isBlank(periodId)) { return "无法确定考核周期,无法发送飞书公示通知"; } String periodName = resolvePeriodDisplayName(ctx, periodId); AssessmentResultDescriptionCollection collection = loadDescriptionByPeriod(ctx, periodId); if (collection == null || collection.isEmpty()) { return "【" + periodName + "】绩效结果暂未审批,无法发送飞书公示通知"; } int total = collection.size(); int approvedCount = 0; for (int i = 0; i < collection.size(); i++) { AssessmentResultDescriptionInfo info = collection.get(i); if (info != null && AutoStatusEnum.SPTG.equals(info.getAutoStatus())) { approvedCount++; } } if (approvedCount < total) { return "【" + periodName + "】绩效结果暂未审批,无法发送飞书公示通知"; } return null; } /** * HR 发起前校验:当前查询条件下待发起中心,各等级(S/A+/A/B/C)实际人数之和须等于总人数。 * 组织快速过滤选中某中心时,仅校验该中心;未选组织时校验权限范围内全部待发起中心。 * * @return 可发起时返回 null;不可发起时返回前端提示文案 */ public static String validateGradeActualEqualsTotalForHrStart(Context ctx, String periodId, String orgId, Set adminOrgRangeIds, String expectStatusValue) { Map queryResult = queryReport(ctx, periodId, orgId, adminOrgRangeIds); if (!"200".equals(String.valueOf(queryResult.get("code")))) { return String.valueOf(queryResult.get("msg")); } Map data = (Map) queryResult.get("data"); List> rows = data != null && data.get("rows") != null ? (List>) data.get("rows") : new ArrayList<>(); List invalidOrgs = new ArrayList<>(); for (Map row : rows) { if (row == null || !expectStatusValue.equals(String.valueOf(row.get("autoStatus")))) { continue; } int totalCount = toIntValue(row.get("totalCount")); int actualSum = sumGradeActualCount(row); if (actualSum != totalCount) { invalidOrgs.add(formatOrgGradeCountMismatch(row, actualSum, totalCount)); } } if (invalidOrgs.isEmpty()) { return null; } return String.join("", invalidOrgs); } private static String formatOrgGradeCountMismatch(Map row, int actualSum, int totalCount) { return resolveOrgDisplayName(row) + "待评定人员绩效等级未完成结果审核(" + actualSum + "/" + totalCount + "),不能发起结果审批。"; } private static String resolveOrgDisplayName(Map row) { if (row == null) { return "未知组织"; } String centerName = StringUtils.trimToNull(String.valueOf(row.get("centerName"))); if (centerName != null && !"null".equalsIgnoreCase(centerName)) { return centerName; } String orgName = StringUtils.trimToNull(String.valueOf(row.get("orgName"))); if (orgName != null && !"null".equalsIgnoreCase(orgName)) { return orgName; } String number = StringUtils.trimToNull(String.valueOf(row.get("number"))); if (number != null && !"null".equalsIgnoreCase(number)) { return number; } return "未知组织"; } private static int sumGradeActualCount(Map row) { int sum = 0; for (String grade : GRADE_ORDER) { sum += toIntValue(row.get(toFieldPrefix(grade) + "Actual")); } return sum; } private static int toIntValue(Object value) { if (value == null) { return 0; } if (value instanceof Number) { return ((Number) value).intValue(); } try { return Integer.parseInt(String.valueOf(value).trim()); } catch (NumberFormatException e) { return 0; } } private static String resolvePeriodDisplayName(Context ctx, String periodId) { try { PerfPeriodInfo period = PerfPeriodFactory.getLocalInstance(ctx).getPerfPeriodInfo("where id = '" + periodId + "'"); if (period != null && StringUtils.isNotBlank(period.getName())) { return period.getName(); } } catch (Exception e) { logger.error("resolvePeriodDisplayName failed, periodId=" + periodId, e); } return periodId; } /** * 按考核周期加载全部考核结果说明。 */ private static AssessmentResultDescriptionCollection loadDescriptionByPeriod(Context ctx, String periodId) throws BOSException { IAssessmentResultDescription iBill = AssessmentResultDescriptionFactory.getLocalInstance(ctx); FilterInfo filter = new FilterInfo(); filter.getFilterItems().add(new FilterItemInfo("period.id", periodId, CompareType.EQUALS)); SelectorItemCollection sic = new SelectorItemCollection(); sic.add(new SelectorItemInfo("*")); sic.add(new SelectorItemInfo("period.*")); sic.add(new SelectorItemInfo("adminOrg.*")); EntityViewInfo evi = new EntityViewInfo(); evi.setFilter(filter); evi.setSelector(sic); return iBill.getAssessmentResultDescriptionCollection(evi); } /** * 从主表构建中心上下文列表。 * orgId 有值时按手工组织过滤;否则按 adminOrgRangeIds(系统组织范围)过滤。 */ private static List buildCenterContexts(Context ctx, AssessmentResultDescriptionCollection collection, String orgId, Set adminOrgRangeIds) throws BOSException { List contexts = new ArrayList<>(); if (collection == null) { return contexts; } AdminOrgUnitInfo filterOrg = StringUtils.isNotBlank(orgId) ? CenterOrgUtil.loadOrg(ctx, orgId) : null; for (int i = 0; i < collection.size(); i++) { AssessmentResultDescriptionInfo info = collection.get(i); AdminOrgUnitInfo centerOrg = info.getAdminOrg(); if (centerOrg == null || centerOrg.getId() == null) { continue; } if (filterOrg != null) { if (!matchesOrgFilter(ctx, filterOrg, centerOrg, orgId)) { continue; } } else if (!matchesAdminOrgRange(ctx, centerOrg, adminOrgRangeIds)) { continue; } CenterOrgContext centerCtx = new CenterOrgContext(); centerCtx.orgId = centerOrg.getId().toString(); centerCtx.centerOrg = centerOrg; centerCtx.description = info; contexts.add(centerCtx); } return contexts; } /** * 系统组织范围过滤:中心自身在范围内,或范围内任一组织落在该中心树下。 * 对标品 ListHandler.getCurrentRequestAdminOrgRangeIdSet 的 INCLUDE 语义。 */ private static boolean matchesAdminOrgRange(Context ctx, AdminOrgUnitInfo centerOrg, Set adminOrgRangeIds) throws BOSException { if (adminOrgRangeIds == null || adminOrgRangeIds.isEmpty()) { return true; } String centerId = centerOrg.getId().toString(); if (adminOrgRangeIds.contains(centerId)) { return true; } for (String rangeOrgId : adminOrgRangeIds) { if (StringUtils.isBlank(rangeOrgId)) { continue; } AdminOrgUnitInfo rangeOrg = CenterOrgUtil.loadOrg(ctx, rangeOrgId); if (rangeOrg != null && CenterOrgUtil.isUnderCenterOrg(ctx, rangeOrg, centerOrg)) { return true; } } return false; } /** * 组织过滤:orgId 为中心时精确匹配;为下级部门时匹配其所属中心单据。 */ private static boolean matchesOrgFilter(Context ctx, AdminOrgUnitInfo filterOrg, AdminOrgUnitInfo centerOrg, String orgId) throws BOSException { if (filterOrg == null || centerOrg == null || centerOrg.getId() == null) { return true; } if (orgId.equals(centerOrg.getId().toString())) { return true; } // filterOrg 在中心组织树下(含中心自身) return CenterOrgUtil.isUnderCenterOrg(ctx, filterOrg, centerOrg); } /** * 按中心组织(含全部下级)汇总考核周期内各等级人数,并计算推荐人数。 */ private static Map aggregateGradeByCenter(Context ctx, String periodId, List centerContexts) throws BOSException { Map aggMap = new LinkedHashMap<>(); for (CenterOrgContext centerCtx : centerContexts) { aggMap.put(centerCtx.orgId, new OrgGradeAgg()); } if (centerContexts.isEmpty()) { return aggMap; } EvaResultSummaryCollection coll = loadSummaryByPeriod(ctx, periodId); if (coll == null) { fillRecommendCounts(aggMap); return aggMap; } for (int i = 0; i < coll.size(); i++) { EvaResultSummaryInfo info = coll.get(i); PerfEvaObjectInfo evaObj = info.getEvaObj(); if (evaObj == null || evaObj.getAdminOrgUnit() == null) { continue; } AdminOrgUnitInfo empOrg = evaObj.getAdminOrgUnit(); // 员工落在哪个中心组织树下,就计入该中心 String matchedCenterId = matchCenterForEmployee(ctx, empOrg, centerContexts); if (matchedCenterId == null) { continue; } OrgGradeAgg agg = aggMap.get(matchedCenterId); if (agg == null) { continue; } agg.totalCount++; String grade = resolveGradeLevel(info); if (StringUtils.isNotBlank(grade)) { agg.actualMap.put(grade, agg.actualMap.getOrDefault(grade, 0) + 1); } } fillRecommendCounts(aggMap); return aggMap; } /** * 判断员工所属组织属于哪个中心(中心 + 下级范围),返回中心 orgId。 */ private static String matchCenterForEmployee(Context ctx, AdminOrgUnitInfo empOrg, List centerContexts) throws BOSException { for (CenterOrgContext centerCtx : centerContexts) { if (CenterOrgUtil.isUnderCenterOrg(ctx, empOrg, centerCtx.centerOrg)) { return centerCtx.orgId; } } return null; } /** * 按等级分布规则批量计算各中心标准(推荐)人数 */ private static void fillRecommendCounts(Map aggMap) { for (OrgGradeAgg agg : aggMap.values()) { Map standardMap = calcStandardRecommendCounts(agg.totalCount); agg.recommendMap.putAll(standardMap); } } /** * 计算各等级标准(推荐)人数。 *

* 示例:总人数 10 → S=1, A+=3, A=3, B=2, C=1 */ private static Map calcStandardRecommendCounts(int total) { Map result = new LinkedHashMap<>(); if (total <= 0) { for (String grade : GRADE_ORDER) { result.put(grade, 0); } return result; } int otherSum = 0; for (String grade : ROUNDED_GRADE_ORDER) { int count = calcRoundedRecommend(total, GRADE_PERCENT.get(grade)); result.put(grade, count); otherSum += count; } // A 等级承接四舍五入后的剩余人数 int aCount = total - otherSum; if (aCount < 0) { aCount = 0; } result.put("A", aCount); return result; } /** * 组装报表一行:中心、考核周期、人数合计、各等级推荐/实际、备注、单据状态。 * 字段命名与前端报表列一一对应,一组织一条记录。 */ private static Map buildReportRow(AssessmentResultDescriptionInfo info, OrgGradeAgg gradeAgg, PerfPeriodInfo period) { Map row = new LinkedHashMap<>(); row.put("id", info.getId() != null ? info.getId().toString() : ""); row.put("number", StringUtils.defaultString(info.getNumber(), "")); PerfPeriodInfo rowPeriod = info.getPeriod() != null ? info.getPeriod() : period; if (rowPeriod != null && rowPeriod.getId() != null) { row.put("periodId", rowPeriod.getId().toString()); row.put("periodName", StringUtils.defaultString(rowPeriod.getName(), "")); } else if (period != null && period.getId() != null) { row.put("periodId", period.getId().toString()); row.put("periodName", StringUtils.defaultString(period.getName(), "")); } else { row.put("periodId", ""); row.put("periodName", ""); } AdminOrgUnitInfo adminOrg = info.getAdminOrg(); if (adminOrg != null) { row.put("orgId", adminOrg.getId() != null ? adminOrg.getId().toString() : ""); row.put("orgName", StringUtils.defaultString(adminOrg.getName(), "")); row.put("centerName", StringUtils.defaultString(adminOrg.getName(), "")); } else { row.put("orgId", ""); row.put("orgName", ""); row.put("centerName", ""); } row.put("totalCount", gradeAgg.totalCount); // 各等级推荐/实际,平铺字段便于前端直接绑定列 putGradeFields(row, "S", gradeAgg); putGradeFields(row, "A+", gradeAgg); putGradeFields(row, "A", gradeAgg); putGradeFields(row, "B", gradeAgg); putGradeFields(row, "C", gradeAgg); // 同时提供 grades 数组,便于循环渲染 row.put("grades", buildGradesList(gradeAgg)); row.put("remark", StringUtils.defaultString(info.getRemarks(), "")); row.put("remarks", StringUtils.defaultString(info.getRemarks(), "")); AutoStatusEnum autoStatus = info.getAutoStatus(); String statusValue = autoStatus != null ? autoStatus.getValue() : ""; row.put("autoStatus", statusValue); row.put("autoStatusName", resolveAutoStatusName(autoStatus)); row.put("billStatus", statusValue); row.put("billStatusName", resolveBillStatusName(autoStatus)); return row; } /** * 将单个等级的标准(推荐)/实际人数写入行 Map。 * recommend=标准人数(按比例计算),actual=实际人数(考核结果真实统计)。 */ private static void putGradeFields(Map row, String grade, OrgGradeAgg gradeAgg) { int recommend = gradeAgg.recommendMap.getOrDefault(grade, 0); int actual = gradeAgg.actualMap.getOrDefault(grade, 0); String prefix = toFieldPrefix(grade); row.put(prefix + "Recommend", recommend); row.put(prefix + "Actual", actual); row.put(prefix + "Exceed", actual > recommend); } private static List> buildGradesList(OrgGradeAgg gradeAgg) { List> grades = new ArrayList<>(); for (String grade : GRADE_ORDER) { int recommend = gradeAgg.recommendMap.getOrDefault(grade, 0); int actual = gradeAgg.actualMap.getOrDefault(grade, 0); Map item = new LinkedHashMap<>(); item.put("grade", grade); item.put("recommend", recommend); item.put("actual", actual); item.put("exceed", actual > recommend); grades.add(item); } return grades; } /** * 等级 → JSON 字段前缀:S→s, A+→aPlus, A→a, B→b, C→c */ private static String toFieldPrefix(String grade) { if ("S".equals(grade)) { return "s"; } if ("A+".equals(grade)) { return "aPlus"; } if ("A".equals(grade)) { return "a"; } if ("B".equals(grade)) { return "b"; } if ("C".equals(grade)) { return "c"; } return grade.toLowerCase(); } /** * 中心组织上下文:主表单据 + 中心组织信息 */ private static class CenterOrgContext { private String orgId; private AdminOrgUnitInfo centerOrg; private AssessmentResultDescriptionInfo description; } private static EvaResultSummaryCollection loadSummaryByPeriod(Context ctx, String periodId) throws BOSException { IEvaResultSummary iEvaResultSummary = EvaResultSummaryFactory.getLocalInstance(ctx); FilterInfo filter = new FilterInfo(); filter.getFilterItems().add(new FilterItemInfo("period.id", periodId, CompareType.EQUALS)); SelectorItemCollection sic = new SelectorItemCollection(); sic.add(new SelectorItemInfo("*")); sic.add(new SelectorItemInfo("evaObj.*")); sic.add(new SelectorItemInfo("evaObj.adminOrgUnit.*")); sic.add(new SelectorItemInfo("evaObj.adminOrgUnit.parent.*")); EntityViewInfo evi = new EntityViewInfo(); evi.setFilter(filter); evi.setSelector(sic); return iEvaResultSummary.getEvaResultSummaryCollection(evi); } /** * 解析最终绩效等级:审定 > 修订 > 系统等级。 */ private static String resolveGradeLevel(EvaResultSummaryInfo info) { if (info == null) { return ""; } if (StringUtils.isNotBlank(info.getAuditGradeLevel())) { return normalizeGrade(info.getAuditGradeLevel()); } if (StringUtils.isNotBlank(info.getReviseGradeLevel())) { return normalizeGrade(info.getReviseGradeLevel()); } return normalizeGrade(info.getGradeLevel()); } private static String normalizeGrade(String grade) { if (StringUtils.isBlank(grade)) { return ""; } String trimmed = grade.trim(); if ("A+".equals(trimmed) || "A+".equalsIgnoreCase(trimmed)) { return "A+"; } for (String item : GRADE_ORDER) { if (item.equalsIgnoreCase(trimmed)) { return item; } } return trimmed; } /** * S/A+/B/C 标准人数:总人数 × 占比,四舍五入 */ private static int calcRoundedRecommend(int total, int percent) { if (total <= 0) { return 0; } return (int) Math.round(total * percent / 100.0); } private static List> copyGradePercents() { List> list = new ArrayList<>(); for (Map.Entry entry : GRADE_PERCENT.entrySet()) { Map item = new LinkedHashMap<>(); item.put("grade", entry.getKey()); item.put("percent", entry.getValue()); list.add(item); } return list; } private static String resolveAutoStatusName(AutoStatusEnum autoStatus) { if (autoStatus == null) { return ""; } String label = AUTO_STATUS_LABELS.get(autoStatus.getValue()); return StringUtils.isNotBlank(label) ? label : autoStatus.getName(); } /** * 映射为报表「单据状态」列:未提交 / 审批中 / 已通过 */ private static String resolveBillStatusName(AutoStatusEnum autoStatus) { if (autoStatus == null) { return BILL_STATUS_LABELS.get(AutoStatusEnum.WFQ_VALUE); } String label = BILL_STATUS_LABELS.get(autoStatus.getValue()); return StringUtils.isNotBlank(label) ? label : resolveAutoStatusName(autoStatus); } private static PerfPeriodInfo loadPeriod(Context ctx, String periodId) throws BOSException, EASBizException { IPerfPeriod iPerfPeriod = PerfPeriodFactory.getLocalInstance(ctx); return iPerfPeriod.getPerfPeriodInfo("where id = '" + periodId + "'"); } /** * periodId 为空时:直接查 PerfPeriod,状态 {@link EvaPeriodStatusEnum#EVALUATING 考核中}, * 按 createTime 倒序取最新一条。 */ public static String resolveDefaultPeriodId(Context ctx) throws BOSException { IPerfPeriod iPerfPeriod = PerfPeriodFactory.getLocalInstance(ctx); String oql = "where evaPeriodStatus = " + EvaPeriodStatusEnum.EVALUATING.getValue() + " order by createTime desc"; PerfPeriodCollection coll = iPerfPeriod.getPerfPeriodCollection(oql); if (coll == null || coll.isEmpty()) { return null; } PerfPeriodInfo period = coll.get(0); return period != null && period.getId() != null ? period.getId().toString() : null; } private static Map baseResult() { return new LinkedHashMap<>(); } private static Map fail(Map result, String msg) { result.put("code", "500"); result.put("msg", msg); return result; } private static String getStringParam(Map params, String key) { if (params == null || !params.containsKey(key) || params.get(key) == null) { return null; } return String.valueOf(params.get(key)).trim(); } /** * 中心组织等级汇总中间结构 */ private static class OrgGradeAgg { private int totalCount; private final Map recommendMap = new HashMap<>(); private final Map actualMap = new HashMap<>(); } }