package com.kingdee.eas.custom.perfweb.handler; import com.kingdee.bos.Context; import com.kingdee.bos.metadata.entity.*; import com.kingdee.bos.metadata.query.util.CompareType; import com.kingdee.eas.custom.perfweb.utils.FeishuMessageUtil; import com.kingdee.eas.custom.perfweb.utils.UrlParamUtil; import com.kingdee.eas.custom.perfweb.service.CenterPerfStatService; import com.kingdee.shr.base.syssetting.context.SHRContext; import com.kingdee.shr.base.syssetting.exception.SHRWebException; import com.kingdee.shr.base.syssetting.web.json.JSONUtils; import com.kingdee.shr.perfweb.app.base.evalplan.*; import com.kingdee.shr.perfweb.planexecute.handler.EvaResultSummaryManagerListHandler; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ui.ModelMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.*; /** * 类名称: EvaResultSummaryManagerListHandlerEx * 功能描述: 考核结果汇总列表发送飞书消息 * 创建日期: 2026-06-15 10:54 * 作 者: 青梧 * 版 本: 1.0 */ public class EvaResultSummaryManagerListHandlerEx extends EvaResultSummaryManagerListHandler { private static final Logger logger = LoggerFactory.getLogger(EvaResultSummaryManagerListHandlerEx.class); /** 标品考核结果汇总 billState:3 = 已审批(审批通过) */ private static final String BILL_STATE_AUDITED = "3"; /** * 发送飞书消息按钮 Action 入口 *

* 按前端勾选的每条考核结果,向对应被考核人本人各发一条飞书通知(勾选几条发几条)。 * 发送前须校验:对应考核周期下全部「考核结果说明」均已审批通过(autoStatus = SPTG)。 * 单条考核结果须已审批(billState = 3,与列表「绩效状态」一致)。消息正文见 {@link FeishuMessageUtil#buildEvaResultSummaryFeishuMessage}。 */ public void sendFeishuToLeadersAction(HttpServletRequest request, HttpServletResponse response, ModelMap modelMap) throws SHRWebException { Context ctx = SHRContext.getInstance().getContext(); Map res = new HashMap<>(); String billId = this.getBillId(request); if (StringUtils.isBlank(billId)) { res.put("result", "500"); res.put("msg", "请先勾选需要发送消息的考核结果"); JSONUtils.writeJson(response, res); return; } try { // 保留前端勾选顺序,每条 billId 对应一条发送 List selectedBillIds = parseSelectedBillIds(billId); if (selectedBillIds.isEmpty()) { res.put("result", "500"); res.put("msg", "勾选的考核结果ID无效"); JSONUtils.writeJson(response, res); return; } Map summaryById = loadSummaryByIds(ctx, selectedBillIds); if (summaryById.isEmpty()) { res.put("result", "500"); res.put("msg", "未查询到勾选的考核结果数据"); JSONUtils.writeJson(response, res); return; } Set periodIds = collectPeriodIds(summaryById); for (String periodId : periodIds) { String blockMsg = CenterPerfStatService.validateAllDescriptionApprovedForNotify(ctx, periodId); if (blockMsg != null) { res.put("result", "500"); res.put("msg", blockMsg); JSONUtils.writeJson(response, res); return; } } String pcurl = UrlParamUtil.buildPerfPortalFeishuMessageUrl(); String appurl = pcurl; int successCount = 0; int skippedNotApproved = 0; int skippedNoPerson = 0; int skippedNotFound = 0; int failCount = 0; for (int i = 0; i < selectedBillIds.size(); i++) { String selectedId = selectedBillIds.get(i); EvaResultSummaryInfo summaryInfo = summaryById.get(selectedId); if (summaryInfo == null) { skippedNotFound++; continue; } if (!isApproved(summaryInfo)) { skippedNotApproved++; continue; } PerfEvaObjectInfo evaObj = summaryInfo.getEvaObj(); PerfPeriodInfo period = summaryInfo.getPeriod(); if (evaObj == null || evaObj.getPerson() == null || StringUtils.isBlank(evaObj.getPerson().getNumber()) || period == null) { skippedNoPerson++; continue; } String receiverId = evaObj.getPerson().getNumber(); String periodName = period.getName(); String messageContent = FeishuMessageUtil.buildEvaResultSummaryFeishuMessage(periodName); String workFlowName = "绩效结果公示通知"; String uuid = "esn_" + selectedId + "_" + receiverId+"_"+System.currentTimeMillis();; FeishuMessageUtil.ApprovalBotResult sendResult = FeishuMessageUtil.sendRemindMessage( receiverId, workFlowName, messageContent, pcurl, appurl, uuid); if (sendResult.isSuccess()) { successCount++; } else { failCount++; logger.error("考核结果汇总-飞书消息发送失败,billId={},receiverId={},msg={}", selectedId, receiverId, sendResult.getMsg()); } } if (successCount == 0) { res.put("result", "500"); if (skippedNotApproved > 0) { res.put("msg", "勾选的考核结果均未审批通过,无法发送(共 " + skippedNotApproved + " 条)"); } else if (skippedNoPerson > 0) { res.put("msg", "勾选的考核结果中未找到有效的被考核人工号"); } else if (failCount > 0) { res.put("msg", "飞书消息推送失败,请检查员工工号及飞书接口配置"); } else { res.put("msg", "未找到可推送的考核结果"); } JSONUtils.writeJson(response, res); return; } StringBuilder msg = new StringBuilder("飞书消息推送成功,共发送 ").append(successCount).append(" 条"); if (skippedNotApproved > 0) { msg.append(";").append(skippedNotApproved).append(" 条未审批已跳过"); } if (skippedNoPerson > 0) { msg.append(";").append(skippedNoPerson).append(" 条无有效工号已跳过"); } if (skippedNotFound > 0) { msg.append(";").append(skippedNotFound).append(" 条未查询到数据已跳过"); } if (failCount > 0) { msg.append(";").append(failCount).append(" 条发送失败"); } res.put("result", "200"); res.put("msg", msg.toString()); logger.info("考核结果汇总-飞书消息推送完成,成功={},未审批跳过={},无工号跳过={},失败={}", successCount, skippedNotApproved, skippedNoPerson, failCount); } catch (Exception e) { logger.error("考核结果汇总-飞书消息推送异常", e); res.put("result", "500"); res.put("msg", "飞书消息推送失败:" + e.getMessage()); } JSONUtils.writeJson(response, res); } private List parseSelectedBillIds(String billId) { List selectedBillIds = new ArrayList<>(); Set seen = new HashSet<>(); for (String id : billId.split(",")) { if (StringUtils.isBlank(id)) { continue; } String trimmed = id.trim(); if (seen.add(trimmed)) { selectedBillIds.add(trimmed); } } return selectedBillIds; } private Map loadSummaryByIds(Context ctx, List selectedBillIds) throws Exception { IEvaResultSummary iEvaResultSummary = EvaResultSummaryFactory.getLocalInstance(ctx); FilterInfo filter = new FilterInfo(); filter.getFilterItems().add(new FilterItemInfo("id", new HashSet<>(selectedBillIds), CompareType.INCLUDE)); SelectorItemCollection sic = new SelectorItemCollection(); sic.add(new SelectorItemInfo("*")); sic.add(new SelectorItemInfo("evaObj.*")); sic.add(new SelectorItemInfo("evaObj.person.*")); sic.add(new SelectorItemInfo("evaObj.workFlow.*")); sic.add(new SelectorItemInfo("period.*")); EntityViewInfo evi = new EntityViewInfo(); evi.setFilter(filter); evi.setSelector(sic); EvaResultSummaryCollection coll = iEvaResultSummary.getEvaResultSummaryCollection(evi); Map summaryById = new HashMap<>(); if (coll == null || coll.isEmpty()) { return summaryById; } for (int i = 0; i < coll.size(); i++) { EvaResultSummaryInfo info = coll.get(i); if (info != null && info.getId() != null) { summaryById.put(info.getId().toString(), info); } } return summaryById; } private Set collectPeriodIds(Map summaryById) { Set periodIds = new LinkedHashSet<>(); for (EvaResultSummaryInfo info : summaryById.values()) { if (info == null || info.getPeriod() == null || info.getPeriod().getId() == null) { continue; } periodIds.add(info.getPeriod().getId().toString()); } return periodIds; } private boolean isApproved(EvaResultSummaryInfo info) { if (info == null) { return false; } return BILL_STATE_AUDITED.equals(StringUtils.trimToEmpty(info.getString("billState"))); } }