增加构建通知
This commit is contained in:
parent
62c1a8b0d1
commit
13f8be9146
@ -229,7 +229,13 @@ public enum ResponseCode {
|
||||
DEPLOY_PERMISSION_DENIED(3009, "deploy.permission.denied"),
|
||||
DEPLOY_ENVIRONMENT_LOCKED(3010, "deploy.environment.locked"),
|
||||
DEPLOY_APPROVAL_REQUIRED(3011, "deploy.approval.required"),
|
||||
DEPLOY_RECORD_NOT_FOUND(3012, "deploy.record.not.found");
|
||||
DEPLOY_RECORD_NOT_FOUND(3012, "deploy.record.not.found"),
|
||||
|
||||
// 通知模板相关错误码 (3100-3119)
|
||||
NOTIFICATION_TEMPLATE_NOT_FOUND(3100, "notification.template.not.found"),
|
||||
NOTIFICATION_TEMPLATE_CODE_EXISTS(3101, "notification.template.code.exists"),
|
||||
NOTIFICATION_TEMPLATE_DISABLED(3102, "notification.template.disabled"),
|
||||
NOTIFICATION_TEMPLATE_RENDER_ERROR(3103, "notification.template.render.error");
|
||||
|
||||
private final int code;
|
||||
private final String messageKey; // 国际化消息key
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
package com.qqchen.deploy.backend.notification.api;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.api.Response;
|
||||
import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 通知发送API控制器
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/notification")
|
||||
@Tag(name = "通知发送", description = "通知发送相关接口")
|
||||
@Validated
|
||||
public class NotificationApiController {
|
||||
|
||||
@Resource
|
||||
private INotificationService notificationService;
|
||||
|
||||
@Operation(summary = "发送通知消息")
|
||||
@PostMapping("/send")
|
||||
public Response<Void> send(@Valid @RequestBody SendNotificationRequest request) {
|
||||
notificationService.send(request);
|
||||
return Response.success();
|
||||
}
|
||||
}
|
||||
@ -4,11 +4,9 @@ import com.qqchen.deploy.backend.framework.api.Response;
|
||||
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||
import com.qqchen.deploy.backend.notification.dto.NotificationChannelDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.NotificationChannelQuery;
|
||||
import com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationChannelService;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
@ -42,9 +40,6 @@ public class NotificationChannelApiController extends BaseController<Notificatio
|
||||
@Resource
|
||||
private INotificationChannelService notificationChannelService;
|
||||
|
||||
@Resource
|
||||
private INotificationSendService notificationSendService;
|
||||
|
||||
@Override
|
||||
public Response<NotificationChannelDTO> create(@Validated @RequestBody NotificationChannelDTO dto) {
|
||||
return super.create(dto);
|
||||
@ -128,14 +123,6 @@ public class NotificationChannelApiController extends BaseController<Notificatio
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "发送通知消息")
|
||||
@PostMapping("/send")
|
||||
public Response<Void> send(
|
||||
@Parameter(description = "通知请求", required = true) @RequestBody BaseSendNotificationRequest request
|
||||
) {
|
||||
notificationSendService.send(request);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exportData(HttpServletResponse response, List<NotificationChannelDTO> data) {
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
package com.qqchen.deploy.backend.notification.api;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.api.Response;
|
||||
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||
import com.qqchen.deploy.backend.notification.dto.NotificationTemplateDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.NotificationTemplateQuery;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.TemplateRenderRequest;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationTemplateService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通知模板API控制器
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/notification-template")
|
||||
@Tag(name = "通知模板管理", description = "通知模板的增删改查、渲染预览、发送测试等功能")
|
||||
@Validated
|
||||
public class NotificationTemplateApiController extends BaseController<NotificationTemplate, NotificationTemplateDTO, Long, NotificationTemplateQuery> {
|
||||
|
||||
@Resource
|
||||
private INotificationTemplateService notificationTemplateService;
|
||||
|
||||
|
||||
|
||||
@Operation(summary = "根据编码获取模板")
|
||||
@GetMapping("/code/{code}")
|
||||
public Response<NotificationTemplateDTO> getByCode(@Parameter(description = "模板编码", required = true) @PathVariable String code) {
|
||||
NotificationTemplateDTO template = notificationTemplateService.getByCode(code);
|
||||
return Response.success(template);
|
||||
}
|
||||
|
||||
@Operation(summary = "渲染模板预览")
|
||||
@PostMapping("/render")
|
||||
public Response<String> renderTemplate(@Valid @RequestBody TemplateRenderRequest request) {
|
||||
String result = notificationTemplateService.renderTemplate(request.getTemplateCode(), request.getParams());
|
||||
return Response.success(result);
|
||||
}
|
||||
|
||||
@Operation(summary = "启用通知模板")
|
||||
@PutMapping("/{id}/enable")
|
||||
public Response<Void> enable(@Parameter(description = "模板ID", required = true) @PathVariable Long id) {
|
||||
notificationTemplateService.enable(id);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Operation(summary = "禁用通知模板")
|
||||
@PutMapping("/{id}/disable")
|
||||
public Response<Void> disable(@Parameter(description = "模板ID", required = true) @PathVariable Long id) {
|
||||
notificationTemplateService.disable(id);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exportData(HttpServletResponse response, List<NotificationTemplateDTO> data) {
|
||||
// TODO: 实现导出功能
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package com.qqchen.deploy.backend.notification.config;
|
||||
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.TemplateExceptionHandler;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* FreeMarker配置
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Component
|
||||
public class FreeMarkerConfig {
|
||||
|
||||
@Bean
|
||||
public Configuration freemarkerConfig() {
|
||||
Configuration config = new Configuration(Configuration.VERSION_2_3_32);
|
||||
|
||||
// 设置默认编码
|
||||
config.setDefaultEncoding(StandardCharsets.UTF_8.name());
|
||||
|
||||
// 设置异常处理器
|
||||
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
|
||||
|
||||
// 设置日期格式
|
||||
config.setDateFormat("yyyy-MM-dd");
|
||||
config.setTimeFormat("HH:mm:ss");
|
||||
config.setDateTimeFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// 设置数字格式(避免科学计数法)
|
||||
config.setNumberFormat("0.######");
|
||||
|
||||
// 设置布尔值格式
|
||||
config.setBooleanFormat("true,false");
|
||||
|
||||
// 禁用自动转义(因为我们可能需要输出HTML)
|
||||
config.setAutoEscapingPolicy(Configuration.DISABLE_AUTO_ESCAPING_POLICY);
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
@ -58,7 +58,7 @@ public abstract class NotificationChannelConverter implements BaseConverter<Noti
|
||||
// 更新基本字段
|
||||
entity.setName(dto.getName());
|
||||
entity.setChannelType(dto.getChannelType());
|
||||
entity.setStatus(dto.getStatus());
|
||||
entity.setEnabled(dto.getEnabled());
|
||||
entity.setDescription(dto.getDescription());
|
||||
|
||||
// 更新config字段
|
||||
|
||||
@ -0,0 +1,16 @@
|
||||
package com.qqchen.deploy.backend.notification.converter;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
|
||||
import com.qqchen.deploy.backend.notification.dto.NotificationTemplateDTO;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* 通知模板转换器
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Mapper(componentModel = "spring")
|
||||
public interface NotificationTemplateConverter extends BaseConverter<NotificationTemplate, NotificationTemplateDTO> {
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package com.qqchen.deploy.backend.notification.dto;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelStatusEnum;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
@ -32,8 +31,8 @@ public class NotificationChannelDTO extends BaseDTO {
|
||||
@NotNull(message = "渠道配置不能为空")
|
||||
private BaseNotificationConfigDTO config;
|
||||
|
||||
@Schema(description = "状态", example = "ENABLED")
|
||||
private NotificationChannelStatusEnum status;
|
||||
@Schema(description = "是否启用", example = "true")
|
||||
private Boolean enabled;
|
||||
|
||||
@Schema(description = "描述", example = "研发部通知群,用于部署通知")
|
||||
private String description;
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
package com.qqchen.deploy.backend.notification.dto;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 通知模板DTO
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "通知模板DTO")
|
||||
public class NotificationTemplateDTO extends BaseDTO {
|
||||
|
||||
@Schema(description = "模板名称", example = "Jenkins构建通知")
|
||||
@NotBlank(message = "模板名称不能为空")
|
||||
@Size(max = 100, message = "模板名称长度不能超过100个字符")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "模板编码", example = "jenkins_build_wework")
|
||||
@NotBlank(message = "模板编码不能为空")
|
||||
@Size(max = 50, message = "模板编码长度不能超过50个字符")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "模板描述", example = "用于Jenkins构建结果通知的模板")
|
||||
@Size(max = 500, message = "模板描述长度不能超过500个字符")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "渠道类型", example = "WEWORK")
|
||||
@NotNull(message = "渠道类型不能为空")
|
||||
private NotificationChannelTypeEnum channelType;
|
||||
|
||||
@Schema(description = "内容模板", example = "### 构建通知\\n**项目**: ${projectName}")
|
||||
@NotBlank(message = "内容模板不能为空")
|
||||
private String contentTemplate;
|
||||
|
||||
@Schema(description = "是否启用", example = "true")
|
||||
private Boolean enabled = true;
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
package com.qqchen.deploy.backend.notification.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 发送通知请求
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@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<String, Object> params;
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package com.qqchen.deploy.backend.notification.dto.template;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.annotation.QueryField;
|
||||
import com.qqchen.deploy.backend.framework.enums.QueryType;
|
||||
import com.qqchen.deploy.backend.framework.query.BaseQuery;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 通知模板查询条件
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Schema(description = "通知模板查询条件")
|
||||
public class NotificationTemplateQuery extends BaseQuery {
|
||||
|
||||
@QueryField(type = QueryType.LIKE)
|
||||
@Schema(description = "模板名称(模糊查询)", example = "Jenkins")
|
||||
private String name;
|
||||
|
||||
@QueryField(type = QueryType.LIKE)
|
||||
@Schema(description = "模板编码(模糊查询)", example = "jenkins")
|
||||
private String code;
|
||||
|
||||
@QueryField(type = QueryType.EQUAL)
|
||||
@Schema(description = "渠道类型", example = "WEWORK")
|
||||
private NotificationChannelTypeEnum channelType;
|
||||
|
||||
@QueryField(type = QueryType.EQUAL)
|
||||
@Schema(description = "是否启用", example = "true")
|
||||
private Boolean enabled;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package com.qqchen.deploy.backend.notification.dto.template;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 模板渲染请求
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "模板渲染请求")
|
||||
public class TemplateRenderRequest {
|
||||
|
||||
@Schema(description = "模板编码", example = "jenkins_build_wework")
|
||||
@NotBlank(message = "模板编码不能为空")
|
||||
private String templateCode;
|
||||
|
||||
@Schema(description = "模板参数", example = "{\"projectName\": \"deploy-ease-platform\", \"buildNumber\": 123}")
|
||||
private Map<String, Object> params;
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package com.qqchen.deploy.backend.notification.dto.template;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 模板发送请求
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "模板发送请求")
|
||||
public class TemplateSendRequest {
|
||||
|
||||
@Schema(description = "模板编码", example = "jenkins_build_wework")
|
||||
@NotBlank(message = "模板编码不能为空")
|
||||
private String templateCode;
|
||||
|
||||
@Schema(description = "渠道ID", example = "1")
|
||||
@NotNull(message = "渠道ID不能为空")
|
||||
private Long channelId;
|
||||
|
||||
@Schema(description = "模板参数", example = "{\"projectName\": \"deploy-ease-platform\", \"buildNumber\": 123}")
|
||||
private Map<String, Object> params;
|
||||
}
|
||||
@ -2,7 +2,6 @@ package com.qqchen.deploy.backend.notification.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelStatusEnum;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import com.vladmihalcea.hibernate.type.json.JsonType;
|
||||
import jakarta.persistence.*;
|
||||
@ -46,11 +45,10 @@ public class NotificationChannel extends Entity<Long> {
|
||||
private Map<String, Object> config;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* 是否启用
|
||||
*/
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private NotificationChannelStatusEnum status = NotificationChannelStatusEnum.ENABLED;
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
|
||||
@ -0,0 +1,59 @@
|
||||
package com.qqchen.deploy.backend.notification.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
|
||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 通知模板实体
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "sys_notification_template")
|
||||
@LogicDelete
|
||||
public class NotificationTemplate extends Entity<Long> {
|
||||
|
||||
/**
|
||||
* 模板名称
|
||||
*/
|
||||
@Column(nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 模板编码(唯一标识)
|
||||
*/
|
||||
@Column(nullable = false, length = 50, unique = true)
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 模板描述
|
||||
*/
|
||||
@Column(length = 500)
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 渠道类型
|
||||
*/
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(nullable = false, length = 20)
|
||||
private NotificationChannelTypeEnum channelType;
|
||||
|
||||
/**
|
||||
* 内容模板(FreeMarker格式)
|
||||
*/
|
||||
@Column(nullable = false, columnDefinition = "TEXT")
|
||||
private String contentTemplate;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
@Column(nullable = false)
|
||||
private Boolean enabled = true;
|
||||
}
|
||||
@ -16,7 +16,7 @@ import java.util.List;
|
||||
*/
|
||||
@Repository
|
||||
public interface INotificationChannelRepository extends IBaseRepository<NotificationChannel, Long> {
|
||||
|
||||
|
||||
/**
|
||||
* 根据名称和删除标记查询是否存在
|
||||
*
|
||||
@ -24,25 +24,6 @@ public interface INotificationChannelRepository extends IBaseRepository<Notifica
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByNameAndDeletedFalse(String name);
|
||||
|
||||
/**
|
||||
* 根据渠道类型和状态查询渠道列表
|
||||
*
|
||||
* @param channelType 渠道类型
|
||||
* @param status 状态
|
||||
* @return 渠道列表
|
||||
*/
|
||||
List<NotificationChannel> findByChannelTypeAndStatusAndDeletedFalse(
|
||||
NotificationChannelTypeEnum channelType,
|
||||
NotificationChannelStatusEnum status
|
||||
);
|
||||
|
||||
/**
|
||||
* 根据状态查询渠道列表
|
||||
*
|
||||
* @param status 状态
|
||||
* @return 渠道列表
|
||||
*/
|
||||
List<NotificationChannel> findByStatusAndDeletedFalse(NotificationChannelStatusEnum status);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
package com.qqchen.deploy.backend.notification.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelTypeEnum;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 通知模板Repository接口
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Repository
|
||||
public interface INotificationTemplateRepository extends IBaseRepository<NotificationTemplate, Long> {
|
||||
|
||||
/**
|
||||
* 根据编码查找模板
|
||||
*/
|
||||
Optional<NotificationTemplate> findByCode(String code);
|
||||
|
||||
/**
|
||||
* 根据编码和启用状态查找模板
|
||||
*/
|
||||
Optional<NotificationTemplate> findByCodeAndEnabled(String code, Boolean enabled);
|
||||
|
||||
/**
|
||||
* 根据渠道类型查找模板
|
||||
*/
|
||||
List<NotificationTemplate> findByChannelTypeAndEnabled(NotificationChannelTypeEnum channelType, Boolean enabled);
|
||||
|
||||
/**
|
||||
* 检查编码是否存在(排除指定ID)
|
||||
*/
|
||||
@Query("SELECT COUNT(t) > 0 FROM NotificationTemplate t WHERE t.code = :code AND t.id != :id")
|
||||
boolean existsByCodeAndIdNot(@Param("code") String code, @Param("id") Long id);
|
||||
|
||||
/**
|
||||
* 分页查询模板
|
||||
*/
|
||||
@Query("SELECT t FROM NotificationTemplate t WHERE " +
|
||||
"(:name IS NULL OR t.name LIKE %:name%) AND " +
|
||||
"(:code IS NULL OR t.code LIKE %:code%) AND " +
|
||||
"(:channelType IS NULL OR t.channelType = :channelType) AND " +
|
||||
"(:enabled IS NULL OR t.enabled = :enabled)")
|
||||
Page<NotificationTemplate> findByConditions(
|
||||
@Param("name") String name,
|
||||
@Param("code") String code,
|
||||
@Param("channelType") NotificationChannelTypeEnum channelType,
|
||||
@Param("enabled") Boolean enabled,
|
||||
Pageable pageable
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.qqchen.deploy.backend.notification.service;
|
||||
|
||||
import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest;
|
||||
|
||||
/**
|
||||
* 通知服务接口
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
public interface INotificationService {
|
||||
|
||||
/**
|
||||
* 发送通知消息
|
||||
*
|
||||
* @param request 发送请求(包含渠道ID、模板ID和参数)
|
||||
*/
|
||||
void send(SendNotificationRequest request);
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
package com.qqchen.deploy.backend.notification.service;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.notification.dto.NotificationTemplateDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.NotificationTemplateQuery;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通知模板Service接口
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
public interface INotificationTemplateService extends IBaseService<NotificationTemplate, NotificationTemplateDTO, NotificationTemplateQuery, Long> {
|
||||
|
||||
/**
|
||||
* 渲染模板
|
||||
*
|
||||
* @param templateCode 模板编码
|
||||
* @param params 模板参数
|
||||
* @return 渲染后的内容
|
||||
*/
|
||||
String renderTemplate(String templateCode, Map<String, Object> params);
|
||||
|
||||
|
||||
/**
|
||||
* 根据编码获取模板
|
||||
*
|
||||
* @param code 模板编码
|
||||
* @return 模板DTO
|
||||
*/
|
||||
NotificationTemplateDTO getByCode(String code);
|
||||
|
||||
/**
|
||||
* 检查编码是否存在
|
||||
*
|
||||
* @param code 模板编码
|
||||
* @param id 排除的ID(编辑时使用)
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByCode(String code, Long id);
|
||||
|
||||
/**
|
||||
* 启用通知模板
|
||||
*
|
||||
* @param id 模板ID
|
||||
*/
|
||||
void enable(Long id);
|
||||
|
||||
/**
|
||||
* 禁用通知模板
|
||||
*
|
||||
* @param id 模板ID
|
||||
*/
|
||||
void disable(Long id);
|
||||
}
|
||||
@ -15,7 +15,6 @@ import com.qqchen.deploy.backend.notification.dto.NotificationChannelQuery;
|
||||
import com.qqchen.deploy.backend.notification.dto.BaseSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.entity.config.WeworkNotificationConfig;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
|
||||
import com.qqchen.deploy.backend.notification.enums.NotificationChannelStatusEnum;
|
||||
import com.qqchen.deploy.backend.notification.factory.NotificationChannelAdapterFactory;
|
||||
import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationChannelService;
|
||||
@ -97,7 +96,7 @@ public class NotificationChannelServiceImpl
|
||||
NotificationChannel channel = notificationChannelRepository.findById(id)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
|
||||
|
||||
channel.setStatus(NotificationChannelStatusEnum.ENABLED);
|
||||
channel.setEnabled(true);
|
||||
notificationChannelRepository.save(channel);
|
||||
|
||||
log.info("启用通知渠道: id={}, name={}", id, channel.getName());
|
||||
@ -109,7 +108,7 @@ public class NotificationChannelServiceImpl
|
||||
NotificationChannel channel = notificationChannelRepository.findById(id)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
|
||||
|
||||
channel.setStatus(NotificationChannelStatusEnum.DISABLED);
|
||||
channel.setEnabled(false);
|
||||
notificationChannelRepository.save(channel);
|
||||
|
||||
log.info("禁用通知渠道: id={}, name={}", id, channel.getName());
|
||||
@ -130,7 +129,7 @@ public class NotificationChannelServiceImpl
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
|
||||
|
||||
// 3. 校验渠道状态
|
||||
if (channel.getStatus() != NotificationChannelStatusEnum.ENABLED) {
|
||||
if (!channel.getEnabled()) {
|
||||
throw new BusinessException(ResponseCode.DATA_NOT_FOUND);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,147 @@
|
||||
package com.qqchen.deploy.backend.notification.service.impl;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||
import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.dto.SendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
|
||||
import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository;
|
||||
import com.qqchen.deploy.backend.notification.repository.INotificationTemplateRepository;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationService;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationTemplateService;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通知服务实现类
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class NotificationServiceImpl implements INotificationService {
|
||||
|
||||
@Resource
|
||||
private INotificationTemplateService notificationTemplateService;
|
||||
|
||||
@Resource
|
||||
private INotificationSendService notificationSendService;
|
||||
|
||||
@Resource
|
||||
private INotificationChannelRepository notificationChannelRepository;
|
||||
|
||||
@Resource
|
||||
private INotificationTemplateRepository notificationTemplateRepository;
|
||||
|
||||
@Override
|
||||
public void send(SendNotificationRequest request) {
|
||||
// 1. 获取通知模板
|
||||
NotificationTemplate template = notificationTemplateRepository.findById(request.getNotificationTemplateId())
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
|
||||
|
||||
// 2. 获取通知渠道
|
||||
NotificationChannel channel = notificationChannelRepository.findById(request.getChannelId())
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND));
|
||||
|
||||
// 3. 验证模板和渠道类型是否匹配
|
||||
if (!template.getChannelType().equals(channel.getChannelType())) {
|
||||
throw new BusinessException(ResponseCode.INVALID_PARAM);
|
||||
}
|
||||
|
||||
// 4. 验证模板和渠道是否启用
|
||||
if (!template.getEnabled()) {
|
||||
throw new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_DISABLED);
|
||||
}
|
||||
if (!channel.getEnabled()) {
|
||||
throw new BusinessException(ResponseCode.DATA_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 5. 渲染模板内容
|
||||
String content = notificationTemplateService.renderTemplate(template.getCode(), request.getParams());
|
||||
|
||||
// 6. 根据渠道类型发送通知
|
||||
switch (template.getChannelType()) {
|
||||
case WEWORK -> sendWeworkNotification(request.getChannelId(), content, request.getParams());
|
||||
case EMAIL -> sendEmailNotification(request.getChannelId(), content, request.getParams());
|
||||
default -> throw new BusinessException(ResponseCode.INVALID_PARAM);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送企业微信通知
|
||||
*/
|
||||
private void sendWeworkNotification(Long channelId, String content, Map<String, Object> params) {
|
||||
WeworkSendNotificationRequest request = new WeworkSendNotificationRequest();
|
||||
request.setChannelId(channelId);
|
||||
request.setContent(content);
|
||||
|
||||
// 根据内容判断消息类型,或从参数中获取
|
||||
WeworkMessageTypeEnum messageType = WeworkMessageTypeEnum.MARKDOWN; // 默认使用 MARKDOWN
|
||||
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<String>) params.get("mentionedMobileList"));
|
||||
}
|
||||
if (params.containsKey("mentionedUserList")) {
|
||||
request.setMentionedUserList((List<String>) params.get("mentionedUserList"));
|
||||
}
|
||||
}
|
||||
|
||||
notificationSendService.send(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件通知
|
||||
*/
|
||||
private void sendEmailNotification(Long channelId, String content, Map<String, Object> 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);
|
||||
|
||||
// 是否HTML格式从参数中获取
|
||||
Boolean isHtml = false;
|
||||
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<String>) params.get("toReceivers"));
|
||||
|
||||
// 可选参数
|
||||
if (params != null) {
|
||||
if (params.containsKey("ccReceivers")) {
|
||||
request.setCcReceivers((List<String>) params.get("ccReceivers"));
|
||||
}
|
||||
if (params.containsKey("bccReceivers")) {
|
||||
request.setBccReceivers((List<String>) params.get("bccReceivers"));
|
||||
}
|
||||
}
|
||||
|
||||
notificationSendService.send(request);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
package com.qqchen.deploy.backend.notification.service.impl;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||
import com.qqchen.deploy.backend.notification.converter.NotificationTemplateConverter;
|
||||
import com.qqchen.deploy.backend.notification.dto.EmailSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.dto.NotificationTemplateDTO;
|
||||
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.dto.template.NotificationTemplateQuery;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationTemplate;
|
||||
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
|
||||
import com.qqchen.deploy.backend.notification.repository.INotificationTemplateRepository;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationTemplateService;
|
||||
import freemarker.template.Configuration;
|
||||
import freemarker.template.Template;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通知模板Service实现类
|
||||
*
|
||||
* @author qqchen
|
||||
* @since 2025-11-12
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class NotificationTemplateServiceImpl extends BaseServiceImpl<NotificationTemplate, NotificationTemplateDTO, NotificationTemplateQuery, Long> implements INotificationTemplateService {
|
||||
|
||||
@Resource
|
||||
private INotificationTemplateRepository notificationTemplateRepository;
|
||||
|
||||
@Resource
|
||||
private NotificationTemplateConverter notificationTemplateConverter;
|
||||
|
||||
@Resource
|
||||
private Configuration freemarkerConfig;
|
||||
|
||||
@Override
|
||||
protected void validateUniqueConstraints(NotificationTemplateDTO dto) {
|
||||
// 检查编码是否重复
|
||||
if (existsByCode(dto.getCode(), dto.getId())) {
|
||||
throw new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_CODE_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String renderTemplate(String templateCode, Map<String, Object> params) {
|
||||
NotificationTemplate template = getTemplateByCode(templateCode);
|
||||
return processTemplate(template.getContentTemplate(), params);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public NotificationTemplateDTO getByCode(String code) {
|
||||
NotificationTemplate template = getTemplateByCode(code);
|
||||
return notificationTemplateConverter.toDto(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean existsByCode(String code, Long id) {
|
||||
if (id == null) {
|
||||
return notificationTemplateRepository.findByCode(code).isPresent();
|
||||
}
|
||||
return notificationTemplateRepository.existsByCodeAndIdNot(code, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据编码获取模板实体
|
||||
*/
|
||||
private NotificationTemplate getTemplateByCode(String code) {
|
||||
return notificationTemplateRepository.findByCodeAndEnabled(code, true)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FreeMarker模板处理
|
||||
*/
|
||||
private String processTemplate(String templateContent, Map<String, Object> params) {
|
||||
try {
|
||||
Template template = new Template("notification", new StringReader(templateContent), freemarkerConfig);
|
||||
StringWriter writer = new StringWriter();
|
||||
template.process(params, writer);
|
||||
return writer.toString();
|
||||
} catch (Exception e) {
|
||||
log.error("模板渲染失败: {}", e.getMessage(), e);
|
||||
throw new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_RENDER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void enable(Long id) {
|
||||
NotificationTemplate template = notificationTemplateRepository.findById(id)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
|
||||
template.setEnabled(true);
|
||||
notificationTemplateRepository.save(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void disable(Long id) {
|
||||
NotificationTemplate template = notificationTemplateRepository.findById(id)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.NOTIFICATION_TEMPLATE_NOT_FOUND));
|
||||
template.setEnabled(false);
|
||||
notificationTemplateRepository.save(template);
|
||||
}
|
||||
}
|
||||
@ -75,8 +75,10 @@ VALUES
|
||||
(203, '定时任务管理', '/deploy/schedule-jobs', 'Deploy/ScheduleJob/List', 'ClockCircleOutlined', 'deploy:schedule-job', 2, 200, 3, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 环境管理
|
||||
(204, '环境管理', '/deploy/environments', 'Deploy/Environment/List', 'CloudOutlined', 'deploy:environment', 2, 200, 4, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 消息中心
|
||||
(205, '消息中心', '/deploy/notification-channels', 'Deploy/NotificationChannel/List', 'BellOutlined', 'deploy:notification-channel', 2, 200, 5, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 消息渠道管理
|
||||
(205, '消息渠道管理', '/deploy/notification-channels', 'Deploy/NotificationChannel/List', 'BellOutlined', 'deploy:notification-channel', 2, 200, 5, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
-- 通知模板
|
||||
(206, '通知模板', '/deploy/notification-templates', 'Deploy/NotificationTemplate/List', 'FileTextOutlined', 'deploy:notification-template', 2, 200, 6, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
|
||||
-- 资源管理
|
||||
(300, '资源管理', '/resource', NULL, 'DatabaseOutlined', NULL, 1, NULL, 3, FALSE, TRUE, 'system', '2024-01-01 00:00:00', 0, FALSE),
|
||||
@ -301,7 +303,16 @@ INSERT INTO sys_permission (id, create_time, menu_id, code, name, type, sort) VA
|
||||
(323, NOW(), 104, 'workflow:form:create', '表单创建', 'FUNCTION', 3),
|
||||
(324, NOW(), 104, 'workflow:form:update', '表单修改', 'FUNCTION', 4),
|
||||
(325, NOW(), 104, 'workflow:form:delete', '表单删除', 'FUNCTION', 5),
|
||||
(326, NOW(), 104, 'workflow:form:publish', '发布表单', 'FUNCTION', 6);
|
||||
(326, NOW(), 104, 'workflow:form:publish', '发布表单', 'FUNCTION', 6),
|
||||
|
||||
-- 通知模板管理 (menu_id=206)
|
||||
(2061, NOW(), 206, 'notification:template:view', '查看通知模板', 'FUNCTION', 1),
|
||||
(2062, NOW(), 206, 'notification:template:create', '新增通知模板', 'FUNCTION', 2),
|
||||
(2063, NOW(), 206, 'notification:template:update', '编辑通知模板', 'FUNCTION', 3),
|
||||
(2064, NOW(), 206, 'notification:template:delete', '删除通知模板', 'FUNCTION', 4),
|
||||
(2065, NOW(), 206, 'notification:template:toggle', '启用/禁用通知模板', 'FUNCTION', 5),
|
||||
(2066, NOW(), 206, 'notification:template:copy', '复制通知模板', 'FUNCTION', 6),
|
||||
(2067, NOW(), 206, 'notification:template:preview', '预览通知模板', 'FUNCTION', 7);
|
||||
|
||||
--
|
||||
-- -- 团队配置管理 (无对应菜单,menu_id=NULL)
|
||||
@ -1195,11 +1206,11 @@ INSERT INTO workflow_node_definition (
|
||||
|
||||
-- 企业微信通知渠道示例
|
||||
INSERT INTO sys_notification_channel
|
||||
(name, channel_type, config, status, description, create_by, create_time, update_by, update_time, version, deleted)
|
||||
(name, channel_type, config, enabled, description, create_by, create_time, update_by, update_time, version, deleted)
|
||||
VALUES
|
||||
('研发部企业微信群', 'WEWORK',
|
||||
'{"webhookUrl":"https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=example-key-please-replace"}',
|
||||
'DISABLED',
|
||||
0,
|
||||
'研发部通知群,用于部署通知(示例数据,请修改为实际的Webhook地址)',
|
||||
'admin', NOW(), 'admin', NOW(), 0, 0);
|
||||
|
||||
@ -1308,3 +1319,144 @@ INSERT INTO deploy_server_category (id, name, code, icon, description, sort, ena
|
||||
(3, '中间件服务器', 'MIDDLEWARE_SERVER', 'cluster', '消息队列、搜索引擎等中间件', 3, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0),
|
||||
(4, '应用服务器', 'APP_SERVER', 'cloud-server', '业务应用服务器', 4, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0),
|
||||
(5, '其他', 'OTHER', 'hdd', '其他类型服务器', 99, 1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0);
|
||||
|
||||
-- =====================================================
|
||||
-- 通知模板初始数据
|
||||
-- =====================================================
|
||||
|
||||
-- 插入通知模板初始数据
|
||||
INSERT INTO sys_notification_template (id, create_by, create_time, update_by, update_time, version, deleted,
|
||||
name, code, description, channel_type, content_template, enabled) VALUES
|
||||
-- Jenkins构建通知模板
|
||||
(1, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0,
|
||||
'Jenkins构建通知-企业微信', 'jenkins_build_wework', 'Jenkins构建结果通知模板(企业微信)', 'WEWORK',
|
||||
'### 🚀 Jenkins构建通知
|
||||
|
||||
**项目名称**: ${projectName}
|
||||
**构建号**: #${buildNumber}
|
||||
**构建状态**: <#if buildStatus == "SUCCESS">✅ 成功<#elseif buildStatus == "FAILURE">❌ 失败<#else>🔄 构建中</#if>
|
||||
<#if buildTime??>**构建时间**: ${buildTime}</#if>
|
||||
<#if duration??>**构建耗时**: ${duration}</#if>
|
||||
|
||||
<#if buildStatus == "FAILURE">
|
||||
⚠️ **构建失败,请及时处理!**
|
||||
</#if>
|
||||
|
||||
---
|
||||
*Deploy Ease Platform 自动通知*', 1),
|
||||
|
||||
(2, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0,
|
||||
'Jenkins构建通知-邮件', 'jenkins_build_email', 'Jenkins构建结果通知模板(邮件)', 'EMAIL',
|
||||
'<h2>🚀 Jenkins构建通知</h2>
|
||||
<table style="border-collapse: collapse; width: 100%;">
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>项目名称</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">${projectName}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>构建号</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">#${buildNumber}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>构建状态</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">
|
||||
<#if buildStatus == "SUCCESS">
|
||||
<span style="color: green;">✅ 成功</span>
|
||||
<#elseif buildStatus == "FAILURE">
|
||||
<span style="color: red;">❌ 失败</span>
|
||||
<#else>
|
||||
<span style="color: orange;">🔄 构建中</span>
|
||||
</#if>
|
||||
</td>
|
||||
</tr>
|
||||
<#if buildTime??>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>构建时间</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">${buildTime}</td>
|
||||
</tr>
|
||||
</#if>
|
||||
<#if duration??>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>构建耗时</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">${duration}</td>
|
||||
</tr>
|
||||
</#if>
|
||||
</table>
|
||||
|
||||
<#if buildStatus == "FAILURE">
|
||||
<p style="color: red; font-weight: bold;">⚠️ 构建失败,请及时处理!</p>
|
||||
</#if>
|
||||
|
||||
<hr>
|
||||
<p style="color: #666; font-size: 12px;">Deploy Ease Platform 自动通知</p>', 1),
|
||||
|
||||
-- 部署通知模板
|
||||
(3, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0,
|
||||
'部署通知-企业微信', 'deploy_notification_wework', '应用部署结果通知模板(企业微信)', 'WEWORK',
|
||||
'### 📦 应用部署通知
|
||||
|
||||
**应用名称**: ${appName}
|
||||
**部署环境**: ${environment}
|
||||
**部署状态**: <#if deployStatus == "SUCCESS">✅ 部署成功<#else>❌ 部署失败</#if>
|
||||
**部署版本**: ${version}
|
||||
**部署时间**: ${deployTime}
|
||||
|
||||
<#if deployUrl??>
|
||||
**访问地址**: ${deployUrl}
|
||||
</#if>
|
||||
|
||||
<#if deployStatus == "SUCCESS">
|
||||
🎉 **应用已成功部署上线!**
|
||||
<#else>
|
||||
⚠️ **部署失败,请检查日志!**
|
||||
</#if>
|
||||
|
||||
---
|
||||
*Deploy Ease Platform 自动通知*', 1),
|
||||
|
||||
(4, 'system', '2024-01-01 00:00:00', 'system', '2024-01-01 00:00:00', 1, 0,
|
||||
'部署通知-邮件', 'deploy_notification_email', '应用部署结果通知模板(邮件)', 'EMAIL',
|
||||
'<h2>📦 应用部署通知</h2>
|
||||
<table style="border-collapse: collapse; width: 100%;">
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>应用名称</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">${appName}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>部署环境</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">${environment}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>部署状态</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">
|
||||
<#if deployStatus == "SUCCESS">
|
||||
<span style="color: green;">✅ 部署成功</span>
|
||||
<#else>
|
||||
<span style="color: red;">❌ 部署失败</span>
|
||||
</#if>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>部署版本</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">${version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>部署时间</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;">${deployTime}</td>
|
||||
</tr>
|
||||
<#if deployUrl??>
|
||||
<tr>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>访问地址</strong></td>
|
||||
<td style="padding: 8px; border: 1px solid #ddd;"><a href="${deployUrl}">${deployUrl}</a></td>
|
||||
</tr>
|
||||
</#if>
|
||||
</table>
|
||||
|
||||
<#if deployStatus == "SUCCESS">
|
||||
<p style="color: green; font-weight: bold;">🎉 应用已成功部署上线!</p>
|
||||
<#else>
|
||||
<p style="color: red; font-weight: bold;">⚠️ 部署失败,请检查日志!</p>
|
||||
</#if>
|
||||
|
||||
<hr>
|
||||
<p style="color: #666; font-size: 12px;">Deploy Ease Platform 自动通知</p>', 1);
|
||||
|
||||
@ -926,11 +926,11 @@ CREATE TABLE sys_notification_channel
|
||||
name VARCHAR(100) NOT NULL COMMENT '渠道名称(如:研发部企业微信群)',
|
||||
channel_type VARCHAR(50) NOT NULL COMMENT '渠道类型(WEWORK, FEISHU, DINGTALK, SMS, EMAIL, SLACK)',
|
||||
config JSON NOT NULL COMMENT '渠道配置(JSON格式,不同渠道存储不同字段)',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'ENABLED' COMMENT '状态(ENABLED-启用, DISABLED-禁用)',
|
||||
enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用',
|
||||
description VARCHAR(500) NULL COMMENT '描述说明',
|
||||
|
||||
INDEX idx_channel_type (channel_type),
|
||||
INDEX idx_status (status),
|
||||
INDEX idx_enabled (enabled),
|
||||
INDEX idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='通知渠道配置表';
|
||||
|
||||
@ -1144,3 +1144,26 @@ CREATE TABLE deploy_record
|
||||
CONSTRAINT fk_deploy_record_team_app FOREIGN KEY (team_application_id) REFERENCES deploy_team_application (id)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='部署记录表';
|
||||
|
||||
-- 通知模板表
|
||||
CREATE TABLE sys_notification_template
|
||||
(
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
|
||||
create_by VARCHAR(100) NULL COMMENT '创建人',
|
||||
create_time DATETIME(6) NULL COMMENT '创建时间',
|
||||
update_by VARCHAR(100) NULL COMMENT '更新人',
|
||||
update_time DATETIME(6) NULL COMMENT '更新时间',
|
||||
version INT NOT NULL DEFAULT 1 COMMENT '版本号',
|
||||
deleted BIT NOT NULL DEFAULT 0 COMMENT '是否删除',
|
||||
|
||||
name VARCHAR(100) NOT NULL COMMENT '模板名称',
|
||||
code VARCHAR(50) NOT NULL COMMENT '模板编码',
|
||||
description VARCHAR(500) NULL COMMENT '模板描述',
|
||||
channel_type VARCHAR(20) NOT NULL COMMENT '渠道类型',
|
||||
content_template TEXT NOT NULL COMMENT '内容模板',
|
||||
enabled BIT NOT NULL DEFAULT 1 COMMENT '是否启用',
|
||||
|
||||
UNIQUE KEY uk_code (code),
|
||||
KEY idx_channel_type (channel_type),
|
||||
KEY idx_enabled (enabled)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='通知模板表';
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user