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": {