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")));
}
}