福利发消息整改
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package com.budwk.app.base.sms;
|
package com.budwk.app.base.sms;
|
||||||
|
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
import com.budwk.app.sys.models.Sys_user;
|
||||||
|
import org.nutz.lang.util.NutMap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -47,6 +48,15 @@ public interface SmsService {
|
|||||||
* @param content 消息正文
|
* @param content 消息正文
|
||||||
* @param pcUrl PC端跳转链接
|
* @param pcUrl PC端跳转链接
|
||||||
* @param mobileUrl 手机端跳转链接
|
* @param mobileUrl 手机端跳转链接
|
||||||
|
* @return 统一消息平台返回的消息标识集合;每个标识可用于查询该批消息的最终发送结果
|
||||||
*/
|
*/
|
||||||
void massSendByUsers(List<Sys_user> users, String title, String content, String pcUrl, String mobileUrl);
|
List<String> massSendByUsers(List<Sys_user> users, String title, String content, String pcUrl, String mobileUrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询学校统一消息平台的批量发送结果。
|
||||||
|
*
|
||||||
|
* @param messageId 批量发送接口返回的消息标识;同一批次的接收人使用该标识查询最终送达结果
|
||||||
|
* @return 查询结果,包含消息总数、成功数、失败数及失败接收人数组;调用失败时抛出业务异常
|
||||||
|
*/
|
||||||
|
NutMap getMessageResult(String messageId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.nutz.json.Json;
|
|||||||
import org.nutz.lang.Lang;
|
import org.nutz.lang.Lang;
|
||||||
import org.nutz.lang.util.NutMap;
|
import org.nutz.lang.util.NutMap;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -66,12 +67,18 @@ public class SmsYpiServiceImpl implements SmsService {
|
|||||||
* 兼容统一消息V4新增的批量发送接口;旧版实现不再注册为发送服务,仅保留历史调用能力。
|
* 兼容统一消息V4新增的批量发送接口;旧版实现不再注册为发送服务,仅保留历史调用能力。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void massSendByUsers(List<Sys_user> users, String title, String content, String pcUrl, String mobileUrl) {
|
public List<String> massSendByUsers(List<Sys_user> users, String title, String content, String pcUrl, String mobileUrl) {
|
||||||
List<String> loginNames = users.stream()
|
List<String> loginNames = users.stream()
|
||||||
.map(Sys_user::getLoginname)
|
.map(Sys_user::getLoginname)
|
||||||
.filter(StrUtil::isNotBlank)
|
.filter(StrUtil::isNotBlank)
|
||||||
.toList();
|
.toList();
|
||||||
massSend(loginNames, title, content, StrUtil.blankToDefault(mobileUrl, pcUrl));
|
massSend(loginNames, title, content, StrUtil.blankToDefault(mobileUrl, pcUrl));
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NutMap getMessageResult(String messageId) {
|
||||||
|
throw new UnsupportedOperationException("旧版学校消息网关不支持统一消息V4发送结果查询");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.nutz.integration.jedis.RedisService;
|
|||||||
import org.nutz.ioc.impl.PropertiesProxy;
|
import org.nutz.ioc.impl.PropertiesProxy;
|
||||||
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.lang.util.NutMap;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -63,9 +64,9 @@ public class UnifiedMessageV4ServiceImpl implements SmsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void massSendByUsers(List<Sys_user> users, String title, String content, String pcUrl, String mobileUrl) {
|
public List<String> massSendByUsers(List<Sys_user> users, String title, String content, String pcUrl, String mobileUrl) {
|
||||||
if (users == null || users.isEmpty()) {
|
if (users == null || users.isEmpty()) {
|
||||||
return;
|
return List.of();
|
||||||
}
|
}
|
||||||
List<Receiver> receivers = users.stream()
|
List<Receiver> receivers = users.stream()
|
||||||
.filter(user -> StrUtil.isNotBlank(user.getLoginname()) && StrUtil.isNotBlank(user.getUsername()))
|
.filter(user -> StrUtil.isNotBlank(user.getLoginname()) && StrUtil.isNotBlank(user.getUsername()))
|
||||||
@@ -74,13 +75,14 @@ public class UnifiedMessageV4ServiceImpl implements SmsService {
|
|||||||
if (receivers.isEmpty()) {
|
if (receivers.isEmpty()) {
|
||||||
throw new BaseException("学校统一消息发送失败:接收人工号或姓名不能为空");
|
throw new BaseException("学校统一消息发送失败:接收人工号或姓名不能为空");
|
||||||
}
|
}
|
||||||
sendMessage(title, content, createReceivers(receivers), pcUrl, mobileUrl);
|
return sendMessage(title, content, createReceivers(receivers), pcUrl, mobileUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 调用统一消息V4普通消息接口;有链接时按外链模式同时传递PC和手机端地址。
|
* 调用统一消息V4普通消息接口;有链接时按外链模式同时传递PC和手机端地址。
|
||||||
|
* 返回值为平台入队后生成的消息标识集合,供业务侧随后查询最终逐人发送结果。
|
||||||
*/
|
*/
|
||||||
private void sendMessage(String title, String content, JSONArray receivers, String pcUrl, String mobileUrl) {
|
private List<String> sendMessage(String title, String content, JSONArray receivers, String pcUrl, String mobileUrl) {
|
||||||
String token = getAccessToken();
|
String token = getAccessToken();
|
||||||
boolean hasLink = StrUtil.isNotBlank(pcUrl) || StrUtil.isNotBlank(mobileUrl);
|
boolean hasLink = StrUtil.isNotBlank(pcUrl) || StrUtil.isNotBlank(mobileUrl);
|
||||||
JSONObject body = JSONUtil.createObj();
|
JSONObject body = JSONUtil.createObj();
|
||||||
@@ -108,7 +110,20 @@ public class UnifiedMessageV4ServiceImpl implements SmsService {
|
|||||||
if (response.getInt("state", 0) != 200) {
|
if (response.getInt("state", 0) != 200) {
|
||||||
throw new BaseException("学校统一消息发送失败:{}", response.getStr("message", responseBody));
|
throw new BaseException("学校统一消息发送失败:{}", response.getStr("message", responseBody));
|
||||||
}
|
}
|
||||||
log.info("学校统一消息发送成功,接收人数量={},response={}", receivers.size(), responseBody);
|
JSONArray messageIdArray = response.getJSONArray("data");
|
||||||
|
if (messageIdArray == null || messageIdArray.isEmpty()) {
|
||||||
|
throw new BaseException("学校统一消息发送失败:平台未返回消息标识");
|
||||||
|
}
|
||||||
|
List<String> messageIds = messageIdArray.stream()
|
||||||
|
.map(String::valueOf)
|
||||||
|
.filter(StrUtil::isNotBlank)
|
||||||
|
.toList();
|
||||||
|
if (messageIds.isEmpty()) {
|
||||||
|
throw new BaseException("学校统一消息发送失败:平台返回的消息标识为空");
|
||||||
|
}
|
||||||
|
log.info("学校统一消息发送已入队,接收人数量={},messageIds={},response={}",
|
||||||
|
receivers.size(), messageIds, responseBody);
|
||||||
|
return messageIds;
|
||||||
} catch (BaseException e) {
|
} catch (BaseException e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -117,6 +132,47 @@ public class UnifiedMessageV4ServiceImpl implements SmsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 调用统一消息V4结果查询接口。
|
||||||
|
* 参数为批量发送返回的messageId;返回NutMap中的messageTotal、successCount、failCount、resultState和failedUsers
|
||||||
|
* 分别表示平台统计的总人数、成功人数、失败人数、结果状态和失败用户明细。
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public NutMap getMessageResult(String messageId) {
|
||||||
|
if (StrUtil.isBlank(messageId)) {
|
||||||
|
throw new BaseException("学校统一消息结果查询失败:消息标识不能为空");
|
||||||
|
}
|
||||||
|
String resultUrl = getRequiredConfig("school-message.result-url").replace("{messageId}", messageId);
|
||||||
|
try {
|
||||||
|
HttpRequest request = HttpRequest.post(resultUrl)
|
||||||
|
.header("domain-name", getRequiredConfig("school-message.domain-name"))
|
||||||
|
.header("token", getAccessToken());
|
||||||
|
addInterceptDomainHeader(request);
|
||||||
|
String responseBody = request.execute().body();
|
||||||
|
JSONObject response = JSONUtil.parseObj(responseBody);
|
||||||
|
if (response.getInt("state", 0) != 200 || response.getJSONObject("data") == null) {
|
||||||
|
throw new BaseException("学校统一消息结果查询失败:{}", response.getStr("message", responseBody));
|
||||||
|
}
|
||||||
|
JSONObject data = response.getJSONObject("data");
|
||||||
|
NutMap result = NutMap.NEW()
|
||||||
|
.addv("messageId", messageId)
|
||||||
|
.addv("messageTotal", data.getInt("msgTotal", 0))
|
||||||
|
.addv("resultState", data.getStr("state"))
|
||||||
|
.addv("successCount", data.getInt("successCount", 0))
|
||||||
|
.addv("failCount", data.getInt("failCount", 0))
|
||||||
|
.addv("failedUsers", data.getJSONArray("user"));
|
||||||
|
log.info("学校统一消息结果查询成功,messageId={},messageTotal={},successCount={},failCount={},resultState={}",
|
||||||
|
messageId, result.getInt("messageTotal", 0), result.getInt("successCount", 0),
|
||||||
|
result.getInt("failCount", 0), result.getString("resultState"));
|
||||||
|
return result;
|
||||||
|
} catch (BaseException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("学校统一消息结果查询异常,url={},messageId={}", resultUrl, messageId, e);
|
||||||
|
throw new BaseException("学校统一消息结果查询异常:{}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取学校统一消息V4令牌;文档有效期为300秒,缓存270秒避免临界过期。
|
* 获取学校统一消息V4令牌;文档有效期为300秒,缓存270秒避免临界过期。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.budwk.app.flow.param;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学校OA批量待办创建参数。
|
||||||
|
* 公共流程字段在本对象中传递,接收人差异字段放在userList中,对应学校OA的/handle/batch/insert接口。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SchoolOaTodoBatchCreateParam {
|
||||||
|
|
||||||
|
private String flowTypeName;
|
||||||
|
private String flowId;
|
||||||
|
private String title;
|
||||||
|
private String stepName;
|
||||||
|
private String creatorCode;
|
||||||
|
private String creatorName;
|
||||||
|
private String creatorTime;
|
||||||
|
private String startPcPreviewUrl;
|
||||||
|
private String startAppPreviewUrl;
|
||||||
|
private List<SchoolOaTodoReceiverParam> userList;
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package com.budwk.app.flow.param;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 学校OA批量待办中的单个接收人参数,对应批量接口userList数组的一个元素。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SchoolOaTodoReceiverParam {
|
||||||
|
|
||||||
|
private String pcUrl;
|
||||||
|
private String appUrl;
|
||||||
|
private String uniqueId;
|
||||||
|
private String receiveCode;
|
||||||
|
private String receiveName;
|
||||||
|
private String receiveTime;
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.budwk.app.flow.service;
|
package com.budwk.app.flow.service;
|
||||||
|
|
||||||
import com.budwk.app.flow.entity.ProcessTask;
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
|
import com.budwk.app.flow.param.SchoolOaTodoBatchCreateParam;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 学校 OA 待办同步服务。
|
* 学校 OA 待办同步服务。
|
||||||
@@ -43,30 +44,17 @@ public interface SchoolOaTodoService {
|
|||||||
void updateFlowFinishedStepName(Long processInstanceId);
|
void updateFlowFinishedStepName(Long processInstanceId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建福利选择提醒待办。
|
* 创建学校OA批量待办。
|
||||||
*
|
*
|
||||||
* @param projectId 福利项目ID,用于构造学校OA业务标识
|
* @param todoParam 批量待办公共字段及userList接收人数组
|
||||||
* @param title 待办标题,学校OA接口没有独立正文时用于展示提醒内容
|
|
||||||
* @param pcUrl PC端福利选择地址
|
|
||||||
* @param appUrl 手机端福利选择地址
|
|
||||||
* @param creatorId 待办创建人ID
|
|
||||||
* @param receiverId 待办接收人ID
|
|
||||||
* @return 学校OA待办唯一值
|
|
||||||
*/
|
*/
|
||||||
String createWelfareReminderTodo(String projectId, String title, String pcUrl, String appUrl, String creatorId, String receiverId);
|
void createBatchTodo(SchoolOaTodoBatchCreateParam todoParam);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将指定的学校OA福利提醒待办改为已办。
|
* 根据待办唯一值将学校OA待办改为已办。
|
||||||
*
|
*
|
||||||
* @param uniqueId 创建待办时记录的学校OA唯一值
|
* @param uniqueId 创建待办时传入的唯一标识
|
||||||
*/
|
*/
|
||||||
void completeWelfareReminderTodo(String uniqueId);
|
void completeTodoByUniqueId(String uniqueId);
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除用户已完成福利选择对应的学校OA提醒待办。
|
|
||||||
*
|
|
||||||
* @param projectId 福利项目ID
|
|
||||||
* @param userId 完成选择的用户ID
|
|
||||||
*/
|
|
||||||
void deleteWelfareReminderTodo(String projectId, String userId);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import com.budwk.app.flow.entity.ProcessInstance;
|
|||||||
import com.budwk.app.flow.entity.ProcessTask;
|
import com.budwk.app.flow.entity.ProcessTask;
|
||||||
import com.budwk.app.flow.entity.ProcessTaskActor;
|
import com.budwk.app.flow.entity.ProcessTaskActor;
|
||||||
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
import com.budwk.app.flow.enums.ProcessTaskStateEnum;
|
||||||
|
import com.budwk.app.flow.param.SchoolOaTodoBatchCreateParam;
|
||||||
|
import com.budwk.app.flow.param.SchoolOaTodoReceiverParam;
|
||||||
import com.budwk.app.flow.service.SchoolOaTodoService;
|
import com.budwk.app.flow.service.SchoolOaTodoService;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
import com.budwk.app.sys.models.Sys_user;
|
||||||
import com.budwk.app.web.commons.base.Globals;
|
import com.budwk.app.web.commons.base.Globals;
|
||||||
@@ -27,6 +29,7 @@ import org.nutz.ioc.loader.annotation.Inject;
|
|||||||
import org.nutz.ioc.loader.annotation.IocBean;
|
import org.nutz.ioc.loader.annotation.IocBean;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -201,48 +204,63 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String createWelfareReminderTodo(String projectId, String title, String pcUrl, String appUrl, String creatorId, String receiverId) {
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
if (!isSchoolOaEnabled("创建福利选择提醒待办", null, null)) {
|
public void createBatchTodo(SchoolOaTodoBatchCreateParam todoParam) {
|
||||||
return null;
|
if (!isSchoolOaEnabled("创建批量待办", null, null)) {
|
||||||
|
throw new BaseException("学校OA待办开关状态已变化,本次待办未发送");
|
||||||
}
|
}
|
||||||
if (StrUtil.hasBlank(projectId, title, pcUrl, appUrl, creatorId, receiverId)) {
|
if (todoParam == null || StrUtil.hasBlank(todoParam.getFlowTypeName(), todoParam.getFlowId(), todoParam.getTitle(),
|
||||||
throw new BaseException("学校OA福利选择提醒待办参数不完整");
|
todoParam.getStepName(), todoParam.getCreatorCode(), todoParam.getCreatorName(), todoParam.getCreatorTime(),
|
||||||
|
todoParam.getStartPcPreviewUrl(), todoParam.getStartAppPreviewUrl())
|
||||||
|
|| todoParam.getUserList() == null || todoParam.getUserList().isEmpty()) {
|
||||||
|
throw new BaseException("学校OA批量待办创建参数不完整");
|
||||||
}
|
}
|
||||||
|
|
||||||
Sys_user creator = dao.fetch(Sys_user.class, creatorId);
|
List<JSONObject> userList = new ArrayList<>();
|
||||||
if (creator == null || StrUtil.hasBlank(creator.getLoginname(), creator.getUsername())) {
|
for (SchoolOaTodoReceiverParam receiverParam : todoParam.getUserList()) {
|
||||||
throw new BaseException("学校OA福利选择提醒待办创建人工号或姓名为空,userId={}", creatorId);
|
if (receiverParam == null || StrUtil.hasBlank(receiverParam.getPcUrl(), receiverParam.getAppUrl(),
|
||||||
|
receiverParam.getUniqueId(), receiverParam.getReceiveCode(), receiverParam.getReceiveName(),
|
||||||
|
receiverParam.getReceiveTime())) {
|
||||||
|
throw new BaseException("学校OA批量待办接收人参数不完整");
|
||||||
|
}
|
||||||
|
JSONObject receiverBody = new JSONObject();
|
||||||
|
receiverBody.set("pcUrl", receiverParam.getPcUrl());
|
||||||
|
receiverBody.set("appUrl", receiverParam.getAppUrl());
|
||||||
|
receiverBody.set("uniqueId", receiverParam.getUniqueId());
|
||||||
|
receiverBody.set("receiveCode", receiverParam.getReceiveCode());
|
||||||
|
receiverBody.set("receiveName", receiverParam.getReceiveName());
|
||||||
|
receiverBody.set("receiveTime", receiverParam.getReceiveTime());
|
||||||
|
userList.add(receiverBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sys_user receiver = dao.fetch(Sys_user.class, receiverId);
|
// 学校OA批量接口的公共流程字段在根节点,接收人差异字段仅放在userList中。
|
||||||
if (receiver == null || StrUtil.hasBlank(receiver.getLoginname(), receiver.getUsername())) {
|
JSONObject body = new JSONObject();
|
||||||
throw new BaseException("学校OA福利选择提醒待办接收人工号或姓名为空,userId={}", receiverId);
|
body.set("flowTypeName", todoParam.getFlowTypeName());
|
||||||
}
|
body.set("flowId", todoParam.getFlowId());
|
||||||
return sendWelfareReminderTodo(projectId, title, pcUrl, appUrl, creator, receiver,
|
body.set("title", todoParam.getTitle());
|
||||||
formatTime(System.currentTimeMillis()));
|
body.set("stepName", todoParam.getStepName());
|
||||||
|
body.set("creatorCode", todoParam.getCreatorCode());
|
||||||
|
body.set("creatorName", todoParam.getCreatorName());
|
||||||
|
body.set("creatorTime", todoParam.getCreatorTime());
|
||||||
|
body.set("startPcPreviewUrl", todoParam.getStartPcPreviewUrl());
|
||||||
|
body.set("startAppPreviewUrl", todoParam.getStartAppPreviewUrl());
|
||||||
|
body.set("userList", userList);
|
||||||
|
|
||||||
|
String batchInsertUrl = requireConfig("school-oa.todo.batch-insert-url");
|
||||||
|
String responseBody = sendTodoRequest(batchInsertUrl, body, "学校OA批量待办创建失败", "学校OA批量待办创建异常");
|
||||||
|
log.info("学校OA批量待办创建成功,flowId={},receiverCount={},response={}",
|
||||||
|
todoParam.getFlowId(), userList.size(), responseBody);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void completeWelfareReminderTodo(String uniqueId) {
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
if (!isSchoolOaEnabled("完成福利选择提醒待办", null, null) || StrUtil.isBlank(uniqueId)) {
|
public void completeTodoByUniqueId(String uniqueId) {
|
||||||
|
if (!isSchoolOaEnabled("完成待办", null, null) || StrUtil.isBlank(uniqueId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String updateUrl = requireConfig("school-oa.todo.update-url").replace("{uniqueId}", uniqueId);
|
String updateUrl = requireConfig("school-oa.todo.update-url").replace("{uniqueId}", uniqueId);
|
||||||
String responseBody = sendTodoRequest(updateUrl,
|
String responseBody = sendTodoRequest(updateUrl, "学校OA待办完成失败", "学校OA待办完成异常");
|
||||||
"学校OA福利选择提醒待办完成失败", "学校OA福利选择提醒待办完成异常");
|
log.info("学校OA待办完成成功,uniqueId={},response={}", uniqueId, responseBody);
|
||||||
log.info("学校OA福利选择提醒待办完成成功,uniqueId={},response={}", uniqueId, responseBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void deleteWelfareReminderTodo(String projectId, String userId) {
|
|
||||||
if (!isSchoolOaEnabled("删除福利选择提醒待办", null, null) || StrUtil.hasBlank(projectId, userId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 兼容删除改造前按项目和用户生成的固定唯一值,新的重复提醒不再调用删除逻辑。
|
|
||||||
String uniqueId = buildWelfareReminderFlowId(projectId, userId);
|
|
||||||
String deleteUrl = requireConfig("school-oa.todo.delete-url").replace("{uniqueId}", uniqueId);
|
|
||||||
sendTodoRequest(deleteUrl, "学校OA福利选择提醒待办删除失败", "学校OA福利选择提醒待办删除异常");
|
|
||||||
log.info("学校OA福利选择提醒待办删除成功,projectId={},userId={},uniqueId={}", projectId, userId, uniqueId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -273,29 +291,8 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
|
|||||||
body.set("receiveTime", receiveTime);
|
body.set("receiveTime", receiveTime);
|
||||||
|
|
||||||
String insertUrl = requireConfig("school-oa.todo.insert-url");
|
String insertUrl = requireConfig("school-oa.todo.insert-url");
|
||||||
String requestBody = JSONUtil.toJsonStr(body);
|
String responseBody = sendTodoRequest(insertUrl, body, "学校OA待办创建失败", "学校OA待办创建异常");
|
||||||
log.info("学校OA待办创建请求,url={},taskId={},processInstanceId={},receiveCode={},body={}",
|
log.info("学校OA待办创建成功,taskId={},receiveCode={},response={}", task.getId(), actor.getActorAccount(), responseBody);
|
||||||
insertUrl, task.getId(), instance.getId(), actor.getActorAccount(), requestBody);
|
|
||||||
try {
|
|
||||||
HttpRequest request = HttpUtil.createPost(insertUrl);
|
|
||||||
setTodoRequestHeaders(request);
|
|
||||||
request.body(requestBody);
|
|
||||||
|
|
||||||
String responseBody = request.execute().body();
|
|
||||||
log.info("学校OA待办创建响应,taskId={},receiveCode={},response={}", task.getId(), actor.getActorAccount(), responseBody);
|
|
||||||
JSONObject response = JSONUtil.parseObj(responseBody);
|
|
||||||
if (response.getInt("state", 0) != 200) {
|
|
||||||
log.warn("学校OA待办创建失败响应,taskId={},receiveCode={},response={}", task.getId(), actor.getActorAccount(), responseBody);
|
|
||||||
throw new BaseException("学校OA待办创建失败:{}", response.getStr("message", responseBody));
|
|
||||||
}
|
|
||||||
log.info("学校OA待办创建成功,taskId={},receiveCode={},response={}", task.getId(), actor.getActorAccount(), responseBody);
|
|
||||||
} catch (BaseException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("学校OA待办创建异常,url={},taskId={},processInstanceId={},receiveCode={},body={}",
|
|
||||||
insertUrl, task.getId(), instance.getId(), actor.getActorAccount(), requestBody, e);
|
|
||||||
throw new BaseException("学校OA待办创建异常:{}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,9 +306,8 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String uniqueId = task.getId() + "_" + actor.getActorId();
|
String uniqueId = task.getId() + "_" + actor.getActorId();
|
||||||
String updateUrl = requireConfig("school-oa.todo.update-url").replace("{uniqueId}", uniqueId);
|
completeTodoByUniqueId(uniqueId);
|
||||||
String responseBody = sendTodoRequest(updateUrl, "学校OA待办完成失败", "学校OA待办完成异常");
|
log.info("学校OA待办完成成功,taskId={},receiveCode={},uniqueId={}", task.getId(), actor.getActorAccount(), uniqueId);
|
||||||
log.info("学校OA待办完成成功,taskId={},receiveCode={},uniqueId={},response={}", task.getId(), actor.getActorAccount(), uniqueId, responseBody);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -399,79 +395,6 @@ public class SchoolOaTodoServiceImpl implements SchoolOaTodoService {
|
|||||||
return baseUrl + separator + "taskId=" + task.getId() + "&instanceId=" + task.getProcessInstanceId();
|
return baseUrl + separator + "taskId=" + task.getId() + "&instanceId=" + task.getProcessInstanceId();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 按学校OA固定待办格式创建福利选择提醒,标题承载自定义提醒内容。
|
|
||||||
*/
|
|
||||||
private String sendWelfareReminderTodo(String projectId, String title, String pcUrl, String appUrl,
|
|
||||||
Sys_user creator, Sys_user receiver, String creatorTime) {
|
|
||||||
String uniqueId = buildWelfareReminderUniqueId(projectId, receiver.getId());
|
|
||||||
JSONObject body = new JSONObject();
|
|
||||||
body.set("flowTypeName", "福利选择");
|
|
||||||
body.set("flowId", buildWelfareReminderFlowId(projectId, receiver.getId()));
|
|
||||||
body.set("title", title);
|
|
||||||
body.set("stepName", "福利选择提醒");
|
|
||||||
body.set("creatorCode", creator.getLoginname());
|
|
||||||
body.set("creatorName", creator.getUsername());
|
|
||||||
body.set("creatorTime", creatorTime);
|
|
||||||
body.set("pcUrl", pcUrl);
|
|
||||||
body.set("appUrl", appUrl);
|
|
||||||
body.set("pcPreviewUrl", pcUrl);
|
|
||||||
body.set("appPreviewUrl", appUrl);
|
|
||||||
// 同一项目和用户固定使用一个唯一值,确保学校OA最多存在一条福利提醒待办。
|
|
||||||
body.set("uniqueId", uniqueId);
|
|
||||||
body.set("receiveCode", receiver.getLoginname());
|
|
||||||
body.set("receiveName", receiver.getUsername());
|
|
||||||
body.set("receiveTime", creatorTime);
|
|
||||||
|
|
||||||
String insertUrl = requireConfig("school-oa.todo.insert-url");
|
|
||||||
String requestBody = JSONUtil.toJsonStr(body);
|
|
||||||
log.info("学校OA福利选择提醒待办创建请求,url={},projectId={},receiveCode={},body={}",
|
|
||||||
insertUrl, projectId, receiver.getLoginname(), requestBody);
|
|
||||||
JSONObject response = executeWelfareReminderTodoRequest(insertUrl, requestBody, projectId, receiver.getLoginname());
|
|
||||||
String responseMessage = response.getStr("message", "");
|
|
||||||
if (response.getInt("state", 0) != 200) {
|
|
||||||
// 历史待办已存在时视为创建成功,由本系统补记待办记录并阻止后续重复创建。
|
|
||||||
if (StrUtil.contains(responseMessage, "已存在")) {
|
|
||||||
log.info("学校OA福利选择提醒待办已存在,按发送成功处理,projectId={},receiveCode={},uniqueId={}",
|
|
||||||
projectId, receiver.getLoginname(), uniqueId);
|
|
||||||
return uniqueId;
|
|
||||||
}
|
|
||||||
throw new BaseException("学校OA福利选择提醒待办创建失败:{}", StrUtil.blankToDefault(responseMessage, JSONUtil.toJsonStr(response)));
|
|
||||||
}
|
|
||||||
log.info("学校OA福利选择提醒待办创建成功,projectId={},receiveCode={},response={}",
|
|
||||||
projectId, receiver.getLoginname(), JSONUtil.toJsonStr(response));
|
|
||||||
return uniqueId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用学校OA插入待办接口并返回原始响应;网络和解析异常统一转换为业务异常。
|
|
||||||
*/
|
|
||||||
private JSONObject executeWelfareReminderTodoRequest(String insertUrl, String requestBody, String projectId, String receiverLoginName) {
|
|
||||||
try {
|
|
||||||
HttpRequest request = HttpUtil.createPost(insertUrl);
|
|
||||||
setTodoRequestHeaders(request);
|
|
||||||
request.body(requestBody);
|
|
||||||
String responseBody = request.execute().body();
|
|
||||||
log.info("学校OA福利选择提醒待办创建响应,projectId={},receiveCode={},response={}",
|
|
||||||
projectId, receiverLoginName, responseBody);
|
|
||||||
return JSONUtil.parseObj(responseBody);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("学校OA福利选择提醒待办创建异常,url={},projectId={},receiveCode={},body={}",
|
|
||||||
insertUrl, projectId, receiverLoginName, requestBody, e);
|
|
||||||
throw new BaseException("学校OA福利选择提醒待办创建异常:{}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 同一项目和用户共用固定流程标识。 */
|
|
||||||
private String buildWelfareReminderFlowId(String projectId, String userId) {
|
|
||||||
return "welfare_reminder_" + projectId + "_" + userId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 同一项目和用户固定使用一个待办唯一值。 */
|
|
||||||
private String buildWelfareReminderUniqueId(String projectId, String userId) {
|
|
||||||
return buildWelfareReminderFlowId(projectId, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String buildAppTaskUrl(String h5FormKey, ProcessTask task) {
|
private String buildAppTaskUrl(String h5FormKey, ProcessTask task) {
|
||||||
// 部分流程没有配置 H5 审核页,学校 OA 的移动端地址为空时按要求传固定域名兜底。
|
// 部分流程没有配置 H5 审核页,学校 OA 的移动端地址为空时按要求传固定域名兜底。
|
||||||
if (StrUtil.isBlank(h5FormKey)) {
|
if (StrUtil.isBlank(h5FormKey)) {
|
||||||
|
|||||||
+1
@@ -107,6 +107,7 @@ public class WelfareSelectionSituationController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@At
|
@At
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
@SLog(type = "welfare", tag = "选择情况", msg = "发送福利选择提醒")
|
@SLog(type = "welfare", tag = "选择情况", msg = "发送福利选择提醒")
|
||||||
@SaCheckPermission("welfare.selection.situation")
|
@SaCheckPermission("welfare.selection.situation")
|
||||||
@ApiOperation("发送福利选择提醒")
|
@ApiOperation("发送福利选择提醒")
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package com.budwk.app.zhgh.welfare.model;
|
||||||
|
|
||||||
|
import com.budwk.app.base.model.BaseModel;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import org.nutz.dao.entity.annotation.ColDefine;
|
||||||
|
import org.nutz.dao.entity.annotation.ColType;
|
||||||
|
import org.nutz.dao.entity.annotation.Column;
|
||||||
|
import org.nutz.dao.entity.annotation.Comment;
|
||||||
|
import org.nutz.dao.entity.annotation.Index;
|
||||||
|
import org.nutz.dao.entity.annotation.Name;
|
||||||
|
import org.nutz.dao.entity.annotation.Table;
|
||||||
|
import org.nutz.dao.entity.annotation.TableIndexes;
|
||||||
|
import org.nutz.dao.interceptor.annotation.PrevInsert;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 福利选择学校统一消息发送记录。
|
||||||
|
* 每次提醒批次中的每位接收人各保存一条记录,用于回写统一消息平台的最终成功或失败结果。
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
@Table("welfare_reminder_message")
|
||||||
|
@Comment("福利选择学校统一消息发送记录")
|
||||||
|
@TableIndexes({
|
||||||
|
@Index(name = "UK_WELFARE_REMINDER_MESSAGE_BATCH_USER", fields = {"messageBatchId", "userId"}, unique = true),
|
||||||
|
@Index(name = "IDX_WELFARE_REMINDER_MESSAGE_PROJECT_STATUS", fields = {"projectId", "messageStatus"}, unique = false)
|
||||||
|
})
|
||||||
|
public class WelfareReminderMessage extends BaseModel {
|
||||||
|
|
||||||
|
/** 已提交统一消息平台,等待查询最终结果。 */
|
||||||
|
public static final int STATUS_WAITING_RESULT = 0;
|
||||||
|
/** 统一消息平台返回该接收人发送成功。 */
|
||||||
|
public static final int STATUS_SUCCESS = 1;
|
||||||
|
/** 统一消息平台返回该接收人发送失败,或发送前参数校验失败。 */
|
||||||
|
public static final int STATUS_FAILED = 2;
|
||||||
|
/** 统一消息结果查询异常,尚未能确认接收人的最终发送状态。 */
|
||||||
|
public static final int STATUS_RESULT_QUERY_FAILED = 3;
|
||||||
|
|
||||||
|
@Name
|
||||||
|
@Comment("ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
@PrevInsert(uu32 = true)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("消息发送批次ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String messageBatchId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("福利项目ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String projectId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("接收用户ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String userId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("统一消息平台消息标识,多个标识以英文逗号分隔")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 500)
|
||||||
|
private String messageId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("接收人工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
|
private String receiverCode;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("接收人姓名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String receiverName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("发送人ID")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 32)
|
||||||
|
private String senderId;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("发送人工号")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 50)
|
||||||
|
private String senderCode;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("发送人姓名")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String senderName;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("消息标题")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 100)
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("消息内容")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("状态:0等待结果、1成功、2失败、3结果查询异常")
|
||||||
|
@ColDefine(type = ColType.INT)
|
||||||
|
private Integer messageStatus;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("提交到统一消息平台时间")
|
||||||
|
@ColDefine(type = ColType.DATETIME)
|
||||||
|
private Date sendTime;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("查询到最终结果时间")
|
||||||
|
@ColDefine(type = ColType.DATETIME)
|
||||||
|
private Date resultTime;
|
||||||
|
|
||||||
|
@Column
|
||||||
|
@Comment("发送或结果查询失败原因")
|
||||||
|
@ColDefine(type = ColType.VARCHAR, width = 1000)
|
||||||
|
private String failMessage;
|
||||||
|
}
|
||||||
+435
-38
@@ -6,14 +6,21 @@ import cn.afterturn.easypoi.excel.entity.ExportParams;
|
|||||||
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
||||||
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
||||||
import cn.afterturn.easypoi.excel.export.ExcelExportService;
|
import cn.afterturn.easypoi.excel.export.ExcelExportService;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONArray;
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
import com.budwk.app.base.constant.RoleConstant;
|
import com.budwk.app.base.constant.RoleConstant;
|
||||||
import com.budwk.app.base.page.Pagination;
|
import com.budwk.app.base.page.Pagination;
|
||||||
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
import com.budwk.app.base.service.impl.BaseServiceImpl;
|
||||||
import com.budwk.app.base.utils.CommonDownloadUtil;
|
import com.budwk.app.base.utils.CommonDownloadUtil;
|
||||||
|
import com.budwk.app.base.utils.ManyAddOrRenewUtil;
|
||||||
import com.budwk.app.base.utils.PageUtil;
|
import com.budwk.app.base.utils.PageUtil;
|
||||||
//import com.budwk.app.sys.models.Sys_file;
|
//import com.budwk.app.sys.models.Sys_file;
|
||||||
import com.budwk.app.base.sms.SmsService;
|
import com.budwk.app.base.sms.SmsService;
|
||||||
|
import com.budwk.app.flow.param.SchoolOaTodoBatchCreateParam;
|
||||||
|
import com.budwk.app.flow.param.SchoolOaTodoReceiverParam;
|
||||||
import com.budwk.app.flow.service.SchoolOaTodoService;
|
import com.budwk.app.flow.service.SchoolOaTodoService;
|
||||||
import com.budwk.app.sys.models.Sys_user;
|
import com.budwk.app.sys.models.Sys_user;
|
||||||
import com.budwk.app.sys.services.SysFileService;
|
import com.budwk.app.sys.services.SysFileService;
|
||||||
@@ -25,6 +32,7 @@ import com.budwk.app.zhgh.dayofficework.message.strategy.impl.LocalMessageSendSt
|
|||||||
import com.budwk.app.zhgh.welfare.model.WelfareList;
|
import com.budwk.app.zhgh.welfare.model.WelfareList;
|
||||||
import com.budwk.app.zhgh.welfare.model.WelfareProject;
|
import com.budwk.app.zhgh.welfare.model.WelfareProject;
|
||||||
import com.budwk.app.zhgh.welfare.model.WelfareProjectSubjectOption;
|
import com.budwk.app.zhgh.welfare.model.WelfareProjectSubjectOption;
|
||||||
|
import com.budwk.app.zhgh.welfare.model.WelfareReminderMessage;
|
||||||
import com.budwk.app.zhgh.welfare.model.WelfareReminderTodo;
|
import com.budwk.app.zhgh.welfare.model.WelfareReminderTodo;
|
||||||
import com.budwk.app.zhgh.welfare.model.WelfareUserSelection;
|
import com.budwk.app.zhgh.welfare.model.WelfareUserSelection;
|
||||||
import com.budwk.app.zhgh.welfare.param.WelfareSelectionSituationPageForm;
|
import com.budwk.app.zhgh.welfare.param.WelfareSelectionSituationPageForm;
|
||||||
@@ -37,8 +45,11 @@ import org.nutz.dao.Cnd;
|
|||||||
import org.nutz.dao.Dao;
|
import org.nutz.dao.Dao;
|
||||||
import org.nutz.dao.Sqls;
|
import org.nutz.dao.Sqls;
|
||||||
import org.nutz.dao.sql.Sql;
|
import org.nutz.dao.sql.Sql;
|
||||||
|
import org.nutz.aop.interceptor.ioc.TransAop;
|
||||||
|
import org.nutz.ioc.aop.Aop;
|
||||||
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.lang.random.R;
|
||||||
import org.nutz.lang.util.NutMap;
|
import org.nutz.lang.util.NutMap;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
@@ -65,6 +76,8 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
private SmsService smsService;
|
private SmsService smsService;
|
||||||
@Inject
|
@Inject
|
||||||
private SchoolOaTodoService schoolOaTodoService;
|
private SchoolOaTodoService schoolOaTodoService;
|
||||||
|
@Inject
|
||||||
|
private ManyAddOrRenewUtil manyAddOrRenewUtil;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPreferredMobile(String userId) {
|
public String getPreferredMobile(String userId) {
|
||||||
@@ -168,11 +181,13 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public NutMap sendReminder(WelfareSelectionSituationPageForm pageForm, String[] userIds, String content) {
|
public NutMap sendReminder(WelfareSelectionSituationPageForm pageForm, String[] userIds, String content) {
|
||||||
List<String> recipientIds = getReminderRecipientIds(pageForm, userIds);
|
List<String> recipientIds = getReminderRecipientIds(pageForm, userIds);
|
||||||
if (recipientIds.isEmpty()) {
|
if (recipientIds.isEmpty()) {
|
||||||
return buildReminderResult(0, 0, 0, 0, 0,
|
return buildReminderResult(0, 0, 0, 0, 0, 0,
|
||||||
Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSchoolOa")));
|
Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSms")),
|
||||||
|
Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSchoolOa")), 0, 0);
|
||||||
}
|
}
|
||||||
// 各消息渠道统一使用福利业务标题,学校OA再拼接自定义正文作为待办标题。
|
// 各消息渠道统一使用福利业务标题,学校OA再拼接自定义正文作为待办标题。
|
||||||
String title = "智慧工会职工福利:";
|
String title = "智慧工会职工福利:";
|
||||||
@@ -183,20 +198,41 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
localMessageSendStrategy.send(title, content, 2, recipientIds, null);
|
localMessageSendStrategy.send(title, content, 2, recipientIds, null);
|
||||||
|
|
||||||
List<Sys_user> receiverUsers = dao().query(Sys_user.class, Cnd.where(Sys_user::getId, "in", recipientIds));
|
List<Sys_user> receiverUsers = dao().query(Sys_user.class, Cnd.where(Sys_user::getId, "in", recipientIds));
|
||||||
|
boolean messageEnabled = Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSms"));
|
||||||
|
boolean todoEnabled = Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSchoolOa"));
|
||||||
|
String senderId = SecurityUtil.getUserId();
|
||||||
|
Sys_user sender = null;
|
||||||
|
if (messageEnabled || todoEnabled) {
|
||||||
|
sender = dao().fetch(Sys_user.class, senderId);
|
||||||
|
if (sender == null || StrUtil.hasBlank(sender.getId(), sender.getLoginname(), sender.getUsername())) {
|
||||||
|
throw new IllegalStateException("福利选择提醒创建人信息不完整");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int messageSuccessCount = 0;
|
||||||
|
int messageFailedCount = 0;
|
||||||
|
int messageResultQueryFailedCount = 0;
|
||||||
// AppSms 控制学校消息平台发送,消息链接跳转到手机端福利选择列表。
|
// AppSms 控制学校消息平台发送,消息链接跳转到手机端福利选择列表。
|
||||||
if (Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSms")) && !receiverUsers.isEmpty()) {
|
if (messageEnabled) {
|
||||||
smsService.massSendByUsers(receiverUsers, title, content, pcUrl, appUrl);
|
NutMap messageResult = sendReminderMessageBatch(pageForm.getProjectId(), recipientIds, receiverUsers,
|
||||||
|
sender, title, content, pcUrl, appUrl);
|
||||||
|
messageSuccessCount = messageResult.getInt("successCount", 0);
|
||||||
|
messageFailedCount = messageResult.getInt("failedCount", 0);
|
||||||
|
messageResultQueryFailedCount = messageResult.getInt("resultQueryFailedCount", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean todoEnabled = Boolean.TRUE.equals(Globals.MyConfig.getBoolean("AppSchoolOa"));
|
|
||||||
int todoSuccessCount = 0;
|
int todoSuccessCount = 0;
|
||||||
int existingTodoCount = 0;
|
int existingTodoCount = 0;
|
||||||
int todoFailedCount = 0;
|
int todoFailedCount = 0;
|
||||||
if (todoEnabled) {
|
if (todoEnabled) {
|
||||||
Map<String, Sys_user> receiverUserMap = receiverUsers.stream()
|
Map<String, Sys_user> receiverUserMap = receiverUsers.stream()
|
||||||
.collect(Collectors.toMap(Sys_user::getId, user -> user, (left, right) -> left));
|
.collect(Collectors.toMap(Sys_user::getId, user -> user, (left, right) -> left));
|
||||||
|
Map<String, WelfareReminderTodo> reminderTodoMap = getReminderTodoMap(pageForm.getProjectId(), recipientIds);
|
||||||
|
List<WelfareReminderTodo> newSendingReminderTodos = new ArrayList<>();
|
||||||
|
List<WelfareReminderTodo> retrySendingReminderTodos = new ArrayList<>();
|
||||||
|
List<String> sendingReceiverIds = new ArrayList<>();
|
||||||
for (String recipientId : recipientIds) {
|
for (String recipientId : recipientIds) {
|
||||||
WelfareReminderTodo reminderTodo = getReminderTodo(pageForm.getProjectId(), recipientId);
|
WelfareReminderTodo reminderTodo = reminderTodoMap.get(recipientId);
|
||||||
if (isExistingReminderTodo(reminderTodo)) {
|
if (isExistingReminderTodo(reminderTodo)) {
|
||||||
existingTodoCount++;
|
existingTodoCount++;
|
||||||
continue;
|
continue;
|
||||||
@@ -204,21 +240,15 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
|
|
||||||
Sys_user receiver = receiverUserMap.get(recipientId);
|
Sys_user receiver = receiverUserMap.get(recipientId);
|
||||||
try {
|
try {
|
||||||
// 发送前先落库为“发送中”,确保每一次实际发起的OA待办都可追溯。
|
// 仅在内存中组装记录,随后按“新增”和“重试”分别执行批量数据库写入。
|
||||||
reminderTodo = saveSendingReminderTodo(reminderTodo, pageForm.getProjectId(), receiver,
|
reminderTodo = prepareSendingReminderTodo(reminderTodo, pageForm.getProjectId(), receiver,
|
||||||
SecurityUtil.getUserId(), title + content, content);
|
sender, title + content, content);
|
||||||
String uniqueId = schoolOaTodoService.createWelfareReminderTodo(pageForm.getProjectId(), title + content,
|
sendingReceiverIds.add(recipientId);
|
||||||
pcUrl, appUrl, SecurityUtil.getUserId(), recipientId);
|
if (reminderTodoMap.containsKey(recipientId)) {
|
||||||
if (StrUtil.isBlank(uniqueId)) {
|
retrySendingReminderTodos.add(reminderTodo);
|
||||||
throw new IllegalStateException("学校OA待办开关状态已变化,本次待办未发送");
|
} else {
|
||||||
|
newSendingReminderTodos.add(reminderTodo);
|
||||||
}
|
}
|
||||||
reminderTodo.setOaUniqueId(uniqueId);
|
|
||||||
reminderTodo.setTodoStatus(WelfareReminderTodo.STATUS_PENDING);
|
|
||||||
reminderTodo.setSendTime(new Date());
|
|
||||||
reminderTodo.setFinishTime(null);
|
|
||||||
reminderTodo.setFailMessage(null);
|
|
||||||
dao().update(reminderTodo);
|
|
||||||
todoSuccessCount++;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
todoFailedCount++;
|
todoFailedCount++;
|
||||||
saveReminderTodoFailure(reminderTodo, pageForm.getProjectId(), recipientId, receiver,
|
saveReminderTodoFailure(reminderTodo, pageForm.getProjectId(), recipientId, receiver,
|
||||||
@@ -227,12 +257,42 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
pageForm.getProjectId(), recipientId, e);
|
pageForm.getProjectId(), recipientId, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!sendingReceiverIds.isEmpty()) {
|
||||||
|
persistSendingReminderTodos(pageForm.getProjectId(), newSendingReminderTodos,
|
||||||
|
retrySendingReminderTodos, senderId);
|
||||||
|
log.info("福利选择提醒待办批量写入发送中完成,projectId={},接收人总数={},已有待办跳过={},新增记录={},失败重试记录={}",
|
||||||
|
pageForm.getProjectId(), recipientIds.size(), existingTodoCount,
|
||||||
|
newSendingReminderTodos.size(), retrySendingReminderTodos.size());
|
||||||
|
try {
|
||||||
|
SchoolOaTodoBatchCreateParam todoParam = buildWelfareReminderBatchTodoParam(
|
||||||
|
pageForm.getProjectId(), title + content, pcUrl, appUrl, sender,
|
||||||
|
sendingReceiverIds, receiverUserMap);
|
||||||
|
schoolOaTodoService.createBatchTodo(todoParam);
|
||||||
|
} catch (Exception e) {
|
||||||
|
int updatedCount = updateReminderTodoBatchStatus(pageForm.getProjectId(), sendingReceiverIds,
|
||||||
|
senderId, WelfareReminderTodo.STATUS_FAILED, null, limitFailureMessage(e.getMessage()));
|
||||||
|
todoFailedCount += sendingReceiverIds.size();
|
||||||
|
log.error("福利选择提醒待办批量发送失败并批量更新状态,projectId={},待办人数={},数据库更新行数={},状态={},失败原因={}",
|
||||||
|
pageForm.getProjectId(), sendingReceiverIds.size(), updatedCount,
|
||||||
|
WelfareReminderTodo.STATUS_FAILED, e.getMessage(), e);
|
||||||
|
return buildReminderResult(recipientIds.size(), recipientIds.size(), messageSuccessCount,
|
||||||
|
messageFailedCount, messageResultQueryFailedCount, todoSuccessCount,
|
||||||
|
messageEnabled, todoEnabled, existingTodoCount, todoFailedCount);
|
||||||
|
}
|
||||||
|
int updatedCount = updateReminderTodoBatchStatus(pageForm.getProjectId(), sendingReceiverIds,
|
||||||
|
senderId, WelfareReminderTodo.STATUS_PENDING, new Date(), null);
|
||||||
|
todoSuccessCount = sendingReceiverIds.size();
|
||||||
|
log.info("福利选择提醒待办批量发送成功并批量更新状态,projectId={},待办人数={},数据库更新行数={},状态={}",
|
||||||
|
pageForm.getProjectId(), todoSuccessCount, updatedCount, WelfareReminderTodo.STATUS_PENDING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return buildReminderResult(recipientIds.size(), recipientIds.size(), todoSuccessCount,
|
return buildReminderResult(recipientIds.size(), recipientIds.size(), messageSuccessCount,
|
||||||
existingTodoCount, todoFailedCount, todoEnabled);
|
messageFailedCount, messageResultQueryFailedCount, todoSuccessCount,
|
||||||
|
messageEnabled, todoEnabled, existingTodoCount, todoFailedCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Aop(TransAop.READ_COMMITTED)
|
||||||
public void completeReminderTodo(String projectId, String userId) {
|
public void completeReminderTodo(String projectId, String userId) {
|
||||||
WelfareReminderTodo reminderTodo = getReminderTodo(projectId, userId);
|
WelfareReminderTodo reminderTodo = getReminderTodo(projectId, userId);
|
||||||
if (reminderTodo == null || !Objects.equals(reminderTodo.getTodoStatus(), WelfareReminderTodo.STATUS_PENDING)
|
if (reminderTodo == null || !Objects.equals(reminderTodo.getTodoStatus(), WelfareReminderTodo.STATUS_PENDING)
|
||||||
@@ -240,7 +300,7 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
schoolOaTodoService.completeWelfareReminderTodo(reminderTodo.getOaUniqueId());
|
schoolOaTodoService.completeTodoByUniqueId(reminderTodo.getOaUniqueId());
|
||||||
reminderTodo.setTodoStatus(WelfareReminderTodo.STATUS_COMPLETED);
|
reminderTodo.setTodoStatus(WelfareReminderTodo.STATUS_COMPLETED);
|
||||||
reminderTodo.setFinishTime(new Date());
|
reminderTodo.setFinishTime(new Date());
|
||||||
reminderTodo.setFailMessage(null);
|
reminderTodo.setFailMessage(null);
|
||||||
@@ -253,6 +313,209 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量发送福利选择统一消息并回写逐人结果。
|
||||||
|
* 每名接收人先落一条等待结果记录;统一消息平台接收整批请求后,使用返回的消息标识查询结果,
|
||||||
|
* 再依据失败用户工号批量更新本地成功、失败或查询异常状态。
|
||||||
|
*
|
||||||
|
* @param projectId 福利项目ID
|
||||||
|
* @param recipientIds 本次提醒的全部接收用户ID
|
||||||
|
* @param receiverUsers 已查询到的接收人用户信息
|
||||||
|
* @param sender 发起提醒的系统用户,用于记录发送人信息
|
||||||
|
* @param title 统一消息标题,长度不得超过学校接口要求的100个字符
|
||||||
|
* @param content 统一消息正文
|
||||||
|
* @param pcUrl PC端福利选择链接
|
||||||
|
* @param mobileUrl 移动端福利选择链接
|
||||||
|
* @return 包含成功数、失败数和结果查询异常数的统计结果
|
||||||
|
*/
|
||||||
|
private NutMap sendReminderMessageBatch(String projectId, List<String> recipientIds, List<Sys_user> receiverUsers,
|
||||||
|
Sys_user sender, String title, String content, String pcUrl, String mobileUrl) {
|
||||||
|
if (StrUtil.hasBlank(projectId, title, content) || recipientIds.isEmpty()
|
||||||
|
|| sender == null || StrUtil.hasBlank(sender.getId(), sender.getLoginname(), sender.getUsername())) {
|
||||||
|
throw new IllegalArgumentException("福利选择统一消息批量发送参数不完整");
|
||||||
|
}
|
||||||
|
if (title.length() > 100) {
|
||||||
|
throw new IllegalArgumentException("福利选择统一消息标题长度不能超过100个字符");
|
||||||
|
}
|
||||||
|
|
||||||
|
String senderId = sender.getId();
|
||||||
|
String messageBatchId = R.UU32();
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
Map<String, Sys_user> receiverUserMap = receiverUsers.stream()
|
||||||
|
.collect(Collectors.toMap(Sys_user::getId, user -> user, (left, right) -> left));
|
||||||
|
List<WelfareReminderMessage> records = new ArrayList<>();
|
||||||
|
List<WelfareReminderMessage> validRecords = new ArrayList<>();
|
||||||
|
List<Sys_user> validUsers = new ArrayList<>();
|
||||||
|
for (String recipientId : recipientIds) {
|
||||||
|
Sys_user receiver = receiverUserMap.get(recipientId);
|
||||||
|
WelfareReminderMessage record = createReminderMessageRecord(messageBatchId, projectId, recipientId,
|
||||||
|
receiver, sender, title, content, now);
|
||||||
|
records.add(record);
|
||||||
|
if (receiver == null || StrUtil.hasBlank(receiver.getLoginname(), receiver.getUsername())) {
|
||||||
|
record.setMessageStatus(WelfareReminderMessage.STATUS_FAILED);
|
||||||
|
record.setFailMessage("学校统一消息发送失败:接收人工号或姓名为空");
|
||||||
|
} else {
|
||||||
|
validRecords.add(record);
|
||||||
|
validUsers.add(receiver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.info("福利选择统一消息记录已在内存组装完成,projectId={},messageBatchId={},接收人总数={},可发送人数={},接收人信息失败人数={}",
|
||||||
|
projectId, messageBatchId, records.size(), validUsers.size(), records.size() - validUsers.size());
|
||||||
|
|
||||||
|
if (validUsers.isEmpty()) {
|
||||||
|
persistReminderMessageRecordsAsync(records, projectId, messageBatchId);
|
||||||
|
return NutMap.NEW().addv("successCount", 0).addv("failedCount", records.size()).addv("resultQueryFailedCount", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> messageIds;
|
||||||
|
String messageIdText;
|
||||||
|
try {
|
||||||
|
messageIds = smsService.massSendByUsers(validUsers, title, content, pcUrl, mobileUrl);
|
||||||
|
if (messageIds == null || messageIds.isEmpty()) {
|
||||||
|
throw new IllegalStateException("学校统一消息平台未返回消息标识");
|
||||||
|
}
|
||||||
|
messageIdText = String.join(",", messageIds);
|
||||||
|
Date sendTime = new Date();
|
||||||
|
validRecords.forEach(record -> {
|
||||||
|
record.setMessageId(messageIdText);
|
||||||
|
record.setMessageStatus(WelfareReminderMessage.STATUS_WAITING_RESULT);
|
||||||
|
record.setSendTime(sendTime);
|
||||||
|
record.setFailMessage(null);
|
||||||
|
record.setUpdatedBy(senderId);
|
||||||
|
record.setUpdatedAt(System.currentTimeMillis());
|
||||||
|
});
|
||||||
|
log.info("福利选择统一消息批量发送已入队,等待结果查询后异步写入记录,projectId={},messageBatchId={},messageIds={},接收人数={}",
|
||||||
|
projectId, messageBatchId, messageIds, validRecords.size());
|
||||||
|
} catch (Exception e) {
|
||||||
|
markReminderMessageRecords(validRecords, senderId, WelfareReminderMessage.STATUS_FAILED,
|
||||||
|
null, null, limitFailureMessage(e.getMessage()));
|
||||||
|
persistReminderMessageRecordsAsync(records, projectId, messageBatchId);
|
||||||
|
log.error("福利选择统一消息批量发送失败,已提交异步入库记录,projectId={},messageBatchId={},接收人数={},失败原因={}",
|
||||||
|
projectId, messageBatchId, validRecords.size(), e.getMessage(), e);
|
||||||
|
return NutMap.NEW().addv("successCount", 0).addv("failedCount", records.size()).addv("resultQueryFailedCount", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Map<String, String> failedMessageByCode = queryFailedMessageByReceiverCode(messageIds);
|
||||||
|
Date resultTime = new Date();
|
||||||
|
for (WelfareReminderMessage record : validRecords) {
|
||||||
|
String failMessage = failedMessageByCode.get(record.getReceiverCode());
|
||||||
|
record.setMessageStatus(StrUtil.isBlank(failMessage)
|
||||||
|
? WelfareReminderMessage.STATUS_SUCCESS : WelfareReminderMessage.STATUS_FAILED);
|
||||||
|
record.setResultTime(resultTime);
|
||||||
|
record.setFailMessage(failMessage);
|
||||||
|
record.setUpdatedBy(senderId);
|
||||||
|
record.setUpdatedAt(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
int externalFailedCount = (int) validRecords.stream()
|
||||||
|
.filter(record -> failedMessageByCode.containsKey(record.getReceiverCode()))
|
||||||
|
.count();
|
||||||
|
int failedCount = records.size() - validRecords.size() + externalFailedCount;
|
||||||
|
int successCount = validRecords.size() - externalFailedCount;
|
||||||
|
persistReminderMessageRecordsAsync(records, projectId, messageBatchId);
|
||||||
|
log.info("福利选择统一消息结果查询完成,已提交异步入库记录,projectId={},messageBatchId={},成功人数={},失败人数={},messageIds={}",
|
||||||
|
projectId, messageBatchId, successCount, failedCount, messageIds);
|
||||||
|
return NutMap.NEW().addv("successCount", successCount).addv("failedCount", failedCount).addv("resultQueryFailedCount", 0);
|
||||||
|
} catch (Exception e) {
|
||||||
|
markReminderMessageRecords(validRecords, senderId, WelfareReminderMessage.STATUS_RESULT_QUERY_FAILED,
|
||||||
|
messageIdText, new Date(), limitFailureMessage(e.getMessage()));
|
||||||
|
persistReminderMessageRecordsAsync(records, projectId, messageBatchId);
|
||||||
|
log.error("福利选择统一消息结果查询异常,已提交异步入库记录,projectId={},messageBatchId={},messageIds={},接收人数={},失败原因={}",
|
||||||
|
projectId, messageBatchId, messageIds, validRecords.size(), e.getMessage(), e);
|
||||||
|
return NutMap.NEW().addv("successCount", 0).addv("failedCount", records.size() - validRecords.size())
|
||||||
|
.addv("resultQueryFailedCount", validRecords.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建统一消息接收人记录,并显式补齐fastInsert不会执行的主键和审计字段。
|
||||||
|
*/
|
||||||
|
private WelfareReminderMessage createReminderMessageRecord(String messageBatchId, String projectId, String userId,
|
||||||
|
Sys_user receiver, Sys_user sender, String title,
|
||||||
|
String content, long now) {
|
||||||
|
WelfareReminderMessage record = new WelfareReminderMessage();
|
||||||
|
record.setId(R.UU32());
|
||||||
|
record.setMessageBatchId(messageBatchId);
|
||||||
|
record.setProjectId(projectId);
|
||||||
|
record.setUserId(userId);
|
||||||
|
if (receiver != null) {
|
||||||
|
record.setReceiverCode(receiver.getLoginname());
|
||||||
|
record.setReceiverName(receiver.getUsername());
|
||||||
|
}
|
||||||
|
record.setSenderId(sender.getId());
|
||||||
|
record.setSenderCode(sender.getLoginname());
|
||||||
|
record.setSenderName(sender.getUsername());
|
||||||
|
record.setTitle(limitText(title, 100));
|
||||||
|
record.setContent(limitText(content, 1000));
|
||||||
|
record.setMessageStatus(WelfareReminderMessage.STATUS_WAITING_RESULT);
|
||||||
|
record.setCreatedBy(sender.getId());
|
||||||
|
record.setCreatedAt(now);
|
||||||
|
record.setUpdatedBy(sender.getId());
|
||||||
|
record.setUpdatedAt(now);
|
||||||
|
record.setDelFlag(false);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询所有消息标识的结果并汇总失败用户工号与失败原因。
|
||||||
|
* 当前配置仅使用一个发送渠道,通常只返回一个消息标识;多标识场景仍逐个查询并按工号合并失败结果。
|
||||||
|
*/
|
||||||
|
private Map<String, String> queryFailedMessageByReceiverCode(List<String> messageIds) {
|
||||||
|
Map<String, String> failedMessageByCode = new HashMap<>();
|
||||||
|
for (String messageId : messageIds) {
|
||||||
|
NutMap messageResult = smsService.getMessageResult(messageId);
|
||||||
|
Object failedUsers = messageResult.get("failedUsers");
|
||||||
|
if (failedUsers instanceof JSONArray failedUserArray) {
|
||||||
|
for (Object failedUserValue : failedUserArray) {
|
||||||
|
JSONObject failedUser = JSONUtil.parseObj(failedUserValue);
|
||||||
|
String userCode = failedUser.getStr("userCode");
|
||||||
|
if (StrUtil.isNotBlank(userCode)) {
|
||||||
|
failedMessageByCode.put(userCode, limitFailureMessage(failedUser.getStr("errorInfo")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("0".equals(messageResult.getString("resultState")) && failedMessageByCode.isEmpty()) {
|
||||||
|
throw new IllegalStateException("学校统一消息平台返回发送失败,但未返回失败人员明细,messageId=" + messageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return failedMessageByCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在内存中更新一批统一消息记录状态;所有结果明确后再统一异步插入,避免异步插入和同步更新发生竞争。
|
||||||
|
*/
|
||||||
|
private void markReminderMessageRecords(List<WelfareReminderMessage> records, String senderId, int messageStatus,
|
||||||
|
String messageId, Date resultTime, String failMessage) {
|
||||||
|
if (records.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Date sendTime = messageId == null ? null : new Date();
|
||||||
|
records.forEach(record -> {
|
||||||
|
if (messageId != null) {
|
||||||
|
record.setMessageId(messageId);
|
||||||
|
record.setSendTime(sendTime);
|
||||||
|
}
|
||||||
|
record.setMessageStatus(messageStatus);
|
||||||
|
record.setResultTime(resultTime);
|
||||||
|
record.setFailMessage(failMessage);
|
||||||
|
record.setUpdatedBy(senderId);
|
||||||
|
record.setUpdatedAt(System.currentTimeMillis());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 使用项目线程池异步分批插入最终消息记录。记录已显式设置主键和审计字段,
|
||||||
|
* 因此可安全使用fastInsert;本方法只提交任务,不等待数据库写入完成。
|
||||||
|
*/
|
||||||
|
private void persistReminderMessageRecordsAsync(List<WelfareReminderMessage> records, String projectId, String messageBatchId) {
|
||||||
|
if (records.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manyAddOrRenewUtil.asyncExecuteFastInsert(records, 200);
|
||||||
|
log.info("福利选择统一消息记录已提交异步批量入库,projectId={},messageBatchId={},记录数={},batchSize={}",
|
||||||
|
projectId, messageBatchId, records.size(), 200);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询项目和用户对应的唯一提醒待办记录。
|
* 查询项目和用户对应的唯一提醒待办记录。
|
||||||
*/
|
*/
|
||||||
@@ -264,6 +527,24 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
.and(WelfareReminderTodo::getUserId, "=", userId));
|
.and(WelfareReminderTodo::getUserId, "=", userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量查询当前项目的提醒待办,避免发送前按接收人逐条访问数据库。
|
||||||
|
*
|
||||||
|
* @param projectId 福利项目ID
|
||||||
|
* @param userIds 本次实际接收人ID集合
|
||||||
|
* @return 以用户ID为键的待办记录;未创建过待办的用户不包含在结果中
|
||||||
|
*/
|
||||||
|
private Map<String, WelfareReminderTodo> getReminderTodoMap(String projectId, List<String> userIds) {
|
||||||
|
if (StrUtil.isBlank(projectId) || userIds.isEmpty()) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
return dao().query(WelfareReminderTodo.class, Cnd.where(WelfareReminderTodo::getProjectId, "=", projectId)
|
||||||
|
.and(WelfareReminderTodo::getUserId, "in", userIds))
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(WelfareReminderTodo::getUserId, reminderTodo -> reminderTodo,
|
||||||
|
(left, right) -> left));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送中、待办和已办记录均表示该项目已创建过OA待办,重复提醒时不再创建第二条。
|
* 发送中、待办和已办记录均表示该项目已创建过OA待办,重复提醒时不再创建第二条。
|
||||||
* 发送失败记录允许沿用原唯一值重试。
|
* 发送失败记录允许沿用原唯一值重试。
|
||||||
@@ -288,24 +569,31 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新建或重置待办发送记录。固定的流程ID和唯一值保证同一项目、同一用户最多一条OA待办。
|
* 组装发送中的待办记录。新增记录补齐批量插入所需主键和审计字段,失败重试记录保留原主键。
|
||||||
*/
|
*/
|
||||||
private WelfareReminderTodo saveSendingReminderTodo(WelfareReminderTodo reminderTodo, String projectId,
|
private WelfareReminderTodo prepareSendingReminderTodo(WelfareReminderTodo reminderTodo, String projectId,
|
||||||
Sys_user receiver, String senderId, String title, String content) {
|
Sys_user receiver, Sys_user sender, String title, String content) {
|
||||||
if (receiver == null || StrUtil.hasBlank(receiver.getId(), receiver.getLoginname(), receiver.getUsername())) {
|
if (receiver == null || StrUtil.hasBlank(receiver.getId(), receiver.getLoginname(), receiver.getUsername())) {
|
||||||
throw new IllegalArgumentException("学校OA福利选择提醒接收人信息不完整");
|
throw new IllegalArgumentException("学校OA福利选择提醒接收人信息不完整");
|
||||||
}
|
}
|
||||||
Sys_user sender = dao().fetch(Sys_user.class, senderId);
|
if (sender == null || StrUtil.hasBlank(sender.getId(), sender.getLoginname(), sender.getUsername())) {
|
||||||
if (sender == null || StrUtil.hasBlank(sender.getLoginname(), sender.getUsername())) {
|
|
||||||
throw new IllegalArgumentException("学校OA福利选择提醒创建人信息不完整");
|
throw new IllegalArgumentException("学校OA福利选择提醒创建人信息不完整");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean newRecord = reminderTodo == null;
|
boolean newRecord = reminderTodo == null;
|
||||||
WelfareReminderTodo record = newRecord ? new WelfareReminderTodo() : reminderTodo;
|
WelfareReminderTodo record = newRecord ? new WelfareReminderTodo() : reminderTodo;
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
String uniqueId = buildWelfareReminderUniqueId(projectId, receiver.getId());
|
String uniqueId = buildWelfareReminderUniqueId(projectId, receiver.getId());
|
||||||
|
if (newRecord) {
|
||||||
|
// fastInsert不会触发实体的PrevInsert,主键和审计字段需在批量入库前显式赋值。
|
||||||
|
record.setId(R.UU32());
|
||||||
|
record.setCreatedBy(sender.getId());
|
||||||
|
record.setCreatedAt(now);
|
||||||
|
record.setDelFlag(false);
|
||||||
|
}
|
||||||
record.setProjectId(projectId);
|
record.setProjectId(projectId);
|
||||||
record.setUserId(receiver.getId());
|
record.setUserId(receiver.getId());
|
||||||
record.setOaFlowId(uniqueId);
|
record.setOaFlowId(buildWelfareReminderBatchFlowId(projectId));
|
||||||
record.setOaUniqueId(uniqueId);
|
record.setOaUniqueId(uniqueId);
|
||||||
record.setReceiverCode(receiver.getLoginname());
|
record.setReceiverCode(receiver.getLoginname());
|
||||||
record.setReceiverName(receiver.getUsername());
|
record.setReceiverName(receiver.getUsername());
|
||||||
@@ -318,14 +606,48 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
record.setSendTime(null);
|
record.setSendTime(null);
|
||||||
record.setFinishTime(null);
|
record.setFinishTime(null);
|
||||||
record.setFailMessage(null);
|
record.setFailMessage(null);
|
||||||
if (newRecord) {
|
record.setUpdatedBy(sender.getId());
|
||||||
dao().insert(record);
|
record.setUpdatedAt(now);
|
||||||
} else {
|
|
||||||
dao().update(record);
|
|
||||||
}
|
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量持久化发送中状态:新记录使用fastInsert,历史失败记录使用DAO批量更新。
|
||||||
|
*/
|
||||||
|
private void persistSendingReminderTodos(String projectId, List<WelfareReminderTodo> newRecords,
|
||||||
|
List<WelfareReminderTodo> retryRecords, String senderId) {
|
||||||
|
if (!newRecords.isEmpty()) {
|
||||||
|
dao().fastInsert(newRecords);
|
||||||
|
log.info("福利选择提醒待办批量新增记录完成,projectId={},新增数量={},状态={}",
|
||||||
|
projectId, newRecords.size(), WelfareReminderTodo.STATUS_SENDING);
|
||||||
|
}
|
||||||
|
if (!retryRecords.isEmpty()) {
|
||||||
|
dao().update(retryRecords,
|
||||||
|
"oaFlowId|oaUniqueId|receiverCode|receiverName|senderId|senderCode|senderName|title|content|todoStatus|sendTime|finishTime|failMessage|updatedBy|updatedAt");
|
||||||
|
log.info("福利选择提醒待办批量重试记录更新完成,projectId={},重试数量={},状态={},操作人={}",
|
||||||
|
projectId, retryRecords.size(), WelfareReminderTodo.STATUS_SENDING, senderId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按本批用户统一更新待办状态。成功时写入发送时间,失败时写入统一失败原因。
|
||||||
|
*/
|
||||||
|
private int updateReminderTodoBatchStatus(String projectId, List<String> userIds, String senderId,
|
||||||
|
int todoStatus, Date sendTime, String failMessage) {
|
||||||
|
if (StrUtil.isBlank(projectId) || userIds.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Chain chain = Chain.make("todoStatus", todoStatus)
|
||||||
|
.add("sendTime", sendTime)
|
||||||
|
.add("finishTime", null)
|
||||||
|
.add("failMessage", failMessage)
|
||||||
|
.add("updatedBy", senderId)
|
||||||
|
.add("updatedAt", System.currentTimeMillis());
|
||||||
|
return dao().update(WelfareReminderTodo.class, chain,
|
||||||
|
Cnd.where(WelfareReminderTodo::getProjectId, "=", projectId)
|
||||||
|
.and(WelfareReminderTodo::getUserId, "in", userIds));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存OA待办发送失败原因;若发送前校验失败导致记录尚未创建,则补建一条失败记录。
|
* 保存OA待办发送失败原因;若发送前校验失败导致记录尚未创建,则补建一条失败记录。
|
||||||
*/
|
*/
|
||||||
@@ -336,7 +658,7 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
record = new WelfareReminderTodo();
|
record = new WelfareReminderTodo();
|
||||||
record.setProjectId(projectId);
|
record.setProjectId(projectId);
|
||||||
record.setUserId(userId);
|
record.setUserId(userId);
|
||||||
record.setOaFlowId(buildWelfareReminderUniqueId(projectId, userId));
|
record.setOaFlowId(buildWelfareReminderBatchFlowId(projectId));
|
||||||
record.setOaUniqueId(buildWelfareReminderUniqueId(projectId, userId));
|
record.setOaUniqueId(buildWelfareReminderUniqueId(projectId, userId));
|
||||||
record.setSenderId(SecurityUtil.getUserId());
|
record.setSenderId(SecurityUtil.getUserId());
|
||||||
if (receiver != null) {
|
if (receiver != null) {
|
||||||
@@ -363,9 +685,21 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
/**
|
/**
|
||||||
* 组装发送统计和前端提示,消息与OA待办分别计数,避免把重复跳过误报为发送成功。
|
* 组装发送统计和前端提示,消息与OA待办分别计数,避免把重复跳过误报为发送成功。
|
||||||
*/
|
*/
|
||||||
private NutMap buildReminderResult(int recipientCount, int messageSuccessCount, int todoSuccessCount,
|
private NutMap buildReminderResult(int recipientCount, int localMessageSuccessCount, int messageSuccessCount,
|
||||||
int existingTodoCount, int todoFailedCount, boolean todoEnabled) {
|
int messageFailedCount, int messageResultQueryFailedCount, int todoSuccessCount,
|
||||||
StringBuilder summary = new StringBuilder("消息发送成功").append(messageSuccessCount).append("人");
|
boolean messageEnabled, boolean todoEnabled, int existingTodoCount, int todoFailedCount) {
|
||||||
|
StringBuilder summary = new StringBuilder("本地消息发送成功").append(localMessageSuccessCount).append("人");
|
||||||
|
if (messageEnabled) {
|
||||||
|
summary.append(",学校统一消息发送成功").append(messageSuccessCount).append("人");
|
||||||
|
if (messageFailedCount > 0) {
|
||||||
|
summary.append(",学校统一消息发送失败").append(messageFailedCount).append("人");
|
||||||
|
}
|
||||||
|
if (messageResultQueryFailedCount > 0) {
|
||||||
|
summary.append(",学校统一消息结果查询异常").append(messageResultQueryFailedCount).append("人");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
summary.append(",学校统一消息开关未开启");
|
||||||
|
}
|
||||||
if (todoEnabled) {
|
if (todoEnabled) {
|
||||||
summary.append(",OA待办发送成功").append(todoSuccessCount).append("人");
|
summary.append(",OA待办发送成功").append(todoSuccessCount).append("人");
|
||||||
if (existingTodoCount > 0) {
|
if (existingTodoCount > 0) {
|
||||||
@@ -379,7 +713,11 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
}
|
}
|
||||||
return NutMap.NEW()
|
return NutMap.NEW()
|
||||||
.addv("recipientCount", recipientCount)
|
.addv("recipientCount", recipientCount)
|
||||||
|
.addv("localMessageSuccessCount", localMessageSuccessCount)
|
||||||
.addv("messageSuccessCount", messageSuccessCount)
|
.addv("messageSuccessCount", messageSuccessCount)
|
||||||
|
.addv("messageFailedCount", messageFailedCount)
|
||||||
|
.addv("messageResultQueryFailedCount", messageResultQueryFailedCount)
|
||||||
|
.addv("messageEnabled", messageEnabled)
|
||||||
.addv("todoSuccessCount", todoSuccessCount)
|
.addv("todoSuccessCount", todoSuccessCount)
|
||||||
.addv("existingTodoCount", existingTodoCount)
|
.addv("existingTodoCount", existingTodoCount)
|
||||||
.addv("todoFailedCount", todoFailedCount)
|
.addv("todoFailedCount", todoFailedCount)
|
||||||
@@ -401,6 +739,65 @@ public class WelfareSelectionSituationServiceImpl extends BaseServiceImpl<Welfar
|
|||||||
return safeText.length() > maxLength ? safeText.substring(0, maxLength) : safeText;
|
return safeText.length() > maxLength ? safeText.substring(0, maxLength) : safeText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 组装福利选择的学校OA批量待办参数。
|
||||||
|
* 公共OA服务只负责校验参数和调用接口;福利项目标识、标题、链接及接收人信息均在此处按福利业务规则生成。
|
||||||
|
*
|
||||||
|
* @param projectId 福利项目ID,用于生成学校OA批次流程标识和每个接收人的唯一值
|
||||||
|
* @param title 学校OA待办标题,包含福利提醒正文
|
||||||
|
* @param pcUrl 福利选择PC端跳转地址
|
||||||
|
* @param appUrl 福利选择移动端跳转地址
|
||||||
|
* @param sender 发起提醒的系统用户,提供学校OA创建人工号和姓名
|
||||||
|
* @param receiverIds 本次实际发送的接收人ID集合
|
||||||
|
* @param receiverUserMap 接收人ID与系统用户信息的映射
|
||||||
|
* @return 可直接传给学校OA批量待办接口的参数对象
|
||||||
|
*/
|
||||||
|
private SchoolOaTodoBatchCreateParam buildWelfareReminderBatchTodoParam(String projectId, String title,
|
||||||
|
String pcUrl, String appUrl, Sys_user sender,
|
||||||
|
List<String> receiverIds,
|
||||||
|
Map<String, Sys_user> receiverUserMap) {
|
||||||
|
if (StrUtil.hasBlank(projectId, title, pcUrl, appUrl)
|
||||||
|
|| sender == null || StrUtil.hasBlank(sender.getLoginname(), sender.getUsername())
|
||||||
|
|| receiverIds == null || receiverIds.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("学校OA福利选择提醒批量待办参数不完整");
|
||||||
|
}
|
||||||
|
|
||||||
|
String sendTime = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
|
||||||
|
List<SchoolOaTodoReceiverParam> userList = new ArrayList<>();
|
||||||
|
for (String receiverId : receiverIds) {
|
||||||
|
Sys_user receiver = receiverUserMap.get(receiverId);
|
||||||
|
if (receiver == null || StrUtil.hasBlank(receiver.getLoginname(), receiver.getUsername())) {
|
||||||
|
throw new IllegalArgumentException("学校OA福利选择提醒接收人信息不完整,userId=" + receiverId);
|
||||||
|
}
|
||||||
|
SchoolOaTodoReceiverParam receiverParam = new SchoolOaTodoReceiverParam();
|
||||||
|
receiverParam.setPcUrl(pcUrl);
|
||||||
|
receiverParam.setAppUrl(appUrl);
|
||||||
|
receiverParam.setUniqueId(buildWelfareReminderUniqueId(projectId, receiverId));
|
||||||
|
receiverParam.setReceiveCode(receiver.getLoginname());
|
||||||
|
receiverParam.setReceiveName(receiver.getUsername());
|
||||||
|
receiverParam.setReceiveTime(sendTime);
|
||||||
|
userList.add(receiverParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
SchoolOaTodoBatchCreateParam todoParam = new SchoolOaTodoBatchCreateParam();
|
||||||
|
todoParam.setFlowTypeName("福利选择");
|
||||||
|
todoParam.setFlowId(buildWelfareReminderBatchFlowId(projectId));
|
||||||
|
todoParam.setTitle(title);
|
||||||
|
todoParam.setStepName("福利选择提醒");
|
||||||
|
todoParam.setCreatorCode(sender.getLoginname());
|
||||||
|
todoParam.setCreatorName(sender.getUsername());
|
||||||
|
todoParam.setCreatorTime(sendTime);
|
||||||
|
todoParam.setStartPcPreviewUrl(pcUrl);
|
||||||
|
todoParam.setStartAppPreviewUrl(appUrl);
|
||||||
|
todoParam.setUserList(userList);
|
||||||
|
return todoParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 同一项目的一批福利提醒共用学校OA流程标识,接收人通过uniqueId区分。 */
|
||||||
|
private String buildWelfareReminderBatchFlowId(String projectId) {
|
||||||
|
return "welfare_reminder_" + projectId;
|
||||||
|
}
|
||||||
|
|
||||||
/** 同一项目和用户固定使用一个OA待办唯一值。 */
|
/** 同一项目和用户固定使用一个OA待办唯一值。 */
|
||||||
private String buildWelfareReminderUniqueId(String projectId, String userId) {
|
private String buildWelfareReminderUniqueId(String projectId, String userId) {
|
||||||
return "welfare_reminder_" + projectId + "_" + userId;
|
return "welfare_reminder_" + projectId + "_" + userId;
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ layout("/layouts/platform.html"){
|
|||||||
<!-- </el-form-item>-->
|
<!-- </el-form-item>-->
|
||||||
<!-- </el-descriptions-item>-->
|
<!-- </el-descriptions-item>-->
|
||||||
|
|
||||||
<template v-if="['1', '2'].includes(formData.typeCode)">
|
<template v-if="(chooseType.name || formData.typeName || '').includes('住院')">
|
||||||
<el-descriptions-item label="入院时间">
|
<el-descriptions-item label="入院时间">
|
||||||
<el-form-item label="入院时间" prop="hospitalizationTime">
|
<el-form-item label="入院时间" prop="hospitalizationTime">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const condolenceInfo = {
|
|||||||
<!-- <el-descriptions-item label="收款账户">{{ viewData.bankCardNumber }}</el-descriptions-item>-->
|
<!-- <el-descriptions-item label="收款账户">{{ viewData.bankCardNumber }}</el-descriptions-item>-->
|
||||||
<!-- <el-descriptions-item label="户名">{{ viewData.bankUserName }}</el-descriptions-item>-->
|
<!-- <el-descriptions-item label="户名">{{ viewData.bankUserName }}</el-descriptions-item>-->
|
||||||
<!-- <el-descriptions-item label="开户行">{{ viewData.bankOfDeposit }}</el-descriptions-item>-->
|
<!-- <el-descriptions-item label="开户行">{{ viewData.bankOfDeposit }}</el-descriptions-item>-->
|
||||||
<template v-if="['1', '2'].includes(viewData.typeCode)">
|
<template v-if="(viewData.typeName || '').includes('住院')">
|
||||||
<el-descriptions-item label="入院时间">{{ viewData.hospitalizationTime }}</el-descriptions-item>
|
<el-descriptions-item label="入院时间">{{ viewData.hospitalizationTime }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="出院时间">{{ viewData.leaveHospitalTime }}</el-descriptions-item>
|
<el-descriptions-item label="出院时间">{{ viewData.leaveHospitalTime }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="当年第几次住院">{{ viewData.thisYearHospitalizationNum }}
|
<el-descriptions-item label="当年第几次住院">{{ viewData.thisYearHospitalizationNum }}
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ layout("/layouts/platform_h5.html"){
|
|||||||
<!-- name="bankOfDeposit"-->
|
<!-- name="bankOfDeposit"-->
|
||||||
<!-- ></van-field>-->
|
<!-- ></van-field>-->
|
||||||
|
|
||||||
<template v-if="['1', '2'].includes(formData.typeCode)">
|
<template v-if="(chooseType.name || formData.typeName || '').includes('住院')">
|
||||||
<van-field
|
<van-field
|
||||||
v-model="formData.hospitalizationTime"
|
v-model="formData.hospitalizationTime"
|
||||||
name="hospitalizationTime"
|
name="hospitalizationTime"
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const condolenceInfo = {
|
|||||||
<!-- <van-cell class="direction-column-cell" title="开户行">-->
|
<!-- <van-cell class="direction-column-cell" title="开户行">-->
|
||||||
<!-- {{ viewData.bankOfDeposit || '暂无' }}-->
|
<!-- {{ viewData.bankOfDeposit || '暂无' }}-->
|
||||||
<!-- </van-cell>-->
|
<!-- </van-cell>-->
|
||||||
<template v-if="['1', '2'].includes(viewData.typeCode)">
|
<template v-if="(viewData.typeName || '').includes('住院')">
|
||||||
<van-cell title="入院时间">{{ viewData.hospitalizationTime }}</van-cell>
|
<van-cell title="入院时间">{{ viewData.hospitalizationTime }}</van-cell>
|
||||||
<van-cell title="出院时间">{{ viewData.leaveHospitalTime }}</van-cell>
|
<van-cell title="出院时间">{{ viewData.leaveHospitalTime }}</van-cell>
|
||||||
<van-cell title="当年第几次住院(次)">{{ viewData.thisYearHospitalizationNum }}</van-cell>
|
<van-cell title="当年第几次住院(次)">{{ viewData.thisYearHospitalizationNum }}</van-cell>
|
||||||
|
|||||||
Reference in New Issue
Block a user