diff --git a/alerter/src/main/java/com/usthe/alert/controller/AlertDefineController.java b/alerter/src/main/java/com/usthe/alert/controller/AlertDefineController.java index 7587990..63a789e 100644 --- a/alerter/src/main/java/com/usthe/alert/controller/AlertDefineController.java +++ b/alerter/src/main/java/com/usthe/alert/controller/AlertDefineController.java @@ -21,7 +21,6 @@ import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; import java.util.List; -import java.util.Map; import static com.usthe.common.util.CommonConstants.MONITOR_NOT_EXIST_CODE; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; diff --git a/alerter/src/main/java/com/usthe/alert/controller/AlertsController.java b/alerter/src/main/java/com/usthe/alert/controller/AlertsController.java index 6d04517..bd8c9e1 100644 --- a/alerter/src/main/java/com/usthe/alert/controller/AlertsController.java +++ b/alerter/src/main/java/com/usthe/alert/controller/AlertsController.java @@ -14,6 +14,8 @@ import org.springframework.data.jpa.domain.Specification; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @@ -97,4 +99,16 @@ public class AlertsController { return ResponseEntity.ok(message); } + @PutMapping(path = "/status/{status}") + @ApiOperation(value = "批量修改告警状态", notes = "批量修改告警状态,设置已读未读") + public ResponseEntity> applyAlertDefinesStatus( + @ApiParam(value = "告警状态值", example = "0") @PathVariable Byte status, + @ApiParam(value = "告警IDs", example = "6565463543") @RequestParam(required = false) List ids) { + if (ids != null && status != null && !ids.isEmpty()) { + alertService.editAlertStatus(status, ids); + } + Message message = new Message<>(); + return ResponseEntity.ok(message); + } + } diff --git a/alerter/src/main/java/com/usthe/alert/dao/AlertDao.java b/alerter/src/main/java/com/usthe/alert/dao/AlertDao.java index d17f055..cc955f6 100644 --- a/alerter/src/main/java/com/usthe/alert/dao/AlertDao.java +++ b/alerter/src/main/java/com/usthe/alert/dao/AlertDao.java @@ -3,7 +3,11 @@ package com.usthe.alert.dao; import com.usthe.alert.pojo.entity.Alert; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import java.util.List; import java.util.Set; /** @@ -19,4 +23,13 @@ public interface AlertDao extends JpaRepository, JpaSpecificationEx */ void deleteAlertsByIdIn(Set alertIds); + /** + * 根据告警ID-状态值 更新告警状态 + * @param status 状态值 + * @param ids 告警ID列表 + */ + @Modifying + @Query("update Alert set status = :status where id in :ids") + void updateAlertsStatus(@Param(value = "status") Byte status, @Param(value = "ids") List ids); + } diff --git a/alerter/src/main/java/com/usthe/alert/pojo/entity/Alert.java b/alerter/src/main/java/com/usthe/alert/pojo/entity/Alert.java index 38905b4..9621948 100644 --- a/alerter/src/main/java/com/usthe/alert/pojo/entity/Alert.java +++ b/alerter/src/main/java/com/usthe/alert/pojo/entity/Alert.java @@ -67,7 +67,7 @@ public class Alert { @Length(max = 1024) private String content; - @ApiModelProperty(value = "告警状态: 0-正常告警 1-触发中:阈值触发但未达到告警次数 2-恢复告警", + @ApiModelProperty(value = "告警状态: 0-正常告警(未读) 1-阈值触发但未达到告警次数 2-恢复告警 3-已读已知", example = "1", accessMode = READ_WRITE, position = 7) @Min(0) @Max(2) diff --git a/alerter/src/main/java/com/usthe/alert/service/AlertService.java b/alerter/src/main/java/com/usthe/alert/service/AlertService.java index aa2e9bb..06d2858 100644 --- a/alerter/src/main/java/com/usthe/alert/service/AlertService.java +++ b/alerter/src/main/java/com/usthe/alert/service/AlertService.java @@ -6,6 +6,7 @@ import org.springframework.data.domain.PageRequest; import org.springframework.data.jpa.domain.Specification; import java.util.HashSet; +import java.util.List; /** * 告警信息管理接口 @@ -34,4 +35,11 @@ public interface AlertService { * @param ids 告警IDs */ void deleteAlerts(HashSet ids); + + /** + * 根据告警ID-状态值 更新告警状态 + * @param status 待修改为的告警状态 + * @param ids 待修改的告警IDs + */ + void editAlertStatus(Byte status, List ids); } diff --git a/alerter/src/main/java/com/usthe/alert/service/impl/AlertServiceImpl.java b/alerter/src/main/java/com/usthe/alert/service/impl/AlertServiceImpl.java index 4c96fa8..96a4d1f 100644 --- a/alerter/src/main/java/com/usthe/alert/service/impl/AlertServiceImpl.java +++ b/alerter/src/main/java/com/usthe/alert/service/impl/AlertServiceImpl.java @@ -12,6 +12,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.HashSet; +import java.util.List; /** * 告警信息服务实现 @@ -40,4 +41,10 @@ public class AlertServiceImpl implements AlertService { public void deleteAlerts(HashSet ids) { alertDao.deleteAlertsByIdIn(ids); } + + @Override + public void editAlertStatus(Byte status, List ids) { + alertDao.updateAlertsStatus(status, ids); + } + } diff --git a/manager/src/main/resources/db/schema.sql b/manager/src/main/resources/db/schema.sql index 8018cfe..34bd205 100644 --- a/manager/src/main/resources/db/schema.sql +++ b/manager/src/main/resources/db/schema.sql @@ -116,7 +116,7 @@ CREATE TABLE alert alert_define_id bigint not null comment '告警关联的告警定义ID', priority tinyint not null default 0 comment '告警级别 0:高-emergency-紧急告警-红色 1:中-critical-严重告警-橙色 2:低-warning-警告告警-黄色', content varchar(255) not null comment '告警通知实际内容', - status tinyint not null default 0 comment '告警状态: 0-正常告警 1-阈值触发但未达到告警次数 2-恢复告警', + status tinyint not null default 0 comment '告警状态: 0-正常告警(未读) 1-阈值触发但未达到告警次数 2-恢复告警 3-已读已知', times int not null comment '触发次数,即达到告警定义的触发阈值次数要求后才会发告警', gmt_create timestamp default current_timestamp comment 'create time', primary key (id) diff --git a/web-app/src/app/pojo/Alert.ts b/web-app/src/app/pojo/Alert.ts index a84dc7f..bed0855 100644 --- a/web-app/src/app/pojo/Alert.ts +++ b/web-app/src/app/pojo/Alert.ts @@ -3,7 +3,9 @@ export class Alert { target!: string; monitorId!: number; monitorName!: string; + // 告警级别 0:高-emergency-紧急告警-红色 1:中-critical-严重告警-橙色 2:低-warning-警告告警-黄色 priority: number = 2; + // 告警状态: 0-正常告警(未读) 3-已读已知 status!: number; content!: string; times!: number; diff --git a/web-app/src/app/routes/alert/alert-center/alert-center.component.html b/web-app/src/app/routes/alert/alert-center/alert-center.component.html index 3d96648..6e3b768 100644 --- a/web-app/src/app/routes/alert/alert-center/alert-center.component.html +++ b/web-app/src/app/routes/alert/alert-center/alert-center.component.html @@ -13,13 +13,43 @@ - - +
+ + + + + + + + + + + + + + + + + + + +
所属监控 级别 告警内容 + 状态 告警时间 操作 - + {{ data.target }} @@ -65,11 +96,20 @@ {{ data.content }} + + {{ data.status === 0 ? '未读' : '已读' }} + {{ data.gmtCreate }} + + diff --git a/web-app/src/app/routes/alert/alert-center/alert-center.component.ts b/web-app/src/app/routes/alert/alert-center/alert-center.component.ts index 0279009..ec2efad 100644 --- a/web-app/src/app/routes/alert/alert-center/alert-center.component.ts +++ b/web-app/src/app/routes/alert/alert-center/alert-center.component.ts @@ -23,11 +23,40 @@ export class AlertCenterComponent implements OnInit { alerts!: Alert[]; tableLoading: boolean = false; checkedAlertIds = new Set(); + // 搜索过滤相关属性 + filterStatus: number | undefined; + filterPriority: number | undefined; + filterContent: string | undefined; ngOnInit(): void { this.loadAlertsTable(); } + onFilterSearchAlerts() { + this.tableLoading = true; + let filterAlerts$ = this.alertSvc.searchAlerts(this.filterStatus, this.filterPriority, + this.filterContent, this.pageIndex - 1, this.pageSize) + .subscribe(message => { + filterAlerts$.unsubscribe(); + this.tableLoading = false; + this.checkedAll = false; + this.checkedAlertIds.clear(); + if (message.code === 0) { + let page = message.data; + this.alerts = page.content; + this.pageIndex = page.number + 1; + this.total = page.totalElements; + } else { + console.warn(message.msg); + } + }, error => { + this.tableLoading = false; + filterAlerts$.unsubscribe(); + console.error(error.msg); + }); + + } + sync() { this.loadAlertsTable(); } @@ -51,6 +80,7 @@ export class AlertCenterComponent implements OnInit { }, error => { this.tableLoading = false; alertsInit$.unsubscribe(); + console.error(error.msg); }); } @@ -69,6 +99,35 @@ export class AlertCenterComponent implements OnInit { }); } + onMarkReadAlerts() { + if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) { + this.notifySvc.warning("未选中任何待标记项!",""); + return; + } + this.modal.confirm({ + nzTitle: '请确认是否批量标记已读!', + nzOkText: '确定', + nzCancelText: '取消', + nzOkDanger: true, + nzOkType: "primary", + nzOnOk: () => this.updateAlertsStatus(this.checkedAlertIds, 3) + }); + } + onMarkUnReadAlerts() { + if (this.checkedAlertIds == null || this.checkedAlertIds.size === 0) { + this.notifySvc.warning("未选中任何待标记项!",""); + return; + } + this.modal.confirm({ + nzTitle: '请确认是否批量标记未读!', + nzOkText: '确定', + nzCancelText: '取消', + nzOkDanger: true, + nzOkType: "primary", + nzOnOk: () => this.updateAlertsStatus(this.checkedAlertIds, 0) + }); + } + onDeleteOneAlert(alertId: number) { let alerts = new Set(); alerts.add(alertId); @@ -82,6 +141,32 @@ export class AlertCenterComponent implements OnInit { }); } + onMarkReadOneAlert(alertId: number) { + let alerts = new Set(); + alerts.add(alertId); + this.modal.confirm({ + nzTitle: '请确认是否标记已读!', + nzOkText: '确定', + nzCancelText: '取消', + nzOkDanger: true, + nzOkType: "primary", + nzOnOk: () => this.updateAlertsStatus(alerts, 3) + }); + } + + onMarkUnReadOneAlert(alertId: number) { + let alerts = new Set(); + alerts.add(alertId); + this.modal.confirm({ + nzTitle: '请确认是否标记未读!', + nzOkText: '确定', + nzCancelText: '取消', + nzOkDanger: true, + nzOkType: "primary", + nzOnOk: () => this.updateAlertsStatus(alerts, 0) + }); + } + deleteAlerts(alertIds: Set) { this.tableLoading = true; const deleteAlerts$ = this.alertSvc.deleteAlerts(alertIds) @@ -103,6 +188,27 @@ export class AlertCenterComponent implements OnInit { ); } + updateAlertsStatus(alertIds: Set, status: number) { + this.tableLoading = true; + const markAlertsStatus$ = this.alertSvc.applyAlertsStatus(alertIds, status) + .subscribe(message => { + markAlertsStatus$.unsubscribe(); + if (message.code === 0) { + this.notifySvc.success("标记成功!", ""); + this.loadAlertsTable(); + } else { + this.tableLoading = false; + this.notifySvc.error("标记失败!", message.msg); + } + }, + error => { + this.tableLoading = false; + markAlertsStatus$.unsubscribe(); + this.notifySvc.error("标记失败!", error.msg) + } + ); + } + // begin: 列表多选分页逻辑 checkedAll: boolean = false; onAllChecked(checked: boolean) { @@ -126,6 +232,4 @@ export class AlertCenterComponent implements OnInit { this.loadAlertsTable(); } // end: 列表多选分页逻辑 - - } diff --git a/web-app/src/app/service/alert.service.ts b/web-app/src/app/service/alert.service.ts index 1ba2ac1..f507b5b 100644 --- a/web-app/src/app/service/alert.service.ts +++ b/web-app/src/app/service/alert.service.ts @@ -7,6 +7,8 @@ import {Alert} from "../pojo/Alert"; const alerts_uri = '/alerts'; +const alerts_status_uri = '/alerts/status'; + @Injectable({ providedIn: 'root' }) @@ -29,6 +31,31 @@ export class AlertService { return this.http.get>>(alerts_uri, options); } + public searchAlerts(status: number | undefined, priority: number | undefined, content: string | undefined, + pageIndex: number, pageSize: number) : Observable>> { + pageIndex = pageIndex ? pageIndex : 0; + pageSize = pageSize ? pageSize : 8; + // 注意HttpParams是不可变对象 需要保存set后返回的对象为最新对象 + let httpParams = new HttpParams(); + httpParams = httpParams.appendAll({ + 'sort': 'id', + 'order': 'desc', + 'pageIndex': pageIndex, + 'pageSize': pageSize + }); + if (status != undefined && status != 9) { + httpParams = httpParams.append('status', status); + } + if (priority != undefined && priority != 9) { + httpParams = httpParams.append('priority', priority); + } + if (content != undefined && content != '' && content.trim() != '') { + httpParams = httpParams.append('content', content.trim()); + } + const options = { params: httpParams }; + return this.http.get>>(alerts_uri, options); + } + public deleteAlerts(alertIds: Set) : Observable> { let httpParams = new HttpParams(); alertIds.forEach(alertId => { @@ -40,4 +67,15 @@ export class AlertService { return this.http.delete>(alerts_uri, options); } + public applyAlertsStatus(alertIds: Set, status: number) : Observable> { + let httpParams = new HttpParams(); + alertIds.forEach(alertId => { + // 注意HttpParams是不可变对象 需要保存append后返回的对象为最新对象 + // append方法可以叠加同一key, set方法会把key之前的值覆盖只留一个key-value + httpParams = httpParams.append('ids', alertId); + }) + const options = { params: httpParams }; + return this.http.put>(`${alerts_status_uri}/${status}`, null, options); + } + }