[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 @@
|
||||
|
||||
<div nz-row [nzGutter]="24" class="pt-lg">
|
||||
<div nz-col nzXs="24" nzSm="24" nzMd="24" nzLg="18">
|
||||
<!-- <button nz-button (click)="refresh()" nzType="primary">监控分布</button>-->
|
||||
<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>
|
||||
<br/>
|
||||
<div nz-row [nzGutter]="24" style="margin-top: 10px">
|
||||
<div nz-col nzXs="18" nzSm="18" nzMd="18" nzLg="18" nzOffset="1">
|
||||
<div echarts [options]="appsCountEChartOption" theme='default' [autoResize]= 'true' [loading]="appsCountLoading" (chartClick)="onChartClick($event)"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,61 +1,3 @@
|
||||
@import '~@delon/theme/index';
|
||||
: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;
|
||||
}
|
||||
}
|
||||
.demo-chart {
|
||||
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 {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({
|
||||
selector: 'app-dashboard',
|
||||
@@ -8,55 +19,147 @@ import {G2PieClickItem, G2PieComponent, G2PieData} from "@delon/chart/pie";
|
||||
styleUrls: ['./dashboard.component.less'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class DashboardComponent {
|
||||
export class DashboardComponent implements OnInit, OnDestroy {
|
||||
|
||||
@ViewChild('pie', { static: false }) readonly pie!: G2PieComponent;
|
||||
salesPieData: G2PieData[] = [];
|
||||
total = '';
|
||||
constructor(private msg: NzMessageService,
|
||||
private monitorSvc: MonitorService,
|
||||
@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 {
|
||||
this.appsCountLoading = true;
|
||||
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 {
|
||||
const rv = (min: number = 0, max: number = 5000) => Math.floor(Math.random() * (max - min + 1) + min);
|
||||
this.salesPieData = [
|
||||
{
|
||||
x: '应用服务',
|
||||
y: rv(),
|
||||
},
|
||||
{
|
||||
x: '数据库',
|
||||
y: rv(),
|
||||
},
|
||||
{
|
||||
x: '中间件',
|
||||
y: rv(),
|
||||
},
|
||||
{
|
||||
x: '自定义',
|
||||
y: rv(),
|
||||
},
|
||||
{
|
||||
x: '其它',
|
||||
y: rv(),
|
||||
},
|
||||
];
|
||||
this.total = `${this.salesPieData.reduce((pre, now) => now.y + pre, 0).toFixed(2)}`;
|
||||
if (this.pie) {
|
||||
// 等待组件渲染
|
||||
setTimeout(() => this.pie.changeData());
|
||||
let dashboard$ = this.monitorSvc.getAppsMonitorSummary()
|
||||
.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: [
|
||||
{
|
||||
name: '总量',
|
||||
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: '监控总量' },
|
||||
]
|
||||
},
|
||||
{
|
||||
name: '纳管数量分布',
|
||||
type: 'pie',
|
||||
radius: ['45%', '65%'],
|
||||
labelLine: {
|
||||
length: 30
|
||||
},
|
||||
label: {
|
||||
formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}:}{c} {per|{d}%} ',
|
||||
backgroundColor: '#F6F8FC',
|
||||
borderColor: '#8C8D8E',
|
||||
borderWidth: 1,
|
||||
borderRadius: 4,
|
||||
rich: {
|
||||
a: {
|
||||
color: '#6E7079',
|
||||
lineHeight: 22,
|
||||
align: 'center'
|
||||
},
|
||||
hr: {
|
||||
borderColor: '#8C8D8E',
|
||||
width: '100%',
|
||||
borderWidth: 1,
|
||||
height: 0
|
||||
},
|
||||
b: {
|
||||
color: '#4C5058',
|
||||
fontSize: 14,
|
||||
fontWeight: 'bold',
|
||||
lineHeight: 33
|
||||
},
|
||||
per: {
|
||||
color: '#fff',
|
||||
backgroundColor: '#4C5058',
|
||||
padding: [3, 4],
|
||||
borderRadius: 4
|
||||
}
|
||||
}
|
||||
},
|
||||
data: this.appsCountTableData
|
||||
}
|
||||
]
|
||||
};
|
||||
this.cdr.detectChanges();
|
||||
}
|
||||
}, error => {
|
||||
console.error(error);
|
||||
dashboard$.unsubscribe();
|
||||
});
|
||||
}
|
||||
|
||||
onChartClick(click: any) {
|
||||
if (click != undefined) {
|
||||
let app = click.data?.app;
|
||||
if (app != undefined) {
|
||||
this.router.navigate(['/monitors'], { queryParams: { app: app } });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
format(val: number): string {
|
||||
return `${val.toFixed()}`;
|
||||
}
|
||||
|
||||
handleClick(data: G2PieClickItem): void {
|
||||
this.msg.info(`${data.item.x} - ${data.item.y}`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { NgModule, Type } from '@angular/core';
|
||||
import { SharedModule } from '@shared';
|
||||
import {G2PieModule} from "@delon/chart/pie";
|
||||
import {G2WaterWaveModule} from "@delon/chart/water-wave";
|
||||
// dashboard pages
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { RouteRoutingModule } from './routes-routing.module';
|
||||
import {NgxEchartsModule} from "ngx-echarts";
|
||||
// single pages
|
||||
import { CallbackComponent } from './passport/callback.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 { UserRegisterResultComponent } from './passport/register-result/register-result.component';
|
||||
import { UserRegisterComponent } from './passport/register/register.component';
|
||||
import { RouteRoutingModule } from './routes-routing.module';
|
||||
|
||||
const COMPONENTS: Array<Type<void>> = [
|
||||
DashboardComponent,
|
||||
@@ -25,7 +24,7 @@ const COMPONENTS: Array<Type<void>> = [
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, RouteRoutingModule, G2PieModule, G2WaterWaveModule],
|
||||
imports: [SharedModule, RouteRoutingModule, NgxEchartsModule],
|
||||
declarations: COMPONENTS,
|
||||
})
|
||||
export class RoutesModule {}
|
||||
|
||||
@@ -9,6 +9,7 @@ const monitor_uri = "/monitor";
|
||||
const monitors_uri = "/monitors";
|
||||
const detect_monitor_uri = "/monitor/detect"
|
||||
const manage_monitors_uri = "/monitors/manage";
|
||||
const summary_uri = "/summary";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
@@ -86,4 +87,9 @@ export class MonitorService {
|
||||
public getMonitorMetricData(monitorId: number, metric: string) : Observable<Message<any>> {
|
||||
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