EvaResultSummaryManagerListHandlerEx.java 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package com.kingdee.eas.custom.perfweb.handler;
  2. import com.kingdee.bos.Context;
  3. import com.kingdee.bos.metadata.entity.*;
  4. import com.kingdee.bos.metadata.query.util.CompareType;
  5. import com.kingdee.eas.custom.perfweb.utils.FeishuMessageUtil;
  6. import com.kingdee.eas.custom.perfweb.utils.UrlParamUtil;
  7. import com.kingdee.eas.custom.perfweb.service.CenterPerfStatService;
  8. import com.kingdee.shr.base.syssetting.context.SHRContext;
  9. import com.kingdee.shr.base.syssetting.exception.SHRWebException;
  10. import com.kingdee.shr.base.syssetting.web.json.JSONUtils;
  11. import com.kingdee.shr.perfweb.app.base.evalplan.*;
  12. import com.kingdee.shr.perfweb.planexecute.handler.EvaResultSummaryManagerListHandler;
  13. import org.apache.commons.lang3.StringUtils;
  14. import org.slf4j.Logger;
  15. import org.slf4j.LoggerFactory;
  16. import org.springframework.ui.ModelMap;
  17. import javax.servlet.http.HttpServletRequest;
  18. import javax.servlet.http.HttpServletResponse;
  19. import java.util.*;
  20. /**
  21. * 类名称: EvaResultSummaryManagerListHandlerEx
  22. * 功能描述: 考核结果汇总列表发送飞书消息
  23. * 创建日期: 2026-06-15 10:54
  24. * 作 者: 青梧
  25. * 版 本: 1.0
  26. */
  27. public class EvaResultSummaryManagerListHandlerEx extends EvaResultSummaryManagerListHandler {
  28. private static final Logger logger = LoggerFactory.getLogger(EvaResultSummaryManagerListHandlerEx.class);
  29. /** 标品考核结果汇总 billState:3 = 已审批(审批通过) */
  30. private static final String BILL_STATE_AUDITED = "3";
  31. /**
  32. * 发送飞书消息按钮 Action 入口
  33. * <p>
  34. * 按前端勾选的每条考核结果,向对应<strong>被考核人本人</strong>各发一条飞书通知(勾选几条发几条)。
  35. * 发送前须校验:对应考核周期下全部「考核结果说明」均已审批通过(autoStatus = SPTG)。
  36. * 单条考核结果须已审批(billState = 3,与列表「绩效状态」一致)。消息正文见 {@link FeishuMessageUtil#buildEvaResultSummaryFeishuMessage}。
  37. */
  38. public void sendFeishuToLeadersAction(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException {
  39. Context ctx = SHRContext.getInstance().getContext();
  40. Map<String, Object> res = new HashMap<>();
  41. String billId = this.getBillId(request);
  42. if (StringUtils.isBlank(billId)) {
  43. res.put("result", "500");
  44. res.put("msg", "请先勾选需要发送消息的考核结果");
  45. JSONUtils.writeJson(response, res);
  46. return;
  47. }
  48. try {
  49. // 保留前端勾选顺序,每条 billId 对应一条发送
  50. List<String> selectedBillIds = parseSelectedBillIds(billId);
  51. if (selectedBillIds.isEmpty()) {
  52. res.put("result", "500");
  53. res.put("msg", "勾选的考核结果ID无效");
  54. JSONUtils.writeJson(response, res);
  55. return;
  56. }
  57. Map<String, EvaResultSummaryInfo> summaryById = loadSummaryByIds(ctx, selectedBillIds);
  58. if (summaryById.isEmpty()) {
  59. res.put("result", "500");
  60. res.put("msg", "未查询到勾选的考核结果数据");
  61. JSONUtils.writeJson(response, res);
  62. return;
  63. }
  64. Set<String> periodIds = collectPeriodIds(summaryById);
  65. for (String periodId : periodIds) {
  66. String blockMsg = CenterPerfStatService.validateAllDescriptionApprovedForNotify(ctx, periodId);
  67. if (blockMsg != null) {
  68. res.put("result", "500");
  69. res.put("msg", blockMsg);
  70. JSONUtils.writeJson(response, res);
  71. return;
  72. }
  73. }
  74. String pcurl = UrlParamUtil.buildPerfPortalFeishuMessageUrl();
  75. String appurl = pcurl;
  76. int successCount = 0;
  77. int skippedNotApproved = 0;
  78. int skippedNoPerson = 0;
  79. int skippedNotFound = 0;
  80. int failCount = 0;
  81. for (int i = 0; i < selectedBillIds.size(); i++) {
  82. String selectedId = selectedBillIds.get(i);
  83. EvaResultSummaryInfo summaryInfo = summaryById.get(selectedId);
  84. if (summaryInfo == null) {
  85. skippedNotFound++;
  86. continue;
  87. }
  88. if (!isApproved(summaryInfo)) {
  89. skippedNotApproved++;
  90. continue;
  91. }
  92. PerfEvaObjectInfo evaObj = summaryInfo.getEvaObj();
  93. PerfPeriodInfo period = summaryInfo.getPeriod();
  94. if (evaObj == null || evaObj.getPerson() == null
  95. || StringUtils.isBlank(evaObj.getPerson().getNumber()) || period == null) {
  96. skippedNoPerson++;
  97. continue;
  98. }
  99. String receiverId = evaObj.getPerson().getNumber();
  100. String periodName = period.getName();
  101. String messageContent = FeishuMessageUtil.buildEvaResultSummaryFeishuMessage(periodName);
  102. String workFlowName = "绩效结果公示通知";
  103. String uuid = "esn_" + selectedId + "_" + receiverId+"_"+System.currentTimeMillis();;
  104. FeishuMessageUtil.ApprovalBotResult sendResult = FeishuMessageUtil.sendRemindMessage(
  105. receiverId, workFlowName, messageContent, pcurl, appurl, uuid);
  106. if (sendResult.isSuccess()) {
  107. successCount++;
  108. } else {
  109. failCount++;
  110. logger.error("考核结果汇总-飞书消息发送失败,billId={},receiverId={},msg={}",
  111. selectedId, receiverId, sendResult.getMsg());
  112. }
  113. }
  114. if (successCount == 0) {
  115. res.put("result", "500");
  116. if (skippedNotApproved > 0) {
  117. res.put("msg", "勾选的考核结果均未审批通过,无法发送(共 " + skippedNotApproved + " 条)");
  118. } else if (skippedNoPerson > 0) {
  119. res.put("msg", "勾选的考核结果中未找到有效的被考核人工号");
  120. } else if (failCount > 0) {
  121. res.put("msg", "飞书消息推送失败,请检查员工工号及飞书接口配置");
  122. } else {
  123. res.put("msg", "未找到可推送的考核结果");
  124. }
  125. JSONUtils.writeJson(response, res);
  126. return;
  127. }
  128. StringBuilder msg = new StringBuilder("飞书消息推送成功,共发送 ").append(successCount).append(" 条");
  129. if (skippedNotApproved > 0) {
  130. msg.append(";").append(skippedNotApproved).append(" 条未审批已跳过");
  131. }
  132. if (skippedNoPerson > 0) {
  133. msg.append(";").append(skippedNoPerson).append(" 条无有效工号已跳过");
  134. }
  135. if (skippedNotFound > 0) {
  136. msg.append(";").append(skippedNotFound).append(" 条未查询到数据已跳过");
  137. }
  138. if (failCount > 0) {
  139. msg.append(";").append(failCount).append(" 条发送失败");
  140. }
  141. res.put("result", "200");
  142. res.put("msg", msg.toString());
  143. logger.info("考核结果汇总-飞书消息推送完成,成功={},未审批跳过={},无工号跳过={},失败={}",
  144. successCount, skippedNotApproved, skippedNoPerson, failCount);
  145. } catch (Exception e) {
  146. logger.error("考核结果汇总-飞书消息推送异常", e);
  147. res.put("result", "500");
  148. res.put("msg", "飞书消息推送失败:" + e.getMessage());
  149. }
  150. JSONUtils.writeJson(response, res);
  151. }
  152. private List<String> parseSelectedBillIds(String billId) {
  153. List<String> selectedBillIds = new ArrayList<>();
  154. Set<String> seen = new HashSet<>();
  155. for (String id : billId.split(",")) {
  156. if (StringUtils.isBlank(id)) {
  157. continue;
  158. }
  159. String trimmed = id.trim();
  160. if (seen.add(trimmed)) {
  161. selectedBillIds.add(trimmed);
  162. }
  163. }
  164. return selectedBillIds;
  165. }
  166. private Map<String, EvaResultSummaryInfo> loadSummaryByIds(Context ctx, List<String> selectedBillIds) throws Exception {
  167. IEvaResultSummary iEvaResultSummary = EvaResultSummaryFactory.getLocalInstance(ctx);
  168. FilterInfo filter = new FilterInfo();
  169. filter.getFilterItems().add(new FilterItemInfo("id", new HashSet<>(selectedBillIds), CompareType.INCLUDE));
  170. SelectorItemCollection sic = new SelectorItemCollection();
  171. sic.add(new SelectorItemInfo("*"));
  172. sic.add(new SelectorItemInfo("evaObj.*"));
  173. sic.add(new SelectorItemInfo("evaObj.person.*"));
  174. sic.add(new SelectorItemInfo("evaObj.workFlow.*"));
  175. sic.add(new SelectorItemInfo("period.*"));
  176. EntityViewInfo evi = new EntityViewInfo();
  177. evi.setFilter(filter);
  178. evi.setSelector(sic);
  179. EvaResultSummaryCollection coll = iEvaResultSummary.getEvaResultSummaryCollection(evi);
  180. Map<String, EvaResultSummaryInfo> summaryById = new HashMap<>();
  181. if (coll == null || coll.isEmpty()) {
  182. return summaryById;
  183. }
  184. for (int i = 0; i < coll.size(); i++) {
  185. EvaResultSummaryInfo info = coll.get(i);
  186. if (info != null && info.getId() != null) {
  187. summaryById.put(info.getId().toString(), info);
  188. }
  189. }
  190. return summaryById;
  191. }
  192. private Set<String> collectPeriodIds(Map<String, EvaResultSummaryInfo> summaryById) {
  193. Set<String> periodIds = new LinkedHashSet<>();
  194. for (EvaResultSummaryInfo info : summaryById.values()) {
  195. if (info == null || info.getPeriod() == null || info.getPeriod().getId() == null) {
  196. continue;
  197. }
  198. periodIds.add(info.getPeriod().getId().toString());
  199. }
  200. return periodIds;
  201. }
  202. private boolean isApproved(EvaResultSummaryInfo info) {
  203. if (info == null) {
  204. return false;
  205. }
  206. return BILL_STATE_AUDITED.equals(StringUtils.trimToEmpty(info.getString("billState")));
  207. }
  208. }