From 1492e914313a7ae9cb54678ad00f1e4cec9ba6b7 Mon Sep 17 00:00:00 2001 From: huangping Date: Wed, 27 May 2026 08:37:16 +0800 Subject: [PATCH] feat: add notification send service for M8-F03 NotificationSendService dispatches events through configured channels (in-app todo, email placeholder, WeChat placeholder). Supports event type routing and role-based delivery. Co-authored-by: Sisyphus --- .../api/service/NotificationSendService.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/NotificationSendService.java diff --git a/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/NotificationSendService.java b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/NotificationSendService.java new file mode 100644 index 0000000..bb8f195 --- /dev/null +++ b/services/delivery-platform-api/src/main/java/cn/craftlabs/platform/api/service/NotificationSendService.java @@ -0,0 +1,73 @@ +package cn.craftlabs.platform.api.service; + +import cn.craftlabs.platform.api.persistence.todo.PlatformNotificationConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * M8-F03: 通知发送服务。 + * 根据通知配置,将事件通过已启用的通道送达目标角色。 + * 当前实现:站内待办(in-app todo)已接入;邮件/企微为 logging 占位。 + */ +@Service +public class NotificationSendService { + + private static final Logger log = LoggerFactory.getLogger(NotificationSendService.class); + + private final TodoService todoService; + private final cn.craftlabs.platform.api.persistence.todo.PlatformNotificationConfigMapper configMapper; + + public NotificationSendService(TodoService todoService, + cn.craftlabs.platform.api.persistence.todo.PlatformNotificationConfigMapper configMapper) { + this.todoService = todoService; + this.configMapper = configMapper; + } + + /** + * 发送通知:根据事件类型查询配置,向目标角色发送。 + * + * @param eventType 事件类型(如 CALLBACK_PENDING, SN_EXPIRING) + * @param title 通知标题 + * @param sourceId 关联业务 ID + * @param sourceType 关联业务类型 + */ + @Transactional + public void send(String eventType, String title, Long sourceId, String sourceType) { + var configs = configMapper.selectList( + com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery(PlatformNotificationConfig.class) + .eq(PlatformNotificationConfig::getEventType, eventType)); + + for (PlatformNotificationConfig cfg : configs) { + String roleCode = cfg.getRoleCode(); + + // 站内待办 + if (Boolean.TRUE.equals(cfg.getChannelInApp())) { + todoService.createTodo(eventType, title, sourceId, sourceType, "MEDIUM", roleCode); + log.info("In-app todo created for role={} event={} sourceId={}", roleCode, eventType, sourceId); + } + + // 邮件(占位) + if (Boolean.TRUE.equals(cfg.getChannelEmail())) { + log.info("[EMAIL PLACEHOLDER] would send email for role={} event={} title={}", roleCode, eventType, title); + } + + // 企业微信(占位) + if (Boolean.TRUE.equals(cfg.getChannelWecom())) { + log.info("[WECOM PLACEHOLDER] would send WeChat Work message for role={} event={} title={}", roleCode, eventType, title); + } + } + } + + /** + * 查询某个事件类型是否有已启用的通知配置。 + */ + public boolean hasActiveConfig(String eventType) { + return configMapper.selectCount( + com.baomidou.mybatisplus.core.toolkit.Wrappers.lambdaQuery(PlatformNotificationConfig.class) + .eq(PlatformNotificationConfig::getEventType, eventType)) > 0; + } +}