package com.kingdee.eas.custom.perfweb.handler; import com.alibaba.fastjson.JSONObject; import com.kingdee.bos.BOSException; import com.kingdee.bos.Context; import com.kingdee.bos.ctrl.swing.StringUtils; import com.kingdee.eas.custom.perfweb.util.PersonnelStatUtil; import com.kingdee.eas.custom.perfweb.util.ReportFilterUtil; import com.kingdee.eas.custom.perfweb.util.ReportOrgUtil; import com.kingdee.shr.base.syssetting.context.SHRContext; import com.kingdee.shr.base.syssetting.exception.SHRWebException; import com.kingdee.shr.base.syssetting.json.GridDataEntity; import com.kingdee.shr.base.syssetting.web.handler.ListHandler; import org.apache.log4j.Logger; import org.springframework.ui.ModelMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 类名称: CenterPersonnelStatHandler * 功能描述: 按中心统计人员结构报表数据处理 * 创建日期: 2026-06-05 * 作 者: 青梧 * 版 本: 1.1 * * 返回字段说明: * centerCode - 中心/部门编码(FNUMBER,同名取第一个) * centerName - 中心/部门名称(合计/劳务工等特殊行;品质部为单独汇总行) * personCount - 在职总人数(含下级组织) * personPercentage - 人数占全部中心在职合计的百分比 * formalCount - 正式员工人数(员工类型001) * formalPercentage - 正式员工占本中心总人数的百分比 * trialCount - 试用员工人数(员工类型002) * trialPercentage - 试用员工占本中心总人数的百分比 * keyTalentCount - 关键人才人数(CFGjrc=1) * * 品质部行说明: * 全集团同名「品质部」跨公司合并单独一行,与中心行无互斥关系,不计入合计行累加。 */ public class CenterPersonnelStatHandler extends ListHandler { private static Logger logger = Logger.getLogger(CenterPersonnelStatHandler.class); Context ctx = SHRContext.getInstance().getContext(); /** 单独汇总的品质部名称(跨公司合并) */ private static final String QUALITY_DEPT_NAME = "品质部"; /** * 列表查询入口:按中心汇总在职人数、正式/试用/关键人才人数及占比,末尾追加品质部、劳务工与合计行。 */ @Override protected GridDataEntity getGridRequestData(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException { logger.error("CenterPersonnelStatHandler getGridRequestData------------"); GridDataEntity gridDataEntity = new GridDataEntity(); try { // 快筛(company字段可能为中心F7) + 列表筛选 filterItems String filterItem = ReportFilterUtil.getFilterItems(request); JSONObject fastFilterItemsJson = ReportFilterUtil.parseFastFilterJson(request); logger.error("filterItem: " + filterItem); logger.error("fastFilterItemsJson: " + fastFilterItemsJson); Map paramMap = ReportFilterUtil.parseCompanyParams(fastFilterItemsJson, logger, false); ReportOrgUtil.OrgScope centerScope = ReportFilterUtil.buildCenterOrgScope(ctx, fastFilterItemsJson, logger); logger.error("查询参数: " + paramMap); // 公司F7筛选,用于限定中心所属公司 String companyId = paramMap.get("companyId"); // 劳务工人数来自基础资料手工维护,不参与中心明细循环 int laborCount = PersonnelStatUtil.getLaborCount(ctx, logger); // 按中心名称去重合并(排除130) List centers = getCenterList(companyId, filterItem, centerScope); int totalCount = 0; int totalFormalCount = 0; int totalTrialCount = 0; int totalKeyTalentCount = 0; List> dataList = new ArrayList>(); for (ReportOrgUtil.OrgNameCode center : centers) { String centerName = center.orgName; PersonnelStatUtil.PersonnelStat stat = PersonnelStatUtil.countStructure(ctx, buildCenterStatScope(centerName, companyId), logger); Map row = new HashMap(); row.put("centerCode", center.orgCode); // centerCode: 中心编码 row.put("centerName", centerName); // centerName: 中心名称 row.put("personCount", stat.totalCount); // personCount: 在职总人数 row.put("personPercentage", 0.0); // personPercentage: 占比(第二遍回填) row.put("formalCount", stat.formalCount); // formalCount: 正式员工数 row.put("formalPercentage", 0.0); // formalPercentage: 正式占比(第二遍回填) row.put("trialCount", stat.trialCount); // trialCount: 试用员工数 row.put("trialPercentage", 0.0); // trialPercentage: 试用占比(第二遍回填) row.put("keyTalentCount", stat.keyTalentCount); // keyTalentCount: 关键人才数 dataList.add(row); totalCount += stat.totalCount; totalFormalCount += stat.formalCount; totalTrialCount += stat.trialCount; totalKeyTalentCount += stat.keyTalentCount; } // 品质部单独一行(跨公司合并,与中心行无互斥关系,不计入合计累加) PersonnelStatUtil.PersonnelStat qualityStat = PersonnelStatUtil.countStructure(ctx, PersonnelStatUtil.StatScope.dept(QUALITY_DEPT_NAME, companyId), logger); Map qualityRow = new HashMap(); qualityRow.put("centerCode", resolveQualityDeptCode(companyId)); // centerCode: 部门编码 qualityRow.put("centerName", QUALITY_DEPT_NAME); // centerName: 品质部 qualityRow.put("personCount", qualityStat.totalCount); qualityRow.put("personPercentage", 0.0); qualityRow.put("formalCount", qualityStat.formalCount); qualityRow.put("formalPercentage", 0.0); qualityRow.put("trialCount", qualityStat.trialCount); qualityRow.put("trialPercentage", 0.0); qualityRow.put("keyTalentCount", qualityStat.keyTalentCount); dataList.add(qualityRow); // 第二遍循环:基于各中心合计数回填各行占比(含品质部行) for (Map row : dataList) { int personCount = (Integer) row.get("personCount"); int formalCount = (Integer) row.get("formalCount"); int trialCount = (Integer) row.get("trialCount"); // 人数占比 = 本行人数 / 全部中心在职合计 double personPercentage = totalCount > 0 ? (personCount * 100.0 / totalCount) : 0.0; row.put("personPercentage", String.format("%.2f", personPercentage) + "%"); // 正式员工占比 = 本行正式人数 / 本行总人数 double formalPercentage = personCount > 0 ? (formalCount * 100.0 / personCount) : 0.0; row.put("formalPercentage", String.format("%.2f", formalPercentage) + "%"); // 试用员工占比 = 本行试用人数 / 本行总人数 double trialPercentage = personCount > 0 ? (trialCount * 100.0 / personCount) : 0.0; row.put("trialPercentage", String.format("%.2f", trialPercentage) + "%"); } // 正式工合计行(仅统计各中心在编人员,不含品质部重复行与劳务工) Map totalRow = new HashMap(); totalRow.put("centerCode", ""); // centerCode: 合计行留空 totalRow.put("centerName", "合计"); // centerName: 正式工合计 totalRow.put("personCount", totalCount); // personCount: 各中心在职合计 totalRow.put("personPercentage", totalCount > 0 ? "100.00%" : "0.00%"); totalRow.put("formalCount", totalFormalCount); // formalCount: 正式员工合计 totalRow.put("formalPercentage", totalCount > 0 ? String.format("%.2f", totalFormalCount * 100.0 / totalCount) + "%" : "0.00%"); totalRow.put("trialCount", totalTrialCount); // trialCount: 试用员工合计 totalRow.put("trialPercentage", totalCount > 0 ? String.format("%.2f", totalTrialCount * 100.0 / totalCount) + "%" : "0.00%"); totalRow.put("keyTalentCount", totalKeyTalentCount); // keyTalentCount: 关键人才合计 dataList.add(totalRow); // 劳务工行:人数取自基础资料,无正式/试用等细分字段 Map laborRow = new HashMap(); laborRow.put("centerCode", ""); // centerCode: 劳务工行留空 laborRow.put("centerName", "劳务工"); // centerName: 劳务工标识 laborRow.put("personCount", laborCount); // personCount: 劳务工人数 dataList.add(laborRow); // 含劳务工的总计行 int totalWithLabor = totalCount + laborCount; Map totalWithLaborRow = new HashMap(); totalWithLaborRow.put("centerCode", ""); // centerCode: 含劳务工合计行留空 totalWithLaborRow.put("centerName", "合计(含劳务工)"); // centerName: 含劳务工合计 totalWithLaborRow.put("personCount", totalWithLabor); // personCount: 正式+劳务工合计 dataList.add(totalWithLaborRow); gridDataEntity.setRows(dataList); gridDataEntity.setTotal(dataList.size()); gridDataEntity.setPage(1); gridDataEntity.setRecords(dataList.size()); logger.error("按中心统计报表数据查询成功,总记录数: " + dataList.size()); } catch (SQLException e) { logger.error("数据库查询失败", e); throw new SHRWebException("数据查询失败: " + e.getMessage()); } catch (BOSException e) { logger.error("业务异常", e); throw new SHRWebException("业务处理失败: " + e.getMessage()); } catch (Exception e) { logger.error("未知异常", e); throw new SHRWebException("系统异常: " + e.getMessage()); } ReportFilterUtil.applyGridUserData(request, gridDataEntity); return gridDataEntity; } /** * 查询品质部编码(跨公司同名取第一个)。 */ private String resolveQualityDeptCode(String companyId) throws BOSException, SQLException { List depts = ReportOrgUtil.getDistinctOrgNameCodes(ctx, ReportOrgUtil.LAYER_DEPT, companyId); for (ReportOrgUtil.OrgNameCode dept : depts) { if (QUALITY_DEPT_NAME.equals(dept.orgName)) { return dept.orgCode; } } return ""; } /** * 查询去重后的中心名称编码列表(跨公司合并,排除130)。 */ private List getCenterList(String companyId, String filterItemsStr, ReportOrgUtil.OrgScope centerScope) throws BOSException, SQLException { List centers = ReportOrgUtil.getDistinctOrgNameCodes( ctx, ReportOrgUtil.LAYER_CENTER, companyId); centers = applyCenterFastFilter(centers, centerScope); List result = ReportOrgUtil.filterOrgNameCodes(centers, filterItemsStr); logger.error("中心数量: " + result.size()); return result; } private List applyCenterFastFilter(List centers, ReportOrgUtil.OrgScope centerScope) { if (centerScope == null) { return centers; } if (!StringUtils.isEmpty(centerScope.orgName)) { List filtered = new ArrayList(); for (ReportOrgUtil.OrgNameCode center : centers) { if (centerScope.orgName.equals(center.orgName)) { filtered.add(center); } } return filtered.isEmpty() ? centers : filtered; } return centers; } private PersonnelStatUtil.StatScope buildCenterStatScope(String centerName, String companyId) { return PersonnelStatUtil.StatScope.center(centerName, companyId); } }