From 1e93fffecc4cda088845b1ce699ec59b57b483f2 Mon Sep 17 00:00:00 2001 From: dengqichen Date: Wed, 10 Dec 2025 14:42:37 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=90=8E=E7=AB=AF=E3=80=91=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E6=9C=8D=E5=8A=A1=E5=99=A8=E7=A6=BB?= =?UTF-8?q?=E7=BA=BF=E5=91=8A=E8=AD=A6=E8=BF=9E=E7=BB=AD=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=E6=9C=BA=E5=88=B6=EF=BC=88=E9=81=BF=E5=85=8D?= =?UTF-8?q?=E4=B8=B4=E6=97=B6=E7=BD=91=E7=BB=9C=E6=B3=A2=E5=8A=A8=E8=AF=AF?= =?UTF-8?q?=E6=8A=A5=EF=BC=89=20=20=20=20=20-=20=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=EF=BC=9Adeploy=5Fserver=5Fmonitor=20=E8=A1=A8?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20status=20=E5=AD=97=E6=AE=B5=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E9=87=87=E9=9B=86=E7=8A=B6=E6=80=81=EF=BC=88SUCCESS/F?= =?UTF-8?q?AILURE=EF=BC=89=20=20=20=20=20-=20=E6=A1=86=E6=9E=B6=E5=B1=82?= =?UTF-8?q?=EF=BC=9A=E6=96=B0=E5=A2=9E=20StatusEnum=20=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9E=9A=E4=B8=BE=E7=B1=BB=EF=BC=8CMonitorMe?= =?UTF-8?q?tricEnum=20=E5=A2=9E=E5=8A=A0=20SERVER=5FSTATUS=20=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E7=B1=BB=E5=9E=8B=20=20=20=20=20-=20=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=B1=82=EF=BC=9AServerMonitor=20=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20status=20=E5=AD=97=E6=AE=B5=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E6=A0=87=E8=AF=86=E9=87=87=E9=9B=86=E7=8A=B6=E6=80=81?= =?UTF-8?q?=20=20=20=20=20-=20Repository=EF=BC=9AIServerMonitorRepository?= =?UTF-8?q?=20=E5=A2=9E=E5=8A=A0=20findRecentMonitorRecords=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E6=9F=A5=E8=AF=A2=E6=9C=80=E8=BF=91N=E6=9D=A1?= =?UTF-8?q?=E7=9B=91=E6=8E=A7=E8=AE=B0=E5=BD=95=20=20=20=20=20-=20Service?= =?UTF-8?q?=EF=BC=9AIServerMonitorService=20=E5=A2=9E=E5=8A=A0=20saveMonit?= =?UTF-8?q?orRecord=EF=BC=88=E4=BF=9D=E5=AD=98=E5=8D=95=E6=9D=A1=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=EF=BC=89=E5=92=8C=20countConsecutiveFailures=EF=BC=88?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E8=BF=9E=E7=BB=AD=E5=A4=B1=E8=B4=A5=E6=AC=A1?= =?UTF-8?q?=E6=95=B0=EF=BC=89=E6=96=B9=E6=B3=95=20=20=20=20=20-=20?= =?UTF-8?q?=E5=91=8A=E8=AD=A6=E6=9C=8D=E5=8A=A1=EF=BC=9AIServerAlertServic?= =?UTF-8?q?e=20=E5=A2=9E=E5=8A=A0=20checkServerStatusAlert=EF=BC=88?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E7=8A=B6=E6=80=81=E5=91=8A=E8=AD=A6=EF=BC=89?= =?UTF-8?q?=E5=92=8C=20resolveServerStatusAlert=EF=BC=88=E8=A7=A3=E9=99=A4?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=91=8A=E8=AD=A6=EF=BC=89=E6=96=B9=E6=B3=95?= =?UTF-8?q?=20=20=20=20=20-=20=E5=91=8A=E8=AD=A6=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=EF=BC=9AServerAlertServiceImpl=20=E5=AE=9E=E7=8E=B0=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=E7=8A=B6=E6=80=81=E5=91=8A=E8=AD=A6=E7=9A=84?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E3=80=81=E7=BA=A7=E5=88=AB=E5=8D=87=E7=BA=A7?= =?UTF-8?q?=EF=BC=88WARNING=E2=86=92CRITICAL=EF=BC=89=E3=80=81=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E8=A7=A3=E9=99=A4=E9=80=BB=E8=BE=91=20=20=20=20=20-?= =?UTF-8?q?=20=E8=B0=83=E5=BA=A6=E5=99=A8=EF=BC=9AServerMonitorScheduler?= =?UTF-8?q?=20=E9=9B=86=E6=88=90=E8=BF=9E=E7=BB=AD=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=E6=A3=80=E6=B5=8B=EF=BC=8C=E8=BF=9E=E6=8E=A5=E6=88=90=E5=8A=9F?= =?UTF-8?q?=E6=97=B6=E6=8F=92=E5=85=A5SUCCESS=E8=AE=B0=E5=BD=95=E5=B9=B6?= =?UTF-8?q?=E8=A7=A3=E9=99=A4=E5=91=8A=E8=AD=A6=EF=BC=8C=E8=BF=9E=E6=8E=A5?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E6=97=B6=E6=8F=92=E5=85=A5FAILURE=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=B9=B6=E8=A7=A6=E5=8F=91=E5=91=8A=E8=AD=A6=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=20=20=20=20=20-=20=E6=95=B0=E6=8D=AE=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=EF=BC=9A=E5=A2=9E=E5=8A=A0=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E7=8A=B6=E6=80=81=E5=91=8A=E8=AD=A6?= =?UTF-8?q?=E8=A7=84=E5=88=99=EF=BC=88=E8=BF=9E=E7=BB=AD3=E6=AC=A1?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E8=A7=A6=E5=8F=91=E8=AD=A6=E5=91=8A=EF=BC=8C?= =?UTF-8?q?5=E6=AC=A1=E8=A7=A6=E5=8F=91=E4=B8=A5=E9=87=8D=E5=B9=B6?= =?UTF-8?q?=E6=A0=87=E8=AE=B0=E7=A6=BB=E7=BA=BF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 优化:统一监控告警通知模板,简化配置参数 - ServerMonitorNotificationConfig 删除 serverOfflineTemplateId 字段,所有监控告警(CPU/内存/磁盘/网络/服务器状态)统一使用 resourceAlertTemplateId - ServerMonitorScheduler.collectServerMetrics 方法删除 serverOfflineTemplateId 参数 - ServerAlertServiceImpl.sendServerStatusNotification 改用统一的资源告警模板,模板参数与其他监控告警保持一致 修复:删除冗余代码和未使用的类 - 删除 CollectionStatusEnum.java(已被 StatusEnum 取代) - 删除 ServerMonitorScheduler.sendServerOfflineNotification 方法(改由 ServerAlertService 统一处理) 优化:告警通知模板支持百分比和次数两种单位 - 通知模板使用 FreeMarker 条件判断,根据 alertType 自动显示"连续失败X次"或"使用率X%" - 严重级别告警显示红色并提示"请立即处理",警告级别提示"请注意观察" 【前端】 修复:告警规则表单规则范围下拉框无法滚动选择问题(移除嵌套滚动容器干扰) 优化:规则范围选择器升级为带搜索的Popover组件(支持按服务器名称/IP搜索,固定高度可滚动) 优化:规则范围数据加载从分页接口改为列表接口 --- .../dto/ServerMonitorNotificationConfig.java | 8 +- .../backend/deploy/entity/ServerMonitor.java | 8 + .../repository/IServerAlertLogRepository.java | 8 + .../IServerAlertRuleRepository.java | 10 + .../repository/IServerMonitorRepository.java | 14 ++ .../scheduler/ServerMonitorScheduler.java | 128 ++++++----- .../deploy/service/IServerAlertService.java | 19 ++ .../deploy/service/IServerMonitorService.java | 17 ++ .../service/impl/ServerAlertServiceImpl.java | 214 ++++++++++++++++++ .../impl/ServerMonitorServiceImpl.java | 37 +++ .../service/impl/ServerServiceImpl.java | 43 +++- .../framework/enums/MonitorMetricEnum.java | 9 +- .../backend/framework/enums/StatusEnum.java | 28 +++ .../db/changelog/init/v1.0.0-data.sql | 52 +++-- .../db/changelog/init/v1.0.0-schema.sql | 3 + .../db/changelog/sql/20251209141300-01.sql | 44 ++-- 16 files changed, 546 insertions(+), 96 deletions(-) create mode 100644 backend/src/main/java/com/qqchen/deploy/backend/framework/enums/StatusEnum.java diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/ServerMonitorNotificationConfig.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/ServerMonitorNotificationConfig.java index 21ad8d0d..7356561c 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/ServerMonitorNotificationConfig.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/dto/ServerMonitorNotificationConfig.java @@ -20,12 +20,8 @@ public class ServerMonitorNotificationConfig { private Long notificationChannelId; /** - * 服务器离线通知模板ID - */ - private Long serverOfflineTemplateId; - - /** - * 资源预警通知模板ID + * 资源告警通知模板ID + * 用于所有监控告警(CPU、内存、磁盘、网络、服务器状态) */ private Long resourceAlertTemplateId; } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/ServerMonitor.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/ServerMonitor.java index f95b10f5..27d41528 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/ServerMonitor.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/entity/ServerMonitor.java @@ -1,5 +1,6 @@ package com.qqchen.deploy.backend.deploy.entity; +import com.qqchen.deploy.backend.framework.enums.StatusEnum; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Data; @@ -73,4 +74,11 @@ public class ServerMonitor { */ @Column(name = "collect_time", nullable = false) private LocalDateTime collectTime; + + /** + * 采集状态 + */ + @Enumerated(EnumType.STRING) + @Column(name = "status", nullable = false, length = 20) + private StatusEnum status = StatusEnum.SUCCESS; } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerAlertLogRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerAlertLogRepository.java index 04eaa9e6..08e21bb9 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerAlertLogRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerAlertLogRepository.java @@ -4,6 +4,7 @@ import com.qqchen.deploy.backend.deploy.entity.ServerAlertLog; import com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum; import com.qqchen.deploy.backend.framework.enums.ServerAlertStatusEnum; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -44,4 +45,11 @@ public interface IServerAlertLogRepository extends JpaRepository { + + /** + * 删除指定服务器的所有告警规则 + */ + @Modifying + @Query("DELETE FROM ServerAlertRule r WHERE r.serverId = :serverId") + int deleteByServerId(@Param("serverId") Long serverId); } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerMonitorRepository.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerMonitorRepository.java index 374c3921..65cc9e98 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerMonitorRepository.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/repository/IServerMonitorRepository.java @@ -33,4 +33,18 @@ public interface IServerMonitorRepository extends JpaRepository findRecentMonitorRecords(@Param("serverId") Long serverId, org.springframework.data.domain.Pageable pageable); } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/scheduler/ServerMonitorScheduler.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/scheduler/ServerMonitorScheduler.java index a9138552..28ec7cec 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/scheduler/ServerMonitorScheduler.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/scheduler/ServerMonitorScheduler.java @@ -69,22 +69,19 @@ public class ServerMonitorScheduler { * 此方法由定时任务管理系统调用 * * @param notificationChannelId 通知渠道ID(可选,为null则不发送通知) - * @param serverOfflineTemplateId 服务器离线通知模板ID(可选) - * @param resourceAlertTemplateId 资源告警通知模板ID(可选) + * @param resourceAlertTemplateId 资源告警通知模板ID(可选,用于所有监控告警) */ public void collectServerMetrics(Long notificationChannelId, - Long serverOfflineTemplateId, Long resourceAlertTemplateId) { // 构建通知配置对象 ServerMonitorNotificationConfig config = null; if (notificationChannelId != null) { config = new ServerMonitorNotificationConfig(); config.setNotificationChannelId(notificationChannelId); - config.setServerOfflineTemplateId(serverOfflineTemplateId); config.setResourceAlertTemplateId(resourceAlertTemplateId); - log.debug("开始采集服务器监控数据: channelId={}, offlineTemplateId={}, alertTemplateId={}", - notificationChannelId, serverOfflineTemplateId, resourceAlertTemplateId); + log.debug("开始采集服务器监控数据: channelId={}, alertTemplateId={}", + notificationChannelId, resourceAlertTemplateId); } else { log.debug("开始采集服务器监控数据(不发送通知)"); } @@ -201,30 +198,88 @@ public class ServerMonitorScheduler { passphrase ); - // 3. 连接成功,更新服务器状态 - server.setStatus(ServerStatusEnum.ONLINE); - server.setLastConnectTime(LocalDateTime.now()); - serverRepository.save(server); + // 3. 连接成功,插入成功记录 + ServerMonitor successRecord = ServerMonitor.builder() + .serverId(server.getId()) + .status(com.qqchen.deploy.backend.framework.enums.StatusEnum.SUCCESS) + .collectTime(LocalDateTime.now()) + .build(); + monitorService.saveMonitorRecord(successRecord); - log.info("✓ 服务器连接成功: {} ({})", server.getServerName(), server.getHostIp()); + // 4. 解除服务器状态告警(如果存在) + try { + alertService.resolveServerStatusAlert(server.getId()); + } catch (Exception e) { + log.warn("解除服务器状态告警失败: serverId={}", server.getId(), e); + } - // 4. 采集监控数据(复用同一个SSH连接) + // 5. 更新服务器状态为ONLINE + if (server.getStatus() == ServerStatusEnum.OFFLINE) { + server.setStatus(ServerStatusEnum.ONLINE); + server.setLastConnectTime(LocalDateTime.now()); + serverRepository.save(server); + log.info("✓ 服务器已恢复在线: {} ({})", server.getServerName(), server.getHostIp()); + } else { + server.setStatus(ServerStatusEnum.ONLINE); + server.setLastConnectTime(LocalDateTime.now()); + serverRepository.save(server); + log.info("✓ 服务器连接成功: {} ({})", server.getServerName(), server.getHostIp()); + } + + // 6. 采集监控数据(复用同一个SSH连接) return collectServerMonitorData(server, sshClient, sshService); } catch (Exception e) { - // 连接失败,更新服务器状态为离线 - log.error("✗ 服务器连接失败: {} ({}) - {}", - server.getServerName(), server.getHostIp(), e.getMessage()); + // 连接失败,插入失败记录 + ServerMonitor failureRecord = ServerMonitor.builder() + .serverId(server.getId()) + .status(com.qqchen.deploy.backend.framework.enums.StatusEnum.FAILURE) + .collectTime(LocalDateTime.now()) + .build(); - server.setStatus(ServerStatusEnum.OFFLINE); - serverRepository.save(server); + try { + monitorService.saveMonitorRecord(failureRecord); + } catch (Exception saveError) { + log.error("保存失败记录异常: serverId={}", server.getId(), saveError); + } - // 发送离线通知 - if (config != null && config.getNotificationChannelId() != null && config.getServerOfflineTemplateId() != null) { + // 统计连续失败次数 + int failureCount = 0; + try { + failureCount = monitorService.countConsecutiveFailures(server.getId(), 10); + log.error("✗ 服务器连接失败 [连续{}次]: {} ({}) - {}", + failureCount, server.getServerName(), server.getHostIp(), e.getMessage()); + } catch (Exception countError) { + log.error("统计连续失败次数异常: serverId={}", server.getId(), countError); + log.error("✗ 服务器连接失败: {} ({}) - {}", + server.getServerName(), server.getHostIp(), e.getMessage()); + } + + // 检查服务器状态告警(传入所有规则,避免重复查询) + if (failureCount > 0 && config != null) { try { - sendServerOfflineNotification(server, config); - } catch (Exception notifyError) { - log.error("发送服务器离线通知失败: serverId={}", server.getId(), notifyError); + // 查询所有规则(在外层已查询,这里重新查询以确保最新) + List allRules = alertRuleRepository.findAll(); + alertService.checkServerStatusAlert(server.getId(), failureCount, allRules, config); + + // 如果达到严重阈值,标记服务器为OFFLINE + ServerAlertRule statusRule = allRules.stream() + .filter(rule -> rule.getAlertType() == com.qqchen.deploy.backend.framework.enums.MonitorMetricEnum.SERVER_STATUS) + .filter(rule -> Boolean.TRUE.equals(rule.getEnabled())) + .filter(rule -> rule.getServerId() == null || server.getId().equals(rule.getServerId())) + .findFirst() + .orElse(null); + + if (statusRule != null && failureCount >= statusRule.getCriticalThreshold().intValue()) { + if (server.getStatus() != ServerStatusEnum.OFFLINE) { + server.setStatus(ServerStatusEnum.OFFLINE); + serverRepository.save(server); + log.warn("🔴 服务器已标记为离线: {} (连续失败{}次)", + server.getServerName(), failureCount); + } + } + } catch (Exception alertError) { + log.error("检查服务器状态告警失败: serverId={}", server.getId(), alertError); } } @@ -238,35 +293,6 @@ public class ServerMonitorScheduler { } } - /** - * 发送服务器离线通知 - */ - private void sendServerOfflineNotification(Server server, ServerMonitorNotificationConfig config) { - try { - // 1. 构建模板参数 - Map templateParams = new HashMap<>(); - templateParams.put("serverName", server.getServerName()); - templateParams.put("serverIp", server.getHostIp()); - templateParams.put("offlineTime", LocalDateTime.now().format( - java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); - - // 2. 构建SendNotificationRequest - SendNotificationRequest request = new SendNotificationRequest(); - request.setChannelId(config.getNotificationChannelId()); - request.setNotificationTemplateId(config.getServerOfflineTemplateId()); - request.setTemplateParams(templateParams); - - // 3. 发送通知(NotificationService会自动根据渠道类型创建请求对象) - notificationService.send(request); - - log.info("服务器离线通知已发送: serverId={}, serverName={}, ip={}", - server.getId(), server.getServerName(), server.getHostIp()); - } catch (Exception e) { - log.error("发送服务器离线通知异常: serverId={}", server.getId(), e); - throw e; - } - } - /** * 采集服务器监控数据(CPU、内存、磁盘、网络使用率) * diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerAlertService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerAlertService.java index 1cf5fad4..cc424a8c 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerAlertService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerAlertService.java @@ -32,4 +32,23 @@ public interface IServerAlertService { void checkAlertRules(Long serverId, ServerMonitorDataDTO monitorData, List allRules, ServerMonitorNotificationConfig config); + + /** + * 检查服务器状态告警(连接失败场景) + * + * @param serverId 服务器ID + * @param failureCount 连续失败次数 + * @param allRules 所有告警规则 + * @param config 通知配置 + */ + void checkServerStatusAlert(Long serverId, int failureCount, + List allRules, + ServerMonitorNotificationConfig config); + + /** + * 解除服务器状态告警(连接恢复场景) + * + * @param serverId 服务器ID + */ + void resolveServerStatusAlert(Long serverId); } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerMonitorService.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerMonitorService.java index bf521046..d722071f 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerMonitorService.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/IServerMonitorService.java @@ -29,4 +29,21 @@ public interface IServerMonitorService { * @return 最新的监控记录,如果没有则返回null */ ServerMonitor getLastMonitorData(Long serverId); + + /** + * 保存单条监控记录(包括失败记录) + * + * @param monitor 监控记录 + */ + void saveMonitorRecord(ServerMonitor monitor); + + /** + * 统计指定服务器的连续失败次数 + * 查询最近的监控记录,从最新开始统计连续FAILURE状态的数量 + * + * @param serverId 服务器ID + * @param checkLimit 检查最近多少条记录(默认10条) + * @return 连续失败次数 + */ + int countConsecutiveFailures(Long serverId, int checkLimit); } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerAlertServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerAlertServiceImpl.java index 0995710c..f2f1c4b5 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerAlertServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerAlertServiceImpl.java @@ -491,4 +491,218 @@ public class ServerAlertServiceImpl implements IServerAlertService { throw e; } } + + @Override + public void checkServerStatusAlert(Long serverId, int failureCount, + List allRules, + ServerMonitorNotificationConfig config) { + // 获取SERVER_STATUS类型的有效规则(优先专属规则) + ServerAlertRule statusRule = getEffectiveRule(serverId, MonitorMetricEnum.SERVER_STATUS, allRules); + + if (statusRule == null) { + log.debug("未找到启用的服务器状态告警规则: serverId={}", serverId); + return; + } + + int warningCount = statusRule.getWarningThreshold().intValue(); + int criticalCount = statusRule.getCriticalThreshold().intValue(); + + log.debug("检查服务器状态告警: serverId={}, failureCount={}, warningCount={}, criticalCount={}", + serverId, failureCount, warningCount, criticalCount); + + // 判断当前应该触发的告警级别 + MonitorAlertLevelEnum currentLevel = null; + int threshold = 0; + + if (failureCount >= criticalCount) { + currentLevel = MonitorAlertLevelEnum.CRITICAL; + threshold = criticalCount; + } else if (failureCount >= warningCount) { + currentLevel = MonitorAlertLevelEnum.WARNING; + threshold = warningCount; + } + + // 查询是否已有活跃告警 + Optional existingAlertOpt = alertLogRepository.findActiveOrPendingAlert( + serverId, statusRule.getId(), MonitorMetricEnum.SERVER_STATUS); + + if (currentLevel != null) { + // 需要触发告警 + if (existingAlertOpt.isPresent()) { + // 已有告警,检查是否需要升级 + ServerAlertLog existingAlert = existingAlertOpt.get(); + if (currentLevel.ordinal() > existingAlert.getAlertLevel().ordinal()) { + // 级别升级:WARNING → CRITICAL + updateServerStatusAlertLevel(existingAlert, statusRule, currentLevel, + failureCount, threshold, config); + } else { + log.debug("服务器状态告警已存在且级别未变化: serverId={}, level={}", + serverId, currentLevel); + } + } else { + // 创建新告警 + createServerStatusAlert(serverId, statusRule, currentLevel, failureCount, threshold, config); + } + } + } + + @Override + public void resolveServerStatusAlert(Long serverId) { + // 查询所有SERVER_STATUS类型的规则 + List statusRules = alertRuleRepository.findAll().stream() + .filter(rule -> rule.getAlertType() == MonitorMetricEnum.SERVER_STATUS) + .collect(java.util.stream.Collectors.toList()); + + for (ServerAlertRule rule : statusRules) { + Optional activeAlertOpt = alertLogRepository.findActiveOrPendingAlert( + serverId, rule.getId(), MonitorMetricEnum.SERVER_STATUS); + + if (activeAlertOpt.isPresent()) { + resolveAlert(activeAlertOpt.get()); + log.info("✅ 服务器状态告警已解除: serverId={}, ruleId={}", serverId, rule.getId()); + } + } + } + + /** + * 获取有效规则(优先专属规则,其次全局规则) + */ + private ServerAlertRule getEffectiveRule(Long serverId, MonitorMetricEnum alertType, + List allRules) { + ServerAlertRule specificRule = null; + ServerAlertRule globalRule = null; + + for (ServerAlertRule rule : allRules) { + if (rule.getAlertType() != alertType || !Boolean.TRUE.equals(rule.getEnabled())) { + continue; + } + + if (serverId.equals(rule.getServerId())) { + specificRule = rule; + break; // 找到专属规则,直接返回 + } else if (rule.getServerId() == null) { + globalRule = rule; + } + } + + return specificRule != null ? specificRule : globalRule; + } + + /** + * 创建服务器状态告警 + */ + private void createServerStatusAlert(Long serverId, ServerAlertRule rule, + MonitorAlertLevelEnum level, int failureCount, + int threshold, ServerMonitorNotificationConfig config) { + Server server = serverRepository.findById(serverId).orElse(null); + if (server == null) { + log.warn("服务器不存在: serverId={}", serverId); + return; + } + + ServerAlertLog alertLog = new ServerAlertLog(); + alertLog.setServerId(serverId); + alertLog.setRuleId(rule.getId()); + alertLog.setAlertType(MonitorMetricEnum.SERVER_STATUS); + alertLog.setAlertLevel(level); + alertLog.setAlertValue(new BigDecimal(failureCount)); + alertLog.setThresholdValue(new BigDecimal(threshold)); + alertLog.setAlertTime(LocalDateTime.now()); + alertLog.setStatus(ServerAlertStatusEnum.PENDING); + alertLog.setAlertMessage(String.format("服务器连续%d次连接失败,达到%s级别(阈值:%d次)", + failureCount, level.getDescription(), threshold)); + + try { + alertLogRepository.save(alertLog); + log.warn("🔔 服务器状态告警已创建: serverId={}, serverName={}, level={}, failureCount={}", + serverId, server.getServerName(), level, failureCount); + + // 发送通知 + sendServerStatusNotification(alertLog, server, config); + } catch (Exception e) { + log.error("创建服务器状态告警失败: serverId={}", serverId, e); + } + } + + /** + * 更新服务器状态告警级别 + */ + private void updateServerStatusAlertLevel(ServerAlertLog alertLog, ServerAlertRule rule, + MonitorAlertLevelEnum newLevel, int failureCount, + int threshold, ServerMonitorNotificationConfig config) { + Server server = serverRepository.findById(alertLog.getServerId()).orElse(null); + if (server == null) { + return; + } + + MonitorAlertLevelEnum oldLevel = alertLog.getAlertLevel(); + alertLog.setAlertLevel(newLevel); + alertLog.setAlertValue(new BigDecimal(failureCount)); + alertLog.setThresholdValue(new BigDecimal(threshold)); + alertLog.setAlertMessage(String.format("服务器连续%d次连接失败,达到%s级别(阈值:%d次)", + failureCount, newLevel.getDescription(), threshold)); + + try { + alertLogRepository.save(alertLog); + log.warn("⬆️ 服务器状态告警级别升级: id={}, serverId={}, {} → {}, failureCount={}", + alertLog.getId(), alertLog.getServerId(), oldLevel, newLevel, failureCount); + + // 重新发送通知 + sendServerStatusNotification(alertLog, server, config); + } catch (Exception e) { + log.error("更新服务器状态告警级别失败", e); + } + } + + /** + * 发送服务器状态通知 + * 使用统一的资源告警模板(与CPU/内存/磁盘告警相同) + */ + private void sendServerStatusNotification(ServerAlertLog alertLog, Server server, + ServerMonitorNotificationConfig config) { + if (config == null || config.getNotificationChannelId() == null || + config.getResourceAlertTemplateId() == null) { + log.debug("通知配置不完整,跳过发送服务器状态通知"); + return; + } + + try { + // 查询规则信息 + ServerAlertRule rule = alertRuleRepository.findById(alertLog.getRuleId()).orElse(null); + if (rule == null) { + log.warn("告警规则不存在: ruleId={}", alertLog.getRuleId()); + return; + } + + // 构建模板参数(与其他监控告警保持一致) + Map templateParams = new HashMap<>(); + templateParams.put("serverName", server.getServerName()); + templateParams.put("ruleName", rule.getRuleName()); + templateParams.put("alertType", rule.getAlertType().getDescription()); + templateParams.put("resourceInfo", "服务器状态"); + templateParams.put("alertLevel", alertLog.getAlertLevel().getDescription()); + templateParams.put("currentValue", alertLog.getAlertValue().intValue()); + templateParams.put("threshold", alertLog.getThresholdValue().intValue()); + templateParams.put("alertTime", alertLog.getAlertTime().format( + java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); + + SendNotificationRequest request = new SendNotificationRequest(); + request.setChannelId(config.getNotificationChannelId()); + request.setNotificationTemplateId(config.getResourceAlertTemplateId()); + request.setTemplateParams(templateParams); + + notificationService.send(request); + + // 更新通知状态 + alertLog.setNotified(true); + alertLog.setNotifyTime(LocalDateTime.now()); + alertLog.setStatus(ServerAlertStatusEnum.ACTIVE); + alertLogRepository.save(alertLog); + + log.info("✅ 服务器状态告警通知已发送: serverId={}, level={}", + alertLog.getServerId(), alertLog.getAlertLevel()); + } catch (Exception e) { + log.error("发送服务器状态通知异常: serverId={}", alertLog.getServerId(), e); + } + } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerMonitorServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerMonitorServiceImpl.java index 2cb58202..92c0707b 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerMonitorServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerMonitorServiceImpl.java @@ -6,8 +6,11 @@ import com.qqchen.deploy.backend.deploy.dto.ServerMonitorDataDTO; import com.qqchen.deploy.backend.deploy.entity.ServerMonitor; import com.qqchen.deploy.backend.deploy.repository.IServerMonitorRepository; import com.qqchen.deploy.backend.deploy.service.IServerMonitorService; +import com.qqchen.deploy.backend.framework.enums.StatusEnum; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -80,6 +83,40 @@ public class ServerMonitorServiceImpl implements IServerMonitorService { .networkRx(dto.getNetworkRx()) .networkTx(dto.getNetworkTx()) .collectTime(dto.getCollectTime()) + .status(StatusEnum.SUCCESS) // 成功采集的记录 .build(); } + + @Override + @Transactional + public void saveMonitorRecord(ServerMonitor monitor) { + monitorRepository.save(monitor); + log.debug("保存监控记录: serverId={}, status={}", monitor.getServerId(), monitor.getStatus()); + } + + @Override + public int countConsecutiveFailures(Long serverId, int checkLimit) { + // 查询最近N条记录 + Pageable pageable = PageRequest.of(0, checkLimit); + List recentRecords = monitorRepository.findRecentMonitorRecords(serverId, pageable); + + if (recentRecords == null || recentRecords.isEmpty()) { + log.debug("没有找到监控记录: serverId={}", serverId); + return 0; + } + + // 从最新记录开始统计连续失败次数 + int failureCount = 0; + for (ServerMonitor record : recentRecords) { + if (StatusEnum.FAILURE.equals(record.getStatus())) { + failureCount++; + } else { + // 遇到成功记录,停止统计 + break; + } + } + + log.debug("统计连续失败次数: serverId={}, count={}", serverId, failureCount); + return failureCount; + } } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerServiceImpl.java b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerServiceImpl.java index 3e4393bc..cb758c65 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerServiceImpl.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/deploy/service/impl/ServerServiceImpl.java @@ -8,6 +8,9 @@ import com.qqchen.deploy.backend.deploy.enums.ServerStatusEnum; import com.qqchen.deploy.backend.framework.enums.AuthTypeEnum; import com.qqchen.deploy.backend.deploy.query.ServerQuery; import com.qqchen.deploy.backend.deploy.repository.IServerRepository; +import com.qqchen.deploy.backend.deploy.repository.IServerMonitorRepository; +import com.qqchen.deploy.backend.deploy.repository.IServerAlertRuleRepository; +import com.qqchen.deploy.backend.deploy.repository.IServerAlertLogRepository; import com.qqchen.deploy.backend.deploy.repository.ISSHAuditLogRepository; import com.qqchen.deploy.backend.deploy.service.IServerService; import com.qqchen.deploy.backend.framework.annotation.ServiceType; @@ -42,6 +45,15 @@ public class ServerServiceImpl @Resource private ISSHAuditLogRepository sshAuditLogRepository; + + @Resource + private IServerMonitorRepository serverMonitorRepository; + + @Resource + private IServerAlertRuleRepository serverAlertRuleRepository; + + @Resource + private IServerAlertLogRepository serverAlertLogRepository; public ServerServiceImpl(IServerRepository serverRepository) { this.serverRepository = serverRepository; @@ -247,6 +259,7 @@ public class ServerServiceImpl * @return 完整的硬件信息 */ @Override + @Transactional public ServerInfoDTO collectHardwareInfo(Long serverId) { long startTime = System.currentTimeMillis(); ServerInfoDTO info = new ServerInfoDTO(); @@ -320,22 +333,46 @@ public class ServerServiceImpl * 1. 服务器:物理删除(没有@LogicDelete注解) * 2. 审计日志:逻辑删除(有@LogicDelete注解) * 3. 审计日志永久保留,仅标记deleted=true,确保审计可追溯 + * 4. 监控记录、告警规则、告警记录:物理删除(无需保留历史) */ @Override @Transactional public void delete(Long id) { log.info("删除服务器: serverId={}", id); - // 1. 逻辑删除关联的SSH审计日志(保留历史记录) + // 1. 物理删除关联的告警记录(需要先删除,因为它依赖告警规则) + try { + int alertLogCount = serverAlertLogRepository.deleteByServerId(id); + log.info("已删除服务器关联的告警记录: serverId={}, count={}", id, alertLogCount); + } catch (Exception e) { + log.warn("删除服务器关联的告警记录失败: serverId={}, error={}", id, e.getMessage()); + } + + // 2. 物理删除关联的告警规则 + try { + int alertRuleCount = serverAlertRuleRepository.deleteByServerId(id); + log.info("已删除服务器关联的告警规则: serverId={}, count={}", id, alertRuleCount); + } catch (Exception e) { + log.warn("删除服务器关联的告警规则失败: serverId={}, error={}", id, e.getMessage()); + } + + // 3. 物理删除关联的监控记录 + try { + int monitorCount = serverMonitorRepository.deleteByServerId(id); + log.info("已删除服务器关联的监控记录: serverId={}, count={}", id, monitorCount); + } catch (Exception e) { + log.warn("删除服务器关联的监控记录失败: serverId={}, error={}", id, e.getMessage()); + } + + // 4. 逻辑删除关联的SSH审计日志(保留历史记录) try { sshAuditLogRepository.deleteByServerId(id); log.info("已逻辑删除服务器关联的SSH审计日志: serverId={}", id); } catch (Exception e) { log.warn("逻辑删除服务器关联的SSH审计日志失败: serverId={}, error={}", id, e.getMessage()); - // 继续执行,即使审计日志删除失败也要删除服务器 } - // 2. 物理删除服务器 + // 5. 物理删除服务器 super.delete(id); log.info("服务器删除成功: serverId={}", id); } diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/MonitorMetricEnum.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/MonitorMetricEnum.java index 7dc434d2..5a705c75 100644 --- a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/MonitorMetricEnum.java +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/MonitorMetricEnum.java @@ -31,7 +31,14 @@ public enum MonitorMetricEnum { /** * 网络告警(MB/s) */ - NETWORK("NETWORK", "网络使用率", "MB/s"); + NETWORK("NETWORK", "网络使用率", "MB/s"), + + /** + * 服务器状态告警(次数) + * warningThreshold: 警告级别的连续失败次数 + * criticalThreshold: 严重级别的连续失败次数(标记离线) + */ + SERVER_STATUS("SERVER_STATUS", "服务器状态", "次"); private final String code; private final String description; diff --git a/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/StatusEnum.java b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/StatusEnum.java new file mode 100644 index 00000000..166b5221 --- /dev/null +++ b/backend/src/main/java/com/qqchen/deploy/backend/framework/enums/StatusEnum.java @@ -0,0 +1,28 @@ +package com.qqchen.deploy.backend.framework.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 状态枚举 + * Framework 提供的通用状态类型,适用于监控数据采集、任务执行等场景 + * + * @author qqchen + * @since 2025-12-10 + */ +@Getter +@AllArgsConstructor +public enum StatusEnum { + /** + * 成功 + */ + SUCCESS("SUCCESS", "成功"), + + /** + * 失败 + */ + FAILURE("FAILURE", "失败"); + + private final String code; + private final String description; +} diff --git a/backend/src/main/resources/db/changelog/init/v1.0.0-data.sql b/backend/src/main/resources/db/changelog/init/v1.0.0-data.sql index 1413f2a3..5e9c51ff 100644 --- a/backend/src/main/resources/db/changelog/init/v1.0.0-data.sql +++ b/backend/src/main/resources/db/changelog/init/v1.0.0-data.sql @@ -8,7 +8,7 @@ VALUES (1, NOW(), 'admin', '系统管理租户', '北京市朝阳区', '管理 -- 初始化部门数据 INSERT INTO sys_department (id, create_time, code, name, description, parent_id, sort, enabled) -VALUES +VALUES (1, NOW(), 'ROOT', '总公司', '总公司', NULL, 0, 1), (5, NOW(), 'DL', '大连', NULL, 1, 1, 1), (6, NOW(), 'CD', '成都', NULL, 1, 2, 1), @@ -16,7 +16,7 @@ VALUES -- 初始化用户数据(密码统一为:123456) INSERT INTO sys_user (id, create_time, username, password, nickname, email, phone, department_id, enabled) -VALUES +VALUES (1, NOW(), 'admin', '$2a$10$5jQmYewM2slT.OFeNjnQGOQrImu0aeXVxHxWsV8BCJ.cQiOHBHpVS', '超级管理员', 'admin@system.com', '13800138000', 1, 1), (5, NOW(), 'tangfengmin', '$2a$10$Ela/xvMnUjpI5fqgXwF1sebpbxNAOaBo2Ar5hVqyAQvTZm/r.btqa', '汤峰岷', 'tangfengmin@iscmtech.com', NULL, 5, 1), (6, NOW(), 'shengzeqiang', '$2a$10$jeuU3FvTya3ZbS28yvVafu5W5pBc.s8/ZGNHQ7pkhHNp/VsI2wpw2', '盛泽强', 'shengzeqiang@iscmtech.com', NULL, 5, 1), @@ -28,11 +28,12 @@ VALUES (12, NOW(), 'wangdongzhu', '$2a$10$OErv/EvBXUocMutXZJe3C.k1gq9/8rrF63pz8mWRBLoORGb/8ELIO', '王栋柱', 'wangdongzhu@iscmtech.com', NULL, 5, 1), (13, NOW(), 'yangzhenfu', '$2a$10$.WBc0pXTQnrDn2IUm.eRneH9jfu7TIZg2na.K3WaluvjIEts2Iasm', '杨振夫', 'yangzhenfu@iscmtech.com', '15842461837', 5, 1), (14, NOW(), 'songwei', '$2a$10$8ChswMOtgkvZCGsa/wvMM.wfhL5NL9uqCasyHZ6hiDG45vFu/EQRG', '宋伟', 'songwei@iscmtech.com', NULL, 5, 1), -(15, NOW(), 'lukuan', '$2a$10$hlDCAqOWxZso7APbMClF1.Fp6xhnb8av5s.MDnC1tf0QfHfZRayNq', '路宽', 'lukuan@babyfs.cn', '13888888888', 7, 1); +(15, NOW(), 'lukuan', '$2a$10$hlDCAqOWxZso7APbMClF1.Fp6xhnb8av5s.MDnC1tf0QfHfZRayNq', '路宽', 'lukuan@babyfs.cn', '13888888888', 7, 1), +(16, NOW(), 'yangfan', '$2a$10$hYdpTUGG3q3Og2OA2uE39.5CnBDeUQRyqsM5OwoKUSWj2ZJUdOb0u', '杨帆', 'yangfan@iscmtech.com', NULL, 5, 1); -- 初始化系统参数 INSERT INTO sys_param (id, create_time, code, name, value, type, description, enabled) -VALUES +VALUES (1, NOW(), 'SYSTEM_NAME', '系统名称', 'Deploy Ease Platform', 'STRING', '系统显示名称', 1), (2, NOW(), 'SYSTEM_LOGO', '系统Logo', '/static/logo.png', 'STRING', '系统Logo路径', 1), (3, NOW(), 'LOGIN_BACKGROUND', '登录背景', '/static/login-bg.jpg', 'STRING', '登录页面背景图片', 1); @@ -118,14 +119,14 @@ VALUES -- 初始化角色标签 INSERT INTO sys_role_tag (id, create_time, name, color) -VALUES +VALUES (1, NOW(), '系统内置', '#ff4d4f'), (2, NOW(), '重要角色', '#ffa940'), (3, NOW(), '普通角色', '#73d13d'); -- 初始化角色标签关联 INSERT INTO sys_role_tag_relation (role_id, tag_id) -VALUES +VALUES (1, 1), (2, 1), (2, 2), @@ -133,7 +134,7 @@ VALUES -- 初始化用户角色关联 INSERT INTO sys_user_role (user_id, role_id) -VALUES +VALUES (1, 1), -- admin - 管理员 (5, 3), -- tangfengmin - 开发 (6, 3), -- shengzeqiang - 开发 @@ -145,11 +146,13 @@ VALUES (12, 3), -- wangdongzhu - 开发 (13, 3), -- yangzhenfu - 开发 (14, 1), -- songwei - 管理员 -(15, 3); -- lukuan - 开发 +(15, 3), -- lukuan - 开发 +(16, 1), -- yangfan - 管理员 +(16, 2); -- yangfan - 运维 -- 初始化角色菜单关联 INSERT INTO sys_role_menu (role_id, menu_id) -VALUES +VALUES -- 管理员角色(拥有所有菜单) (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (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), -- 运维角色 @@ -537,22 +540,22 @@ DELETE FROM sys_role_permission; -- 管理员拥有所有权限 INSERT INTO sys_role_permission (role_id, permission_id) -VALUES +VALUES (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 11), (1, 12), (1, 13), (1, 14), (1, 15), (1, 16), (1, 17), (1, 18), (1, 21), (1, 22), (1, 23), (1, 24), (1, 25), (1, 26), (1, 27), (1, 31), (1, 32), (1, 33), (1, 34), (1, 35), (1, 41), (1, 42), (1, 43), (1, 44), (1, 45), (1, 46), (1, 51), (1, 52), (1, 101), (1, 102), (1, 103), (1, 104), (1, 105), (1, 111), (1, 112), (1, 113), (1, 114), (1, 115), (1, 121), (1, 122), (1, 123), (1, 124), (1, 125), (1, 126), (1, 127), (1, 128), (1, 129), (1, 130), (1, 131), (1, 141), (1, 142), (1, 143), (1, 144), (1, 145), (1, 151), (1, 152), (1, 153), (1, 154), (1, 155), (1, 156), (1, 157), (1, 158), (1, 159), (1, 201), (1, 202), (1, 203), (1, 204), (1, 205), (1, 206), (1, 207), (1, 211), (1, 212), (1, 213), (1, 221), (1, 222), (1, 223), (1, 231), (1, 232), (1, 233), (1, 234), (1, 235), (1, 236), (1, 301), (1, 302), (1, 303), (1, 304), (1, 305), (1, 306), (1, 307), (1, 311), (1, 312), (1, 313), (1, 314), (1, 315), (1, 321), (1, 322), (1, 323), (1, 324), (1, 325), (1, 326), (1, 501), (1, 502), (1, 503), (1, 504), (1, 505), (1, 506), (1, 2061), (1, 2062), (1, 2063), (1, 2064), (1, 2065), (1, 2066), (1, 2067); -- 运维角色权限 INSERT INTO sys_role_permission (role_id, permission_id) -VALUES +VALUES (2, 101), (2, 102), (2, 103), (2, 104), (2, 105), (2, 111), (2, 112), (2, 113), (2, 114), (2, 115), (2, 121), (2, 122), (2, 123), (2, 124), (2, 125), (2, 126), (2, 127), (2, 128), (2, 129), (2, 130), (2, 131), (2, 141), (2, 142), (2, 143), (2, 144), (2, 145), (2, 151), (2, 152), (2, 153), (2, 154), (2, 155), (2, 156), (2, 157), (2, 158), (2, 159); -- 开发角色权限 INSERT INTO sys_role_permission (role_id, permission_id) -VALUES +VALUES (3, 501), (3, 502), (3, 503), (3, 504), (3, 505), (3, 506); -- 初始化权限模板 INSERT INTO sys_permission_template (id, create_time, code, name, type, description, enabled) -VALUES +VALUES (1, NOW(), 'FULL_PERMISSION', '完整权限模板', 1, '包含所有系统权限的模板', 1), (2, NOW(), 'BASIC_PERMISSION', '基础权限模板', 1, '包含基本操作权限的模板', 1); @@ -577,7 +580,7 @@ INSERT INTO sys_external_system ( id, create_by, create_time, deleted, update_by, update_time, version, name, type, url, remark, sort, enabled, auth_type, username, password, token, sync_status, last_sync_time, last_connect_time, config -) VALUES +) VALUES (1, 'admin', NOW(), 0, 'admin', NOW(), 9, '链宇JENKINS', 'JENKINS', 'https://ly-jenkins.iscmtech.com', '链宇JENKINS', 1, 1, 'BASIC', 'admin', 'b2d6f7e59ba92d0e7e5924018cfd91d61c1faf16b38daaaad27b9b273068c45ce9ace612c33800454db4c8099a5802ae', NULL, @@ -635,7 +638,7 @@ INSERT INTO form_definition ( id, name, `key`, form_version, category_id, description, `schema`, tags, status, is_template, create_by, create_time, update_by, update_time, version, deleted ) VALUES -(2, '部署表单', 'deploy-form', 1, 4, '', '{"fields":[{"id":"field_1762752319676_e1xws30b1","name":"grid_1762752319676","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752361412_f30h9gjou","name":"jenkins.serverId","type":"input","label":"JENKINS服务器","hidden":true,"required":false,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752334430_66a0kzims","name":"grid_1762752319676_copy_1762752334430","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752390005_a50w8lszi","name":"jenkins.jobName","type":"input","label":"jobName","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335032_8bky41k4c","name":"grid_1762752319676_copy_1762752335032","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752418342_8inxz8rvi","name":"jenkins.branch","type":"input","label":"分支","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335398_5xhewg0zq","name":"grid_1762752319676_copy_1762752335398","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752438046_6twc4raqr","name":"teamId","type":"input","label":"teamId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335577_0x4amo9qf","name":"grid_1762752319676_copy_1762752335577","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752448941_i82959069","name":"teamApplicationId","type":"input","label":"teamApplicationId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335769_0qiosnz76","name":"grid_1762752319676_copy_1762752335769","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752459828_bepmj343m","name":"applicationId","type":"input","label":"applicationId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335942_131m2qjq6","name":"grid_1762752319676_copy_1762752335942","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752474328_73gkcmzq7","name":"applicationCode","type":"input","label":"applicationCode","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336090_89by9g7th","name":"grid_1762752319676_copy_1762752336090","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752482872_wz9x42mw3","name":"applicationName","type":"input","label":"applicationName","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336283_f3bxgxm6r","name":"grid_1762752319676_copy_1762752336283","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752497372_cdy3hw5wv","name":"environmentId","type":"input","label":"environmentId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336459_m385kcntl","name":"grid_1762752319676_copy_1762752336459","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752491499_1x19c8nii","name":"environmentCode","type":"input","label":"environmentCode","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336623_ucx26c6gz","name":"grid_1762752319676_copy_1762752336623","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752517722_cf7urti6m","name":"environmentName","type":"input","label":"environmentName","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336800_0oyor17da","name":"grid_1762752319676_copy_1762752336800","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752531624_3ts5glb6a","name":"approval.required","type":"input","label":"approval.required","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336961_wvkhpamoc","name":"grid_1762752319676_copy_1762752336961","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752551116_45izftfxb","name":"approval.userNames","type":"input","label":"approval.userNames","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752337312_p7sycmpz7","name":"grid_1762752319676_copy_1762752337312","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752593304_st091maez","name":"notification.notificationChannelId","type":"input","label":"notification.notificationChannelId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083334603_4lilw52rl","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083334603","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083334603_7k9h8bbjo","name":"notification.preApprovalNotificationEnabled","type":"input","label":"notification.preApprovalNotificationEnabled","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752337137_j3c61hpyo","name":"grid_1762752319676_copy_1762752337137","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752611613_53p41q60n","name":"notification.diffNotificationTemplateId","type":"input","label":"notification.diffNotificationTemplateId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083311988_gv2xmdyx8","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083311988_i1e1wgifa","name":"notification.preApprovalNotificationTemplateId","type":"input","label":"notification.preApprovalNotificationTemplateId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083335787_v48wsdpfo","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083335787","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083335787_ooy472ae9","name":"notification.buildNotificationEnabled","type":"input","label":"notification.buildNotificationEnabled","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083336723_tgg9f4mmm","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083336723","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083336723_89tbrzif1","name":"notification.buildNotificationTemplateId","type":"input","label":"notification.buildNotificationTemplateId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083337546_m3ll1juva","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083337546","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083337546_gkmdgnrua","name":"notification.buildFailureFileEnabled","type":"input","label":"notification.buildFailureFileEnabled","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840600568_1wx1u41dn","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840600568_y86iq0p2p","name":"sourceRepository.systemId","type":"input","label":"sourceRepository.systemId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840651019_4hfu2no9x","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840651019_4pqkrtq51","name":"sourceRepository.projectId","type":"input","label":"sourceRepository.projectId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840687061_oklskdh7l","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840687061_rrzoz2r6v","name":"sourceRepository.branch","type":"input","label":"sourceRepository.branch","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840701760_kh8d6xuh0","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061_copy_1764840701760","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840701760_h6nsr16i7","name":"targetRepository.projectId","type":"input","label":"targetRepository.projectId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840701235_mefcrmow6","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061_copy_1764840701235","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840701235_rqipw1duz","name":"targetRepository.systemId","type":"input","label":"targetRepository.systemId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840702192_00wdhyb8p","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061_copy_1764840702192","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840702192_ueel90096","name":"targetRepository.branch","type":"input","label":"targetRepository.branch","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752611613_7fwwwheii","name":"grid_1762752611613","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752617388_qisqw9kxo","name":"deployUser","type":"input","label":"部署人","hidden":true,"required":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763175632590_dxl45pyit","name":"grid_1762752611613_copy_1763175632590","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763175632590_ifgs4x8zm","name":"deployRemark","type":"input","label":"部署内容","required":true,"placeholder":"请输入","validationRules":[{"type":"pattern","value":"/^\\\\[(task|bugfix)-\\\\d+\\\\].+$/","message":"请填写正确的[task-x]或者[bugfix-x]","trigger":"blur"}]}],[]],"columnSpans":[4,16,4]}],"version":"1.0","formConfig":{"size":"middle","labelAlign":"top"}}', +(2, '部署表单', 'deploy-form', 1, 4, '', '{"fields":[{"id":"field_1762752319676_e1xws30b1","name":"grid_1762752319676","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752361412_f30h9gjou","name":"jenkins.serverId","type":"input","label":"JENKINS服务器","hidden":true,"required":false,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752334430_66a0kzims","name":"grid_1762752319676_copy_1762752334430","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752390005_a50w8lszi","name":"jenkins.jobName","type":"input","label":"jobName","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335032_8bky41k4c","name":"grid_1762752319676_copy_1762752335032","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752418342_8inxz8rvi","name":"jenkins.branch","type":"input","label":"分支","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335398_5xhewg0zq","name":"grid_1762752319676_copy_1762752335398","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752438046_6twc4raqr","name":"teamId","type":"input","label":"teamId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335577_0x4amo9qf","name":"grid_1762752319676_copy_1762752335577","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752448941_i82959069","name":"teamApplicationId","type":"input","label":"teamApplicationId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335769_0qiosnz76","name":"grid_1762752319676_copy_1762752335769","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752459828_bepmj343m","name":"applicationId","type":"input","label":"applicationId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752335942_131m2qjq6","name":"grid_1762752319676_copy_1762752335942","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752474328_73gkcmzq7","name":"applicationCode","type":"input","label":"applicationCode","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336090_89by9g7th","name":"grid_1762752319676_copy_1762752336090","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752482872_wz9x42mw3","name":"applicationName","type":"input","label":"applicationName","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336283_f3bxgxm6r","name":"grid_1762752319676_copy_1762752336283","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752497372_cdy3hw5wv","name":"environmentId","type":"input","label":"environmentId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336459_m385kcntl","name":"grid_1762752319676_copy_1762752336459","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752491499_1x19c8nii","name":"environmentCode","type":"input","label":"environmentCode","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336623_ucx26c6gz","name":"grid_1762752319676_copy_1762752336623","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752517722_cf7urti6m","name":"environmentName","type":"input","label":"environmentName","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336800_0oyor17da","name":"grid_1762752319676_copy_1762752336800","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752531624_3ts5glb6a","name":"approval.required","type":"input","label":"approval.required","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752336961_wvkhpamoc","name":"grid_1762752319676_copy_1762752336961","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752551116_45izftfxb","name":"approval.userNames","type":"input","label":"approval.userNames","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752337312_p7sycmpz7","name":"grid_1762752319676_copy_1762752337312","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752593304_st091maez","name":"notification.notificationChannelId","type":"input","label":"notification.notificationChannelId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083334603_4lilw52rl","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083334603","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083334603_7k9h8bbjo","name":"notification.preApprovalNotificationEnabled","type":"input","label":"notification.preApprovalNotificationEnabled","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752337137_j3c61hpyo","name":"grid_1762752319676_copy_1762752337137","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752611613_53p41q60n","name":"notification.diffNotificationTemplateId","type":"input","label":"notification.diffNotificationTemplateId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083311988_gv2xmdyx8","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083311988_i1e1wgifa","name":"notification.preApprovalNotificationTemplateId","type":"input","label":"notification.preApprovalNotificationTemplateId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083335787_v48wsdpfo","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083335787","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083335787_ooy472ae9","name":"notification.buildNotificationEnabled","type":"input","label":"notification.buildNotificationEnabled","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083336723_tgg9f4mmm","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083336723","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083336723_89tbrzif1","name":"notification.buildNotificationTemplateId","type":"input","label":"notification.buildNotificationTemplateId","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763083337546_m3ll1juva","name":"grid_1762752319676_copy_1762752337137_copy_1763083311988_copy_1763083337546","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763083337546_gkmdgnrua","name":"notification.buildFailureFileEnabled","type":"input","label":"notification.buildFailureFileEnabled","hidden":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840600568_1wx1u41dn","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840600568_y86iq0p2p","name":"sourceRepository.systemId","type":"input","label":"sourceRepository.systemId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840651019_4hfu2no9x","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840651019_4pqkrtq51","name":"sourceRepository.projectId","type":"input","label":"sourceRepository.projectId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840687061_oklskdh7l","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840687061_rrzoz2r6v","name":"sourceRepository.branch","type":"input","label":"sourceRepository.branch","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840701760_kh8d6xuh0","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061_copy_1764840701760","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840701760_h6nsr16i7","name":"targetRepository.projectId","type":"input","label":"targetRepository.projectId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840701235_mefcrmow6","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061_copy_1764840701235","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840701235_rqipw1duz","name":"targetRepository.systemId","type":"input","label":"targetRepository.systemId","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1764840702192_00wdhyb8p","name":"grid_1762752611613_copy_1763175632590_copy_1764840600568_copy_1764840651019_copy_1764840687061_copy_1764840702192","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1764840702192_ueel90096","name":"targetRepository.branch","type":"input","label":"targetRepository.branch","hidden":true,"required":true,"placeholder":"请输入","validationRules":[]}],[]],"columnSpans":[4,16,4]},{"id":"field_1762752611613_7fwwwheii","name":"grid_1762752611613","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1762752617388_qisqw9kxo","name":"deployUser","type":"input","label":"部署人","hidden":true,"required":true,"placeholder":"请输入"}],[]],"columnSpans":[4,16,4]},{"id":"field_1763175632590_dxl45pyit","name":"grid_1762752611613_copy_1763175632590","type":"grid","label":"栅格布局","gutter":16,"columns":3,"children":[[],[{"id":"field_1763175632590_ifgs4x8zm","name":"deployRemark","type":"input","label":"部署内容","required":true,"placeholder":"请输入","validationRules":[{"type":"pattern","value":"/^\\\\[(task|bugfix)-\\\\d+\\\\].+$/","message":"请填写正确的[task-x]或者[bugfix-x]","trigger":"blur"}]}],[]],"columnSpans":[4,16,4]}],"version":"1.0","formConfig":{"size":"middle","labelAlign":"top"}}', NULL, 'PUBLISHED', 0, 'admin', NOW(), 'admin', NOW(), 0, 0); -- 工作流定义数据(graph字段已压缩为单行JSON) @@ -671,6 +674,10 @@ INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_ INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_name`, `app_desc`, `language`, `application_category_id`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (20, 'datax-admin', 'datax-admin', '', 0, 1, b'1', 0, 'songwei', NOW(), 'songwei', NOW(), 1, b'0'); INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_name`, `app_desc`, `language`, `application_category_id`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (21, 'scp-algorithm', 'scp-algorithm', '', 0, 1, b'1', 0, 'songwei', NOW(), 'songwei', NOW(), 1, b'0'); INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_name`, `app_desc`, `language`, `application_category_id`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (22, 'scp-forecast-model', 'scp-forecast-model', '', 2, 1, b'1', 0, 'songwei', NOW(), 'songwei', NOW(), 1, b'0'); +INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_name`, `app_desc`, `language`, `application_category_id`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (23, 'etl-ignite-server', 'etl-ignite-server', '内存数据库', 0, 2, b'1', 0, 'admin', NOW(), 'admin', NOW(), 1, b'0'); +INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_name`, `app_desc`, `language`, `application_category_id`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (24, 'etl-integration-ui-server', 'etl-integration-ui-server', 'UI server', 0, 2, b'1', 0, 'admin', NOW(), 'admin', NOW(), 1, b'0'); +INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_name`, `app_desc`, `language`, `application_category_id`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (25, 'etl-executor', 'etl-executor', 'etl执行器', 0, 2, b'1', 0, 'admin', NOW(), 'admin', NOW(), 1, b'0'); +INSERT INTO `deploy-ease-platform`.`deploy_application` (`id`, `app_code`, `app_name`, `app_desc`, `language`, `application_category_id`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (26, 'etl-scheduler', 'etl-scheduler', 'etl调度器', 0, 2, b'1', 0, 'admin', NOW(), 'admin', NOW(), 1, b'0'); INSERT INTO `deploy-ease-platform`.`deploy_environment` (`id`, `tenant_code`, `env_code`, `env_name`, `env_desc`, `enabled`, `sort`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`) VALUES (1, NULL, 'LONGI-DEV', '隆基DEV', NULL, b'1', 1, 'admin', NOW(), 'admin', NOW(), 2, b'0'); @@ -756,6 +763,11 @@ INSERT INTO `deploy-ease-platform`.`deploy_team_application` (`id`, `create_by`, INSERT INTO `deploy-ease-platform`.`deploy_team_application` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `application_id`, `environment_id`, `build_type`, `source_git_system_id`, `source_git_project_id`, `source_branch`, `target_git_system_id`, `target_git_project_id`, `target_branch`, `deploy_system_id`, `deploy_job`, `workflow_definition_id`) VALUES (81, 'songwei', NOW(), 'songwei', NOW(), 1, b'0', 3, 6, 7, 'JENKINS', 2, 300, 'feature/upgrade', NULL, NULL, NULL, 1, 'lixiang-scp-ws', 1); INSERT INTO `deploy-ease-platform`.`deploy_team_application` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `application_id`, `environment_id`, `build_type`, `source_git_system_id`, `source_git_project_id`, `source_branch`, `target_git_system_id`, `target_git_project_id`, `target_branch`, `deploy_system_id`, `deploy_job`, `workflow_definition_id`) VALUES (82, 'songwei', NOW(), 'songwei', NOW(), 1, b'0', 3, 17, 7, 'JENKINS', 2, 636, 'develop', NULL, NULL, NULL, 1, 'pro-scp-xxl-job', 1); +INSERT INTO `deploy-ease-platform`.`deploy_team_application` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `application_id`, `environment_id`, `build_type`, `source_git_system_id`, `source_git_project_id`, `source_branch`, `target_git_system_id`, `target_git_project_id`, `target_branch`, `deploy_system_id`, `deploy_job`, `workflow_definition_id`) VALUES (83, 'admin', NOW(), 'admin', NOW(), 1, b'0', 5, 23, 5, 'NATIVE', 6, 7, 'release/1.0-localization', NULL, NULL, NULL, NULL, '', 2); +INSERT INTO `deploy-ease-platform`.`deploy_team_application` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `application_id`, `environment_id`, `build_type`, `source_git_system_id`, `source_git_project_id`, `source_branch`, `target_git_system_id`, `target_git_project_id`, `target_branch`, `deploy_system_id`, `deploy_job`, `workflow_definition_id`) VALUES (84, 'admin', NOW(), 'admin', NOW(), 1, b'0', 5, 26, 5, 'JENKINS', 6, 7, 'release/1.0-localization', NULL, NULL, NULL, NULL, '', 2); +INSERT INTO `deploy-ease-platform`.`deploy_team_application` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `application_id`, `environment_id`, `build_type`, `source_git_system_id`, `source_git_project_id`, `source_branch`, `target_git_system_id`, `target_git_project_id`, `target_branch`, `deploy_system_id`, `deploy_job`, `workflow_definition_id`) VALUES (85, 'admin', NOW(), 'admin', NOW(), 1, b'0', 5, 25, 5, 'NATIVE', 6, 7, 'release/1.0-localization', NULL, NULL, NULL, NULL, '', 2); +INSERT INTO `deploy-ease-platform`.`deploy_team_application` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `application_id`, `environment_id`, `build_type`, `source_git_system_id`, `source_git_project_id`, `source_branch`, `target_git_system_id`, `target_git_project_id`, `target_branch`, `deploy_system_id`, `deploy_job`, `workflow_definition_id`) VALUES (86, 'admin', NOW(), 'admin', NOW(), 1, b'0', 5, 24, 5, 'NATIVE', 6, 7, 'release/1.0-localization', NULL, NULL, NULL, NULL, '', 2); + INSERT INTO `deploy-ease-platform`.`deploy_team_environment_config` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `environment_id`, `approval_required`, `approver_user_ids`, `require_code_review`, `remark`) VALUES (8, 'admin', NOW(), 'admin', NOW(), 1, b'0', 5, 5, b'0', NULL, b'0', ''); INSERT INTO `deploy-ease-platform`.`deploy_team_environment_config` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `environment_id`, `approval_required`, `approver_user_ids`, `require_code_review`, `remark`) VALUES (9, 'admin', NOW(), 'admin', NOW(), 1, b'0', 4, 1, b'0', NULL, b'0', ''); INSERT INTO `deploy-ease-platform`.`deploy_team_environment_config` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `team_id`, `environment_id`, `approval_required`, `approver_user_ids`, `require_code_review`, `remark`) VALUES (10, 'admin', NOW(), 'admin', NOW(), 1, b'0', 4, 2, b'1', '[6]', b'0', ''); @@ -831,8 +843,8 @@ INSERT INTO `deploy-ease-platform`.`sys_notification_channel` (`id`, `create_by` INSERT INTO `deploy-ease-platform`.`sys_notification_template` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `name`, `code`, `description`, `channel_type`, `title_template`, `content_template`, `enabled`, `template_config`) VALUES (8, 'admin', NOW(), 'dengqichen', NOW(), 36, b'0', 'JENKINS构建状态通知', 'jenkins_build_notification', '', 'WEWORK', '## <#if environmentName??>${environmentName}环境构建通知', '>项目:<#if applicationName??>${applicationName}(${applicationCode})\r\n<#if buildStatus??>\r\n<#switch buildStatus>\r\n<#case \"SUCCESS\">\r\n>状态:构建成功\r\n<#break>\r\n<#case \"BUILDING\">\r\n>状态:构建中\r\n<#break>\r\n<#case \"ABORTED\">\r\n>状态:构建被取消\r\n<#break>\r\n<#default>\r\n>状态:构建失败\r\n\r\n\r\n<#if buildStatus?? && buildStatus != \"BUILDING\">\r\n<#if buildDurationFormatted??>\r\n>耗时:${buildDurationFormatted}\r\n\r\n<#if buildEndTime??>\r\n>时间:${buildEndTime}\r\n\r\n<#else>\r\n<#if buildStartTime??>\r\n>时间:${buildStartTime}\r\n\r\n\r\n<#if commitMessage??>\r\n>内容:\r\n<#list commitMessage?split(\'\\n\') as line>\r\n>${line}\r\n\r\n', b'1', '{\"channelType\": \"WEWORK\", \"messageType\": \"MARKDOWN\"}'); INSERT INTO `deploy-ease-platform`.`sys_notification_template` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `name`, `code`, `description`, `channel_type`, `title_template`, `content_template`, `enabled`, `template_config`) VALUES (9, 'admin', NOW(), 'admin', NOW(), 10, b'0', '国产化构建通知', 'localization_build_notification', '国产化模版', 'WEWORK', '## <#if environmentName??>${environmentName}环境变更通知', '>项目:<#if applicationName??>${applicationName}(${applicationCode})\r\n<#-- 通过判断HTTP节点输出是否存在来区分阶段 -->\r\n<#if sid_d7bd35dc_37cc_4868_9c8a_9c854d5d6bbf?? && sid_d7bd35dc_37cc_4868_9c8a_9c854d5d6bbf.outputs??>\r\n<#-- ========== 构建结束阶段(HTTP节点已执行)========== -->\r\n<#assign httpOutput = sid_d7bd35dc_37cc_4868_9c8a_9c854d5d6bbf.outputs>\r\n<#if httpOutput.isSuccess!false>\r\n<#if httpOutput.responseBody?? && httpOutput.responseBody.status?? && httpOutput.responseBody.status == \"success\">\r\n>状态:构建成功\r\n<#if httpOutput.responseBody.duration??>\r\n>耗时:${httpOutput.responseBody.duration}秒\r\n\r\n<#if httpOutput.responseBody.endTime??>\r\n>时间:${httpOutput.responseBody.endTime}\r\n\r\n<#else>\r\n>状态:构建失败\r\n<#if httpOutput.responseBody?? && httpOutput.responseBody.error??>\r\n>错误:${httpOutput.responseBody.error}\r\n\r\n\r\n<#else>\r\n>状态:构建失败\r\n<#if httpOutput.statusCode?? && httpOutput.statusCode gt 0>\r\n>HTTP状态码:${httpOutput.statusCode}\r\n<#else>\r\n>错误类型:网络连接异常\r\n\r\n<#if httpOutput.errorMessage??>\r\n>错误详情:${httpOutput.errorMessage}\r\n\r\n<#if httpOutput.responseTime??>\r\n>请求耗时:${httpOutput.responseTime}ms\r\n\r\n\r\n<#else>\r\n<#-- ========== 构建中阶段(HTTP节点未执行)========== -->\r\n>状态:构建中\r\n<#if deployDate??>\r\n<#attempt>\r\n<#assign deployDateTime = deployDate?datetime.iso>\r\n>时间:${deployDateTime?string(\"yyyy-MM-dd HH:mm:ss\")}\r\n<#recover>\r\n>时间:${deployDate}\r\n\r\n\r\n\r\n>内容:<#if deployRemark??>${deployRemark}<#else>无构建内容\r\n', b'1', '{\"channelType\": \"WEWORK\", \"messageType\": \"MARKDOWN\"}'); INSERT INTO `deploy-ease-platform`.`sys_notification_template` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `name`, `code`, `description`, `channel_type`, `title_template`, `content_template`, `enabled`, `template_config`) VALUES (10, 'admin', NOW(), 'admin', NOW(), 3, b'0', 'Git同步检测通知', 'git_sync_code_check_notification', '', 'WEWORK', '## 代码同步检查异常', '${sid_e5f930da_062e_4819_b976_8d8172c7f14a.outputs.checkDetail}', b'1', '{\"channelType\": \"WEWORK\", \"messageType\": \"MARKDOWN\"}'); -INSERT INTO `deploy-ease-platform`.`sys_notification_template` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `name`, `code`, `description`, `channel_type`, `title_template`, `content_template`, `enabled`, `template_config`) VALUES (11, 'admin', NOW(), 'dengqichen', NOW(), 5, b'0', '服务器阈值预警通知', 'server_threshold_warning_notification', '', 'WEWORK', '## 服务器(${resourceInfo})${alertLevel}通知', '> 服务器:${serverName}\r\n> 告警规则:${ruleName}-${alertType}\r\n> 当前值:${currentValue}%,阈值:${threshold}%\r\n> 告警时间:${alertTime}\r\n\r\n请及时处理告警信息!', b'1', '{\"channelType\": \"WEWORK\", \"messageType\": \"MARKDOWN\"}'); -INSERT INTO `deploy-ease-platform`.`sys_notification_template` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `name`, `code`, `description`, `channel_type`, `title_template`, `content_template`, `enabled`, `template_config`) VALUES (12, 'admin', NOW(), 'dengqichen', NOW(), 2, b'0', '服务器离线预警', 'server_offline_warning_notification', '', 'WEWORK', '## 服务器离线通知', '> 服务器名称:${serverName}\r\n\r\n**离线详情**\r\n> 检测时间:${offlineTime}\r\n> 状态:服务器无法访问\r\n\r\n请立即处理服务器离线问题!', b'1', '{\"channelType\": \"WEWORK\", \"messageType\": \"MARKDOWN\"}'); +INSERT INTO `deploy-ease-platform`.`sys_notification_template` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `name`, `code`, `description`, `channel_type`, `title_template`, `content_template`, `enabled`, `template_config`) VALUES (11, 'admin', NOW(), 'admin', NOW(), 8, b'0', '服务器阈值预警通知', 'server_threshold_warning_notification', '', 'WEWORK', '> 服务器:**${serverName}**', '> 规则:${ruleName}(${alertType})\r\n<#if alertType == \"服务器状态\">\r\n> 状态:连续失败 ${currentValue} 次,阈值 ${threshold} 次\r\n<#else>\r\n> 使用率:${currentValue}%,阈值 ${threshold}%\r\n\r\n<#if alertLevel == \"严重\">\r\n> 级别:🔴 严重\r\n<#else>\r\n> 级别:⚠️ 警告\r\n\r\n> 时间:${alertTime}\r\n<#if alertLevel == \"严重\">\r\n**⚠️ 请立即处理告警信息!**\r\n<#else>\r\n请注意观察,及时处理告警信息。\r\n', b'1', '{\"channelType\": \"WEWORK\", \"messageType\": \"MARKDOWN\"}'); +INSERT INTO `deploy-ease-platform`.`sys_notification_template` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `name`, `code`, `description`, `channel_type`, `title_template`, `content_template`, `enabled`, `template_config`) VALUES (12, 'admin', NOW(), 'admin', NOW(), 4, b'1', '服务器离线预警', 'server_offline_warning_notification', '', 'WEWORK', '## 服务器离线告警', '> 检测服务器名称为:${serverName},当前处于离线状态\r\n> 检测时间:${offlineTime}\r\n\r\n请确认是否存在服务器问题', b'1', '{\"channelType\": \"WEWORK\", \"messageType\": \"MARKDOWN\"}'); INSERT INTO `deploy-ease-platform`.`schedule_job_category` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `code`, `name`, `description`, `icon`, `color`, `enabled`, `sort`) VALUES (1, 'system', NOW(), 'system', NOW(), 1, b'0', 'DATA_CLEAN', '数据清理', '定期清理系统历史数据和临时文件', 'DeleteOutlined', '#ff4d4f', b'1', 1); INSERT INTO `deploy-ease-platform`.`schedule_job_category` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `code`, `name`, `description`, `icon`, `color`, `enabled`, `sort`) VALUES (2, 'system', NOW(), 'system', NOW(), 1, b'0', 'DATA_SYNC', '数据同步', '同步外部系统数据到本地', 'SyncOutlined', '#1890ff', b'1', 2); @@ -853,12 +865,12 @@ INSERT INTO `deploy-ease-platform`.`schedule_job` (`id`, `create_by`, `create_ti INSERT INTO `deploy-ease-platform`.`schedule_job` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `job_name`, `job_description`, `category_id`, `bean_name`, `method_name`, `form_definition_id`, `method_params`, `cron_expression`, `status`, `concurrent`, `last_execute_time`, `next_execute_time`, `execute_count`, `success_count`, `fail_count`, `timeout_seconds`, `retry_count`, `alert_email`) VALUES (14, 'admin', NOW(), 'admin', NOW(), 27, b'0', '隆基Git仓库组同步', '定期同步Git仓库组信息,每天凌晨2点执行', 2, 'repositoryGroupServiceImpl', 'syncGroups', NULL, '{\"externalSystemId\": 4}', '0 0 3 * * ?', 'DISABLED', b'0', NOW(), NOW(), 0, 0, 0, 3600, 2, ''); INSERT INTO `deploy-ease-platform`.`schedule_job` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `job_name`, `job_description`, `category_id`, `bean_name`, `method_name`, `form_definition_id`, `method_params`, `cron_expression`, `status`, `concurrent`, `last_execute_time`, `next_execute_time`, `execute_count`, `success_count`, `fail_count`, `timeout_seconds`, `retry_count`, `alert_email`) VALUES (15, 'admin', NOW(), 'admin', NOW(), 1212, b'0', '隆基Git项目同步', '定期同步Git项目信息,每天凌晨3点执行', 2, 'repositoryProjectServiceImpl', 'syncProjects', NULL, '{\"externalSystemId\": 4}', '0 */5 * * * ?', 'DISABLED', b'0', NOW(), NOW(), 7, 7, 0, 3600, 2, ''); INSERT INTO `deploy-ease-platform`.`schedule_job` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `job_name`, `job_description`, `category_id`, `bean_name`, `method_name`, `form_definition_id`, `method_params`, `cron_expression`, `status`, `concurrent`, `last_execute_time`, `next_execute_time`, `execute_count`, `success_count`, `fail_count`, `timeout_seconds`, `retry_count`, `alert_email`) VALUES (16, 'admin', NOW(), 'admin', NOW(), 5727, b'0', '隆基Git分支同步', '定期同步Git仓库分支信息,每5分钟执行一次', 2, 'repositoryBranchServiceImpl', 'syncBranches', NULL, '{\"externalSystemId\": 4}', '0 */5 * * * ?', 'DISABLED', b'0', NOW(), NOW(), 7, 7, 0, 3600, 2, ''); -INSERT INTO `deploy-ease-platform`.`schedule_job` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `job_name`, `job_description`, `category_id`, `bean_name`, `method_name`, `form_definition_id`, `method_params`, `cron_expression`, `status`, `concurrent`, `last_execute_time`, `next_execute_time`, `execute_count`, `success_count`, `fail_count`, `timeout_seconds`, `retry_count`, `alert_email`) VALUES (17, 'admin', NOW(), 'admin', NOW(), 20, b'0', '服务器预警', '', 4, 'serverMonitorScheduler', 'collectServerMetrics', NULL, '{\"notificationChannelId\": 5, \"serverOfflineTemplateId\": 12, \"resourceAlertTemplateId\": 11}', '0 */5 * * * ?', 'DISABLED', b'0', NOW(), NOW(), 15, 15, 0, 300, 0, ''); - +INSERT INTO `deploy-ease-platform`.`schedule_job` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `job_name`, `job_description`, `category_id`, `bean_name`, `method_name`, `form_definition_id`, `method_params`, `cron_expression`, `status`, `concurrent`, `last_execute_time`, `next_execute_time`, `execute_count`, `success_count`, `fail_count`, `timeout_seconds`, `retry_count`, `alert_email`) VALUES (17, 'admin', NOW(), 'admin', NOW(), 49, b'0', '服务器预警', '', 4, 'serverMonitorScheduler', 'collectServerMetrics', NULL, '{\"notificationChannelId\": 5, \"resourceAlertTemplateId\": 11}', '0 */5 * * * ?', 'DISABLED', b'0', NOW(), NULL, 39, 38, 1, 300, 0, ''); -- 全局告警规则 INSERT INTO `deploy-ease-platform`.`deploy_server_alert_rule` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `server_id`, `rule_name`, `alert_type`, `warning_threshold`, `critical_threshold`, `duration_minutes`, `enabled`, `description`) VALUES (1, NULL, NOW(), NULL, NOW(), 0, 0, NULL, '全局CPU告警规则', 'CPU', 75.00, 90.00, 5, 1, '全局规则:CPU使用率超过75%触发警告,超过90%触发严重告警'); INSERT INTO `deploy-ease-platform`.`deploy_server_alert_rule` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `server_id`, `rule_name`, `alert_type`, `warning_threshold`, `critical_threshold`, `duration_minutes`, `enabled`, `description`) VALUES (2, NULL, NOW(), NULL, NOW(), 0, 0, NULL, '全局内存告警规则', 'MEMORY', 75.00, 90.00, 5, 1, '全局规则:内存使用率超过75%触发警告,超过90%触发严重告警'); INSERT INTO `deploy-ease-platform`.`deploy_server_alert_rule` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `server_id`, `rule_name`, `alert_type`, `warning_threshold`, `critical_threshold`, `duration_minutes`, `enabled`, `description`) VALUES (3, NULL, NOW(), NULL, NOW(), 0, 0, NULL, '全局磁盘告警规则', 'DISK', 80.00, 90.00, 5, 1, '全局规则:磁盘使用率超过80%触发警告,超过90%触发严重告警'); -INSERT INTO `deploy-ease-platform`.`deploy_server_alert_rule` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `server_id`, `rule_name`, `alert_type`, `warning_threshold`, `critical_threshold`, `duration_minutes`, `enabled`, `description`) VALUES (4, NULL, NOW(), NULL, NOW(), 0, 0, NULL, '全局网络流量告警规则', 'NETWORK', 100.00, 200.00, 5, 0, '全局规则:网络流量超过100MB/s触发警告,超过200MB/s触发严重告警(默认禁用,需根据实际带宽调整)'); \ No newline at end of file +INSERT INTO `deploy-ease-platform`.`deploy_server_alert_rule` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `server_id`, `rule_name`, `alert_type`, `warning_threshold`, `critical_threshold`, `duration_minutes`, `enabled`, `description`) VALUES (4, NULL, NOW(), NULL, NOW(), 0, 0, NULL, '全局网络流量告警规则', 'NETWORK', 100.00, 200.00, 5, 0, '全局规则:网络流量超过100MB/s触发警告,超过200MB/s触发严重告警(默认禁用,需根据实际带宽调整)'); +INSERT INTO `deploy-ease-platform`.`deploy_server_alert_rule` (`id`, `create_by`, `create_time`, `update_by`, `update_time`, `version`, `deleted`, `server_id`, `rule_name`, `alert_type`, `warning_threshold`, `critical_threshold`, `duration_minutes`, `enabled`, `description`) VALUES (5, NULL, NOW(), NULL, NOW(), 0, 0, NULL, '全局服务器状态告警规则', 'SERVER_STATUS', 3.00, 5.00, 5, 1, '全局规则:连续3次检测失败触发警告,连续5次触发严重告警并标记服务器离线'); \ No newline at end of file diff --git a/backend/src/main/resources/db/changelog/init/v1.0.0-schema.sql b/backend/src/main/resources/db/changelog/init/v1.0.0-schema.sql index b5dbf07e..4ac2bb96 100644 --- a/backend/src/main/resources/db/changelog/init/v1.0.0-schema.sql +++ b/backend/src/main/resources/db/changelog/init/v1.0.0-schema.sql @@ -1178,6 +1178,9 @@ CREATE TABLE deploy_server_monitor -- 采集时间 collect_time DATETIME NOT NULL COMMENT '采集时间', + -- 采集状态 + status VARCHAR(20) NOT NULL DEFAULT 'SUCCESS' COMMENT '采集状态:SUCCESS-成功, FAILURE-失败', + INDEX idx_server_time (server_id, collect_time), INDEX idx_collect_time (collect_time), CONSTRAINT fk_monitor_server FOREIGN KEY (server_id) REFERENCES deploy_server (id) diff --git a/backend/src/main/resources/db/changelog/sql/20251209141300-01.sql b/backend/src/main/resources/db/changelog/sql/20251209141300-01.sql index 2ec95840..66e2c22b 100644 --- a/backend/src/main/resources/db/changelog/sql/20251209141300-01.sql +++ b/backend/src/main/resources/db/changelog/sql/20251209141300-01.sql @@ -12,22 +12,36 @@ INSERT INTO system_release ( ) VALUES ( 'system', NOW(), 'system', NOW(), 1, 0, - 1.13, 'ALL', NOW(), + 1.15, 'ALL', NOW(), '【后端】 -- 日志优化:生产环境日志级别调整(空结果/开始/详细过程→DEBUG,减少冗余输出) -- 连接池优化:HikariCP泄漏检测阈值调整为35分钟(匹配Jenkins构建轮询时长) -- SSH日志优化:SSHJ底层日志降级为WARN(屏蔽Transport/SecureRandom等无业务价值日志) -- 监控日志优化:服务器连接成功日志提升为INFO(便于生产环境状态监控) -- Liquibase优化:目录结构调整(XML/SQL分离,changes/只放XML,sql/只放SQL,避免重复执行) -- Security优化:白名单配置化(SecurityConfig/JwtAuthenticationFilter统一使用配置文件管理免认证路径) -- 系统监控:新增"系统指标"菜单(实时查看JVM、CPU、内存、线程、连接池等性能指标) -- Actuator集成:开放监控端点(health/metrics/threaddump/heapdump/env/loggers,支持动态调整日志级别) -- 配置管理:新增SecurityWhitelistProperties配置类(集中管理Security白名单,支持环境差异化配置) -【前端】 -- 新增:系统指标监控页面(实时监控JVM内存、CPU、线程、连接池、GC,30秒自动刷新) -- 新增:线程分析工具(状态筛选、智能排序、堆栈展开、问题线程识别、一键导出含堆栈) -- 优化:内存单位统一为GB(图表、趋势图、卡片全局一致,清理历史数据) -- 修复:Actuator接口代理和调用方式(新增/actuator代理配置) +新增:服务器离线告警连续失败检测机制(避免临时网络波动误报) + - 数据库:deploy_server_monitor 表增加 status 字段记录采集状态(SUCCESS/FAILURE) + - 框架层:新增 StatusEnum 通用状态枚举类,MonitorMetricEnum 增加 SERVER_STATUS 监控类型 + - 实体层:ServerMonitor 实体增加 status 字段用于标识采集状态 + - Repository:IServerMonitorRepository 增加 findRecentMonitorRecords 方法查询最近N条监控记录 + - Service:IServerMonitorService 增加 saveMonitorRecord(保存单条记录)和 countConsecutiveFailures(统计连续失败次数)方法 + - 告警服务:IServerAlertService 增加 checkServerStatusAlert(检查状态告警)和 resolveServerStatusAlert(解除状态告警)方法 + - 告警实现:ServerAlertServiceImpl 实现服务器状态告警的创建、级别升级(WARNING→CRITICAL)、自动解除逻辑 + - 调度器:ServerMonitorScheduler 集成连续失败检测,连接成功时插入SUCCESS记录并解除告警,连接失败时插入FAILURE记录并触发告警检测 + - 数据初始化:增加全局服务器状态告警规则(连续3次失败触发警告,5次触发严重并标记离线) + +优化:统一监控告警通知模板,简化配置参数 + - ServerMonitorNotificationConfig 删除 serverOfflineTemplateId 字段,所有监控告警(CPU/内存/磁盘/网络/服务器状态)统一使用 resourceAlertTemplateId + - ServerMonitorScheduler.collectServerMetrics 方法删除 serverOfflineTemplateId 参数 + - ServerAlertServiceImpl.sendServerStatusNotification 改用统一的资源告警模板,模板参数与其他监控告警保持一致 + +修复:删除冗余代码和未使用的类 + - 删除 CollectionStatusEnum.java(已被 StatusEnum 取代) + - 删除 ServerMonitorScheduler.sendServerOfflineNotification 方法(改由 ServerAlertService 统一处理) + +优化:告警通知模板支持百分比和次数两种单位 + - 通知模板使用 FreeMarker 条件判断,根据 alertType 自动显示"连续失败X次"或"使用率X%" + - 严重级别告警显示红色并提示"请立即处理",警告级别提示"请注意观察" + + 【前端】 +修复:告警规则表单规则范围下拉框无法滚动选择问题(移除嵌套滚动容器干扰) +优化:规则范围选择器升级为带搜索的Popover组件(支持按服务器名称/IP搜索,固定高度可滚动) +优化:规则范围数据加载从分页接口改为列表接口 ', 0, NULL, NULL, 0 );