增加系统版本通知功能
This commit is contained in:
parent
78c2ef0dd9
commit
94ef1ef9eb
@ -0,0 +1,124 @@
|
||||
package com.qqchen.deploy.backend.system.api;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.api.Response;
|
||||
import com.qqchen.deploy.backend.framework.controller.BaseController;
|
||||
import com.qqchen.deploy.backend.system.dto.SystemReleaseDTO;
|
||||
import com.qqchen.deploy.backend.system.entity.SystemRelease;
|
||||
import com.qqchen.deploy.backend.system.query.SystemReleaseQuery;
|
||||
import com.qqchen.deploy.backend.system.service.ISystemReleaseService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录 Controller
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/system-release")
|
||||
@Tag(name = "系统版本发布管理", description = "系统版本发布记录管理相关接口")
|
||||
public class SystemReleaseApiController
|
||||
extends BaseController<SystemRelease, SystemReleaseDTO, Long, SystemReleaseQuery> {
|
||||
|
||||
@Resource
|
||||
private ISystemReleaseService systemReleaseService;
|
||||
|
||||
@Override
|
||||
@PostMapping
|
||||
@Operation(summary = "创建发布记录", description = "创建新的版本发布记录")
|
||||
public Response<SystemReleaseDTO> create(@Validated @RequestBody SystemReleaseDTO dto) {
|
||||
return super.create(dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PutMapping("/{id}")
|
||||
@Operation(summary = "更新发布记录", description = "更新指定ID的版本发布记录")
|
||||
public Response<SystemReleaseDTO> update(@PathVariable Long id, @Validated @RequestBody SystemReleaseDTO dto) {
|
||||
return super.update(id, dto);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DeleteMapping("/{id}")
|
||||
@Operation(summary = "删除发布记录", description = "删除指定ID的版本发布记录(逻辑删除)")
|
||||
public Response<Void> delete(@PathVariable Long id) {
|
||||
return super.delete(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("/{id}")
|
||||
@Operation(summary = "查询发布记录详情", description = "根据ID查询版本发布记录详情")
|
||||
public Response<SystemReleaseDTO> findById(@PathVariable Long id) {
|
||||
return super.findById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询所有发布记录", description = "查询所有版本发布记录列表")
|
||||
public Response<List<SystemReleaseDTO>> findAll() {
|
||||
return super.findAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询发布记录", description = "分页查询版本发布记录")
|
||||
public Response<Page<SystemReleaseDTO>> page(SystemReleaseQuery query) {
|
||||
return super.page(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("/query")
|
||||
@Operation(summary = "条件查询发布记录", description = "根据条件查询版本发布记录列表")
|
||||
public Response<List<SystemReleaseDTO>> findAll(SystemReleaseQuery query) {
|
||||
return super.findAll(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping("/batch")
|
||||
@Operation(summary = "批量处理发布记录", description = "批量创建/更新版本发布记录")
|
||||
public CompletableFuture<Response<Void>> batchProcess(@RequestBody List<SystemReleaseDTO> dtos) {
|
||||
return super.batchProcess(dtos);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取未通知的发布记录列表
|
||||
*/
|
||||
@GetMapping("/unnotified")
|
||||
@Operation(summary = "获取未通知的发布记录", description = "查询所有未发送通知的版本发布记录")
|
||||
public Response<List<SystemReleaseDTO>> getUnnotifiedReleases() {
|
||||
List<SystemReleaseDTO> releases = systemReleaseService.getUnnotifiedReleases();
|
||||
return Response.success(releases);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标记为已通知
|
||||
*/
|
||||
@PutMapping("/{id}/notify")
|
||||
@Operation(summary = "标记为已通知", description = "将指定发布记录标记为已发送通知")
|
||||
public Response<Void> markAsNotified(@PathVariable Long id) {
|
||||
systemReleaseService.markAsNotified(id);
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定模块的最新发布记录
|
||||
*/
|
||||
@GetMapping("/latest/{module}")
|
||||
@Operation(summary = "获取最新发布记录", description = "获取指定模块的最新版本发布记录")
|
||||
public Response<SystemReleaseDTO> getLatestReleaseByModule(@PathVariable String module) {
|
||||
SystemReleaseDTO release = systemReleaseService.getLatestReleaseByModule(module);
|
||||
return Response.success(release);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void exportData(HttpServletResponse response, List<SystemReleaseDTO> data) {
|
||||
log.info("导出系统版本发布记录数据,数据量:{}", data.size());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package com.qqchen.deploy.backend.system.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
|
||||
/**
|
||||
* 系统版本发布配置
|
||||
*/
|
||||
@Configuration
|
||||
public class SystemReleaseConfig {
|
||||
|
||||
/**
|
||||
* 配置任务调度器
|
||||
* 用于延迟执行系统维护任务
|
||||
*/
|
||||
@Bean
|
||||
public TaskScheduler systemMaintenanceTaskScheduler() {
|
||||
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
|
||||
scheduler.setPoolSize(5);
|
||||
scheduler.setThreadNamePrefix("system-maintenance-");
|
||||
scheduler.setWaitForTasksToCompleteOnShutdown(false);
|
||||
scheduler.setAwaitTerminationSeconds(0);
|
||||
scheduler.initialize();
|
||||
return scheduler;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.qqchen.deploy.backend.system.converter;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
|
||||
import com.qqchen.deploy.backend.system.dto.SystemReleaseDTO;
|
||||
import com.qqchen.deploy.backend.system.entity.SystemRelease;
|
||||
import org.mapstruct.Mapper;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录转换器
|
||||
*/
|
||||
@Mapper(config = BaseConverter.class)
|
||||
public interface SystemReleaseConverter extends BaseConverter<SystemRelease, SystemReleaseDTO> {
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
package com.qqchen.deploy.backend.system.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录 DTO
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SystemReleaseDTO extends BaseDTO {
|
||||
|
||||
/**
|
||||
* 发布版本号(如 1.51)
|
||||
*/
|
||||
@NotNull(message = "版本号不能为空")
|
||||
private BigDecimal releaseVersion;
|
||||
|
||||
/**
|
||||
* 模块类型:BACKEND/FRONTEND/ALL
|
||||
*/
|
||||
@NotBlank(message = "模块类型不能为空")
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 发布时间
|
||||
*/
|
||||
@NotNull(message = "发布时间不能为空")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime releaseDate;
|
||||
|
||||
/**
|
||||
* 变更内容(换行分隔)
|
||||
*/
|
||||
private String changes;
|
||||
|
||||
/**
|
||||
* 是否已发送版本发布通知
|
||||
*/
|
||||
private Boolean notified;
|
||||
|
||||
/**
|
||||
* 延迟执行分钟数(创建后多久开始维护,为空则不触发维护)
|
||||
*/
|
||||
private Integer delayMinutes;
|
||||
|
||||
/**
|
||||
* 预计维护时长(分钟)
|
||||
*/
|
||||
private Integer estimatedDuration;
|
||||
|
||||
/**
|
||||
* 是否自动停止服务
|
||||
*/
|
||||
private Boolean enableAutoShutdown;
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package com.qqchen.deploy.backend.system.entity;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.domain.Entity;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录实体
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@jakarta.persistence.Entity
|
||||
@Table(name = "system_release")
|
||||
public class SystemRelease extends Entity<Long> {
|
||||
|
||||
/**
|
||||
* 发布版本号(如 1.51)
|
||||
*/
|
||||
@Column(name = "release_version", nullable = false, precision = 10, scale = 2)
|
||||
private BigDecimal releaseVersion;
|
||||
|
||||
/**
|
||||
* 模块类型:BACKEND/FRONTEND/ALL
|
||||
*/
|
||||
@Column(name = "module", nullable = false, length = 20)
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 发布时间
|
||||
*/
|
||||
@Column(name = "release_date", nullable = false)
|
||||
private LocalDateTime releaseDate;
|
||||
|
||||
/**
|
||||
* 变更内容(换行分隔)
|
||||
*/
|
||||
@Column(name = "changes", columnDefinition = "TEXT")
|
||||
private String changes;
|
||||
|
||||
/**
|
||||
* 是否已发送版本发布通知
|
||||
*/
|
||||
@Column(name = "notified", nullable = false)
|
||||
private Boolean notified = false;
|
||||
|
||||
/**
|
||||
* 延迟执行分钟数(创建后多久开始维护,为空则不触发维护)
|
||||
*/
|
||||
@Column(name = "delay_minutes")
|
||||
private Integer delayMinutes;
|
||||
|
||||
/**
|
||||
* 预计维护时长(分钟)
|
||||
*/
|
||||
@Column(name = "estimated_duration")
|
||||
private Integer estimatedDuration;
|
||||
|
||||
/**
|
||||
* 是否自动停止服务
|
||||
*/
|
||||
@Column(name = "enable_auto_shutdown", nullable = false)
|
||||
private Boolean enableAutoShutdown = false;
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
package com.qqchen.deploy.backend.system.listener;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
|
||||
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
|
||||
import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
|
||||
import com.qqchen.deploy.backend.system.entity.SystemRelease;
|
||||
import com.qqchen.deploy.backend.system.repository.ISystemReleaseRepository;
|
||||
import com.qqchen.deploy.backend.system.service.ISystemReleaseService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 系统版本发布启动监听器
|
||||
* 应用启动完成后,自动发送最新版本通知
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class SystemReleaseStartupListener {
|
||||
|
||||
@Autowired
|
||||
private ISystemReleaseRepository releaseRepository;
|
||||
|
||||
@Autowired
|
||||
private ISystemReleaseService releaseService;
|
||||
|
||||
@Autowired
|
||||
private INotificationChannelRepository notificationChannelRepository;
|
||||
|
||||
@Autowired
|
||||
private INotificationSendService notificationSendService;
|
||||
|
||||
@Value("${deploy.notification.release.channel-id}")
|
||||
private Long notificationChannelId;
|
||||
|
||||
/**
|
||||
* 应用启动完成事件监听
|
||||
*/
|
||||
@EventListener(ApplicationReadyEvent.class)
|
||||
public void onApplicationReady() {
|
||||
try {
|
||||
log.info("========================================");
|
||||
log.info("检查是否有未通知的版本发布记录...");
|
||||
|
||||
// 查询最新的未通知版本(按版本号降序)
|
||||
SystemRelease latestRelease = releaseRepository
|
||||
.findFirstByNotifiedFalseAndDeletedFalseOrderByReleaseVersionDesc();
|
||||
|
||||
if (latestRelease != null) {
|
||||
log.info("发现未通知的版本发布记录");
|
||||
log.info("版本号: {}", latestRelease.getReleaseVersion());
|
||||
log.info("模块: {}", latestRelease.getModule());
|
||||
|
||||
// 发送版本发布通知
|
||||
sendReleaseNotification(latestRelease);
|
||||
|
||||
// 标记为已通知
|
||||
releaseService.markAsNotified(latestRelease.getId());
|
||||
|
||||
log.info("版本发布通知已发送并标记");
|
||||
} else {
|
||||
log.info("没有未通知的版本发布记录");
|
||||
}
|
||||
|
||||
log.info("========================================");
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("版本发布通知处理失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送版本发布通知
|
||||
*/
|
||||
private void sendReleaseNotification(SystemRelease release) {
|
||||
try {
|
||||
// 查询通知渠道
|
||||
NotificationChannel channel = notificationChannelRepository.findById(notificationChannelId)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND,
|
||||
new Object[]{"通知渠道ID=" + notificationChannelId + "不存在"}));
|
||||
|
||||
// 准备通知内容(加上版本号)
|
||||
String changes = release.getChanges() != null ? release.getChanges() : "暂无变更内容";
|
||||
String message = String.format("版本号:%s\n\n%s", release.getReleaseVersion(), changes);
|
||||
|
||||
log.info("发送版本发布通知(v{}):\n{}", release.getReleaseVersion(), message);
|
||||
|
||||
// 创建企微通知请求
|
||||
WeworkSendNotificationRequest request = new WeworkSendNotificationRequest();
|
||||
request.setContent(message);
|
||||
request.setTitle("系统版本上线通知");
|
||||
request.setMessageType(WeworkMessageTypeEnum.TEXT);
|
||||
|
||||
// 发送通知
|
||||
notificationSendService.send(channel, request);
|
||||
|
||||
log.info("版本发布通知发送成功");
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("发送版本发布通知失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
package com.qqchen.deploy.backend.system.query;
|
||||
|
||||
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 lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录查询对象
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SystemReleaseQuery extends BaseQuery {
|
||||
|
||||
/**
|
||||
* 版本号(精确查询)
|
||||
*/
|
||||
@QueryField(field = "releaseVersion")
|
||||
private BigDecimal releaseVersion;
|
||||
|
||||
/**
|
||||
* 版本号范围查询 - 最小版本
|
||||
*/
|
||||
@QueryField(field = "releaseVersion", type = QueryType.GREATER_EQUAL)
|
||||
private BigDecimal releaseVersionMin;
|
||||
|
||||
/**
|
||||
* 版本号范围查询 - 最大版本
|
||||
*/
|
||||
@QueryField(field = "releaseVersion", type = QueryType.LESS_EQUAL)
|
||||
private BigDecimal releaseVersionMax;
|
||||
|
||||
/**
|
||||
* 模块类型(精确查询)
|
||||
*/
|
||||
@QueryField(field = "module")
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 是否已通知
|
||||
*/
|
||||
@QueryField(field = "notified")
|
||||
private Boolean notified;
|
||||
|
||||
/**
|
||||
* 发布时间开始
|
||||
*/
|
||||
@QueryField(field = "releaseDate", type = QueryType.GREATER_EQUAL)
|
||||
private LocalDateTime releaseDateStart;
|
||||
|
||||
/**
|
||||
* 发布时间结束
|
||||
*/
|
||||
@QueryField(field = "releaseDate", type = QueryType.LESS_EQUAL)
|
||||
private LocalDateTime releaseDateEnd;
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
package com.qqchen.deploy.backend.system.repository;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
|
||||
import com.qqchen.deploy.backend.system.entity.SystemRelease;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录仓储接口
|
||||
*/
|
||||
@Repository
|
||||
public interface ISystemReleaseRepository extends IBaseRepository<SystemRelease, Long> {
|
||||
|
||||
/**
|
||||
* 根据版本号和模块查询(排除已删除)
|
||||
*
|
||||
* @param releaseVersion 版本号
|
||||
* @param module 模块类型
|
||||
* @return 发布记录
|
||||
*/
|
||||
SystemRelease findByReleaseVersionAndModuleAndDeletedFalse(BigDecimal releaseVersion, String module);
|
||||
|
||||
/**
|
||||
* 检查版本号和模块是否存在(排除已删除)
|
||||
*
|
||||
* @param releaseVersion 版本号
|
||||
* @param module 模块类型
|
||||
* @return 是否存在
|
||||
*/
|
||||
boolean existsByReleaseVersionAndModuleAndDeletedFalse(BigDecimal releaseVersion, String module);
|
||||
|
||||
/**
|
||||
* 查询未通知的发布记录(排除已删除)
|
||||
*
|
||||
* @return 未通知的发布记录列表
|
||||
*/
|
||||
List<SystemRelease> findByNotifiedFalseAndDeletedFalseOrderByReleaseDateDesc();
|
||||
|
||||
/**
|
||||
* 根据模块查询最新的发布记录(排除已删除)
|
||||
*
|
||||
* @param module 模块类型
|
||||
* @return 最新的发布记录
|
||||
*/
|
||||
SystemRelease findTopByModuleAndDeletedFalseOrderByReleaseDateDesc(String module);
|
||||
|
||||
/**
|
||||
* 查询最新的未通知版本(按版本号降序)
|
||||
*
|
||||
* @return 最新的未通知版本
|
||||
*/
|
||||
SystemRelease findFirstByNotifiedFalseAndDeletedFalseOrderByReleaseVersionDesc();
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package com.qqchen.deploy.backend.system.service;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.service.IBaseService;
|
||||
import com.qqchen.deploy.backend.system.dto.SystemReleaseDTO;
|
||||
import com.qqchen.deploy.backend.system.entity.SystemRelease;
|
||||
import com.qqchen.deploy.backend.system.query.SystemReleaseQuery;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录服务接口
|
||||
*/
|
||||
public interface ISystemReleaseService extends IBaseService<SystemRelease, SystemReleaseDTO, SystemReleaseQuery, Long> {
|
||||
|
||||
/**
|
||||
* 获取未通知的发布记录列表
|
||||
*
|
||||
* @return 未通知的发布记录列表
|
||||
*/
|
||||
List<SystemReleaseDTO> getUnnotifiedReleases();
|
||||
|
||||
/**
|
||||
* 标记为已通知
|
||||
*
|
||||
* @param id 发布记录ID
|
||||
*/
|
||||
void markAsNotified(Long id);
|
||||
|
||||
/**
|
||||
* 获取指定模块的最新发布记录
|
||||
*
|
||||
* @param module 模块类型
|
||||
* @return 最新发布记录
|
||||
*/
|
||||
SystemReleaseDTO getLatestReleaseByModule(String module);
|
||||
}
|
||||
@ -0,0 +1,261 @@
|
||||
package com.qqchen.deploy.backend.system.service.impl;
|
||||
|
||||
import com.qqchen.deploy.backend.framework.annotation.ServiceType;
|
||||
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
|
||||
import com.qqchen.deploy.backend.framework.exception.BusinessException;
|
||||
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
|
||||
import com.qqchen.deploy.backend.notification.dto.WeworkSendNotificationRequest;
|
||||
import com.qqchen.deploy.backend.notification.entity.NotificationChannel;
|
||||
import com.qqchen.deploy.backend.notification.enums.WeworkMessageTypeEnum;
|
||||
import com.qqchen.deploy.backend.notification.repository.INotificationChannelRepository;
|
||||
import com.qqchen.deploy.backend.notification.service.INotificationSendService;
|
||||
import com.qqchen.deploy.backend.system.dto.SystemReleaseDTO;
|
||||
import com.qqchen.deploy.backend.system.entity.SystemRelease;
|
||||
import com.qqchen.deploy.backend.system.query.SystemReleaseQuery;
|
||||
import com.qqchen.deploy.backend.system.repository.ISystemReleaseRepository;
|
||||
import com.qqchen.deploy.backend.system.service.ISystemReleaseService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 系统版本发布记录服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@ServiceType(ServiceType.Type.DATABASE)
|
||||
public class SystemReleaseServiceImpl
|
||||
extends BaseServiceImpl<SystemRelease, SystemReleaseDTO, SystemReleaseQuery, Long>
|
||||
implements ISystemReleaseService {
|
||||
|
||||
private final ISystemReleaseRepository systemReleaseRepository;
|
||||
|
||||
@Autowired
|
||||
private TaskScheduler taskScheduler;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private INotificationChannelRepository notificationChannelRepository;
|
||||
|
||||
@Autowired
|
||||
private INotificationSendService notificationSendService;
|
||||
|
||||
@Value("${deploy.notification.release.channel-id}")
|
||||
private Long notificationChannelId;
|
||||
|
||||
/**
|
||||
* 维护任务映射:releaseId -> ScheduledFuture
|
||||
* 用于跟踪和取消已调度的维护任务
|
||||
*/
|
||||
private final Map<Long, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
|
||||
|
||||
public SystemReleaseServiceImpl(ISystemReleaseRepository systemReleaseRepository) {
|
||||
this.systemReleaseRepository = systemReleaseRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SystemReleaseDTO create(SystemReleaseDTO dto) {
|
||||
// 调用父类方法保存
|
||||
SystemReleaseDTO savedDto = super.create(dto);
|
||||
|
||||
// 如果设置了延迟时间,则调度维护任务(无论是否自动停止服务)
|
||||
if (dto.getDelayMinutes() != null && dto.getDelayMinutes() > 0) {
|
||||
SystemRelease release = converter.toEntity(savedDto);
|
||||
scheduleMaintenanceTask(release);
|
||||
}
|
||||
|
||||
return savedDto;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SystemReleaseDTO update(Long id, SystemReleaseDTO dto) {
|
||||
// 先取消旧的维护任务
|
||||
cancelMaintenanceTask(id);
|
||||
|
||||
// 调用父类方法更新
|
||||
SystemReleaseDTO updatedDto = super.update(id, dto);
|
||||
|
||||
// 如果设置了延迟时间,重新调度维护任务
|
||||
if (dto.getDelayMinutes() != null && dto.getDelayMinutes() > 0) {
|
||||
SystemRelease release = converter.toEntity(updatedDto);
|
||||
scheduleMaintenanceTask(release);
|
||||
}
|
||||
|
||||
return updatedDto;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Long id) {
|
||||
// 取消已调度的维护任务
|
||||
cancelMaintenanceTask(id);
|
||||
|
||||
// 调用父类方法删除
|
||||
super.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消维护任务
|
||||
*/
|
||||
private void cancelMaintenanceTask(Long releaseId) {
|
||||
ScheduledFuture<?> future = scheduledTasks.remove(releaseId);
|
||||
if (future != null && !future.isDone()) {
|
||||
boolean cancelled = future.cancel(false);
|
||||
log.warn("取消维护任务,Release ID: {}, 取消结果: {}", releaseId, cancelled);
|
||||
} else {
|
||||
log.debug("没有找到待取消的维护任务,Release ID: {}", releaseId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调度维护任务(延迟执行)
|
||||
*/
|
||||
private void scheduleMaintenanceTask(SystemRelease release) {
|
||||
// 计算执行时间
|
||||
Date executeTime = Date.from(
|
||||
LocalDateTime.now()
|
||||
.plusMinutes(release.getDelayMinutes())
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.toInstant()
|
||||
);
|
||||
|
||||
log.warn("已调度系统维护任务,版本: {}, 执行时间: {}, 预计耗时: {}分钟",
|
||||
release.getReleaseVersion(), executeTime, release.getEstimatedDuration());
|
||||
|
||||
// 延迟执行维护任务,并保存任务引用
|
||||
ScheduledFuture<?> future = taskScheduler.schedule(() -> {
|
||||
executeMaintenance(release);
|
||||
// 执行完成后从Map中移除
|
||||
scheduledTasks.remove(release.getId());
|
||||
}, executeTime);
|
||||
|
||||
// 保存任务引用,用于后续取消
|
||||
scheduledTasks.put(release.getId(), future);
|
||||
|
||||
log.info("维护任务已保存到调度器,Release ID: {}", release.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行维护任务
|
||||
*/
|
||||
private void executeMaintenance(SystemRelease release) {
|
||||
try {
|
||||
log.warn("========================================");
|
||||
log.warn("系统维护任务开始执行");
|
||||
log.warn("版本: {}", release.getReleaseVersion());
|
||||
log.warn("预计耗时: {} 分钟", release.getEstimatedDuration());
|
||||
log.warn("自动停止服务: {}", release.getEnableAutoShutdown());
|
||||
log.warn("========================================");
|
||||
|
||||
// 1. 发送维护通知
|
||||
sendMaintenanceNotification(release);
|
||||
|
||||
// 2. 检查是否需要自动停止服务
|
||||
if (!Boolean.TRUE.equals(release.getEnableAutoShutdown())) {
|
||||
log.warn("未启用自动停止服务,维护通知已发送,请手动停止服务进行维护");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 等待3秒让通知发出去
|
||||
log.warn("等待3秒,确保通知发送完成...");
|
||||
Thread.sleep(3000);
|
||||
|
||||
// 4. 优雅关闭应用
|
||||
log.warn("系统开始优雅关闭...");
|
||||
((ConfigurableApplicationContext) applicationContext).close();
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.error("系统维护任务被中断", e);
|
||||
} catch (Exception e) {
|
||||
log.error("系统维护任务执行失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送维护通知
|
||||
*/
|
||||
private void sendMaintenanceNotification(SystemRelease release) {
|
||||
try {
|
||||
// 查询通知渠道
|
||||
NotificationChannel channel = notificationChannelRepository.findById(notificationChannelId)
|
||||
.orElseThrow(() -> new BusinessException(ResponseCode.DATA_NOT_FOUND,
|
||||
new Object[]{"通知渠道ID=" + notificationChannelId + "不存在"}));
|
||||
|
||||
// 准备维护通知内容(简化版,只显示关键信息)
|
||||
StringBuilder messageBuilder = new StringBuilder();
|
||||
messageBuilder.append(String.format("版本号:%s\n", release.getReleaseVersion()));
|
||||
messageBuilder.append("系统即将开始维护升级\n");
|
||||
messageBuilder.append(String.format("预计维护时长:%d 分钟\n",
|
||||
release.getEstimatedDuration() != null ? release.getEstimatedDuration() : 10));
|
||||
|
||||
// 如果启用自动停止,增加提示
|
||||
if (Boolean.TRUE.equals(release.getEnableAutoShutdown())) {
|
||||
messageBuilder.append("本次升级程序将自动停止\n");
|
||||
}
|
||||
|
||||
messageBuilder.append("\n望周知。");
|
||||
String message = messageBuilder.toString();
|
||||
|
||||
log.warn("发送维护通知(v{}):\n{}", release.getReleaseVersion(), message);
|
||||
|
||||
// 创建企微通知请求
|
||||
WeworkSendNotificationRequest request = new WeworkSendNotificationRequest();
|
||||
request.setContent(message);
|
||||
request.setTitle("系统维护通知");
|
||||
request.setMessageType(WeworkMessageTypeEnum.TEXT);
|
||||
|
||||
// 发送通知
|
||||
notificationSendService.send(channel, request);
|
||||
|
||||
log.info("维护通知发送成功");
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("发送维护通知失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SystemReleaseDTO> getUnnotifiedReleases() {
|
||||
log.info("获取未通知的发布记录列表");
|
||||
List<SystemRelease> releases = systemReleaseRepository.findByNotifiedFalseAndDeletedFalseOrderByReleaseDateDesc();
|
||||
return releases.stream()
|
||||
.map(converter::toDto)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void markAsNotified(Long id) {
|
||||
log.info("标记发布记录为已通知,ID: {}", id);
|
||||
SystemRelease release = systemReleaseRepository.findById(id)
|
||||
.orElseThrow(() -> new RuntimeException("发布记录不存在"));
|
||||
release.setNotified(true);
|
||||
systemReleaseRepository.save(release);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SystemReleaseDTO getLatestReleaseByModule(String module) {
|
||||
log.info("获取模块最新发布记录,模块: {}", module);
|
||||
SystemRelease release = systemReleaseRepository.findTopByModuleAndDeletedFalseOrderByReleaseDateDesc(module);
|
||||
return release != null ? converter.toDto(release) : null;
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,7 @@ spring:
|
||||
max-request-size: 1GB # 整个请求最大大小
|
||||
file-size-threshold: 0 # 文件写入磁盘的阈值
|
||||
datasource:
|
||||
url: jdbc:mysql://172.16.0.116:3306/deploy-ease-platform?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&createDatabaseIfNotExist=true
|
||||
url: jdbc:mysql://172.16.0.116:3306/deploy-ease-platform?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&createDatabaseIfNotExist=true&allowMultiQueries=true
|
||||
username: root
|
||||
password: lianyu_123
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
@ -40,6 +40,8 @@ spring:
|
||||
pool-name: HikariCP-Pool
|
||||
# 是否允许JMX管理连接池
|
||||
register-mbeans: true
|
||||
# 连接泄漏检测阈值(毫秒),超过此时间未归还的连接将被记录
|
||||
leak-detection-threshold: 60000
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
@ -66,7 +68,7 @@ spring:
|
||||
cache-duration: 3600
|
||||
liquibase:
|
||||
enabled: true
|
||||
change-log: classpath:db/changelog/db.changelog-master.yaml
|
||||
change-log: classpath:db/changelog/db.changelog-master.xml
|
||||
drop-first: false
|
||||
default-schema: deploy-ease-platform
|
||||
contexts: default
|
||||
@ -103,6 +105,19 @@ logging:
|
||||
org.hibernate.orm.jdbc.bind: INFO
|
||||
com.qqchen.deploy.backend.framework.utils.EntityPathResolver: DEBUG
|
||||
com.qqchen.deploy.backend: DEBUG
|
||||
# 监控配置
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,metrics,info
|
||||
metrics:
|
||||
enable:
|
||||
hikari: true
|
||||
tomcat: true
|
||||
jvm: true
|
||||
system: true
|
||||
|
||||
jwt:
|
||||
secret: 'thisIsAVeryVerySecretKeyForJwtTokenGenerationAndValidation123456789'
|
||||
expiration: 86400
|
||||
@ -120,3 +135,7 @@ deploy:
|
||||
# 加密盐值(强烈建议使用环境变量 ENCRYPTION_SALT)
|
||||
# 盐值必须是16位十六进制字符串(只能包含0-9和a-f)
|
||||
salt: ${ENCRYPTION_SALT:a1b2c3d4e5f6a7b8}
|
||||
# 系统版本发布通知配置
|
||||
notification:
|
||||
release:
|
||||
channel-id: 5 # 版本通知渠道ID(生产环境)
|
||||
|
||||
@ -9,7 +9,7 @@ spring:
|
||||
max-request-size: 1GB # 整个请求最大大小
|
||||
file-size-threshold: 0 # 文件写入磁盘的阈值
|
||||
datasource:
|
||||
url: jdbc:mysql://172.22.222.111:3306/deploy-ease-platform?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&createDatabaseIfNotExist=true
|
||||
url: jdbc:mysql://172.22.222.111:3306/deploy-ease-platform?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true&createDatabaseIfNotExist=true&allowMultiQueries=true
|
||||
username: deploy-ease-platform
|
||||
password: Qichen5210523
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
@ -40,6 +40,8 @@ spring:
|
||||
pool-name: HikariCP-Pool
|
||||
# 是否允许JMX管理连接池
|
||||
register-mbeans: true
|
||||
# 连接泄漏检测阈值(毫秒),超过此时间未归还的连接将被记录
|
||||
leak-detection-threshold: 60000
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
@ -66,7 +68,7 @@ spring:
|
||||
cache-duration: 3600
|
||||
liquibase:
|
||||
enabled: true
|
||||
change-log: classpath:db/changelog/db.changelog-master.yaml
|
||||
change-log: classpath:db/changelog/db.changelog-master.xml
|
||||
drop-first: false
|
||||
default-schema: deploy-ease-platform
|
||||
contexts: default
|
||||
@ -103,6 +105,19 @@ logging:
|
||||
org.hibernate.orm.jdbc.bind: INFO
|
||||
com.qqchen.deploy.backend.framework.utils.EntityPathResolver: DEBUG
|
||||
com.qqchen.deploy.backend: DEBUG
|
||||
# 监控配置
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,metrics,info
|
||||
metrics:
|
||||
enable:
|
||||
hikari: true
|
||||
tomcat: true
|
||||
jvm: true
|
||||
system: true
|
||||
|
||||
jwt:
|
||||
secret: 'thisIsAVeryVerySecretKeyForJwtTokenGenerationAndValidation123456789'
|
||||
expiration: 86400
|
||||
@ -120,3 +135,7 @@ deploy:
|
||||
# 加密盐值(生产环境建议使用环境变量 ENCRYPTION_SALT)
|
||||
# 盐值必须是16位十六进制字符串(只能包含0-9和a-f)
|
||||
salt: ${ENCRYPTION_SALT:a1b2c3d4e5f6a7b8}
|
||||
# 系统版本发布通知配置
|
||||
notification:
|
||||
release:
|
||||
channel-id: 2 # 版本通知渠道ID
|
||||
|
||||
@ -0,0 +1,44 @@
|
||||
-- --------------------------------------------------------------------------------------
|
||||
-- 系统版本发布记录 - 初始数据
|
||||
-- 功能:插入当前版本的发布记录
|
||||
-- 作者:qqchen
|
||||
-- 日期:2025-12-09
|
||||
-- --------------------------------------------------------------------------------------
|
||||
|
||||
-- 插入 1.50 前后端统一发布记录
|
||||
INSERT INTO system_release (
|
||||
create_by, create_time, update_by, update_time, version, deleted,
|
||||
release_version, module, release_date, changes, notified, delay_minutes, estimated_duration, enable_auto_shutdown
|
||||
)
|
||||
VALUES (
|
||||
'system', NOW(), 'system', NOW(), 1, 0,
|
||||
1.0, 'ALL', NOW(),
|
||||
'【后端】
|
||||
• 新增:系统版本维护任务调度跟踪机制(ConcurrentHashMap管理)
|
||||
• 新增:版本删除时自动取消已调度的维护任务
|
||||
• 新增:版本更新时自动重新调度维护任务
|
||||
• 新增:维护通知根据自动停止标志动态提示
|
||||
• 新增:网络流量监控支持速率计算和告警
|
||||
• 新增:服务器监控优化(累计值存储+速率实时计算)
|
||||
• 新增:系统版本管理功能
|
||||
• 修复:网络流量计算逻辑错误(累计值/速率混用)
|
||||
• 修复:MySQL连接池配置不足问题(200/80)
|
||||
• 修复:版本创建调度逻辑错误(不应判断enableAutoShutdown)
|
||||
• 优化:DTO字段设计,区分存储字段和计算字段
|
||||
• 优化:告警检查器架构,避免依赖倒置
|
||||
• 优化:Git分支同步日志,减少无变化分支日志输出
|
||||
• 优化:通知渠道ID配置外部化(application.yml/application-prod.yml)
|
||||
• 优化:版本发布通知增加版本号前缀
|
||||
• 优化:维护通知内容简化(仅显示版本号、维护时长、自动停止提示)
|
||||
• 优化:通知格式统一(从"v1.50"改为"版本号:1.50")
|
||||
|
||||
【前端】
|
||||
• 新增:系统版本管理页面(支持版本记录的 CRUD 操作)
|
||||
• 新增:版本号自动获取和验证(新版本自动递增,不允许低于最大版本)
|
||||
• 新增:维护配置功能(延迟执行、预计时长、自动停止服务)
|
||||
• 新增:版本通知状态管理(标记已通知、查询未通知版本)
|
||||
• 新增:模块类型分类(后端/前端/全栈)
|
||||
• 优化:表单验证规则(所有字段改为必填,提升数据完整性)
|
||||
• 优化:版本列表展示(支持分页、筛选、搜索)',
|
||||
0, NULL, NULL, 0
|
||||
);
|
||||
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
|
||||
http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.3.xsd">
|
||||
|
||||
<!-- 清理旧数据(如果表结构已变更) -->
|
||||
<changeSet id="20251209112700-cleanup" author="qqchen">
|
||||
<preConditions onFail="CONTINUE">
|
||||
<tableExists tableName="system_release"/>
|
||||
</preConditions>
|
||||
<sql>TRUNCATE TABLE system_release;</sql>
|
||||
<sql>DELETE FROM DATABASECHANGELOG WHERE ID='20251209112700';</sql>
|
||||
</changeSet>
|
||||
|
||||
<!-- 插入新数据 -->
|
||||
<changeSet id="20251209112700-v2" author="qqchen">
|
||||
<sqlFile path="20251209112700-01.sql" relativeToChangelogFile="true"/>
|
||||
</changeSet>
|
||||
</databaseChangeLog>
|
||||
@ -27,3 +27,17 @@ databaseChangeLog:
|
||||
endDelimiter: ";"
|
||||
rollback:
|
||||
- empty
|
||||
|
||||
- changeSet:
|
||||
id: 20251209112700
|
||||
author: qqchen
|
||||
runOnChange: false
|
||||
failOnError: true
|
||||
comment: "系统版本发布记录 - v1.5.0初始数据"
|
||||
sqlFile:
|
||||
path: db/changelog/changes/20251209112700-01.sql
|
||||
stripComments: false
|
||||
splitStatements: true
|
||||
endDelimiter: ";"
|
||||
rollback:
|
||||
- empty
|
||||
@ -108,7 +108,9 @@ VALUES
|
||||
-- 权限管理(隐藏菜单)
|
||||
(6, '权限管理', '/system/permissions', 'System/Permission/List', 'SafetyOutlined', 'system:permission', 2, 1, 50, TRUE, TRUE, 'system', NOW(), 0, FALSE),
|
||||
-- 在线用户管理
|
||||
(7, '在线用户', '/system/online', 'System/Online/List', 'UserSwitchOutlined', 'system:online:view', 2, 1, 60, FALSE, TRUE, 'system', NOW(), 0, FALSE);
|
||||
(7, '在线用户', '/system/online', 'System/Online/List', 'UserSwitchOutlined', 'system:online:view', 2, 1, 60, FALSE, TRUE, 'system', NOW(), 0, FALSE),
|
||||
-- 系统版本管理
|
||||
(8, '系统版本', '/system/releases', 'System/Release/List', 'RocketOutlined', 'system:release', 2, 1, 70, FALSE, TRUE, 'system', NOW(), 0, FALSE);
|
||||
|
||||
-- ==================== 初始化角色数据 ====================
|
||||
DELETE FROM sys_role WHERE id < 100;
|
||||
@ -154,7 +156,7 @@ VALUES
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
VALUES
|
||||
-- 管理员角色(拥有所有菜单)
|
||||
(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 99), (1, 100), (1, 101), (1, 102), (1, 104), (1, 200), (1, 201), (1, 202), (1, 203), (1, 204), (1, 205), (1, 206), (1, 300), (1, 301), (1, 302), (1, 303), (1, 304), (1, 1011), (1, 1041), (1, 1042),
|
||||
(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 99), (1, 100), (1, 101), (1, 102), (1, 104), (1, 200), (1, 201), (1, 202), (1, 203), (1, 204), (1, 205), (1, 206), (1, 300), (1, 301), (1, 302), (1, 303), (1, 304), (1, 1011), (1, 1041), (1, 1042),
|
||||
-- 运维角色
|
||||
(2, 99), (2, 200), (2, 201), (2, 202), (2, 203), (2, 204), (2, 205), (2, 300), (2, 301), (2, 302), (2, 303), (2, 304),
|
||||
-- 开发角色(只有工作台)
|
||||
@ -221,6 +223,16 @@ INSERT INTO sys_permission (id, create_time, menu_id, code, name, type, sort) VA
|
||||
(51, NOW(), 7, 'system:online:view', '查看在线用户', 'FUNCTION', 1),
|
||||
(52, NOW(), 7, 'system:online:kick', '强制下线', 'FUNCTION', 2),
|
||||
|
||||
-- 系统版本管理 (menu_id=8)
|
||||
(61, NOW(), 8, 'system:release:list', '版本查询', 'FUNCTION', 1),
|
||||
(62, NOW(), 8, 'system:release:view', '版本详情', 'FUNCTION', 2),
|
||||
(63, NOW(), 8, 'system:release:create', '版本创建', 'FUNCTION', 3),
|
||||
(64, NOW(), 8, 'system:release:update', '版本修改', 'FUNCTION', 4),
|
||||
(65, NOW(), 8, 'system:release:delete', '版本删除', 'FUNCTION', 5),
|
||||
(66, NOW(), 8, 'system:release:notify', '标记为已通知', 'FUNCTION', 6),
|
||||
(67, NOW(), 8, 'system:release:latest', '获取最新版本', 'FUNCTION', 7),
|
||||
(68, NOW(), 8, 'system:release:unnotified', '获取未通知版本', 'FUNCTION', 8),
|
||||
|
||||
-- 运维管理权限
|
||||
-- 团队管理 (menu_id=201)
|
||||
(101, NOW(), 201, 'deploy:team:list', '团队查询', 'FUNCTION', 1),
|
||||
@ -1355,3 +1355,29 @@ CREATE TABLE deploy_ssh_audit_log
|
||||
-- 2. 删除用户/服务器时,审计日志不应被物理删除
|
||||
-- 3. user_id/server_id 仅作为历史记录字段,通过冗余字段可查询
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='SSH终端审计日志表';
|
||||
|
||||
-- 系统版本发布记录表
|
||||
CREATE TABLE system_release
|
||||
(
|
||||
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 '是否删除',
|
||||
|
||||
release_version DECIMAL(10,2) NOT NULL COMMENT '发布版本号(如 1.50)',
|
||||
module VARCHAR(20) NOT NULL COMMENT '模块类型:BACKEND/FRONTEND/ALL',
|
||||
release_date DATETIME(6) NOT NULL COMMENT '发布时间',
|
||||
changes TEXT NULL COMMENT '变更内容(换行分隔)',
|
||||
notified BIT NOT NULL DEFAULT 0 COMMENT '是否已发送版本发布通知',
|
||||
delay_minutes INT NULL COMMENT '延迟执行分钟数(创建后多久开始维护,为空则不触发维护)',
|
||||
estimated_duration INT NULL COMMENT '预计维护时长(分钟)',
|
||||
enable_auto_shutdown BIT NOT NULL DEFAULT 0 COMMENT '是否自动停止服务',
|
||||
|
||||
UNIQUE KEY uk_version_module (release_version, module),
|
||||
KEY idx_release_date (release_date),
|
||||
KEY idx_notified (notified),
|
||||
KEY idx_deleted (deleted)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='系统版本发布记录表';
|
||||
Loading…
Reference in New Issue
Block a user