[web-app] 仪表盘-监控总览
This commit is contained in:
134
web-app/src/app/routes/dashboard/ColorTheme.ts
Normal file
134
web-app/src/app/routes/dashboard/ColorTheme.ts
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
import {ThemeOption} from "ngx-echarts";
|
||||||
|
|
||||||
|
export const CoolTheme: ThemeOption = {
|
||||||
|
color: [
|
||||||
|
'#b21ab4',
|
||||||
|
'#6f0099',
|
||||||
|
'#2a2073',
|
||||||
|
'#0b5ea8',
|
||||||
|
'#17aecc',
|
||||||
|
'#b3b3ff',
|
||||||
|
'#eb99ff',
|
||||||
|
'#fae6ff',
|
||||||
|
'#e6f2ff',
|
||||||
|
'#eeeeee'
|
||||||
|
],
|
||||||
|
|
||||||
|
title: {
|
||||||
|
textStyle: {
|
||||||
|
fontWeight: 'normal',
|
||||||
|
color: '#00aecd',
|
||||||
|
center: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
visualMap: {
|
||||||
|
color: ['#00aecd', '#a2d4e6']
|
||||||
|
},
|
||||||
|
|
||||||
|
toolbox: {
|
||||||
|
color: ['#00aecd', '#00aecd', '#00aecd', '#00aecd']
|
||||||
|
},
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||||
|
axisPointer: {
|
||||||
|
// Axis indicator, coordinate trigger effective
|
||||||
|
type: 'line', // The default is a straight line: 'line' | 'shadow'
|
||||||
|
lineStyle: {
|
||||||
|
// Straight line indicator style settings
|
||||||
|
color: '#00aecd',
|
||||||
|
type: 'dashed'
|
||||||
|
},
|
||||||
|
crossStyle: {
|
||||||
|
color: '#00aecd'
|
||||||
|
},
|
||||||
|
shadowStyle: {
|
||||||
|
// Shadow indicator style settings
|
||||||
|
color: 'rgba(200,200,200,0.3)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Area scaling controller
|
||||||
|
dataZoom: {
|
||||||
|
dataBackgroundColor: '#eee', // Data background color
|
||||||
|
fillerColor: 'rgba(144,197,237,0.2)', // Fill the color
|
||||||
|
handleColor: '#00aecd' // Handle color
|
||||||
|
},
|
||||||
|
|
||||||
|
timeline: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#00aecd'
|
||||||
|
},
|
||||||
|
controlStyle: {
|
||||||
|
color: '#00aecd',
|
||||||
|
borderColor: '00aecd'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
candlestick: {
|
||||||
|
itemStyle: {
|
||||||
|
color: '#00aecd',
|
||||||
|
color0: '#a2d4e6'
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
width: 1,
|
||||||
|
color: '#00aecd',
|
||||||
|
color0: '#a2d4e6'
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: '#b21ab4',
|
||||||
|
color0: '#0b5ea8'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
chord: {
|
||||||
|
padding: 4,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#b21ab4',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: 'rgba(128, 128, 128, 0.5)'
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(128, 128, 128, 0.5)'
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: '#0b5ea8'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
graph: {
|
||||||
|
itemStyle: {
|
||||||
|
color: '#b21ab4'
|
||||||
|
},
|
||||||
|
linkStyle: {
|
||||||
|
color: '#2a2073'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
map: {
|
||||||
|
itemStyle: {
|
||||||
|
color: '#c12e34'
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: '#ddd'
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
color: '#c12e34'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
gauge: {
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: [
|
||||||
|
[0.2, '#dddddd'],
|
||||||
|
[0.8, '#00aecd'],
|
||||||
|
[1, '#f5ccff']
|
||||||
|
],
|
||||||
|
width: 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,27 +1,6 @@
|
|||||||
|
<br/>
|
||||||
<div nz-row [nzGutter]="24" class="pt-lg">
|
<div nz-row [nzGutter]="24" style="margin-top: 10px">
|
||||||
<div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="18">
|
<div nz-col nzXs="18" nzSm="18" nzMd="18" nzLg="18" nzOffset="1">
|
||||||
<!-- <button nz-button (click)="refresh()" nzType="primary">监控分布</button>-->
|
<div echarts [options]="appsCountEChartOption" theme='default' [autoResize]= 'true' [loading]="appsCountLoading" (chartClick)="onChartClick($event)"></div>
|
||||||
<nz-card nzTitle="在网监控" class="pie-card">
|
|
||||||
<g2-pie
|
|
||||||
#pie
|
|
||||||
[hasLegend]="true"
|
|
||||||
title="在网监控数量"
|
|
||||||
subTitle="监控数量"
|
|
||||||
[total]="433"
|
|
||||||
[valueFormat]="format"
|
|
||||||
[data]="salesPieData"
|
|
||||||
height="294"
|
|
||||||
repaint="false"
|
|
||||||
(clickItem)="handleClick($event)"
|
|
||||||
></g2-pie>
|
|
||||||
</nz-card>
|
|
||||||
</div>
|
|
||||||
<div nz-col nzXs="24" nzSm="24" nzMd="12" nzLg="6">
|
|
||||||
<nz-card nzTitle="监控资源使用情况" class="pie-card">
|
|
||||||
<div class="text-center">
|
|
||||||
<g2-water-wave [title]="'已监控License占比'" [percent]="34" [height]="161"></g2-water-wave>
|
|
||||||
</div>
|
|
||||||
</nz-card>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,61 +1,3 @@
|
|||||||
@import '~@delon/theme/index';
|
.demo-chart {
|
||||||
:host ::ng-deep {
|
|
||||||
.map-chart {
|
|
||||||
height: 457px;
|
|
||||||
padding-top: 24px;
|
|
||||||
text-align: center;
|
|
||||||
img {
|
|
||||||
display: inline-block;
|
|
||||||
max-width: 100%;
|
|
||||||
max-height: 437px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.pie-card {
|
|
||||||
.pie-stat {
|
|
||||||
font-size: 24px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.active-chart {
|
|
||||||
position: relative;
|
|
||||||
g2-mini-area {
|
|
||||||
margin-top: 32px;
|
|
||||||
}
|
|
||||||
.active-grid {
|
|
||||||
p {
|
|
||||||
position: absolute;
|
|
||||||
top: 80px;
|
|
||||||
width: 100%;
|
|
||||||
padding-bottom: 4px;
|
|
||||||
border-bottom: 1px dashed #e9e9e9;
|
|
||||||
}
|
|
||||||
p:last-child {
|
|
||||||
top: 115px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.active-legend {
|
|
||||||
position: relative;
|
|
||||||
height: 20px;
|
|
||||||
margin-top: 8px;
|
|
||||||
font-size: 0;
|
|
||||||
line-height: 20px;
|
|
||||||
span {
|
|
||||||
display: inline-block;
|
|
||||||
width: 33.33%;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
span:first-child {
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
span:last-child {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: @screen-lg) {
|
|
||||||
.map-chart {
|
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,17 @@
|
|||||||
import {ChangeDetectionStrategy, Component, ViewChild} from '@angular/core';
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
ChangeDetectorRef,
|
||||||
|
Component,
|
||||||
|
Inject,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit
|
||||||
|
} from '@angular/core';
|
||||||
import {NzMessageService} from "ng-zorro-antd/message";
|
import {NzMessageService} from "ng-zorro-antd/message";
|
||||||
import {G2PieClickItem, G2PieComponent, G2PieData} from "@delon/chart/pie";
|
import {MonitorService} from "../../service/monitor.service";
|
||||||
|
import { EChartsOption } from 'echarts';
|
||||||
|
import {I18NService} from "@core";
|
||||||
|
import {ALAIN_I18N_TOKEN} from "@delon/theme";
|
||||||
|
import {Router} from "@angular/router";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dashboard',
|
selector: 'app-dashboard',
|
||||||
@@ -8,55 +19,147 @@ import {G2PieClickItem, G2PieComponent, G2PieData} from "@delon/chart/pie";
|
|||||||
styleUrls: ['./dashboard.component.less'],
|
styleUrls: ['./dashboard.component.less'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class DashboardComponent {
|
export class DashboardComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
@ViewChild('pie', { static: false }) readonly pie!: G2PieComponent;
|
constructor(private msg: NzMessageService,
|
||||||
salesPieData: G2PieData[] = [];
|
private monitorSvc: MonitorService,
|
||||||
total = '';
|
@Inject(ALAIN_I18N_TOKEN) private i18nSvc: I18NService,
|
||||||
|
private router: Router,
|
||||||
|
private cdr: ChangeDetectorRef){}
|
||||||
|
|
||||||
constructor(private msg: NzMessageService){}
|
interval$!: number;
|
||||||
|
appsCountLoading: boolean = true;
|
||||||
|
appsCountTableData: any[] = [];
|
||||||
|
appsCountEChartOption!: EChartsOption;
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.appsCountLoading = true;
|
||||||
this.refresh();
|
this.refresh();
|
||||||
|
this.appsCountLoading = false;
|
||||||
|
// https://stackoverflow.com/questions/43908009/why-is-setinterval-in-an-angular-service-only-firing-one-time
|
||||||
|
this.interval$ = setInterval(this.refresh.bind(this), 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
clearInterval(this.interval$);
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh(): void {
|
refresh(): void {
|
||||||
const rv = (min: number = 0, max: number = 5000) => Math.floor(Math.random() * (max - min + 1) + min);
|
let dashboard$ = this.monitorSvc.getAppsMonitorSummary()
|
||||||
this.salesPieData = [
|
.subscribe(message => {
|
||||||
|
dashboard$.unsubscribe();
|
||||||
|
if (message.code === 0) {
|
||||||
|
// {app:'linux',size: 12}
|
||||||
|
let apps: any[] = message.data.apps;
|
||||||
|
this.appsCountTableData = [];
|
||||||
|
let total = 0;
|
||||||
|
apps.forEach(app => {
|
||||||
|
let appName = this.i18nSvc.fanyi('monitor.app.' + app.app);
|
||||||
|
this.appsCountTableData.push({
|
||||||
|
// 自定义属性
|
||||||
|
app: app.app,
|
||||||
|
// 默认属性
|
||||||
|
name: appName,
|
||||||
|
value: app.size
|
||||||
|
});
|
||||||
|
total = total + app.size? app.size : 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
this.appsCountEChartOption = {
|
||||||
|
title: {
|
||||||
|
text: '监控总览',
|
||||||
|
subtext: '监控类型纳管数量分布',
|
||||||
|
left: 'center'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: '{a} <br/>{b} : {c}个监控 占比({d}%)'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
itemWidth: 80,
|
||||||
|
itemHeight: 20,
|
||||||
|
right: 0,
|
||||||
|
orient: 'vertical'
|
||||||
|
},
|
||||||
|
calculable: true,
|
||||||
|
series: [
|
||||||
{
|
{
|
||||||
x: '应用服务',
|
name: '总量',
|
||||||
y: rv(),
|
type: 'pie',
|
||||||
|
selectedMode: 'single',
|
||||||
|
color: '#722ED1',
|
||||||
|
radius: [0, '30%'],
|
||||||
|
label: {
|
||||||
|
position: 'center',
|
||||||
|
fontSize: 15,
|
||||||
|
color: '#ffffff',
|
||||||
|
fontStyle: 'oblique',
|
||||||
|
formatter: '{a}:{c}',
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
data: [
|
||||||
|
{ value: total, name: '监控总量' },
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: '数据库',
|
name: '纳管数量分布',
|
||||||
y: rv(),
|
type: 'pie',
|
||||||
|
radius: ['45%', '65%'],
|
||||||
|
labelLine: {
|
||||||
|
length: 30
|
||||||
},
|
},
|
||||||
{
|
label: {
|
||||||
x: '中间件',
|
formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}:}{c} {per|{d}%} ',
|
||||||
y: rv(),
|
backgroundColor: '#F6F8FC',
|
||||||
|
borderColor: '#8C8D8E',
|
||||||
|
borderWidth: 1,
|
||||||
|
borderRadius: 4,
|
||||||
|
rich: {
|
||||||
|
a: {
|
||||||
|
color: '#6E7079',
|
||||||
|
lineHeight: 22,
|
||||||
|
align: 'center'
|
||||||
},
|
},
|
||||||
{
|
hr: {
|
||||||
x: '自定义',
|
borderColor: '#8C8D8E',
|
||||||
y: rv(),
|
width: '100%',
|
||||||
|
borderWidth: 1,
|
||||||
|
height: 0
|
||||||
},
|
},
|
||||||
{
|
b: {
|
||||||
x: '其它',
|
color: '#4C5058',
|
||||||
y: rv(),
|
fontSize: 14,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
lineHeight: 33
|
||||||
},
|
},
|
||||||
];
|
per: {
|
||||||
this.total = `${this.salesPieData.reduce((pre, now) => now.y + pre, 0).toFixed(2)}`;
|
color: '#fff',
|
||||||
if (this.pie) {
|
backgroundColor: '#4C5058',
|
||||||
// 等待组件渲染
|
padding: [3, 4],
|
||||||
setTimeout(() => this.pie.changeData());
|
borderRadius: 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
data: this.appsCountTableData
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
this.cdr.detectChanges();
|
||||||
|
}
|
||||||
|
}, error => {
|
||||||
|
console.error(error);
|
||||||
|
dashboard$.unsubscribe();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
format(val: number): string {
|
onChartClick(click: any) {
|
||||||
return `${val.toFixed()}`;
|
if (click != undefined) {
|
||||||
|
let app = click.data?.app;
|
||||||
|
if (app != undefined) {
|
||||||
|
this.router.navigate(['/monitors'], { queryParams: { app: app } });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick(data: G2PieClickItem): void {
|
|
||||||
this.msg.info(`${data.item.x} - ${data.item.y}`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { NgModule, Type } from '@angular/core';
|
import { NgModule, Type } from '@angular/core';
|
||||||
import { SharedModule } from '@shared';
|
import { SharedModule } from '@shared';
|
||||||
import {G2PieModule} from "@delon/chart/pie";
|
|
||||||
import {G2WaterWaveModule} from "@delon/chart/water-wave";
|
|
||||||
// dashboard pages
|
// dashboard pages
|
||||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||||
|
import { RouteRoutingModule } from './routes-routing.module';
|
||||||
|
import {NgxEchartsModule} from "ngx-echarts";
|
||||||
// single pages
|
// single pages
|
||||||
import { CallbackComponent } from './passport/callback.component';
|
import { CallbackComponent } from './passport/callback.component';
|
||||||
import { UserLockComponent } from './passport/lock/lock.component';
|
import { UserLockComponent } from './passport/lock/lock.component';
|
||||||
@@ -11,7 +11,6 @@ import { UserLockComponent } from './passport/lock/lock.component';
|
|||||||
import { UserLoginComponent } from './passport/login/login.component';
|
import { UserLoginComponent } from './passport/login/login.component';
|
||||||
import { UserRegisterResultComponent } from './passport/register-result/register-result.component';
|
import { UserRegisterResultComponent } from './passport/register-result/register-result.component';
|
||||||
import { UserRegisterComponent } from './passport/register/register.component';
|
import { UserRegisterComponent } from './passport/register/register.component';
|
||||||
import { RouteRoutingModule } from './routes-routing.module';
|
|
||||||
|
|
||||||
const COMPONENTS: Array<Type<void>> = [
|
const COMPONENTS: Array<Type<void>> = [
|
||||||
DashboardComponent,
|
DashboardComponent,
|
||||||
@@ -25,7 +24,7 @@ const COMPONENTS: Array<Type<void>> = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [SharedModule, RouteRoutingModule, G2PieModule, G2WaterWaveModule],
|
imports: [SharedModule, RouteRoutingModule, NgxEchartsModule],
|
||||||
declarations: COMPONENTS,
|
declarations: COMPONENTS,
|
||||||
})
|
})
|
||||||
export class RoutesModule {}
|
export class RoutesModule {}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ const monitor_uri = "/monitor";
|
|||||||
const monitors_uri = "/monitors";
|
const monitors_uri = "/monitors";
|
||||||
const detect_monitor_uri = "/monitor/detect"
|
const detect_monitor_uri = "/monitor/detect"
|
||||||
const manage_monitors_uri = "/monitors/manage";
|
const manage_monitors_uri = "/monitors/manage";
|
||||||
|
const summary_uri = "/summary";
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root'
|
providedIn: 'root'
|
||||||
@@ -86,4 +87,9 @@ export class MonitorService {
|
|||||||
public getMonitorMetricData(monitorId: number, metric: string) : Observable<Message<any>> {
|
public getMonitorMetricData(monitorId: number, metric: string) : Observable<Message<any>> {
|
||||||
return this.http.get<Message<any>>(`/monitors/${monitorId}/metrics/${metric}`);
|
return this.http.get<Message<any>>(`/monitors/${monitorId}/metrics/${metric}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAppsMonitorSummary() : Observable<Message<any>> {
|
||||||
|
return this.http.get<Message<any>>(summary_uri);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user