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; /** * 类名称: DeptPersonnelStatHandler * 功能描述: 按部门统计人员结构报表数据处理 * 创建日期: 2026-06-05 * 作 者: 青梧 * 版 本: 1.0 * * 返回字段说明: * deptCode - 部门编码(FNUMBER) * centerName - 部门名称(列表列名沿用centerName) * personCount - 在职总人数(含下级组织) * personPercentage - 人数占全部部门在职合计的百分比 * formalCount - 正式员工人数(员工类型001) * formalPercentage - 正式员工占本部门总人数的百分比 * trialCount - 试用员工人数(员工类型002) * trialPercentage - 试用员工占本部门总人数的百分比 * keyTalentCount - 关键人才人数(CFGjrc=1) */ public class DeptPersonnelStatHandler extends ListHandler { private static Logger logger = Logger.getLogger(DeptPersonnelStatHandler.class); Context ctx = SHRContext.getInstance().getContext(); /** * 列表查询入口:按部门汇总在职人数、正式/试用/关键人才人数及占比,末尾追加合计行。 */ @Override protected GridDataEntity getGridRequestData(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException { logger.error("DeptPersonnelStatHandler 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, true); ReportOrgUtil.OrgScope centerScope = ReportFilterUtil.buildCenterOrgScope(ctx, fastFilterItemsJson, logger); logger.error("查询参数: company=" + paramMap + ", centerScope=" + centerScope.orgName + ", adminOrg=" + centerScope.adminOrg); // 公司F7: 限定人员FCompanyID(company字段非中心层级时生效) String companyId = paramMap.get("companyId"); String centerName = centerScope.orgName; String adminOrgId = centerScope.adminOrg; List deptList = getDeptList(centerName, adminOrgId, companyId, filterItem); logger.error("中心[" + centerName + "]下部门数量: " + deptList.size()); int totalCount = 0; int totalFormalCount = 0; int totalTrialCount = 0; int totalKeyTalentCount = 0; List> dataList = new ArrayList>(); for (ReportOrgUtil.OrgNameCode dept : deptList) { String deptName = dept.orgName; PersonnelStatUtil.PersonnelStat stat = countDeptStat(centerName, adminOrgId, dept.orgCode, deptName, companyId); Map row = new HashMap(); row.put("deptCode", dept.orgCode); // deptCode: 部门编码(同名取第一个) row.put("centerName", deptName); // centerName: 部门名称 row.put("personCount", stat.totalCount); row.put("personPercentage", 0.0); row.put("formalCount", stat.formalCount); row.put("formalPercentage", 0.0); row.put("trialCount", stat.trialCount); row.put("trialPercentage", 0.0); row.put("keyTalentCount", stat.keyTalentCount); dataList.add(row); totalCount += stat.totalCount; totalFormalCount += stat.formalCount; totalTrialCount += stat.trialCount; totalKeyTalentCount += stat.keyTalentCount; } // 第二遍循环:基于全部部门合计数回填各行占比 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("deptCode", ""); totalRow.put("centerName", "合计"); totalRow.put("personCount", totalCount); totalRow.put("personPercentage", totalCount > 0 ? "100.00%" : "0.00%"); totalRow.put("formalCount", totalFormalCount); totalRow.put("formalPercentage", totalCount > 0 ? String.format("%.2f", totalFormalCount * 100.0 / totalCount) + "%" : "0.00%"); totalRow.put("trialCount", totalTrialCount); totalRow.put("trialPercentage", totalCount > 0 ? String.format("%.2f", totalTrialCount * 100.0 / totalCount) + "%" : "0.00%"); totalRow.put("keyTalentCount", totalKeyTalentCount); dataList.add(totalRow); 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; } /** * 查询部门列表:有中心名称时按名称跨公司合并,仅无名称时才用行政组织FID子树。 */ private List getDeptList(String centerName, String adminOrgId, String companyId, String filterItemsStr) throws BOSException, SQLException { List depts; if (!StringUtils.isEmpty(centerName)) { depts = ReportOrgUtil.getDistinctDeptNameCodesUnderCenter(ctx, centerName, companyId); } else if (!StringUtils.isEmpty(adminOrgId)) { depts = ReportOrgUtil.getDistinctDeptNameCodesUnderAdminOrg(ctx, adminOrgId, companyId); } else { depts = ReportOrgUtil.getDistinctOrgNameCodes(ctx, ReportOrgUtil.LAYER_DEPT, companyId); } List result = ReportOrgUtil.filterOrgNameCodes(depts, filterItemsStr); logger.error("部门数量: " + result.size()); return result; } private PersonnelStatUtil.PersonnelStat countDeptStat(String centerName, String adminOrgId, String deptCode, String deptName, String companyId) throws BOSException, SQLException { if (StringUtils.isEmpty(deptName)) { return new PersonnelStatUtil.PersonnelStat(); } PersonnelStatUtil.StatScope scope = buildDeptStatScope(centerName, adminOrgId, deptCode, deptName, companyId); PersonnelStatUtil.PersonnelStat stat = PersonnelStatUtil.countStructure(ctx, scope, logger); logger.error("部门[" + deptName + "/" + deptCode + "]统计: " + stat.totalCount); return stat; } private PersonnelStatUtil.StatScope buildDeptStatScope(String centerName, String adminOrgId, String deptCode, String deptName, String companyId) { if (!StringUtils.isEmpty(centerName) && !StringUtils.isEmpty(deptCode)) { return PersonnelStatUtil.StatScope.deptUnderCenterByCode(centerName, deptCode, companyId); } if (!StringUtils.isEmpty(centerName)) { return PersonnelStatUtil.StatScope.deptUnderCenter(centerName, deptName, companyId); } if (!StringUtils.isEmpty(adminOrgId) && !StringUtils.isEmpty(deptCode)) { return PersonnelStatUtil.StatScope.deptUnderAdminOrgByCode(adminOrgId, deptCode, companyId); } if (!StringUtils.isEmpty(adminOrgId)) { return PersonnelStatUtil.StatScope.deptUnderAdminOrg(adminOrgId, deptName, companyId); } return PersonnelStatUtil.StatScope.dept(deptName, companyId); } }