DeptPersonnelStatHandler.java 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package com.kingdee.eas.custom.perfweb.handler;
  2. import com.alibaba.fastjson.JSONObject;
  3. import com.kingdee.bos.BOSException;
  4. import com.kingdee.bos.Context;
  5. import com.kingdee.bos.ctrl.swing.StringUtils;
  6. import com.kingdee.eas.custom.perfweb.util.PersonnelStatUtil;
  7. import com.kingdee.eas.custom.perfweb.util.ReportFilterUtil;
  8. import com.kingdee.eas.custom.perfweb.util.ReportOrgUtil;
  9. import com.kingdee.shr.base.syssetting.context.SHRContext;
  10. import com.kingdee.shr.base.syssetting.exception.SHRWebException;
  11. import com.kingdee.shr.base.syssetting.json.GridDataEntity;
  12. import com.kingdee.shr.base.syssetting.web.handler.ListHandler;
  13. import org.apache.log4j.Logger;
  14. import org.springframework.ui.ModelMap;
  15. import javax.servlet.http.HttpServletRequest;
  16. import javax.servlet.http.HttpServletResponse;
  17. import java.sql.SQLException;
  18. import java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. /**
  23. * 类名称: DeptPersonnelStatHandler
  24. * 功能描述: 按部门统计人员结构报表数据处理
  25. * 创建日期: 2026-06-05
  26. * 作 者: 青梧
  27. * 版 本: 1.0
  28. *
  29. * 返回字段说明:
  30. * deptCode - 部门编码(FNUMBER)
  31. * centerName - 部门名称(列表列名沿用centerName)
  32. * personCount - 在职总人数(含下级组织)
  33. * personPercentage - 人数占全部部门在职合计的百分比
  34. * formalCount - 正式员工人数(员工类型001)
  35. * formalPercentage - 正式员工占本部门总人数的百分比
  36. * trialCount - 试用员工人数(员工类型002)
  37. * trialPercentage - 试用员工占本部门总人数的百分比
  38. * keyTalentCount - 关键人才人数(CFGjrc=1)
  39. */
  40. public class DeptPersonnelStatHandler extends ListHandler {
  41. private static Logger logger = Logger.getLogger(DeptPersonnelStatHandler.class);
  42. Context ctx = SHRContext.getInstance().getContext();
  43. /**
  44. * 列表查询入口:按部门汇总在职人数、正式/试用/关键人才人数及占比,末尾追加合计行。
  45. */
  46. @Override
  47. protected GridDataEntity getGridRequestData(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException {
  48. logger.error("DeptPersonnelStatHandler getGridRequestData------------");
  49. GridDataEntity gridDataEntity = new GridDataEntity();
  50. try {
  51. // 快筛(company字段可能为中心F7) + 列表筛选 filterItems
  52. String filterItem = ReportFilterUtil.getFilterItems(request);
  53. JSONObject fastFilterItemsJson = ReportFilterUtil.parseFastFilterJson(request);
  54. logger.error("filterItem: " + filterItem);
  55. logger.error("fastFilterItemsJson: " + fastFilterItemsJson);
  56. Map<String, String> paramMap = ReportFilterUtil.parseCompanyParams(fastFilterItemsJson, logger, true);
  57. ReportOrgUtil.OrgScope centerScope = ReportFilterUtil.buildCenterOrgScope(ctx, fastFilterItemsJson, logger);
  58. logger.error("查询参数: company=" + paramMap + ", centerScope=" + centerScope.orgName
  59. + ", adminOrg=" + centerScope.adminOrg);
  60. // 公司F7: 限定人员FCompanyID(company字段非中心层级时生效)
  61. String companyId = paramMap.get("companyId");
  62. String centerName = centerScope.orgName;
  63. String adminOrgId = centerScope.adminOrg;
  64. List<ReportOrgUtil.OrgNameCode> deptList = getDeptList(centerName, adminOrgId, companyId, filterItem);
  65. logger.error("中心[" + centerName + "]下部门数量: " + deptList.size());
  66. int totalCount = 0;
  67. int totalFormalCount = 0;
  68. int totalTrialCount = 0;
  69. int totalKeyTalentCount = 0;
  70. List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>();
  71. for (ReportOrgUtil.OrgNameCode dept : deptList) {
  72. String deptName = dept.orgName;
  73. PersonnelStatUtil.PersonnelStat stat = countDeptStat(centerName, adminOrgId, dept.orgCode, deptName, companyId);
  74. Map<String, Object> row = new HashMap<String, Object>();
  75. row.put("deptCode", dept.orgCode); // deptCode: 部门编码(同名取第一个)
  76. row.put("centerName", deptName); // centerName: 部门名称
  77. row.put("personCount", stat.totalCount);
  78. row.put("personPercentage", 0.0);
  79. row.put("formalCount", stat.formalCount);
  80. row.put("formalPercentage", 0.0);
  81. row.put("trialCount", stat.trialCount);
  82. row.put("trialPercentage", 0.0);
  83. row.put("keyTalentCount", stat.keyTalentCount);
  84. dataList.add(row);
  85. totalCount += stat.totalCount;
  86. totalFormalCount += stat.formalCount;
  87. totalTrialCount += stat.trialCount;
  88. totalKeyTalentCount += stat.keyTalentCount;
  89. }
  90. // 第二遍循环:基于全部部门合计数回填各行占比
  91. for (Map<String, Object> row : dataList) {
  92. int personCount = (Integer) row.get("personCount");
  93. int formalCount = (Integer) row.get("formalCount");
  94. int trialCount = (Integer) row.get("trialCount");
  95. // 人数占比 = 本部门人数 / 全部部门在职合计
  96. double personPercentage = totalCount > 0 ? (personCount * 100.0 / totalCount) : 0.0;
  97. row.put("personPercentage", String.format("%.2f", personPercentage) + "%");
  98. // 正式员工占比 = 本部门正式人数 / 本部门总人数
  99. double formalPercentage = personCount > 0 ? (formalCount * 100.0 / personCount) : 0.0;
  100. row.put("formalPercentage", String.format("%.2f", formalPercentage) + "%");
  101. // 试用员工占比 = 本部门试用人数 / 本部门总人数
  102. double trialPercentage = personCount > 0 ? (trialCount * 100.0 / personCount) : 0.0;
  103. row.put("trialPercentage", String.format("%.2f", trialPercentage) + "%");
  104. }
  105. // 合计行
  106. Map<String, Object> totalRow = new HashMap<String, Object>();
  107. totalRow.put("deptCode", "");
  108. totalRow.put("centerName", "合计");
  109. totalRow.put("personCount", totalCount);
  110. totalRow.put("personPercentage", totalCount > 0 ? "100.00%" : "0.00%");
  111. totalRow.put("formalCount", totalFormalCount);
  112. totalRow.put("formalPercentage", totalCount > 0 ? String.format("%.2f", totalFormalCount * 100.0 / totalCount) + "%" : "0.00%");
  113. totalRow.put("trialCount", totalTrialCount);
  114. totalRow.put("trialPercentage", totalCount > 0 ? String.format("%.2f", totalTrialCount * 100.0 / totalCount) + "%" : "0.00%");
  115. totalRow.put("keyTalentCount", totalKeyTalentCount);
  116. dataList.add(totalRow);
  117. gridDataEntity.setRows(dataList);
  118. gridDataEntity.setTotal(dataList.size());
  119. gridDataEntity.setPage(1);
  120. gridDataEntity.setRecords(dataList.size());
  121. logger.error("按部门统计报表数据查询成功,总记录数: " + dataList.size());
  122. } catch (SQLException e) {
  123. logger.error("数据库查询失败", e);
  124. throw new SHRWebException("数据查询失败: " + e.getMessage());
  125. } catch (BOSException e) {
  126. logger.error("业务异常", e);
  127. throw new SHRWebException("业务处理失败: " + e.getMessage());
  128. } catch (Exception e) {
  129. logger.error("未知异常", e);
  130. throw new SHRWebException("系统异常: " + e.getMessage());
  131. }
  132. ReportFilterUtil.applyGridUserData(request, gridDataEntity);
  133. return gridDataEntity;
  134. }
  135. /**
  136. * 查询部门列表:有中心名称时按名称跨公司合并,仅无名称时才用行政组织FID子树。
  137. */
  138. private List<ReportOrgUtil.OrgNameCode> getDeptList(String centerName, String adminOrgId, String companyId,
  139. String filterItemsStr) throws BOSException, SQLException {
  140. List<ReportOrgUtil.OrgNameCode> depts;
  141. if (!StringUtils.isEmpty(centerName)) {
  142. depts = ReportOrgUtil.getDistinctDeptNameCodesUnderCenter(ctx, centerName, companyId);
  143. } else if (!StringUtils.isEmpty(adminOrgId)) {
  144. depts = ReportOrgUtil.getDistinctDeptNameCodesUnderAdminOrg(ctx, adminOrgId, companyId);
  145. } else {
  146. depts = ReportOrgUtil.getDistinctOrgNameCodes(ctx, ReportOrgUtil.LAYER_DEPT, companyId);
  147. }
  148. List<ReportOrgUtil.OrgNameCode> result = ReportOrgUtil.filterOrgNameCodes(depts, filterItemsStr);
  149. logger.error("部门数量: " + result.size());
  150. return result;
  151. }
  152. private PersonnelStatUtil.PersonnelStat countDeptStat(String centerName, String adminOrgId, String deptCode,
  153. String deptName, String companyId) throws BOSException, SQLException {
  154. if (StringUtils.isEmpty(deptName)) {
  155. return new PersonnelStatUtil.PersonnelStat();
  156. }
  157. PersonnelStatUtil.StatScope scope = buildDeptStatScope(centerName, adminOrgId, deptCode, deptName, companyId);
  158. PersonnelStatUtil.PersonnelStat stat = PersonnelStatUtil.countStructure(ctx, scope, logger);
  159. logger.error("部门[" + deptName + "/" + deptCode + "]统计: " + stat.totalCount);
  160. return stat;
  161. }
  162. private PersonnelStatUtil.StatScope buildDeptStatScope(String centerName, String adminOrgId, String deptCode,
  163. String deptName, String companyId) {
  164. if (!StringUtils.isEmpty(centerName) && !StringUtils.isEmpty(deptCode)) {
  165. return PersonnelStatUtil.StatScope.deptUnderCenterByCode(centerName, deptCode, companyId);
  166. }
  167. if (!StringUtils.isEmpty(centerName)) {
  168. return PersonnelStatUtil.StatScope.deptUnderCenter(centerName, deptName, companyId);
  169. }
  170. if (!StringUtils.isEmpty(adminOrgId) && !StringUtils.isEmpty(deptCode)) {
  171. return PersonnelStatUtil.StatScope.deptUnderAdminOrgByCode(adminOrgId, deptCode, companyId);
  172. }
  173. if (!StringUtils.isEmpty(adminOrgId)) {
  174. return PersonnelStatUtil.StatScope.deptUnderAdminOrg(adminOrgId, deptName, companyId);
  175. }
  176. return PersonnelStatUtil.StatScope.dept(deptName, companyId);
  177. }
  178. }