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 7edbd699..12317e50 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 @@ -492,14 +492,20 @@ public class DeployServiceImpl implements IDeployService { // 构建通知配置 - 使用MapStruct转换器 TeamEnvironmentNotificationConfig notificationConfig = notificationConfigMap.get(configKey); - UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO = - notificationConfigConverter.toUserDTO(notificationConfig, channelMap, templateMap); + UserTeamEnvironmentNotificationConfigDTO notificationConfigDTO; + if (notificationConfig != null) { + notificationConfigDTO = notificationConfigConverter.toUserDTO(notificationConfig, channelMap, templateMap); + } else { + // 没有配置时返回默认值(开关字段为false) + notificationConfigDTO = createDefaultNotificationConfigDTO(); + } dto.setNotificationConfig(notificationConfigDTO); } else { dto.setRequiresApproval(false); dto.setRequireCodeReview(false); dto.setApprovers(Collections.emptyList()); - dto.setNotificationConfig(null); + // 没有配置时返回默认值(开关字段为false) + dto.setNotificationConfig(createDefaultNotificationConfigDTO()); } // 构建应用列表 @@ -723,6 +729,17 @@ public class DeployServiceImpl implements IDeployService { || status == DeployRecordStatusEnums.CREATED; } + /** + * 创建默认的通知配置DTO(开关字段默认为false) + */ + private UserTeamEnvironmentNotificationConfigDTO createDefaultNotificationConfigDTO() { + UserTeamEnvironmentNotificationConfigDTO dto = new UserTeamEnvironmentNotificationConfigDTO(); + dto.setPreApprovalNotificationEnabled(false); + dto.setBuildNotificationEnabled(false); + dto.setBuildFailureFileEnabled(false); + return dto; + } + @Override @Transactional public DeployResultDTO executeDeploy(DeployExecuteRequest request) { diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java index 707ad942..c26a65ab 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/JenkinsBuildServiceImpl.java @@ -16,8 +16,13 @@ import com.qqchen.deploy.backend.deploy.repository.*; import com.qqchen.deploy.backend.deploy.service.IJenkinsBuildService; import com.qqchen.deploy.backend.deploy.service.IJenkinsSyncHistoryService; import com.qqchen.deploy.backend.notification.entity.NotificationChannel; +import com.qqchen.deploy.backend.notification.entity.NotificationTemplate; +import com.qqchen.deploy.backend.notification.entity.config.WeworkTemplateConfig; import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository; +import com.qqchen.deploy.backend.notification.repository.INotificationTemplateRepository; +import com.qqchen.deploy.backend.notification.service.INotificationService; import com.qqchen.deploy.backend.notification.service.INotificationSendService; +import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest; import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest; import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest; import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum; @@ -78,6 +83,12 @@ public class JenkinsBuildServiceImpl extends BaseServiceImpl 任务: %s\n", job.getJobName())); - content.append(String.format("> 构建号: #%d\n", build.getBuildNumber())); + // 1. 检查是否配置了构建通知模板 + if (config.getBuildNotificationTemplateId() == null) { + log.warn("未配置构建通知模板,跳过通知: teamId={}, envId={}", + config.getTeamId(), config.getEnvironmentId()); + return; + } + + // 2. 查询模板 + NotificationTemplate template = notificationTemplateRepository + .findById(config.getBuildNotificationTemplateId()) + .orElse(null); + if (template == null) { + log.warn("构建通知模板不存在: templateId={}", config.getBuildNotificationTemplateId()); + return; + } + + // 3. 构建模板参数 + Map templateParams = new HashMap<>(); + templateParams.put("jobName", job.getJobName()); + templateParams.put("buildNumber", build.getBuildNumber()); + templateParams.put("buildUrl", build.getBuildUrl()); + templateParams.put("status", status); + templateParams.put("startTime", build.getStarttime()); // 状态显示 - String statusDisplay; - switch (status) { - case "SUCCESS": - statusDisplay = "✅ 成功"; - break; - case "FAILURE": - statusDisplay = "❌ 失败"; - break; - case "BUILDING": - statusDisplay = "🔄 构建中"; - break; - default: - statusDisplay = status; - } - content.append(String.format("> 状态: %s\n", statusDisplay)); - content.append(String.format("> 时间: %s\n", build.getStarttime())); + String statusDisplay = switch (status) { + case "SUCCESS" -> "✅ 成功"; + case "FAILURE" -> "❌ 失败"; + case "BUILDING" -> "🔄 构建中"; + default -> status; + }; + templateParams.put("statusDisplay", statusDisplay); - // 耗时(仅结束状态) - if (!"BUILDING".equals(status) && build.getDuration() != null) { + // 耗时 + if (build.getDuration() != null) { long seconds = build.getDuration() / 1000; long minutes = seconds / 60; long secs = seconds % 60; - content.append(String.format("> 耗时: %d分%d秒\n", minutes, secs)); + templateParams.put("duration", String.format("%d分%d秒", minutes, secs)); + templateParams.put("durationMs", build.getDuration()); } - // 构建失败时,发送日志文件(如果开启) - if ("FAILURE".equals(status) && config.getBuildFailureFileEnabled() != null && config.getBuildFailureFileEnabled()) { - // 先发送文本通知 - sendNotificationByChannelType(channel, "Jenkins构建通知", content.toString()); - - // 然后发送日志文件 + // 4. 构建 SendNotificationRequest + SendNotificationRequest request = new SendNotificationRequest(); + request.setNotificationTemplateId(config.getBuildNotificationTemplateId()); + request.setTemplateParams(templateParams); + request.setSendRequest(createSendRequestByChannel(channel, template)); + + // 5. 发送通知 + notificationService.send(request); + + log.info("已发送构建通知: job={}, build={}, status={}, templateId={}", + job.getJobName(), build.getBuildNumber(), status, config.getBuildNotificationTemplateId()); + + // 6. 构建失败时,发送日志文件(如果开启) + if ("FAILURE".equals(status) && Boolean.TRUE.equals(config.getBuildFailureFileEnabled())) { sendBuildFailureLogFile(externalSystem, channel, job.getJobName(), build.getBuildNumber()); - return; // 已发送,直接返回 } - // 发送通知 - sendNotificationByChannelType(channel, "Jenkins构建通知", content.toString()); - - log.info("已发送构建通知: job={}, build={}, status={}", - job.getJobName(), build.getBuildNumber(), status); - } catch (Exception e) { log.error("发送通知失败: job={}, build={}", job.getJobName(), build.getBuildNumber(), e); } } /** - * 根据渠道类型发送通知 + * 根据渠道类型创建对应的发送请求 */ - private void sendNotificationByChannelType(NotificationChannel channel, String title, String content) { + private com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest createSendRequestByChannel( + NotificationChannel channel, NotificationTemplate template) { + switch (channel.getChannelType()) { + case WEWORK: + WeworkSendNotificationRequest weworkRequest = new WeworkSendNotificationRequest(); + weworkRequest.setChannelId(channel.getId()); + weworkRequest.setMessageType(getWeworkMessageType(template)); + return weworkRequest; + case EMAIL: + EmailSendNotificationRequest emailRequest = new EmailSendNotificationRequest(); + emailRequest.setChannelId(channel.getId()); + emailRequest.setToReceivers(Arrays.asList("admin@company.com")); + return emailRequest; + default: + throw new RuntimeException("不支持的渠道类型: " + channel.getChannelType()); + } + } + + /** + * 从模板配置中获取企业微信消息类型 + */ + private WeworkMessageTypeEnum getWeworkMessageType(NotificationTemplate template) { try { - switch (channel.getChannelType()) { - case WEWORK -> { - WeworkSendNotificationRequest weworkRequest = new WeworkSendNotificationRequest(); - weworkRequest.setChannelId(channel.getId()); - weworkRequest.setContent(title + "\n\n" + content); - weworkRequest.setMessageType(WeworkMessageTypeEnum.MARKDOWN); // 使用Markdown格式 - notificationSendService.send(weworkRequest); + if (template.getTemplateConfig() != null) { + WeworkTemplateConfig weworkConfig = JsonUtils.fromMap( + template.getTemplateConfig(), WeworkTemplateConfig.class); + if (weworkConfig != null && weworkConfig.getMessageType() != null) { + return weworkConfig.getMessageType(); } - case EMAIL -> { - EmailSendNotificationRequest emailRequest = new EmailSendNotificationRequest(); - emailRequest.setChannelId(channel.getId()); - emailRequest.setSubject(title); - emailRequest.setContent(content); - // 这里需要设置收件人,但Jenkins构建通知中没有提供 - // 实际应该从团队环境配置或其他地方获取 - emailRequest.setToReceivers(java.util.Arrays.asList("admin@company.com")); - notificationSendService.send(emailRequest); - } - default -> throw new RuntimeException("不支持的渠道类型: " + channel.getChannelType()); } } catch (Exception e) { - log.error("发送通知失败: channelId={}, type={}", channel.getId(), channel.getChannelType(), e); - throw e; + log.warn("解析企业微信模板配置失败,使用默认消息类型: {}", e.getMessage()); } + return WeworkMessageTypeEnum.TEXT; } /**