From efc7f9ceb28547410bee4eb3fe361c9902349e84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=A3=E4=BA=9B=E8=8A=B1=E5=84=BF?= <1156921458@qq.com> Date: Fri, 12 Sep 2025 17:54:47 +0800 Subject: [PATCH] .. --- .../controller/message/SysMessageSender.java | 24 -- .../message/SysSmsMessageSender.java | 4 - .../message/enums/GlobalMessageChannel.java | 27 +++ .../mode/GlobalMessageSendRequest.java | 48 ++++ .../message/models/GlobalMessage.java | 89 +++++++ .../message/models/GlobalMessageReceiver.java | 59 +++++ .../service/GlobalMessageSendService.java | 228 ++++++++++++++++++ .../strategy/GlobalMessageSendStrategy.java | 55 +++++ .../impl/LocalMessageSendStrategy.java | 90 +++++++ .../strategy/impl/SmsMessageSendStrategy.java | 130 ++++++++++ .../controller/HuiminManageController.java | 32 ++- 11 files changed, 756 insertions(+), 30 deletions(-) delete mode 100644 src/main/java/com/budwk/app/sys/controller/message/SysMessageSender.java delete mode 100644 src/main/java/com/budwk/app/sys/controller/message/SysSmsMessageSender.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/enums/GlobalMessageChannel.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/mode/GlobalMessageSendRequest.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessage.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessageReceiver.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/service/GlobalMessageSendService.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/GlobalMessageSendStrategy.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/LocalMessageSendStrategy.java create mode 100644 src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java diff --git a/src/main/java/com/budwk/app/sys/controller/message/SysMessageSender.java b/src/main/java/com/budwk/app/sys/controller/message/SysMessageSender.java deleted file mode 100644 index 923a07d9..00000000 --- a/src/main/java/com/budwk/app/sys/controller/message/SysMessageSender.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.budwk.app.sys.controller.message; - -import com.budwk.app.sys.models.Sys_user; - -/** - * 消息发送者 - */ -public interface SysMessageSender { - - /** - * 发送消息 - * @param message 消息内容 - * @param receiver 接收人 - * @return 发送结果 - */ -// boolean send(Message message, Sys_user receiver); - - /** - * 支持的渠道类型 - * @return 渠道类型 - */ - String getChannelType(); - -} diff --git a/src/main/java/com/budwk/app/sys/controller/message/SysSmsMessageSender.java b/src/main/java/com/budwk/app/sys/controller/message/SysSmsMessageSender.java deleted file mode 100644 index 863e012c..00000000 --- a/src/main/java/com/budwk/app/sys/controller/message/SysSmsMessageSender.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.budwk.app.sys.controller.message; - -public class SysSmsMessageSender { -} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/enums/GlobalMessageChannel.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/enums/GlobalMessageChannel.java new file mode 100644 index 00000000..2e48e683 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/enums/GlobalMessageChannel.java @@ -0,0 +1,27 @@ +package com.budwk.app.zhgh.dayofficework.message.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 消息通道 + */ +@Getter +@AllArgsConstructor +public enum GlobalMessageChannel { + + LOCAL("本地"), + + WECHAT("微信"), + + EMAIL("邮件"), + + SMS("短信"), + + DINGDING("钉钉"), + + WECHAT_ENTERPRISE("企业微信"); + + private final String value; + +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/mode/GlobalMessageSendRequest.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/mode/GlobalMessageSendRequest.java new file mode 100644 index 00000000..328d03f6 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/mode/GlobalMessageSendRequest.java @@ -0,0 +1,48 @@ +package com.budwk.app.zhgh.dayofficework.message.mode; + +import cn.hutool.json.JSONObject; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 消息发送请求 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GlobalMessageSendRequest { + + /** + * 标题 + */ + private String title; + + /** + * 内容 + */ + private String content; + + /** + * 附件 + */ + private List attachments; + + /** + * 消息类型(1:系统通知 2:待办通知) + */ + private Integer type; + + /** + * 配置 + */ + private JSONObject config; + + /** + * 接收人ID + */ + private List receiverIds; + +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessage.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessage.java new file mode 100644 index 00000000..420611b6 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessage.java @@ -0,0 +1,89 @@ +package com.budwk.app.zhgh.dayofficework.message.models; + +import cn.hutool.json.JSONObject; +import com.budwk.app.base.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.List; + +@Table("global_message") +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableMeta("{'mysql-charset':'utf8mb4'}") +@Comment("全局消息") +public class GlobalMessage extends BaseModel { + + @Name + @Comment("ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @Comment("标题") + @ColDefine(type = ColType.VARCHAR, width = 255) + private String title; + + @Column + @Comment("内容") + @ColDefine(type = ColType.TEXT) + private String content; + + @Column + @Comment("附件") + @ColDefine(type = ColType.MYSQL_JSON) + private List attachments; + + @Column + @Comment("消息类型(1:系统公告 2:消息通知)") + @ColDefine(type = ColType.INT) + private Integer type; + + @Column + @Comment("发送人ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String senderId; + + @Column + @Comment("发送人姓名") + @ColDefine(type = ColType.VARCHAR, width = 100) + private String senderName; + + @Column + @Comment("发送人工号") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String senderLoginName; + +// @Column +// @Comment("消息通道(用于第三方消息)") +// @ColDefine(type = ColType.MYSQL_JSON) +// private List channels; + + @Column + @Comment("扩展字段") + @ColDefine(type = ColType.MYSQL_JSON) + private JSONObject ext; + + @Column + @Comment("状态(1:草稿 2:已发送 3:已撤回 4:已删除)") + @ColDefine(type = ColType.INT) + private Integer status; + + @Column + @Comment("发送成功") + @ColDefine(type = ColType.BOOLEAN) + @Default("0") + private Boolean sendSuccess; + + @Column + @Comment("发送结果") + @ColDefine(type = ColType.MYSQL_JSON) + private String sendResult; + + +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessageReceiver.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessageReceiver.java new file mode 100644 index 00000000..23e7fcf8 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/models/GlobalMessageReceiver.java @@ -0,0 +1,59 @@ +package com.budwk.app.zhgh.dayofficework.message.models; + +import com.budwk.app.base.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; + +@Table("global_message_receiver") +@Data +@EqualsAndHashCode(callSuper = true) +@Accessors(chain = true) +@TableMeta("{'mysql-charset':'utf8mb4'}") +@Comment("全局消息接收用户") +public class GlobalMessageReceiver extends BaseModel { + + @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 messageId; + + @Column + @Comment("接收人ID") + @ColDefine(type = ColType.VARCHAR, width = 32) + private String receiverId; + + @Column + @Comment("接收人姓名") + @ColDefine(type = ColType.VARCHAR, width = 100) + private String receiverName; + + @Column + @Comment("接收人工号") + @ColDefine(type = ColType.VARCHAR, width = 50) + private String receiverLoginName; + + @Column + @Comment("阅读状态") + @ColDefine(type = ColType.BOOLEAN) + @Default("0") + private Boolean isRead; + + @Column + @Comment("阅读时间") + @ColDefine(type = ColType.DATETIME) + private Date readTime; + + + +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/service/GlobalMessageSendService.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/service/GlobalMessageSendService.java new file mode 100644 index 00000000..e8ccb4ce --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/service/GlobalMessageSendService.java @@ -0,0 +1,228 @@ +package com.budwk.app.zhgh.dayofficework.message.service; + +import cn.hutool.json.JSONObject; +import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel; +import com.budwk.app.zhgh.dayofficework.message.mode.GlobalMessageSendRequest; +import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy; +import lombok.extern.slf4j.Slf4j; +import org.nutz.dao.Dao; +import org.nutz.ioc.Ioc; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; + +import javax.annotation.PostConstruct; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +/** + * 全局消息发送服务 + */ +@IocBean(create = "initStrategies") +@Slf4j +public class GlobalMessageSendService { + + @Inject + private Dao dao; + + @Inject + private Ioc ioc; + + /** + * 消息发送策略缓存 + */ + private final Map strategyMap = new ConcurrentHashMap<>(); + + /** + * 本地消息策略(必须存在) + */ + private GlobalMessageSendStrategy localStrategy; + + /** + * 初始化策略 + */ + public void initStrategies() { + try { + log.info("开始初始化消息发送策略..."); + + // 获取所有实现了GlobalMessageSendStrategy接口的Bean + String[] beanNames = ioc.getNames(); + for (String beanName : beanNames) { + try { + Object bean = ioc.get(null, beanName); + if (bean instanceof GlobalMessageSendStrategy) { + GlobalMessageSendStrategy strategy = (GlobalMessageSendStrategy) bean; + GlobalMessageChannel channel = strategy.getChannel(); + strategyMap.put(channel, strategy); + + // 缓存本地策略 + if (channel == GlobalMessageChannel.LOCAL) { + localStrategy = strategy; + } + + log.info("注册消息发送策略:{} -> {}", channel.getValue(), strategy.getClass().getSimpleName()); + } + } catch (Exception e) { + log.warn("初始化Bean {}时出错:{}", beanName, e.getMessage()); + } + } + + if (localStrategy == null) { + throw new RuntimeException("本地消息发送策略未找到,系统无法正常工作"); + } + + log.info("消息发送策略初始化完成,共注册{}个策略", strategyMap.size()); + } catch (Exception e) { + log.error("消息发送策略初始化失败", e); + throw new RuntimeException("消息发送策略初始化失败", e); + } + } + + /** + * 发送消息(简化API) + */ + public void sendMessage(String title, String content, List receiverIds) { + sendMessage(title, content, 1, receiverIds, null); + } + + /** + * 发送消息(完整API) + */ + public void sendMessage(String title, String content, Integer type, List receiverIds, JSONObject config) { + GlobalMessageSendRequest request = new GlobalMessageSendRequest(); + request.setTitle(title); + request.setContent(content); + request.setType(type); + request.setReceiverIds(receiverIds); + request.setConfig(config); + + sendMessage(request); + } + + /** + * 发送消息(使用请求对象) + */ + public void sendMessage(GlobalMessageSendRequest request) { + try { + log.info("开始发送全局消息,标题:{},接收人数量:{}", request.getTitle(), + request.getReceiverIds() != null ? request.getReceiverIds().size() : 0); + + // 参数校验 + validateRequest(request); + + // 获取启用的策略 + List enabledStrategies = getEnabledStrategies(); + + if (enabledStrategies.isEmpty()) { + log.warn("没有找到启用的消息发送策略"); + return; + } + + // 执行消息发送 - 本地消息优先,然后是外部策略 + for (GlobalMessageSendStrategy strategy : enabledStrategies) { + try { + // 本地消息必须同步发送,确保优先完成 + if (strategy.getChannel() == GlobalMessageChannel.LOCAL) { + strategy.send(request.getTitle(), request.getContent(), request.getType(), + request.getReceiverIds(), request.getConfig()); + log.info("本地消息发送成功"); + } else { + // 外部消息策略根据配置决定同步或异步 + if (strategy.supportAsync()) { + // 异步发送 + CompletableFuture.runAsync(() -> { + try { + strategy.send(request.getTitle(), request.getContent(), request.getType(), + request.getReceiverIds(), request.getConfig()); + log.info("异步发送消息成功,渠道:{}", strategy.getChannel().getValue()); + } catch (Exception e) { + log.error("异步发送消息失败,渠道:{},错误:{}", strategy.getChannel().getValue(), e.getMessage(), e); + } + }); + } else { + // 同步发送 + strategy.send(request.getTitle(), request.getContent(), request.getType(), + request.getReceiverIds(), request.getConfig()); + log.info("同步发送消息成功,渠道:{}", strategy.getChannel().getValue()); + } + } + } catch (Exception e) { + log.error("发送消息失败,渠道:{},错误:{}", strategy.getChannel().getValue(), e.getMessage(), e); + // 本地消息发送失败时,记录严重错误并抛出异常 + if (strategy.getChannel() == GlobalMessageChannel.LOCAL) { + log.error("本地消息发送失败,这可能影响消息的完整性"); + throw e; + } + } + } + + log.info("全局消息发送完成,标题:{}", request.getTitle()); + } catch (Exception e) { + log.error("全局消息发送失败,标题:{},错误:{}", request.getTitle(), e.getMessage(), e); + throw new RuntimeException("消息发送失败:" + e.getMessage(), e); + } + } + + /** + * 参数校验 + */ + private void validateRequest(GlobalMessageSendRequest request) { + if (request == null) { + throw new IllegalArgumentException("消息发送请求不能为空"); + } + if (request.getTitle() == null || request.getTitle().trim().isEmpty()) { + throw new IllegalArgumentException("消息标题不能为空"); + } + if (request.getContent() == null || request.getContent().trim().isEmpty()) { + throw new IllegalArgumentException("消息内容不能为空"); + } + if (request.getReceiverIds() == null || request.getReceiverIds().isEmpty()) { + throw new IllegalArgumentException("接收人不能为空"); + } + if (request.getType() == null) { + request.setType(1); // 默认为系统消息 + } + } + + /** + * 获取启用的发送策略 + * 本地消息策略必须启用,其他策略根据isEnabled()方法判断 + */ + private List getEnabledStrategies() { + List enabledStrategies = new ArrayList<>(); + + // 本地消息策略必须存在且优先添加 + if (localStrategy != null) { + enabledStrategies.add(localStrategy); + log.debug("添加本地消息策略:{}", localStrategy.getChannel().getValue()); + } + + // 查找其他启用的策略 + for (GlobalMessageSendStrategy strategy : strategyMap.values()) { + // 跳过本地策略(已经添加) + if (strategy.getChannel() == GlobalMessageChannel.LOCAL) { + continue; + } + + // 检查策略是否启用 + if (strategy.isEnabled()) { + enabledStrategies.add(strategy); + log.debug("添加启用的外部消息策略:{}", strategy.getChannel().getValue()); + } else { + log.debug("跳过未启用的消息策略:{}", strategy.getChannel().getValue()); + } + } + + log.info("共找到{}个启用的消息发送策略", enabledStrategies.size()); + return enabledStrategies; + } + + /** + * 获取所有可用的发送策略 + */ + public Map getAvailableStrategies() { + return new HashMap<>(strategyMap); + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/GlobalMessageSendStrategy.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/GlobalMessageSendStrategy.java new file mode 100644 index 00000000..7c578cdf --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/GlobalMessageSendStrategy.java @@ -0,0 +1,55 @@ +package com.budwk.app.zhgh.dayofficework.message.strategy; + +import cn.hutool.json.JSONObject; +import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel; + +import java.util.List; + +/** + * 全局消息发送策略 + */ +public interface GlobalMessageSendStrategy { + + /** + * 获取渠道类型 + */ + GlobalMessageChannel getChannel(); + + /** + * 是否支持异步发送 + */ + default boolean supportAsync() { + return true; + } + + /** + * 是否启用该策略 + * 默认启用,子类可以重写此方法来控制策略的启用状态 + */ + default boolean isEnabled() { + return true; + } + + /** + * 发送消息 + * + * @param title 标题 + * @param content 内容 + * @param type 0:系统消息 1:待办消息 + * @param receiverIds 接收人ID + * @param config 配置 + */ + void send(String title, String content, Integer type, List receiverIds, JSONObject config); + + /** + * 发送消息 + * + * @param title 标题 + * @param content 内容 + * @param type 0:系统消息 1:待办消息 + * @param receiverLoginNames 接收人登录名 + * @param config 配置 + */ + void sendByLoginName(String title, String content, Integer type, List receiverLoginNames, JSONObject config); + +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/LocalMessageSendStrategy.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/LocalMessageSendStrategy.java new file mode 100644 index 00000000..895bc2b6 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/LocalMessageSendStrategy.java @@ -0,0 +1,90 @@ +package com.budwk.app.zhgh.dayofficework.message.strategy.impl; + +import cn.hutool.json.JSONObject; +import com.budwk.app.sys.models.Sys_user; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel; +import com.budwk.app.zhgh.dayofficework.message.models.GlobalMessage; +import com.budwk.app.zhgh.dayofficework.message.models.GlobalMessageReceiver; +import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy; +import lombok.extern.slf4j.Slf4j; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.util.List; + +/** + * 本地消息发送策略 + */ +@IocBean +@Slf4j +public class LocalMessageSendStrategy implements GlobalMessageSendStrategy { + + @Inject + private Dao dao; + + @Override + public GlobalMessageChannel getChannel() { + return GlobalMessageChannel.LOCAL; + } + + @Override + public boolean supportAsync() { + return false; + } + + @Override + public void send(String title, String content, Integer type, List receiverIds, JSONObject config) { + List users = dao.query(Sys_user.class, Cnd.where(Sys_user::getId, "in", receiverIds)); + sendMessage(title, content, type, users, config); + } + + @Override + public void sendByLoginName(String title, String content, Integer type, List receiverLoginNames, JSONObject config) { + List users = dao.query(Sys_user.class, Cnd.where(Sys_user::getLoginname, "in", receiverLoginNames)); + sendMessage(title, content, type, users, config); + } + + private void sendMessage(String title, String content, Integer type, List receivers, JSONObject config) { + try { + log.info("开始发送本地消息,标题:{},接收人数量:{}", title, receivers.size()); + + // 消息主体 + GlobalMessage globalMessage = new GlobalMessage(); + globalMessage.setTitle(title); + globalMessage.setContent(content); + globalMessage.setType(type); + globalMessage.setSenderId(SecurityUtil.getUserId()); + globalMessage.setSenderName(SecurityUtil.getUserUsername()); + globalMessage.setSenderLoginName(SecurityUtil.getUserLoginname()); + globalMessage.setStatus(1); // 草稿状态 + globalMessage.setSendSuccess(false); + dao.insert(globalMessage); + + // 消息接收人 + List receiverList = receivers.stream().map(r -> { + GlobalMessageReceiver receiver = new GlobalMessageReceiver(); + receiver.setMessageId(globalMessage.getId()); + receiver.setReceiverId(r.getId()); + receiver.setReceiverName(r.getUsername()); // 修复:使用用户名而不是登录名 + receiver.setReceiverLoginName(r.getLoginname()); + receiver.setIsRead(false); + return receiver; + }).toList(); + dao.insert(receiverList); + + // 更新消息状态为已发送 + globalMessage.setStatus(2); + globalMessage.setSendSuccess(true); + globalMessage.setSendResult("本地消息发送成功"); + dao.update(globalMessage); + + log.info("本地消息发送成功,消息ID:{},接收人数量:{}", globalMessage.getId(), receivers.size()); + } catch (Exception e) { + log.error("本地消息发送失败,标题:{},错误信息:{}", title, e.getMessage(), e); + throw new RuntimeException("本地消息发送失败:" + e.getMessage(), e); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java new file mode 100644 index 00000000..78e38342 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/dayofficework/message/strategy/impl/SmsMessageSendStrategy.java @@ -0,0 +1,130 @@ +package com.budwk.app.zhgh.dayofficework.message.strategy.impl; + +import cn.hutool.json.JSONObject; +import com.budwk.app.sys.models.Sys_user; +import com.budwk.app.zhgh.dayofficework.message.enums.GlobalMessageChannel; +import com.budwk.app.zhgh.dayofficework.message.strategy.GlobalMessageSendStrategy; +import lombok.extern.slf4j.Slf4j; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.util.List; + +/** + * 短信发送策略 + */ +@IocBean +@Slf4j +public class SmsMessageSendStrategy implements GlobalMessageSendStrategy { + + @Inject + private Dao dao; + + @Override + public GlobalMessageChannel getChannel() { + return GlobalMessageChannel.SMS; + } + + @Override + public boolean supportAsync() { + return true; // 短信发送支持异步 + } + +// @Override +// public boolean isEnabled() { +// return true; +// } + + @Override + public void send(String title, String content, Integer type, List receiverIds, JSONObject config) { + try { + log.info("开始发送短信消息,标题:{},接收人数量:{}", title, receiverIds.size()); + + // 查询用户手机号 + List users = dao.query(Sys_user.class, Cnd.where(Sys_user::getId, "in", receiverIds)); + sendSmsMessage(title, content, type, users, config); + + log.info("短信消息发送完成,标题:{},接收人数量:{}", title, users.size()); + } catch (Exception e) { + log.error("短信消息发送失败,标题:{},错误:{}", title, e.getMessage(), e); + throw new RuntimeException("短信消息发送失败:" + e.getMessage(), e); + } + } + + @Override + public void sendByLoginName(String title, String content, Integer type, List receiverLoginNames, JSONObject config) { + try { + log.info("开始发送短信消息(按登录名),标题:{},接收人数量:{}", title, receiverLoginNames.size()); + + // 查询用户手机号 + List users = dao.query(Sys_user.class, Cnd.where(Sys_user::getLoginname, "in", receiverLoginNames)); + sendSmsMessage(title, content, type, users, config); + + log.info("短信消息发送完成(按登录名),标题:{},接收人数量:{}", title, users.size()); + } catch (Exception e) { + log.error("短信消息发送失败(按登录名),标题:{},错误:{}", title, e.getMessage(), e); + throw new RuntimeException("短信消息发送失败:" + e.getMessage(), e); + } + } + + /** + * 发送短信消息 + */ + private void sendSmsMessage(String title, String content, Integer type, List users, JSONObject config) { + for (Sys_user user : users) { + try { + String mobile = user.getMobile(); + if (mobile == null || mobile.trim().isEmpty()) { + log.warn("用户{}没有手机号,跳过短信发送", user.getUsername()); + continue; + } + + // 构建短信内容 + String smsContent = buildSmsContent(title, content, type); + + // 执行发送 + + boolean success = true; + + if (success) { + log.info("短信发送成功:用户{},手机号:{}", user.getUsername(), mobile); + } else { + log.warn("短信发送失败:用户{},手机号:{}", user.getUsername(), mobile); + } + } catch (Exception e) { + log.error("发送短信给用户{}时出错:{}", user.getUsername(), e.getMessage(), e); + } + } + } + + /** + * 构建短信内容 + */ + private String buildSmsContent(String title, String content, Integer type) { + StringBuilder sb = new StringBuilder(); + + // 根据消息类型添加前缀 + if (type != null && type == 2) { + sb.append("【待办通知】"); + } else { + sb.append("【系统通知】"); + } + + // 添加标题和内容 + sb.append(title); + if (content != null && !content.trim().isEmpty()) { + sb.append(":").append(content); + } + + // 限制短信长度(一般短信限制70个字符) + String smsContent = sb.toString(); + if (smsContent.length() > 67) { + smsContent = smsContent.substring(0, 67) + "..."; + } + + return smsContent; + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/huimin/controller/HuiminManageController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/huimin/controller/HuiminManageController.java index 1aa0fd26..e77cde3e 100644 --- a/src/main/java/com/budwk/app/zhgh/staffbenefit/huimin/controller/HuiminManageController.java +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/huimin/controller/HuiminManageController.java @@ -6,18 +6,24 @@ import cn.hutool.core.util.StrUtil; import com.budwk.app.base.page.Pagination; import com.budwk.app.base.param.PageForm; import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService; import com.budwk.app.zhgh.staffbenefit.huimin.models.Huimin; import com.budwk.app.zhgh.staffbenefit.huimin.service.HuiminService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; import org.nutz.ioc.loader.annotation.Inject; import org.nutz.ioc.loader.annotation.IocBean; import org.nutz.mvc.annotation.At; import org.nutz.mvc.annotation.Ok; import org.nutz.mvc.annotation.Param; +import java.util.Arrays; +import java.util.List; + @IocBean @At("/platform/huimin/manage") @Api(("惠民服务管理")) @@ -28,6 +34,9 @@ public class HuiminManageController { @Inject private HuiminService huiminService; + @Inject + private GlobalMessageSendService globalMessageSendService; + @At("") @SaCheckPermission("huimin.manage") @Ok("beetl:/platform/zhgh/staffbenefit/huimin/manage/index.html") @@ -37,11 +46,30 @@ public class HuiminManageController { @At @SaCheckPermission("huimin.manage") public Result pageData(PageForm pageForm) { + Sql sql = Sqls.create(""" + SELECT + t1.* + FROM + huimin t1 + LEFT JOIN activity_user_scope aus ON t1.groupId = aus.groupId + AND aus.userId = @userId + $condition + """); Cnd cnd = Cnd.NEW(); if(StrUtil.isNotBlank(pageForm.getSearchKeyword())){ - cnd.where().andLike(Huimin::getTitle, pageForm.getSearchKeyword()); + cnd.where().andLike("t1.title", "%" + pageForm.getSearchKeyword() + "%"); } - Pagination pagination = huiminService.listPage(pageForm.getPageNumber(), pageForm.getPageSize(), cnd); + cnd.and(Cnd.exps("aus.groupId","is not",null).or("t1.groupId","is",null)); + sql.setCondition(cnd); + Pagination pagination = huiminService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + + String title = "审批待办"; + String content = "您有一个新的审批任务需要处理,请及时登录系统查看。"; + List receiverIds = Arrays.asList("00198c31ee094466845979ab8dabf83b", "00266dbf9e014376ab76072851b1a8ac"); + + // 自动发送到所有启用的渠道 + globalMessageSendService.sendMessage(title, content, 2, receiverIds, null); + return Result.success(pagination); }