| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 |
- 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 查询服务。
- * <p>
- * 以「考核结果说明」({@code AssessmentResultDescription}) 为主表,一个中心组织对应一条报表数据;
- * 各等级推荐/实际人数从考核结果汇总按<strong>中心及其全部下级组织</strong>范围内员工统计。
- * 审批、飞书推送由列表页 Handler 处理,不在本服务内实现。
- * <p>
- * 入参:periodId(选填,空则取考核中最新考核周期)、orgId(选填,按组织过滤)
- * <p>
- * 作 者: 青梧
- * 创建日期: 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<String> 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<String, Integer> GRADE_PERCENT = new LinkedHashMap<>();
- /**
- * S/A+/B/C 按占比四舍五入取标准人数;A 用剩余人数兜底
- */
- private static final List<String> ROUNDED_GRADE_ORDER = Arrays.asList("S", "A+", "B", "C");
- /**
- * 考核状态枚举值 → 单据字段展示名
- */
- private static final Map<String, String> AUTO_STATUS_LABELS = new LinkedHashMap<>();
- /**
- * 考核状态 → 报表「单据状态」列展示名(未提交 / 审批中 / 已通过)
- */
- private static final Map<String, String> 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<String, Object> 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<String, Object> 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<String, Object> queryReport(Context ctx, String periodId, String orgId, Set<String> adminOrgRangeIds) {
- Map<String, Object> 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<CenterOrgContext> centerContexts = buildCenterContexts(ctx, collection, orgId, adminOrgRangeIds);
- // 按中心组织树汇总各等级人数(中心 + 全部下级部门员工)
- Map<String, OrgGradeAgg> gradeAggMap = aggregateGradeByCenter(ctx, periodId, centerContexts);
- List<Map<String, Object>> 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<String, Object> 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<String> adminOrgRangeIds, String expectStatusValue) {
- Map<String, Object> queryResult = queryReport(ctx, periodId, orgId, adminOrgRangeIds);
- if (!"200".equals(String.valueOf(queryResult.get("code")))) {
- return String.valueOf(queryResult.get("msg"));
- }
- Map<String, Object> data = (Map<String, Object>) queryResult.get("data");
- List<Map<String, Object>> rows = data != null && data.get("rows") != null
- ? (List<Map<String, Object>>) data.get("rows") : new ArrayList<>();
- List<String> invalidOrgs = new ArrayList<>();
- for (Map<String, Object> 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<String, Object> row, int actualSum, int totalCount) {
- return resolveOrgDisplayName(row) + "待评定人员绩效等级未完成结果审核("
- + actualSum + "/" + totalCount + "),不能发起结果审批。";
- }
- private static String resolveOrgDisplayName(Map<String, Object> 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<String, Object> 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<CenterOrgContext> buildCenterContexts(Context ctx, AssessmentResultDescriptionCollection collection, String orgId, Set<String> adminOrgRangeIds) throws BOSException {
- List<CenterOrgContext> 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<String> 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<String, OrgGradeAgg> aggregateGradeByCenter(Context ctx, String periodId, List<CenterOrgContext> centerContexts) throws BOSException {
- Map<String, OrgGradeAgg> 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<CenterOrgContext> centerContexts) throws BOSException {
- for (CenterOrgContext centerCtx : centerContexts) {
- if (CenterOrgUtil.isUnderCenterOrg(ctx, empOrg, centerCtx.centerOrg)) {
- return centerCtx.orgId;
- }
- }
- return null;
- }
- /**
- * 按等级分布规则批量计算各中心标准(推荐)人数
- */
- private static void fillRecommendCounts(Map<String, OrgGradeAgg> aggMap) {
- for (OrgGradeAgg agg : aggMap.values()) {
- Map<String, Integer> standardMap = calcStandardRecommendCounts(agg.totalCount);
- agg.recommendMap.putAll(standardMap);
- }
- }
- /**
- * 计算各等级标准(推荐)人数。
- * <ul>
- * <li>S、A+、B、C:总人数 × 占比,四舍五入取整</li>
- * <li>A:剩余人数 = 总人数 ? (S + A+ + B + C),保证各等级标准人数之和等于总人数</li>
- * </ul>
- * 示例:总人数 10 → S=1, A+=3, A=3, B=2, C=1
- */
- private static Map<String, Integer> calcStandardRecommendCounts(int total) {
- Map<String, Integer> 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<String, Object> buildReportRow(AssessmentResultDescriptionInfo info, OrgGradeAgg gradeAgg, PerfPeriodInfo period) {
- Map<String, Object> 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<String, Object> 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<Map<String, Object>> buildGradesList(OrgGradeAgg gradeAgg) {
- List<Map<String, Object>> grades = new ArrayList<>();
- for (String grade : GRADE_ORDER) {
- int recommend = gradeAgg.recommendMap.getOrDefault(grade, 0);
- int actual = gradeAgg.actualMap.getOrDefault(grade, 0);
- Map<String, Object> 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<Map<String, Object>> copyGradePercents() {
- List<Map<String, Object>> list = new ArrayList<>();
- for (Map.Entry<String, Integer> entry : GRADE_PERCENT.entrySet()) {
- Map<String, Object> 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<String, Object> baseResult() {
- return new LinkedHashMap<>();
- }
- private static Map<String, Object> fail(Map<String, Object> result, String msg) {
- result.put("code", "500");
- result.put("msg", msg);
- return result;
- }
- private static String getStringParam(Map<String, Object> 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<String, Integer> recommendMap = new HashMap<>();
- private final Map<String, Integer> actualMap = new HashMap<>();
- }
- }
|