From 25bf4256176faa4caef9ba1920b178c82220c1a0 Mon Sep 17 00:00:00 2001 From: tomsun28 Date: Sun, 12 Dec 2021 10:33:27 +0800 Subject: [PATCH] =?UTF-8?q?[web-app]=20=E5=91=8A=E8=AD=A6=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=88=97=E8=A1=A8=E4=BF=A1=E6=81=AF=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web-app/src/app/pojo/AlertDefine.ts | 17 ++ .../alert-center/alert-center.component.html | 1 + .../alert-center.component.spec.ts | 25 +++ .../alert-center/alert-center.component.ts | 16 ++ .../alert-notice/alert-notice.component.html | 1 + .../alert-notice.component.spec.ts | 25 +++ .../alert-notice/alert-notice.component.ts | 16 ++ .../app/routes/alert/alert-routing.module.ts | 19 +++ .../alert-setting.component.html | 98 ++++++++++++ .../alert-setting.component.spec.ts | 25 +++ .../alert-setting/alert-setting.component.ts | 150 ++++++++++++++++++ web-app/src/app/routes/alert/alert.module.ts | 27 ++++ .../monitor-list/monitor-list.component.ts | 10 +- .../src/app/routes/routes-routing.module.ts | 3 +- .../app/service/alert-define.service.spec.ts | 16 ++ .../src/app/service/alert-define.service.ts | 66 ++++++++ web-app/src/assets/tmp/app-data.json | 18 +-- web-app/src/assets/tmp/i18n/zh-CN.json | 5 + 18 files changed, 522 insertions(+), 16 deletions(-) create mode 100644 web-app/src/app/pojo/AlertDefine.ts create mode 100644 web-app/src/app/routes/alert/alert-center/alert-center.component.html create mode 100644 web-app/src/app/routes/alert/alert-center/alert-center.component.spec.ts create mode 100644 web-app/src/app/routes/alert/alert-center/alert-center.component.ts create mode 100644 web-app/src/app/routes/alert/alert-notice/alert-notice.component.html create mode 100644 web-app/src/app/routes/alert/alert-notice/alert-notice.component.spec.ts create mode 100644 web-app/src/app/routes/alert/alert-notice/alert-notice.component.ts create mode 100644 web-app/src/app/routes/alert/alert-routing.module.ts create mode 100644 web-app/src/app/routes/alert/alert-setting/alert-setting.component.html create mode 100644 web-app/src/app/routes/alert/alert-setting/alert-setting.component.spec.ts create mode 100644 web-app/src/app/routes/alert/alert-setting/alert-setting.component.ts create mode 100644 web-app/src/app/routes/alert/alert.module.ts create mode 100644 web-app/src/app/service/alert-define.service.spec.ts create mode 100644 web-app/src/app/service/alert-define.service.ts diff --git a/web-app/src/app/pojo/AlertDefine.ts b/web-app/src/app/pojo/AlertDefine.ts new file mode 100644 index 0000000..a84781d --- /dev/null +++ b/web-app/src/app/pojo/AlertDefine.ts @@ -0,0 +1,17 @@ +export class AlertDefine { + id!: number; + app!: string; + metric!: string; + field!: string; + preset!: boolean; + expr!: string; + // 告警级别 0:高-emergency-紧急告警-红色 1:中-critical-严重告警-橙色 2:低-warning-警告告警-黄色 + priority!: number; + duration!: number; + enable!: boolean; + template!: string; + creator!: string; + modifier!: string; + gmtCreate!: number; + gmtUpdate!: 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 new file mode 100644 index 0000000..b7352da --- /dev/null +++ b/web-app/src/app/routes/alert/alert-center/alert-center.component.html @@ -0,0 +1 @@ +

alert-center works!

diff --git a/web-app/src/app/routes/alert/alert-center/alert-center.component.spec.ts b/web-app/src/app/routes/alert/alert-center/alert-center.component.spec.ts new file mode 100644 index 0000000..ee46e65 --- /dev/null +++ b/web-app/src/app/routes/alert/alert-center/alert-center.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AlertCenterComponent } from './alert-center.component'; + +describe('AlertCenterComponent', () => { + let component: AlertCenterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AlertCenterComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AlertCenterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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 new file mode 100644 index 0000000..f38af04 --- /dev/null +++ b/web-app/src/app/routes/alert/alert-center/alert-center.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-alert-center', + templateUrl: './alert-center.component.html', + styles: [ + ] +}) +export class AlertCenterComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/web-app/src/app/routes/alert/alert-notice/alert-notice.component.html b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.html new file mode 100644 index 0000000..7f7375d --- /dev/null +++ b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.html @@ -0,0 +1 @@ +

alert-notice works!

diff --git a/web-app/src/app/routes/alert/alert-notice/alert-notice.component.spec.ts b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.spec.ts new file mode 100644 index 0000000..b1bc346 --- /dev/null +++ b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AlertNoticeComponent } from './alert-notice.component'; + +describe('AlertNoticeComponent', () => { + let component: AlertNoticeComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AlertNoticeComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AlertNoticeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web-app/src/app/routes/alert/alert-notice/alert-notice.component.ts b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.ts new file mode 100644 index 0000000..4a9661f --- /dev/null +++ b/web-app/src/app/routes/alert/alert-notice/alert-notice.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-alert-notice', + templateUrl: './alert-notice.component.html', + styles: [ + ] +}) +export class AlertNoticeComponent implements OnInit { + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/web-app/src/app/routes/alert/alert-routing.module.ts b/web-app/src/app/routes/alert/alert-routing.module.ts new file mode 100644 index 0000000..e0ca76e --- /dev/null +++ b/web-app/src/app/routes/alert/alert-routing.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import {AlertCenterComponent} from "./alert-center/alert-center.component"; +import {AlertSettingComponent} from "./alert-setting/alert-setting.component"; +import {AlertNoticeComponent} from "./alert-notice/alert-notice.component"; + +const routes: Routes = [ + { path: '', component: AlertCenterComponent }, + { path: 'center', component: AlertCenterComponent }, + { path: 'setting', component: AlertSettingComponent }, + { path: 'notice', component: AlertNoticeComponent }, + { path: '**', component: AlertCenterComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AlertRoutingModule { } diff --git a/web-app/src/app/routes/alert/alert-setting/alert-setting.component.html b/web-app/src/app/routes/alert/alert-setting/alert-setting.component.html new file mode 100644 index 0000000..804a13c --- /dev/null +++ b/web-app/src/app/routes/alert/alert-setting/alert-setting.component.html @@ -0,0 +1,98 @@ + + + + + + + + + + 告警阈值配置 + + + + + + + + + + + + + 指标对象 + 阈值触发表达式 + 告警级别 + 持续时间 + 通知模版 + 预置默认 + 最新修改时间 + 操作 + + + + + + + {{ data.app + '.' + data.metric + '.' + data.field }} + + + {{ data.expr}} + + + + + 紧急告警 + + + + 严重告警 + + + + 警告告警 + + + {{ data.duration }} + {{ data.template }} + + + + + + + + + {{ data.gmtUpdate? data.gmtUpdate : data.gmtCreate }} + + + + + + + + + + 总量 {{ total }} + diff --git a/web-app/src/app/routes/alert/alert-setting/alert-setting.component.spec.ts b/web-app/src/app/routes/alert/alert-setting/alert-setting.component.spec.ts new file mode 100644 index 0000000..d0c7903 --- /dev/null +++ b/web-app/src/app/routes/alert/alert-setting/alert-setting.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AlertSettingComponent } from './alert-setting.component'; + +describe('AlertSettingComponent', () => { + let component: AlertSettingComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AlertSettingComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AlertSettingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/web-app/src/app/routes/alert/alert-setting/alert-setting.component.ts b/web-app/src/app/routes/alert/alert-setting/alert-setting.component.ts new file mode 100644 index 0000000..143700f --- /dev/null +++ b/web-app/src/app/routes/alert/alert-setting/alert-setting.component.ts @@ -0,0 +1,150 @@ +import { Component, OnInit } from '@angular/core'; +import {NzTableQueryParams} from "ng-zorro-antd/table"; +import {ActivatedRoute, Router} from "@angular/router"; +import {NzModalService} from "ng-zorro-antd/modal"; +import {NzNotificationService} from "ng-zorro-antd/notification"; +import {NzMessageService} from "ng-zorro-antd/message"; +import {AlertDefineService} from "../../../service/alert-define.service"; +import {AlertDefine} from "../../../pojo/AlertDefine"; + +@Component({ + selector: 'app-alert-setting', + templateUrl: './alert-setting.component.html', + styles: [ + ] +}) +export class AlertSettingComponent implements OnInit { + + constructor(private route: ActivatedRoute, + private router: Router, + private modal: NzModalService, + private notifySvc: NzNotificationService, + private msg: NzMessageService, + private alertDefineSvc: AlertDefineService) { } + + pageIndex: number = 1; + pageSize: number = 8; + total: number = 0; + defines!: AlertDefine[]; + tableLoading: boolean = true; + checkedDefineIds = new Set(); + + ngOnInit(): void { + this.loadAlertDefineTable(); + } + + loadAlertDefineTable() { + this.tableLoading = true; + let alertDefineInit$ = this.alertDefineSvc.getAlertDefines(this.pageIndex - 1, this.pageSize) + .subscribe(message => { + this.tableLoading = false; + this.checkedAll = false; + this.checkedDefineIds.clear(); + if (message.code === 0) { + let page = message.data; + this.defines = page.content; + this.pageIndex = page.number + 1; + this.total = page.totalElements; + } else { + console.warn(message.msg); + } + alertDefineInit$.unsubscribe(); + }, error => { + this.tableLoading = false; + alertDefineInit$.unsubscribe(); + }); + } + + onNewAlertDefine() { + + } + + onEditAlertDefine() { + + } + + onDeleteAlertDefines() { + if (this.checkedDefineIds == null || this.checkedDefineIds.size === 0) { + this.notifySvc.warning("未选中任何待删除项!",""); + return; + } + this.modal.confirm({ + nzTitle: '请确认是否批量删除!', + nzOkText: '确定', + nzCancelText: '取消', + nzOkDanger: true, + nzOkType: "primary", + nzOnOk: () => this.deleteAlertDefines(this.checkedDefineIds) + }); + } + + onDeleteOneAlertDefine(alertDefineId: number) { + let defineIds = new Set(); + defineIds.add(alertDefineId); + this.modal.confirm({ + nzTitle: '请确认是否删除!', + nzOkText: '确定', + nzCancelText: '取消', + nzOkDanger: true, + nzOkType: "primary", + nzOnOk: () => this.deleteAlertDefines(defineIds) + }); + } + + onEditOneAlertDefine(alertDefineId: number) { + + } + + + deleteAlertDefines(defineIds: Set) { + if (defineIds == null || defineIds.size == 0) { + this.notifySvc.warning("未选中任何待删除项!",""); + return; + } + this.tableLoading = true; + const deleteDefines$ = this.alertDefineSvc.deleteAlertDefines(defineIds) + .subscribe(message => { + deleteDefines$.unsubscribe(); + if (message.code === 0) { + this.notifySvc.success("删除成功!", ""); + this.loadAlertDefineTable(); + } else { + this.tableLoading = false; + this.notifySvc.error("删除失败!", message.msg); + } + }, error => { + this.tableLoading = false; + deleteDefines$.unsubscribe(); + this.notifySvc.error("删除失败!", error.msg) + }) + } + + // begin: 列表多选逻辑 + checkedAll: boolean = false; + onAllChecked(checked: boolean) { + if (checked) { + this.defines.forEach(monitor => this.checkedDefineIds.add(monitor.id)); + } else { + this.checkedDefineIds.clear(); + } + } + onItemChecked(monitorId: number, checked: boolean) { + if (checked) { + this.checkedDefineIds.add(monitorId); + } else { + this.checkedDefineIds.delete(monitorId); + } + } + // end: 列表多选逻辑 + + /** + * 分页回调 + * @param params 页码信息 + */ + onTablePageChange(params: NzTableQueryParams) { + const { pageSize, pageIndex, sort, filter } = params; + this.pageIndex = pageIndex; + this.pageSize = pageSize; + // this.loadMonitorTable(); + } +} diff --git a/web-app/src/app/routes/alert/alert.module.ts b/web-app/src/app/routes/alert/alert.module.ts new file mode 100644 index 0000000..1b92db1 --- /dev/null +++ b/web-app/src/app/routes/alert/alert.module.ts @@ -0,0 +1,27 @@ +import { NgModule, Type } from '@angular/core'; +import { SharedModule } from '@shared'; +import { AlertRoutingModule } from './alert-routing.module'; +import {NzBreadCrumbModule} from "ng-zorro-antd/breadcrumb"; +import {NzDividerModule} from "ng-zorro-antd/divider"; +import {AlertCenterComponent} from "./alert-center/alert-center.component"; +import {AlertSettingComponent} from "./alert-setting/alert-setting.component"; +import {AlertNoticeComponent} from "./alert-notice/alert-notice.component"; +import {NzTagModule} from "ng-zorro-antd/tag"; + +const COMPONENTS: Type[] = [ + AlertCenterComponent, + AlertSettingComponent, + AlertNoticeComponent +]; + +@NgModule({ + imports: [ + SharedModule, + AlertRoutingModule, + NzDividerModule, + NzBreadCrumbModule, + NzTagModule, + ], + declarations: COMPONENTS, +}) +export class AlertModule { } diff --git a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts index d7dc7db..a1c13a4 100644 --- a/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts +++ b/web-app/src/app/routes/monitor/monitor-list/monitor-list.component.ts @@ -2,7 +2,6 @@ import { Component, OnInit } from '@angular/core'; import {ActivatedRoute, Router} from "@angular/router"; import {MonitorService} from "../../../service/monitor.service"; import {Monitor} from "../../../pojo/Monitor"; -import {Page} from "../../../pojo/Page"; import {NzModalService} from "ng-zorro-antd/modal"; import {NzNotificationService} from "ng-zorro-antd/notification"; import {NzMessageService} from "ng-zorro-antd/message"; @@ -28,7 +27,6 @@ export class MonitorListComponent implements OnInit { pageSize: number = 8; total: number = 0; monitors!: Monitor[]; - pageMonitors!: Page; tableLoading: boolean = true; checkedMonitorIds = new Set(); @@ -51,10 +49,10 @@ export class MonitorListComponent implements OnInit { this.checkedAll = false; this.checkedMonitorIds.clear(); if (message.code === 0) { - this.pageMonitors = message.data; - this.monitors = this.pageMonitors.content; - this.pageIndex = this.pageMonitors.number + 1; - this.total = this.pageMonitors.totalElements; + let page = message.data; + this.monitors = page.content; + this.pageIndex = page.number + 1; + this.total = page.totalElements; } else { console.warn(message.msg); } diff --git a/web-app/src/app/routes/routes-routing.module.ts b/web-app/src/app/routes/routes-routing.module.ts index 6c15e87..13c0610 100644 --- a/web-app/src/app/routes/routes-routing.module.ts +++ b/web-app/src/app/routes/routes-routing.module.ts @@ -26,7 +26,8 @@ const routes: Routes = [ { path: '', redirectTo: 'dashboard', pathMatch: 'full'}, { path: 'dashboard', component: DashboardComponent, data: { title: '仪表盘' } }, { path: 'exception', loadChildren: () => import('./exception/exception.module').then(m => m.ExceptionModule) }, - { path: 'monitors', loadChildren: () => import('./monitor/monitor.module').then((m) => m.MonitorModule) },] + { path: 'monitors', loadChildren: () => import('./monitor/monitor.module').then((m) => m.MonitorModule) }, + { path: 'alert', loadChildren: () => import('./alert/alert.module').then((m) => m.AlertModule) },] }, // 空白布局 // { diff --git a/web-app/src/app/service/alert-define.service.spec.ts b/web-app/src/app/service/alert-define.service.spec.ts new file mode 100644 index 0000000..343a623 --- /dev/null +++ b/web-app/src/app/service/alert-define.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AlertDefineService } from './alert-define.service'; + +describe('AlertDefineService', () => { + let service: AlertDefineService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AlertDefineService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/web-app/src/app/service/alert-define.service.ts b/web-app/src/app/service/alert-define.service.ts new file mode 100644 index 0000000..729aa73 --- /dev/null +++ b/web-app/src/app/service/alert-define.service.ts @@ -0,0 +1,66 @@ +import { Injectable } from '@angular/core'; +import {HttpClient, HttpParams} from "@angular/common/http"; +import {Observable} from "rxjs"; +import {Message} from "../pojo/Message"; +import {Page} from "../pojo/Page"; +import {AlertDefine} from "../pojo/AlertDefine"; + +const alert_define_uri = "/alert/define"; +const alert_defines_uri = "/alert/defines"; + +@Injectable({ + providedIn: 'root' +}) +export class AlertDefineService { + + constructor(private http : HttpClient) { } + + public newAlertDefine(body: AlertDefine) : Observable> { + return this.http.post>(alert_define_uri, body); + } + + public editAlertDefine(body: AlertDefine) : Observable> { + return this.http.put>(alert_define_uri, body); + } + + public getAlertDefine(alertDefineId: number) : Observable> { + return this.http.get>(`${alert_define_uri}/${alertDefineId}`); + } + + /** + * 应用告警定义与监控关联 + * @param alertDefineId 告警定义ID + * @param monitorMap 关联的监控ID-监控名称 + */ + public applyAlertDefineMonitorsBind(alertDefineId: number, + monitorMap: Record): Observable> { + return this.http.post>(`${alert_define_uri}/${alertDefineId}/monitors`, monitorMap); + } + + public deleteAlertDefines(alertDefineIds: Set) : Observable> { + let httpParams = new HttpParams(); + alertDefineIds.forEach(alertDefineId => { + // 注意HttpParams是不可变对象 需要保存append后返回的对象为最新对象 + // append方法可以叠加同一key, set方法会把key之前的值覆盖只留一个key-value + httpParams = httpParams.append('ids', alertDefineId); + }) + const options = { params: httpParams }; + return this.http.delete>(alert_defines_uri, options); + } + + public getAlertDefines(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 + }); + const options = { params: httpParams }; + return this.http.get>>(alert_defines_uri, options); + } + +} diff --git a/web-app/src/assets/tmp/app-data.json b/web-app/src/assets/tmp/app-data.json index 6ee4dff..bc93782 100644 --- a/web-app/src/assets/tmp/app-data.json +++ b/web-app/src/assets/tmp/app-data.json @@ -90,38 +90,38 @@ "text": "告警中心", "i18n": "menu.alert.center", "icon": "anticon-alert", - "link": "/style/typography" + "link": "/alert/center" }, { "text": "告警配置", "i18n": "menu.alert.setting", - "icon": "anticon-setting", - "link": "/style/typography" + "icon": "anticon-bulb", + "link": "/alert/setting" }, { "text": "告警转发", "i18n": "menu.alert.dispatch", "icon": "anticon-notification", - "link": "/style/typography" + "link": "/alert/notice" } ] }, { "text": "More", - "i18n": "menu.more", + "i18n": "menu.extras", "group": true, "hideInBreadcrumb": true, "children": [ { "text": "Help Center", - "link": "/extras/helpcenter", - "i18n": "menu.extras.helpcenter", + "link": "/extras/help", + "i18n": "menu.extras.help", "icon": "anticon-link" }, { "text": "Settings", - "link": "/extras/settings", - "i18n": "menu.extras.settings", + "link": "/extras/setting", + "i18n": "menu.extras.setting", "icon": "anticon-setting" } ] diff --git a/web-app/src/assets/tmp/i18n/zh-CN.json b/web-app/src/assets/tmp/i18n/zh-CN.json index 9f345e4..aed2726 100644 --- a/web-app/src/assets/tmp/i18n/zh-CN.json +++ b/web-app/src/assets/tmp/i18n/zh-CN.json @@ -27,6 +27,11 @@ "setting": "告警配置", "dispatch": "告警转发" }, + "extras": { + "": "更多", + "help": "帮助中心", + "setting": "设置" + }, "more": "更多" }, "monitor": {