ProbationTurnoverReportHandler.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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.eas.custom.perfweb.util.ReportDateUtil;
  6. import com.kingdee.eas.custom.perfweb.util.ReportFilterUtil;
  7. import com.kingdee.eas.custom.perfweb.util.ReportOrgUtil;
  8. import com.kingdee.eas.custom.perfweb.util.ReportTurnoverUtil;
  9. import com.kingdee.shr.base.syssetting.context.SHRContext;
  10. import com.kingdee.shr.base.syssetting.exception.ShrWebBizException;
  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.*;
  19. /**
  20. * 类名称: ProbationTurnoverReportHandler
  21. * 功能描述: 试用期流失率报表(期间试用期人员主动/被动离职及累计离职、累计入职、累计流失率)
  22. * 创建日期: 2026-06-23
  23. * 作 者: 青梧
  24. * 版 本: 1.1
  25. *
  26. * 返回字段说明:
  27. * month - 月份(合计行显示合计)
  28. * activeResign - 期间试用期人员主动离职(员工类型002)
  29. * passiveResign - 期间试用期人员被动离职
  30. * totalResign - 期间试用期人员离职合计
  31. * newEntry - 期间试用期人员入职人数
  32. * ytdActiveResign - 截止目前累计主动离职
  33. * ytdPassiveResign - 截止目前累计被动离职
  34. * ytdTotalResign - 截止目前累计离职合计
  35. * ytdEntry - 截止目前累计试用期入职
  36. * ytdActiveRate - 截止目前累计主动流失率(两位小数%)
  37. * ytdPassiveRate - 截止目前累计被动流失率(两位小数%)
  38. * ytdTotalRate - 截止目前累计总流失率(两位小数%)
  39. */
  40. public class ProbationTurnoverReportHandler extends ListHandler {
  41. private static Logger logger = Logger.getLogger(ProbationTurnoverReportHandler.class);
  42. Context ctx = SHRContext.getInstance().getContext();
  43. /** 试用员工类型编码 */
  44. private static final String TRIAL_EMPLOYEE_TYPE = "002";
  45. /**
  46. * 列表查询入口:按年度逐月统计试用期人员流失,末尾追加合计行。
  47. */
  48. @Override
  49. protected GridDataEntity getGridRequestData(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws ShrWebBizException {
  50. logger.error("ProbationTurnoverReportHandler getGridRequestData------------");
  51. GridDataEntity gridDataEntity = new GridDataEntity();
  52. try {
  53. // 快筛(company字段可能为中心F7) + 列表筛选
  54. String filterItem = ReportFilterUtil.getFilterItems(request);
  55. JSONObject fastFilterItemsJson = ReportFilterUtil.parseFastFilterJson(request);
  56. logger.error("filterItem: " + filterItem);
  57. logger.error("fastFilterItemsJson: " + fastFilterItemsJson);
  58. ReportOrgUtil.OrgScope scope = ReportFilterUtil.buildCenterOrgScope(ctx, fastFilterItemsJson, logger);
  59. String year = ReportFilterUtil.resolveYear(filterItem, fastFilterItemsJson, logger);
  60. logger.error("查询年度: " + year);
  61. List<Map<String, Object>> monthDataList = getMonthTurnoverData(year, scope);
  62. monthDataList.add(calculateSummary(monthDataList));
  63. gridDataEntity.setRows(monthDataList);
  64. gridDataEntity.setTotal(monthDataList.size());
  65. gridDataEntity.setPage(1);
  66. gridDataEntity.setRecords(monthDataList.size());
  67. logger.error("试用期流失率报表数据查询成功,总记录数: " + monthDataList.size());
  68. } catch (Exception e) {
  69. e.fillInStackTrace();
  70. throw new ShrWebBizException(e.getMessage());
  71. }
  72. ReportFilterUtil.applyGridUserData(request, gridDataEntity);
  73. return gridDataEntity;
  74. }
  75. /**
  76. * 循环1~12月,逐月统计试用期离职/入职及累计指标。
  77. */
  78. private List<Map<String, Object>> getMonthTurnoverData(String year, ReportOrgUtil.OrgScope scope) throws BOSException, SQLException {
  79. List<Map<String, Object>> dataList = new ArrayList<Map<String, Object>>();
  80. int ytdActiveResign = 0;
  81. int ytdPassiveResign = 0;
  82. int ytdTotalResign = 0;
  83. int ytdEntry = 0;
  84. for (int month = 1; month <= 12; month++) {
  85. Map<String, Object> monthData = new LinkedHashMap<String, Object>();
  86. monthData.put("month", ReportDateUtil.formatMonthLabel(year, month)); // month: 月份
  87. String monthStart = ReportDateUtil.getMonthStart(year, month);
  88. String monthEnd = ReportDateUtil.getMonthEnd(year, month);
  89. int activeResignCount = getResignCount(monthStart, monthEnd, false, scope);
  90. monthData.put("activeResign", activeResignCount); // activeResign: 期间主动离职
  91. int passiveResignCount = getResignCount(monthStart, monthEnd, true, scope);
  92. monthData.put("passiveResign", passiveResignCount); // passiveResign: 期间被动离职
  93. int totalResignCount = activeResignCount + passiveResignCount;
  94. monthData.put("totalResign", totalResignCount); // totalResign: 期间离职合计
  95. int newEntryCount = getEntryCount(monthStart, monthEnd, scope);
  96. monthData.put("newEntry", newEntryCount); // newEntry: 期间试用期入职
  97. ytdActiveResign += activeResignCount;
  98. monthData.put("ytdActiveResign", ytdActiveResign); // ytdActiveResign: 累计主动离职
  99. ytdPassiveResign += passiveResignCount;
  100. monthData.put("ytdPassiveResign", ytdPassiveResign); // ytdPassiveResign: 累计被动离职
  101. ytdTotalResign += totalResignCount;
  102. monthData.put("ytdTotalResign", ytdTotalResign); // ytdTotalResign: 累计离职合计
  103. ytdEntry += newEntryCount;
  104. monthData.put("ytdEntry", ytdEntry); // ytdEntry: 累计试用期入职
  105. monthData.put("ytdActiveRate", ReportTurnoverUtil.formatRatioPercent(
  106. ReportTurnoverUtil.calculateRatio(ytdActiveResign, ytdEntry))); // ytdActiveRate: 累计主动流失率
  107. monthData.put("ytdPassiveRate", ReportTurnoverUtil.formatRatioPercent(
  108. ReportTurnoverUtil.calculateRatio(ytdPassiveResign, ytdEntry))); // ytdPassiveRate: 累计被动流失率
  109. monthData.put("ytdTotalRate", ReportTurnoverUtil.formatRatioPercent(
  110. ReportTurnoverUtil.calculateRatio(ytdTotalResign, ytdEntry))); // ytdTotalRate: 累计总流失率
  111. dataList.add(monthData);
  112. }
  113. return dataList;
  114. }
  115. /**
  116. * 统计试用期人员离职人数。
  117. * 口径:取离职单分录离职前员工类型 FOldEmpTypeID=002,不能用人员档案当前类型(离职后可能已变更)。
  118. *
  119. * @param isPassive true=被动离职,false=主动离职
  120. */
  121. private int getResignCount(String monthStart, String monthEnd, boolean isPassive, ReportOrgUtil.OrgScope scope) throws BOSException, SQLException {
  122. StringBuilder sql = new StringBuilder();
  123. sql.append("SELECT COUNT(*) as count ");
  124. sql.append("FROM T_HR_ResignBizBillEntry entry ");
  125. sql.append("INNER JOIN T_HR_ResignBizBill bill ON entry.FBillID = bill.FID ");
  126. sql.append("INNER JOIN T_HR_BDEmployeeType empType ON empType.FID = entry.FOLDEMPTYPEID ");
  127. sql.append("WHERE bill.FBillState = 3 ");
  128. sql.append("AND empType.FNumber = '").append(TRIAL_EMPLOYEE_TYPE).append("' ");
  129. sql.append("AND entry.FBizDate >= '").append(monthStart).append("' ");
  130. sql.append("AND entry.FBizDate <= '").append(monthEnd).append("' ");
  131. ReportTurnoverUtil.appendPassiveResignFilter(sql, isPassive);
  132. ReportOrgUtil.appendAdminOrgScopeFilter(sql, ctx, scope, "entry.FAdminOrgID");
  133. return ReportOrgUtil.executeCountQuery(ctx, sql,
  134. "试用期人员" + (isPassive ? "被动" : "主动") + "离职人数", logger);
  135. }
  136. /**
  137. * 统计试用期人员新入职人数。
  138. */
  139. private int getEntryCount(String monthStart, String monthEnd, ReportOrgUtil.OrgScope scope) throws BOSException, SQLException {
  140. StringBuilder sql = new StringBuilder();
  141. sql.append("SELECT COUNT(*) as count ");
  142. sql.append("FROM T_HR_EmpEnrollBizBillEntry entry ");
  143. sql.append("INNER JOIN T_BD_PERSON person ON entry.FPersonID = person.FID ");
  144. sql.append("INNER JOIN T_HR_BDEmployeeType empType ON empType.FID = person.FEMPLOYEETYPEID ");
  145. sql.append("WHERE empType.FNumber = '").append(TRIAL_EMPLOYEE_TYPE).append("' ");
  146. sql.append("AND entry.FBizDate >= '").append(monthStart).append("' ");
  147. sql.append("AND entry.FBizDate <= '").append(monthEnd).append("' ");
  148. ReportOrgUtil.appendAdminOrgScopeFilter(sql, ctx, scope, "entry.FAdminOrgID");
  149. return ReportOrgUtil.executeCountQuery(ctx, sql, "试用期人员新入职人数", logger);
  150. }
  151. /**
  152. * 合计行:期间字段全年累加,累计字段取12月值并重算流失率。
  153. */
  154. private Map<String, Object> calculateSummary(List<Map<String, Object>> monthDataList) {
  155. Map<String, Object> summary = new LinkedHashMap<String, Object>();
  156. summary.put("month", "合计"); // month: 合计行
  157. int totalActiveResign = 0;
  158. int totalPassiveResign = 0;
  159. int totalResign = 0;
  160. int totalNewEntry = 0;
  161. int totalYtdActiveResign = 0;
  162. int totalYtdPassiveResign = 0;
  163. int totalYtdTotalResign = 0;
  164. int totalYtdEntry = 0;
  165. for (Map<String, Object> monthData : monthDataList) {
  166. totalActiveResign += (Integer) monthData.get("activeResign");
  167. totalPassiveResign += (Integer) monthData.get("passiveResign");
  168. totalResign += (Integer) monthData.get("totalResign");
  169. totalNewEntry += (Integer) monthData.get("newEntry");
  170. }
  171. if (!monthDataList.isEmpty()) {
  172. Map<String, Object> lastMonth = monthDataList.get(monthDataList.size() - 1);
  173. totalYtdActiveResign = (Integer) lastMonth.get("ytdActiveResign");
  174. totalYtdPassiveResign = (Integer) lastMonth.get("ytdPassiveResign");
  175. totalYtdTotalResign = (Integer) lastMonth.get("ytdTotalResign");
  176. totalYtdEntry = (Integer) lastMonth.get("ytdEntry");
  177. }
  178. summary.put("activeResign", totalActiveResign);
  179. summary.put("passiveResign", totalPassiveResign);
  180. summary.put("totalResign", totalResign);
  181. summary.put("newEntry", totalNewEntry);
  182. summary.put("ytdActiveResign", totalYtdActiveResign);
  183. summary.put("ytdPassiveResign", totalYtdPassiveResign);
  184. summary.put("ytdTotalResign", totalYtdTotalResign);
  185. summary.put("ytdEntry", totalYtdEntry);
  186. summary.put("ytdActiveRate", ReportTurnoverUtil.formatRatioPercent(
  187. ReportTurnoverUtil.calculateRatio(totalYtdActiveResign, totalYtdEntry)));
  188. summary.put("ytdPassiveRate", ReportTurnoverUtil.formatRatioPercent(
  189. ReportTurnoverUtil.calculateRatio(totalYtdPassiveResign, totalYtdEntry)));
  190. summary.put("ytdTotalRate", ReportTurnoverUtil.formatRatioPercent(
  191. ReportTurnoverUtil.calculateRatio(totalYtdTotalResign, totalYtdEntry)));
  192. return summary;
  193. }
  194. }