体检统计:"给未选发送消息"bug整改,改成分批发送用户

This commit is contained in:
2026-05-13 10:54:52 +08:00
parent 90c5335526
commit 99fc264143
5 changed files with 331 additions and 126 deletions
@@ -107,6 +107,20 @@ public interface SmsService {
*/ */
void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl); void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl);
/**
* 群发短信文本卡片消息
* @param loginNames 接收人工号列表(必填,不能为空列表)
* @param content 卡片内容(必填)
* @param pcUrl PC端跳转链接(必填)
* @param mobileUrl 移动端跳转链接(必填)
* @param type 类型(如:体检管理)
* @param projectName 项目名称
* @param remark 备注信息
* @return
*/
void massSendTextCard(List<String> loginNames, String content, String pcUrl, String mobileUrl, String type, String projectName, String remark);
/** /**
* 群发图文卡片消息 * 群发图文卡片消息
* @param loginNames 接收人工号列表(必填,不能为空列表) * @param loginNames 接收人工号列表(必填,不能为空列表)
@@ -1,21 +1,29 @@
package com.budwk.app.base.sms.impl.ncu; package com.budwk.app.base.sms.impl.ncu;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import com.budwk.app.base.sms.SmsService; import com.budwk.app.base.sms.SmsService;
import com.budwk.app.base.sms.impl.ncu.util.SmsTokenUtil; import com.budwk.app.base.sms.impl.ncu.util.SmsTokenUtil;
import com.budwk.app.sys.models.Sys_msg;
import com.budwk.app.sys.models.Sys_msg_user;
import com.budwk.app.sys.views.View_user;
import com.budwk.app.web.commons.auth.utils.SecurityUtil;
import com.budwk.app.web.commons.base.Globals; import com.budwk.app.web.commons.base.Globals;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json; import org.nutz.json.Json;
import org.nutz.lang.Lang; import org.nutz.lang.Lang;
import org.nutz.lang.Times;
import java.util.Arrays; import java.util.*;
import java.util.HashMap; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
@@ -29,6 +37,8 @@ public class SmsNcuServiceImpl implements SmsService {
@Inject @Inject
private SmsTokenUtil smsTokenUtil; private SmsTokenUtil smsTokenUtil;
@Inject
private Dao dao;
private static final String SEND_MSG_URL = "https://poa.ncu.edu.cn/apis/messagecenter/v1/poaMessage/messageSend"; private static final String SEND_MSG_URL = "https://poa.ncu.edu.cn/apis/messagecenter/v1/poaMessage/messageSend";
private static final String APP_ID = "72e34a101d3011f1a74cbae5193504f4"; private static final String APP_ID = "72e34a101d3011f1a74cbae5193504f4";
@@ -71,8 +81,7 @@ public class SmsNcuServiceImpl implements SmsService {
@Override @Override
public void massSendMessage(List<String> loginNames, String title, String content) { public void massSendMessage(List<String> loginNames, String title, String content) {
String list = String.join(",", loginNames); this.doSend("text", loginNames, title, content, null, null, null);
this.doSend("text", list, title, content, null, null, null);
} }
@Override @Override
@@ -82,8 +91,12 @@ public class SmsNcuServiceImpl implements SmsService {
@Override @Override
public void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl) { public void massSendTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl) {
String list = String.join(",", loginNames); this.doSend("textCard", loginNames, title, content, pcUrl, mobileUrl, null);
this.doSend("textCard", list, title, content, pcUrl, mobileUrl, null); }
@Override
public void massSendTextCard(List<String> loginNames, String content, String pcUrl, String mobileUrl, String type, String projectName, String remark) {
this.doSendAndMessageRecordByType("textCard", loginNames, "智慧工会", content, pcUrl, mobileUrl, null, type, projectName, remark);
} }
@Override @Override
@@ -93,12 +106,11 @@ public class SmsNcuServiceImpl implements SmsService {
@Override @Override
public void massSendPicTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl) { public void massSendPicTextCard(List<String> loginNames, String title, String content, String pcUrl, String mobileUrl, String picUrl) {
String list = String.join(",", loginNames); this.doSend("news", loginNames, title, content, pcUrl, mobileUrl, picUrl);
this.doSend("news", list, title, content, pcUrl, mobileUrl, picUrl);
} }
private void doSend(String sendType, private void doSend(String sendType,
String receivers, List<String> loginNames,
String title, String title,
String content, String content,
String pcUrl, String pcUrl,
@@ -113,6 +125,7 @@ public class SmsNcuServiceImpl implements SmsService {
return; return;
} }
String receivers = String.join(",", loginNames);
if (Lang.isEmpty(receivers)) { if (Lang.isEmpty(receivers)) {
log.error("【log】send fail by receivers is null"); log.error("【log】send fail by receivers is null");
return; return;
@@ -168,4 +181,168 @@ public class SmsNcuServiceImpl implements SmsService {
log.error("【log】发送消息通知失败", e); log.error("【log】发送消息通知失败", e);
} }
} }
/**
* 消息发送 成功后记录消息信息
*
* @param sendType
* @param loginNames
* @param title
* @param content
* @param pcUrl
* @param mobileUrl
* @param projectName
* @param type
* @param remark
*/
private void doSendAndMessageRecordByType(String sendType, List<String> loginNames, String title,
String content, String pcUrl, String mobileUrl, String picUrl, String type, String projectName, String remark) {
if (!Globals.sso) {
log.error("【log】本地开发模式不允许调用消息接口");
return;
}
if (!Globals.MyConfig.getBoolean("AppNotify", false)) {
log.error("【log】消息配置未开启");
return;
}
//消息推送记录
long time = Times.getTS();
String userId = SecurityUtil.getUserId();
Sys_msg sysMsg = new Sys_msg();
sysMsg.setType(type);
sysMsg.setTitle(projectName);
sysMsg.setNote(content);
sysMsg.setSendAt(time);
sysMsg.setCreatedBy(userId);
sysMsg.setCreatedAt(time);
sysMsg.setUpdatedBy(userId);
sysMsg.setUpdatedAt(time);
sysMsg.setDelFlag(false);
sysMsg.setSendType("show");
List<Sys_msg_user> sysMsgUsersInsert = new ArrayList<>();
List<List<String>> loginNameLists = chunkList(loginNames, 50);
for (List<String> loginNameList : loginNameLists) {
String receivers = String.join(",", loginNameList);
if (Lang.isEmpty(receivers)) {
log.error("【log】send fail by receivers is null");
return;
}
List<Sys_msg_user> sysMsgUsers = loginNameList.stream().map(loginName -> {
Sys_msg_user sysMsgUser = new Sys_msg_user();
sysMsgUser.setLoginname(loginName);
sysMsgUser.setReadAt(Times.getTS());
sysMsgUser.setCreatedAt(time);
sysMsgUser.setCreatedBy(userId);
sysMsgUser.setUpdatedAt(time);
sysMsgUser.setUpdatedBy(userId);
sysMsgUser.setDelFlag(false);
return sysMsgUser;
}).collect(Collectors.toList());
try {
String token = smsTokenUtil.getToken();
if (Lang.isEmpty(token)) {
log.error("【log】send fail by token is null");
return;
}
Map<String, Object> params = new HashMap<>();
params.put("appId", APP_ID);
params.put("sendId", "");
params.put("sendType", Stream.of("WECHAT").toArray());
params.put("messageTypeCode", TEMPLATE_ID);
params.put("promise", false);
params.put("importantIdentity", false);
params.put("toPersons", receivers);
Map<String, Object> dataParams = new HashMap<>();
dataParams.put("title", title);
dataParams.put("paramValueJson", Map.of("content", content));
if ("textCard".equals(sendType)) {
dataParams.put("url", pcUrl);
dataParams.put("mobileUrl", mobileUrl);
}
if ("news".equals(sendType)) {
dataParams.put("url", pcUrl);
dataParams.put("mobileUrl", mobileUrl);
dataParams.put("coverImageUrl", picUrl);
}
params.put("data", dataParams);
log.info("【log】发送消息通知,请求参数:{}", Json.toJson(params));
String body = HttpUtil.createPost(SEND_MSG_URL)
.header("Authorization", token)
.header("Content-Type", "application/json")
.body(Json.toJson(params)).execute().body();
JSONObject resultJsonBody = JSONUtil.parseObj(body);
log.info("【log】发送消息通知,接口响应数据:{}", body);
Integer codeStatus = resultJsonBody.getInt("code");
if (codeStatus == 0) {
log.info("【log】发送消息通知成功");
for (Sys_msg_user sysMsgUser : sysMsgUsers) {
sysMsgUser.setBackStatus(codeStatus);
sysMsgUser.setBackText("发送成功");
}
sysMsgUsersInsert.addAll(sysMsgUsers);
} else {
String message = resultJsonBody.getStr("message");
for (Sys_msg_user sysMsgUser : sysMsgUsers) {
sysMsgUser.setBackStatus(codeStatus);
sysMsgUser.setBackText(message);
}
sysMsgUsersInsert.addAll(sysMsgUsers);
log.info("【log】发送消息通知失败:{}", message);
}
} catch (Exception e) {
String message = "发送失败,接口异常:"+e.getMessage();
for (Sys_msg_user sysMsgUser : sysMsgUsers) {
sysMsgUser.setBackStatus(500);
sysMsgUser.setBackText(message);
}
sysMsgUsersInsert.addAll(sysMsgUsers);
log.error("【log】发送消息通知失败", e);
}
}
//记录发送状态及消息
Set<String> loginNameSet = sysMsgUsersInsert.stream().map(Sys_msg_user::getLoginname).collect(Collectors.toSet());
List<View_user> viewUsers = dao.query(View_user.class, Cnd.where("loginname", "in", loginNameSet));
for (Sys_msg_user sysMsgUser : sysMsgUsersInsert) {
String loginname = sysMsgUser.getLoginname();
View_user viewUser = viewUsers.stream().filter(e -> e.getLoginname().equals(loginname)).findFirst().orElse(null);
if(ObjectUtil.isNotEmpty(viewUser)) {
sysMsgUser.setUserName(viewUser.getUsername());
sysMsgUser.setUnitId(viewUser.getUnitId());
sysMsgUser.setUnitName(viewUser.getUnitName());
sysMsgUser.setUnionId(viewUser.getUnionId());
sysMsgUser.setUnionName(viewUser.getUnionName());
}
}
Sys_msg sys_msg = dao.insert(sysMsg);
for (Sys_msg_user sysMsgUser : sysMsgUsersInsert) {
sysMsgUser.setMsgId(sys_msg.getId());
}
dao.insert(sysMsgUsersInsert);
}
/**
* 不安全的集合
*
* @param list 需要拆分的集合
* @param chunkSize 以多少条数据进行拆分; 每个新集合多少条数据
* @param <T>
* @return
*/
public static <T> List<List<T>> chunkList(List<T> list, int chunkSize) {
List<List<T>> chunks = new CopyOnWriteArrayList<>();
for (int i = 0; i < list.size(); i += chunkSize) {
chunks.add(list.subList(i, Math.min(i + chunkSize, list.size())));
}
return chunks;
}
} }
@@ -9,6 +9,7 @@ import org.nutz.dao.interceptor.annotation.PrevInsert;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date;
import java.util.List; import java.util.List;
@@ -72,4 +73,9 @@ public class Sys_msg extends BaseModel implements Serializable {
@ColDefine(type = ColType.VARCHAR, width = 10) @ColDefine(type = ColType.VARCHAR, width = 10)
private String sendType; private String sendType;
@Column
@Comment("备注")
@ColDefine(type = ColType.TEXT)
private String remarks;
} }
@@ -74,6 +74,11 @@ public class Sys_msg_user extends BaseModel implements Serializable {
@One(field = "msgId") @One(field = "msgId")
private Sys_msg msg; private Sys_msg msg;
@Column
@Comment("发送状态")
@ColDefine(type = ColType.INT)
private Integer backStatus;
@Column @Column
@Comment("反馈内容") @Comment("反馈内容")
@ColDefine(type = ColType.VARCHAR, width = 500) @ColDefine(type = ColType.VARCHAR, width = 500)
@@ -447,7 +447,10 @@ public class HealthCheckupSingleController {
smsService.massSendTextCard(loginNameList, smsService.massSendTextCard(loginNameList,
smsMessage, smsMessage,
"#", "#",
Globals.AppDomain); Globals.AppDomain,
"healthCheckup",
project.getName(),
"未体检人员消息提醒");
return Result.success("提醒成功"); return Result.success("提醒成功");
} else { } else {
return Result.success("不存在未体检人员"); return Result.success("不存在未体检人员");