From 8e6dbec07ecfb8ff56c86fb5a668cfc184713e02 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Thu, 13 Nov 2025 17:58:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9E=84=E5=BB=BA=E9=80=9A?= =?UTF-8?q?=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...nvironmentNotificationConfigConverter.java | 45 +++++++ .../deploy/dto/DeployExecuteRequest.java | 25 +++- .../service/impl/DeployServiceImpl.java | 55 +++++---- .../dto/SendNotificationRequest.java | 15 ++- .../service/impl/NotificationServiceImpl.java | 110 ++---------------- 5 files changed, 121 insertions(+), 129 deletions(-) diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamEnvironmentNotificationConfigConverter.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamEnvironmentNotificationConfigConverter.java index 84230306..19597a10 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamEnvironmentNotificationConfigConverter.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/converter/TeamEnvironmentNotificationConfigConverter.java @@ -1,9 +1,17 @@ package com.qqchen.deploy.backend.deploy.converter; import com.qqchen.deploy.backend.deploy.dto.TeamEnvironmentNotificationConfigDTO; +import com.qqchen.deploy.backend.deploy.dto.UserTeamEnvironmentNotificationConfigDTO; import com.qqchen.deploy.backend.deploy.entity.TeamEnvironmentNotificationConfig; import com.qqchen.deploy.backend.framework.converter.BaseConverter; +import com.qqchen.deploy.backend.notification.entity.NotificationChannel; +import com.qqchen.deploy.backend.notification.entity.NotificationTemplate; +import org.mapstruct.Context; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +import java.util.Map; +import java.util.Optional; /** * 团队环境通知配置Converter @@ -14,4 +22,41 @@ import org.mapstruct.Mapper; @Mapper(componentModel = "spring") public interface TeamEnvironmentNotificationConfigConverter extends BaseConverter { + + /** + * 转换为用户环境通知配置DTO(包含扩展字段) + */ + @Mapping(target = "notificationChannelName", + expression = "java(getChannelName(config.getNotificationChannelId(), channelMap))") + @Mapping(target = "deployNotificationTemplateName", + expression = "java(getTemplateName(config.getDeployNotificationTemplateId(), templateMap))") + @Mapping(target = "buildNotificationTemplateName", + expression = "java(getTemplateName(config.getBuildNotificationTemplateId(), templateMap))") + @Mapping(target = "buildFailureNotificationTemplateName", + expression = "java(getTemplateName(config.getBuildFailureNotificationTemplateId(), templateMap))") + UserTeamEnvironmentNotificationConfigDTO toUserDTO( + TeamEnvironmentNotificationConfig config, + @Context Map channelMap, + @Context Map templateMap + ); + + /** + * 获取渠道名称 + */ + default String getChannelName(Long channelId, Map channelMap) { + return Optional.ofNullable(channelId) + .map(channelMap::get) + .map(NotificationChannel::getName) + .orElse(null); + } + + /** + * 获取模板名称 + */ + default String getTemplateName(Long templateId, Map templateMap) { + return Optional.ofNullable(templateId) + .map(templateMap::get) + .map(NotificationTemplate::getName) + .orElse(null); + } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployExecuteRequest.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployExecuteRequest.java index 5721c21f..356cb765 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployExecuteRequest.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/DeployExecuteRequest.java @@ -106,12 +106,27 @@ public class DeployExecuteRequest { @Data @Schema(description = "通知配置") public static class NotificationConfig { - @Schema(description = "是否需要通知", required = true) - @NotNull(message = "是否需要通知不能为空") - private Boolean required; - + @Schema(description = "通知渠道ID") - private Long channelId; + private Long notificationChannelId; + + @Schema(description = "是否启用部署通知") + private Boolean deployNotificationEnabled; + + @Schema(description = "部署通知模板ID") + private Long deployNotificationTemplateId; + + @Schema(description = "是否启用构建通知") + private Boolean buildNotificationEnabled; + + @Schema(description = "构建通知模板ID") + private Long buildNotificationTemplateId; + + @Schema(description = "构建失败时是否发送日志文件到企业微信") + private Boolean buildFailureFileEnabled; + + @Schema(description = "构建失败通知模板ID") + private Long buildFailureNotificationTemplateId; } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java index 82585ba2..3fdfbaf9 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/DeployServiceImpl.java @@ -4,7 +4,10 @@ import com.qqchen.deploy.backend.deploy.dto.*; import com.qqchen.deploy.backend.deploy.entity.*; import com.qqchen.deploy.backend.deploy.repository.*; import com.qqchen.deploy.backend.notification.entity.NotificationChannel; +import com.qqchen.deploy.backend.notification.entity.NotificationTemplate; import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository; +import com.qqchen.deploy.backend.notification.repository.INotificationTemplateRepository; +import com.qqchen.deploy.backend.deploy.converter.TeamEnvironmentNotificationConfigConverter; import com.qqchen.deploy.backend.deploy.service.IDeployService; import com.qqchen.deploy.backend.framework.security.SecurityUtils; import com.qqchen.deploy.backend.framework.enums.ResponseCode; @@ -46,6 +49,7 @@ import java.time.LocalDateTime; import java.time.ZoneId; import java.util.*; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.util.stream.Collectors.*; @@ -113,6 +117,12 @@ public class DeployServiceImpl implements IDeployService { @Resource private INotificationChannelRepository notificationChannelRepository; + @Resource + private INotificationTemplateRepository notificationTemplateRepository; + + @Resource + private TeamEnvironmentNotificationConfigConverter notificationConfigConverter; + @Override public List getDeployableEnvironments() { @@ -262,7 +272,24 @@ public class DeployServiceImpl implements IDeployService { ); } - // 16. 批量查询审批人信息 + // 16. 批量查询通知模板信息 + Set templateIds = notificationConfigMap.values().stream() + .flatMap(config -> Stream.of( + config.getDeployNotificationTemplateId(), + config.getBuildNotificationTemplateId(), + config.getBuildFailureNotificationTemplateId() + )) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + Map templateMap = new HashMap<>(); + if (!templateIds.isEmpty()) { + notificationTemplateRepository.findAllById(templateIds).forEach(template -> + templateMap.put(template.getId(), template) + ); + } + + // 17. 批量查询审批人信息 Set approverUserIds = teamEnvConfigs.stream() .filter(c -> c.getApproverUserIds() != null) .flatMap(c -> c.getApproverUserIds().stream()) @@ -283,7 +310,7 @@ public class DeployServiceImpl implements IDeployService { currentUserId, teamId, teamMap, ownerMap, membersByTeam, memberUserMap, teamAppsMap, envMap, appMap, systemMap, workflowMap, teamEnvConfigMap, approverMap, - notificationConfigMap, channelMap, + notificationConfigMap, channelMap, templateMap, statisticsMap, latestRecordMap, recentRecordsMap ); if (teamDTO != null) { @@ -314,6 +341,7 @@ public class DeployServiceImpl implements IDeployService { Map approverMap, Map notificationConfigMap, Map channelMap, + Map templateMap, Map statisticsMap, Map latestRecordMap, Map> recentRecordsMap @@ -380,7 +408,7 @@ public class DeployServiceImpl implements IDeployService { teamId, env, envApps, appMap, systemMap, workflowMap, teamEnvConfigMap, approverMap, - notificationConfigMap, channelMap, + notificationConfigMap, channelMap, templateMap, statisticsMap, latestRecordMap, recentRecordsMap ); environments.add(envDTO); @@ -409,6 +437,7 @@ public class DeployServiceImpl implements IDeployService { Map approverMap, Map notificationConfigMap, Map channelMap, + Map templateMap, Map statisticsMap, Map latestRecordMap, Map> recentRecordsMap @@ -451,24 +480,10 @@ public class DeployServiceImpl implements IDeployService { dto.setApprovers(Collections.emptyList()); } - // 构建通知配置 - UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO = null; + // 构建通知配置 - 使用MapStruct转换器 TeamEnvironmentNotificationConfig notificationConfig = notificationConfigMap.get(configKey); - if (notificationConfig != null) { - notificationConfigDTO = new UserTeamEnvironmentNotificationConfigDTO(); - notificationConfigDTO.setNotificationChannelId(notificationConfig.getNotificationChannelId()); - notificationConfigDTO.setDeployNotificationEnabled(notificationConfig.getDeployNotificationEnabled()); - notificationConfigDTO.setBuildNotificationEnabled(notificationConfig.getBuildNotificationEnabled()); - notificationConfigDTO.setBuildFailureFileEnabled(notificationConfig.getBuildFailureFileEnabled()); - - // 设置通知渠道名称 - if (notificationConfig.getNotificationChannelId() != null) { - NotificationChannel channel = channelMap.get(notificationConfig.getNotificationChannelId()); - if (channel != null) { - notificationConfigDTO.setNotificationChannelName(channel.getName()); - } - } - } + UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO = + notificationConfigConverter.toUserDTO(notificationConfig, channelMap, templateMap); dto.setNotificationConfig(notificationConfigDTO); } else { dto.setRequiresApproval(false); diff --git a/backend/src/main/java/com/qqchen/deploy/backend/notification/dto/SendNotificationRequest.java b/backend/src/main/java/com/qqchen/deploy/backend/notification/dto/SendNotificationRequest.java index 8b593ccf..66adb9c9 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/notification/dto/SendNotificationRequest.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/notification/dto/SendNotificationRequest.java @@ -1,6 +1,7 @@ package com.qqchen.deploy.backend.notification.dto; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -16,14 +17,16 @@ import java.util.Map; @Schema(description = "发送通知请求") public class SendNotificationRequest { - @Schema(description = "渠道ID", required = true, example = "1") - @NotNull(message = "渠道ID不能为空") - private Long channelId; - @Schema(description = "通知模板ID", required = true, example = "1") @NotNull(message = "通知模板ID不能为空") private Long notificationTemplateId; - @Schema(description = "模板参数", example = "{\"projectName\":\"测试项目\",\"buildNumber\":\"123\"}") - private Map params; + @Schema(description = "模板渲染参数(仅用于模板变量替换)", + example = "{\"projectName\":\"测试项目\",\"buildNumber\":\"123\"}") + private Map templateParams; + + @Schema(description = "具体的发送请求配置", required = true) + @NotNull(message = "发送请求配置不能为空") + @Valid + private BaseSendNotificationRequest sendRequest; } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java index 02ab05d0..62b732d0 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/notification/service/impl/NotificationServiceImpl.java @@ -54,7 +54,7 @@ public class NotificationServiceImpl implements INotificationService { .orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND)); // 2. 获取通知渠道 - NotificationChannel channel = notificationChannelRepository.findById(request.getChannelId()) + NotificationChannel channel = notificationChannelRepository.findById(request.getSendRequest().getChannelId()) .orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND)); // 3. 验证模板和渠道类型是否匹配 @@ -62,7 +62,12 @@ public class NotificationServiceImpl implements INotificationService { throw new BusinessException(ResponseCode.INVALID_PARAM); } - // 4. 验证模板和渠道是否启用 + // 4. 验证SendRequest渠道类型和模板渠道类型是否匹配 + if (!request.getSendRequest().getChannelType().equals(template.getChannelType())) { + throw new BusinessException(ResponseCode.INVALID_PARAM); + } + + // 5. 验证模板和渠道是否启用 if (!template.getEnabled()) { throw new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_DISABLED); } @@ -70,103 +75,12 @@ public class NotificationServiceImpl implements INotificationService { throw new BusinessException(ResponseCode.DATA_NOT_FOUND); } - // 5. 渲染模板内容 - String content = notificationTemplateService.renderTemplate(template.getContentTemplate(), request.getParams()); + // 6. 渲染模板内容 + String content = notificationTemplateService.renderTemplate(template.getContentTemplate(), request.getTemplateParams()); - // 6. 根据渠道类型发送通知 - switch (template.getChannelType()) { - case WEWORK -> sendWeworkNotification(request.getChannelId(), content, template, request.getParams()); - case EMAIL -> sendEmailNotification(request.getChannelId(), content, template, request.getParams()); - default -> throw new BusinessException(ResponseCode.INVALID_PARAM); - } + // 7. 设置渲染后的内容并发送 + request.getSendRequest().setContent(content); + notificationSendService.send(request.getSendRequest()); } - /** - * 发送企业微信通知 - */ - private void sendWeworkNotification(Long channelId, String content, NotificationTemplate template, Map params) { - WeworkSendNotificationRequest request = new WeworkSendNotificationRequest(); - request.setChannelId(channelId); - request.setContent(content); - - // 从模板配置获取消息类型 - WeworkMessageTypeEnum messageType = WeworkMessageTypeEnum.TEXT; // 默认值 - try { - BaseTemplateConfig baseTemplateConfig = JsonUtils.fromMap(template.getTemplateConfig(), BaseTemplateConfig.class); - if (baseTemplateConfig instanceof WeworkTemplateConfig weworkTemplateConfig) { - messageType = weworkTemplateConfig.getMessageType(); - } - } catch (Exception e) { - log.warn("获取模板配置失败,使用默认消息类型: {}", e.getMessage()); - } - - // params 仍可以覆盖模板配置 - if (params != null && params.containsKey("messageType")) { - messageType = WeworkMessageTypeEnum.valueOf(params.get("messageType").toString()); - } - request.setMessageType(messageType); - - // 从参数中获取@人员信息 - if (params != null) { - if (params.containsKey("mentionedMobileList")) { - request.setMentionedMobileList((List) params.get("mentionedMobileList")); - } - if (params.containsKey("mentionedUserList")) { - request.setMentionedUserList((List) params.get("mentionedUserList")); - } - } - - notificationSendService.send(request); - } - - /** - * 发送邮件通知 - */ - private void sendEmailNotification(Long channelId, String content, NotificationTemplate template, Map params) { - EmailSendNotificationRequest request = new EmailSendNotificationRequest(); - request.setChannelId(channelId); - request.setContent(content); - - // 邮件标题从参数中获取,或使用默认值 - String subject = "系统通知"; - if (params != null && params.containsKey("subject")) { - subject = params.get("subject").toString(); - } - request.setSubject(subject); - - // 从模板配置获取内容类型 - Boolean isHtml = false; // 默认值 - try { - BaseTemplateConfig baseTemplateConfig = JsonUtils.fromMap(template.getTemplateConfig(), BaseTemplateConfig.class); - if (baseTemplateConfig instanceof EmailTemplateConfig emailTemplateConfig) { - isHtml = emailTemplateConfig.getContentType() == EmailContentTypeEnum.HTML; - } - } catch (Exception e) { - log.warn("获取模板配置失败,使用默认内容类型: {}", e.getMessage()); - } - - // params 仍可以覆盖模板配置 - if (params != null && params.containsKey("isHtml")) { - isHtml = (Boolean) params.get("isHtml"); - } - request.setIsHtml(isHtml); - - // 收件人信息(必须) - if (params == null || !params.containsKey("toReceivers")) { - throw new BusinessException(ResponseCode.INVALID_PARAM); - } - request.setToReceivers((List) params.get("toReceivers")); - - // 可选参数 - if (params != null) { - if (params.containsKey("ccReceivers")) { - request.setCcReceivers((List) params.get("ccReceivers")); - } - if (params.containsKey("bccReceivers")) { - request.setBccReceivers((List) params.get("bccReceivers")); - } - } - - notificationSendService.send(request); - } }