feat: 监控前端界面显示

This commit is contained in:
ssongliu 2022-09-06 18:48:14 +08:00
parent 4ba55298b4
commit 7a42e34c2b
15 changed files with 674 additions and 117 deletions

View file

@ -1,6 +1,6 @@
system:
port: 9999
db_type: mysql
db_type: sqlite
level: debug
jwt:

View file

@ -1,11 +1,15 @@
package v1
import (
"time"
"github.com/1Panel-dev/1Panel/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/app/dto"
"github.com/1Panel-dev/1Panel/app/model"
"github.com/1Panel-dev/1Panel/constant"
"github.com/1Panel-dev/1Panel/global"
"github.com/gin-gonic/gin"
"github.com/shirou/gopsutil/net"
)
func (b *BaseApi) LoadMonitor(c *gin.Context) {
@ -18,7 +22,71 @@ func (b *BaseApi) LoadMonitor(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if global.CONF.System.DbType == "sqlite" {
req.StartTime = req.StartTime.Add(8 * time.Hour)
req.EndTime = req.EndTime.Add(8 * time.Hour)
}
// stampStart := req.StartTime.Unix()
// stampEnd := req.EndTime.Unix()
var backdatas []dto.MonitorData
if req.Param == "all" || req.Param == "cpu" || req.Param == "memory" || req.Param == "load" {
var bases []model.MonitorBase
if err := global.DB.
Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
var itemData dto.MonitorData
itemData.Param = "base"
for _, base := range bases {
itemData.Date = append(itemData.Date, base.CreatedAt)
itemData.Value = append(itemData.Value, base)
}
backdatas = append(backdatas, itemData)
}
if req.Param == "all" || req.Param == "io" {
var bases []model.MonitorIO
if err := global.DB.
Where("created_at > ? AND created_at < ?", req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
var itemData dto.MonitorData
itemData.Param = "io"
for _, base := range bases {
itemData.Date = append(itemData.Date, base.CreatedAt)
itemData.Value = append(itemData.Value, base)
}
backdatas = append(backdatas, itemData)
}
if req.Param == "all" || req.Param == "network" {
var bases []model.MonitorNetwork
if err := global.DB.
Where("name = ? AND created_at > ? AND created_at < ?", req.Info, req.StartTime, req.EndTime).
Find(&bases).Error; err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
var itemData dto.MonitorData
itemData.Param = "network"
for _, base := range bases {
itemData.Date = append(itemData.Date, base.CreatedAt)
itemData.Value = append(itemData.Value, base)
}
backdatas = append(backdatas, itemData)
}
helper.SuccessWithData(c, backdatas)
}
func (b *BaseApi) GetNetworkOptions(c *gin.Context) {
netStat, _ := net.IOCounters(true)
var options []string
for _, net := range netStat {
options = append(options, net.Name)
}
helper.SuccessWithData(c, options)
}

View file

@ -1,47 +0,0 @@
package v1
import (
"fmt"
"testing"
"time"
"github.com/shirou/gopsutil/cpu"
"github.com/shirou/gopsutil/disk"
"github.com/shirou/gopsutil/load"
"github.com/shirou/gopsutil/mem"
"github.com/shirou/gopsutil/net"
)
func TestMonito(t *testing.T) {
totalPercent, _ := cpu.Percent(3*time.Second, false) // 总 cpu 使用
perPercents, _ := cpu.Percent(3*time.Second, true) // 各 cpu 使用
fmt.Println("================totalPercent============", totalPercent)
fmt.Println("================perPercents=============", perPercents)
info, _ := load.Avg()
info2, _ := load.Misc()
fmt.Printf("load: \n loadxx: %v load1: %v, load5: %v, load15: %v \n\n", info2, info.Load1, info.Load5, info.Load15)
memory, _ := mem.VirtualMemory()
fmt.Printf("memory: \n memory used: %v, use persent: %v \n\n", memory.Used, memory.UsedPercent)
diskPart, _ := disk.Partitions(true)
// fmt.Println("================disk=============", diskPart)
for _, part := range diskPart {
diskInfo, _ := disk.Usage(part.Mountpoint)
fmt.Printf("inode,disk(%v): \n inode persent: %v, disk used: %v, persent: %v \n", part.Mountpoint, diskInfo.InodesUsedPercent, diskInfo.Used, diskInfo.UsedPercent)
}
fmt.Println()
ioStat, _ := disk.IOCounters()
for _, v := range ioStat {
fmt.Printf("io: \n name: %v, readCount: %v, writeCount: %v \n\n", v.Name, v.ReadCount, v.WriteCount)
}
fmt.Println()
net, _ := net.IOCounters(false)
for _, v := range net {
fmt.Printf("netio: \n %v: send:%v recv:%v \n\n", v.Name, v.BytesSent, v.BytesRecv)
}
fmt.Println()
}

View file

@ -3,8 +3,14 @@ package dto
import "time"
type MonitorSearch struct {
Param string `json:"param" validate:"required,oneof=all cpu memory load disk inode io iops network"`
Param string `json:"param" validate:"required,oneof=all cpu memory load io network"`
Info string `json:"info"`
StartTime time.Time `json:"startTime"`
EndTime time.Time `json:"endTime"`
Unit string `josn:"unit"`
}
type MonitorData struct {
Param string `json:"param" validate:"required,oneof=cpu memory load io network"`
Date []time.Time `json:"date"`
Value []interface{} `json:"value"`
}

View file

@ -21,11 +21,18 @@ type MonitorIO struct {
WriteTime uint64 `gorm:"type:decimal" json:"writeTime"`
ReadByte uint64 `gorm:"type:decimal(32)" json:"readByte"`
WriteByte uint64 `gorm:"type:decimal(32)" json:"writeByte"`
Read uint64 `gorm:"type:decimal" json:"read"`
Write uint64 `gorm:"type:decimal" json:"write"`
Count uint64 `gorm:"type:decimal" json:"count"`
Time uint64 `gorm:"type:decimal" json:"time"`
}
type MonitorNetwork struct {
BaseModel
Name string `json:"name"`
BytesSent uint64 `gorm:"type:decimal(32)" json:"bytesSent"`
BytesRecv uint64 `gorm:"type:decimal(32)" json:"bytesRecv"`
Name string `json:"name"`
BytesSent uint64 `gorm:"type:decimal(32)" json:"bytesSent"`
BytesRecv uint64 `gorm:"type:decimal(32)" json:"bytesRecv"`
Up float64 `gorm:"type:float" json:"up"`
Down float64 `gorm:"type:float" json:"down"`
}

View file

@ -47,15 +47,43 @@ func (m *monitor) Run() {
itemIO.WriteByte = v.WriteBytes
itemIO.ReadTime = v.ReadTime
itemIO.WriteTime = v.WriteTime
var aheadData model.MonitorIO
if err := global.DB.Where("name = ?", v.Name).Order("created_at").Find(&aheadData).Error; err != nil {
_ = global.DB.Create(&itemIO)
continue
}
stime := time.Since(aheadData.CreatedAt).Seconds()
itemIO.Read = uint64(float64(v.ReadBytes-aheadData.ReadByte) / stime)
itemIO.Write = uint64(float64(v.WriteBytes-aheadData.WriteByte) / stime)
itemIO.Count = uint64(float64(v.ReadCount-aheadData.ReadCount) / stime)
writeCount := uint64(float64(v.WriteCount-aheadData.WriteCount) / stime)
if writeCount > itemIO.Count {
itemIO.Count = writeCount
}
itemIO.Time = uint64(float64(v.ReadTime-aheadData.ReadTime) / stime)
writeTime := uint64(float64(v.WriteTime-aheadData.WriteTime) / stime)
if writeTime > itemIO.Time {
itemIO.Time = writeTime
}
_ = global.DB.Create(&itemIO)
}
netStat, _ := net.IOCounters(true)
for _, v := range netStat {
var itemNet model.MonitorNetwork
var aheadData model.MonitorNetwork
itemNet.Name = v.Name
itemNet.BytesSent = v.BytesSent
itemNet.BytesRecv = v.BytesRecv
if err := global.DB.Where("name = ?", v.Name).Order("created_at").Find(&aheadData).Error; err != nil {
_ = global.DB.Create(&itemNet)
continue
}
stime := time.Since(aheadData.CreatedAt).Seconds()
itemNet.Up = float64(v.BytesSent-aheadData.BytesSent) / 1024 / stime
itemNet.Down = float64(v.BytesRecv-aheadData.BytesRecv) / 1024 / stime
_ = global.DB.Create(&itemNet)
}
}

View file

@ -43,6 +43,7 @@ func Routers() *gin.Engine {
systemRouter.InitGroupRouter(PrivateGroup)
systemRouter.InitCommandRouter(PrivateGroup)
systemRouter.InitTerminalRouter(PrivateGroup)
systemRouter.InitMonitorRouter(PrivateGroup)
systemRouter.InitOperationLogRouter(PrivateGroup)
}

View file

@ -6,6 +6,7 @@ type RouterGroup struct {
HostRouter
GroupRouter
CommandRouter
MonitorRouter
OperationLogRouter
}

View file

@ -0,0 +1,19 @@
package router
import (
v1 "github.com/1Panel-dev/1Panel/app/api/v1"
"github.com/1Panel-dev/1Panel/middleware"
"github.com/gin-gonic/gin"
)
type MonitorRouter struct{}
func (s *MonitorRouter) InitMonitorRouter(Router *gin.RouterGroup) {
monitorRouter := Router.Group("monitors").Use(middleware.JwtAuth()).Use(middleware.SessionAuth())
baseApi := v1.ApiGroupApp.BaseApi
{
monitorRouter.POST("/search", baseApi.LoadMonitor)
monitorRouter.GET("/netoptions", baseApi.GetNetworkOptions)
}
}

View file

@ -0,0 +1,13 @@
export namespace Monitor {
export interface MonitorData {
param: string;
date: Array<Date>;
value: Array<any>;
}
export interface MonitorSearch {
param: string;
info: string;
startTime: Date;
endTime: Date;
}
}

View file

@ -0,0 +1,10 @@
import http from '@/api';
import { Monitor } from '../interface/monitor';
export const loadMonitor = (param: Monitor.MonitorSearch) => {
return http.post<Array<Monitor.MonitorData>>(`/monitors/search`, param);
};
export const getNetworkOptions = () => {
return http.get<Array<string>>(`/monitors/netoptions`);
};

View file

@ -11,6 +11,13 @@ export default {
login: 'Login',
conn: 'Connect',
},
search: {
timeStart: 'Time start',
timeEnd: 'Time end',
timeRange: 'To',
dateStart: 'Date start',
dateEnd: 'Date end',
},
table: {
name: 'Name',
group: 'Group',
@ -92,6 +99,25 @@ export default {
changePassword: 'Change Password',
logout: 'Logout',
},
monitor: {
avgLoad: 'Average load',
loadDetail: 'Load detail',
resourceUsage: 'Resource utilization rate',
min: 'Minutes',
read: 'Read',
write: 'Write',
count: 'Times',
readWriteCount: 'Read or write Times',
readWriteTime: 'Read or write delay',
today: 'Today',
yestoday: 'Yestoday',
lastNDay: 'Last {0} day',
memory: 'Memory',
disk: 'Disk',
network: 'Network',
up: 'Up',
down: 'Down',
},
terminal: {
conn: 'connection',
testConn: 'Test connection',

View file

@ -11,6 +11,13 @@ export default {
login: '登陆',
conn: '连接',
},
search: {
timeStart: '开始时间',
timeEnd: '结束时间',
timeRange: '至',
dateStart: '开始日期',
dateEnd: '结束日期',
},
table: {
name: '名称',
group: '组',
@ -92,6 +99,25 @@ export default {
changePassword: '修改密码',
logout: '退出登录',
},
monitor: {
avgLoad: '平均负载',
loadDetail: '负载详情',
resourceUsage: '资源使用率',
min: '分钟',
read: '读取',
write: '写入',
count: '次',
readWriteCount: '读写次数',
readWriteTime: '读写延迟',
today: '今天',
yestoday: '昨天',
lastNDay: ' {0} ',
memory: '内存',
disk: '磁盘',
network: '网络',
up: '上行',
down: '下行',
},
terminal: {
conn: '连接',
testConn: '连接测试',

View file

@ -48,3 +48,16 @@ export function dateFromat(row: number, col: number, dataStr: any) {
second = second < 10 ? `0${String(second)}` : second;
return `${String(y)}-${String(m)}-${String(d)} ${String(h)}:${String(minute)}:${String(second)}`;
}
export function dateFromatWithoutYear(dataStr: any) {
const date = new Date(dataStr);
let m: string | number = date.getMonth() + 1;
m = m < 10 ? `0${String(m)}` : m;
let d: string | number = date.getDate();
d = d < 10 ? `0${String(d)}` : d;
let h: string | number = date.getHours();
h = h < 10 ? `0${String(h)}` : h;
let minute: string | number = date.getMinutes();
minute = minute < 10 ? `0${String(minute)}` : minute;
return `${String(m)}-${String(d)}\n${String(h)}:${String(minute)}`;
}

View file

@ -4,80 +4,116 @@
<el-col :span="24">
<el-card style="overflow: inherit">
<template #header>
<span style="font-size: '30px'; font-weight: 500">平均负载</span>
<el-radio-group style="float: right" size="small" v-model="loadRadio">
<el-radio-button label="昨天" />
<el-radio-button label="今天" />
<el-radio-button label="最近 7 天" />
<el-radio-button label="最近 30 天" />
<el-radio-button label="自定义时间" />
</el-radio-group>
<span style="font-size: 16px; font-weight: 500">{{ $t('monitor.avgLoad') }}</span>
<el-date-picker
@change="search('load')"
v-model="timeRangeLoad"
type="datetimerange"
size="small"
:range-separator="$t('commons.search.timeRange')"
:start-placeholder="$t('commons.search.timeStart')"
:end-placeholder="$t('commons.search.timeEnd')"
:shortcuts="shortcuts"
style="float: right; right: 20px"
>
</el-date-picker>
</template>
<div id="loadChart1" style="width: 100%; height: 300%"></div>
<div id="loadLoadChart" style="width: 100%; height: 400px"></div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20">
<el-row :gutter="20" style="margin-top: 20px">
<el-col :span="12">
<el-card style="overflow: inherit">
<template #header>
<span style="font-size: '30px'; font-weight: 500">CPU</span>
<el-radio-group style="float: right" size="small" v-model="loadRadio">
<el-radio-button label="昨天" />
<el-radio-button label="今天" />
<el-radio-button label="最近 7 天" />
<el-radio-button label="最近 30 天" />
<el-radio-button label="自定义时间" />
</el-radio-group>
<span style="font-size: 16px; font-weight: 500">CPU</span>
<el-date-picker
@change="search('cpu')"
v-model="timeRangeCpu"
type="datetimerange"
size="small"
:range-separator="$t('commons.search.timeRange')"
:start-placeholder="$t('commons.search.timeStart')"
:end-placeholder="$t('commons.search.timeEnd')"
:shortcuts="shortcuts"
style="float: right; right: 20px"
>
</el-date-picker>
</template>
<div id="loadChart2" style="width: 100%; height: 300%"></div>
<div id="loadCPUChart" style="width: 100%; height: 400px"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card style="overflow: inherit">
<template #header>
<span style="font-size: '30px'; font-weight: 500">内存</span>
<el-radio-group style="float: right" size="small" v-model="loadRadio">
<el-radio-button label="昨天" />
<el-radio-button label="今天" />
<el-radio-button label="最近 7 天" />
<el-radio-button label="最近 30 天" />
<el-radio-button label="自定义时间" />
</el-radio-group>
<span style="font-size: 16px; font-weight: 500">{{ $t('monitor.memory') }}</span>
<el-date-picker
@change="search('memory')"
v-model="timeRangeMemory"
type="datetimerange"
size="small"
:range-separator="$t('commons.search.timeRange')"
:start-placeholder="$t('commons.search.timeStart')"
:end-placeholder="$t('commons.search.timeEnd')"
:shortcuts="shortcuts"
style="float: right; right: 20px"
>
</el-date-picker>
</template>
<div id="loadChart3" style="width: 100%; height: 300%"></div>
<div id="loadMemoryChart" style="width: 100%; height: 400px"></div>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20">
<el-row :gutter="20" style="margin-top: 20px">
<el-col :span="12">
<el-card style="overflow: inherit">
<template #header>
<span style="font-size: '30px'; font-weight: 500">磁盘IO</span>
<el-radio-group style="float: right" size="small" v-model="loadRadio">
<el-radio-button label="昨天" />
<el-radio-button label="今天" />
<el-radio-button label="最近 7 天" />
<el-radio-button label="最近 30 天" />
<el-radio-button label="自定义时间" />
</el-radio-group>
<span style="font-size: 16px; font-weight: 500">{{ $t('monitor.disk') }} IO</span>
<el-date-picker
@change="search('io')"
v-model="timeRangeIO"
type="datetimerange"
size="small"
:range-separator="$t('commons.search.timeRange')"
:start-placeholder="$t('commons.search.timeStart')"
:end-placeholder="$t('commons.search.timeEnd')"
:shortcuts="shortcuts"
style="float: right; right: 20px"
>
</el-date-picker>
</template>
<div id="loadChart4" style="width: 100%; height: 300%"></div>
<div id="loadIOChart" style="width: 100%; height: 400px"></div>
</el-card>
</el-col>
<el-col :span="12">
<el-card style="overflow: inherit">
<template #header>
<span style="font-size: '30px'; font-weight: 500">网络IO:</span>
<el-radio-group style="float: right" size="small" v-model="loadRadio">
<el-radio-button label="昨天" />
<el-radio-button label="今天" />
<el-radio-button label="最近 7 天" />
<el-radio-button label="最近 30 天" />
<el-radio-button label="自定义时间" />
</el-radio-group>
<span style="font-size: 16px; font-weight: 500">{{ $t('monitor.network') }} IO</span>
<el-select
v-model="networkChoose"
clearable
filterable
@change="search('network')"
style="margin-left: 20px"
placeholder="Select"
size="small"
>
<el-option v-for="item in netOptions" :key="item" :label="item" :value="item" />
</el-select>
<el-date-picker
@change="search('network')"
v-model="timeRangeNetwork"
type="datetimerange"
size="small"
:range-separator="$t('commons.search.timeRange')"
:start-placeholder="$t('commons.search.timeStart')"
:end-placeholder="$t('commons.search.timeEnd')"
:shortcuts="shortcuts"
style="float: right; right: 20px"
>
</el-date-picker>
</template>
<div id="loadChart5" style="width: 100%; height: 300%"></div>
<div id="loadNetworkChart" style="width: 100%; height: 400px"></div>
</el-card>
</el-col>
</el-row>
@ -85,35 +121,385 @@
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
import * as echarts from 'echarts';
import { loadMonitor, getNetworkOptions } from '@/api/modules/monitor';
import { Monitor } from '@/api/interface/monitor';
import { dateFromatWithoutYear } from '@/utils/util';
import i18n from '@/lang';
const loadRadio = ref();
const zoomStart = ref();
const monitorBase = ref();
const timeRangeLoad = ref<Array<any>>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
const timeRangeCpu = ref<Array<any>>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
const timeRangeMemory = ref<Array<any>>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
const timeRangeIO = ref<Array<any>>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
const timeRangeNetwork = ref<Array<any>>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
const networkChoose = ref();
const netOptions = ref();
const shortcuts = [
{
text: i18n.global.t('monitor.today'),
value: () => {
const end = new Date();
const start = new Date(new Date().setHours(0, 0, 0, 0));
return [start, end];
},
},
{
text: i18n.global.t('monitor.yestoday'),
value: () => {
const yestoday = new Date(new Date().getTime() - 3600 * 1000 * 24 * 1);
const end = new Date(yestoday.setHours(23, 59, 59, 999));
const start = new Date(yestoday.setHours(0, 0, 0, 0));
return [start, end];
},
},
{
text: i18n.global.t('monitor.lastNDay', [3]),
value: () => {
const yestoday = new Date(new Date().getTime() - 3600 * 1000 * 24 * 3);
const end = new Date(yestoday.setHours(23, 59, 59, 999));
const start = new Date(yestoday.setHours(0, 0, 0, 0));
return [start, end];
},
},
{
text: i18n.global.t('monitor.lastNDay', [7]),
value: () => {
const lastweek = new Date(new Date().getTime() - 3600 * 1000 * 24 * 7);
const end = new Date(lastweek.setHours(23, 59, 59, 999));
const start = new Date(lastweek.setHours(0, 0, 0, 0));
return [start, end];
},
},
{
text: i18n.global.t('monitor.lastNDay', [30]),
value: () => {
const lastmonth = new Date(new Date().getTime() - 3600 * 1000 * 24 * 7);
const end = new Date(lastmonth.setHours(23, 59, 59, 999));
const start = new Date(lastmonth.setHours(0, 0, 0, 0));
return [start, end];
},
},
];
const searchTime = ref();
const searchInfo = reactive<Monitor.MonitorSearch>({
param: '',
info: '',
startTime: new Date(new Date().setHours(0, 0, 0, 0)),
endTime: new Date(),
});
function initCharts(key: string) {
console.log(key);
const lineChart = echarts.init(document.getElementById(key) as HTMLElement);
const search = async (param: string) => {
searchInfo.param = param;
switch (param) {
case 'load':
searchTime.value = timeRangeLoad.value;
break;
case 'cpu':
searchTime.value = timeRangeCpu.value;
break;
case 'memory':
searchTime.value = timeRangeMemory.value;
break;
case 'io':
searchTime.value = timeRangeIO.value;
break;
case 'network':
searchTime.value = timeRangeNetwork.value;
searchInfo.info = networkChoose.value;
break;
}
if (searchTime.value && searchTime.value.length === 2) {
searchInfo.startTime = searchTime.value[0];
searchInfo.endTime = searchTime.value[1];
}
const res = await loadMonitor(searchInfo);
if (res.data[0].value === null) {
return;
}
monitorBase.value = res.data;
for (const item of monitorBase.value) {
switch (item.param) {
case 'base':
let baseDate = item.date.map(function (item: any) {
return dateFromatWithoutYear(item);
});
if (param === 'cpu' || param === 'all') {
let cpuData = item.value.map(function (item: any) {
return item.cpu.toFixed(2);
});
let yDatasOfCpu = { name: 'CPU', type: 'line', data: cpuData, showSymbol: false };
initCharts('loadCPUChart', baseDate, yDatasOfCpu, 'CPU', '%');
}
if (param === 'memory' || param === 'all') {
let memoryData = item.value.map(function (item: any) {
return item.memory.toFixed(2);
});
let yDatasOfMem = {
name: i18n.global.t('monitor.memory'),
type: 'line',
data: memoryData,
showSymbol: false,
};
initCharts('loadMemoryChart', baseDate, yDatasOfMem, i18n.global.t('monitor.memory'), '%');
}
if (param === 'load' || param === 'all') {
initLoadCharts(item);
}
break;
case 'io':
initIOCharts(item);
break;
case 'network':
let networkDate = item.date.map(function (item: any) {
return dateFromatWithoutYear(item);
});
let networkUp = item.value.map(function (item: any) {
return item.up.toFixed(2);
});
let yDatasOfUp = {
name: i18n.global.t('monitor.up'),
type: 'line',
data: networkUp,
showSymbol: false,
};
let networkOut = item.value.map(function (item: any) {
return item.down.toFixed(2);
});
let yDatasOfDown = {
name: i18n.global.t('monitor.down'),
type: 'line',
data: networkOut,
showSymbol: false,
};
initCharts('loadNetworkChart', networkDate, [yDatasOfUp, yDatasOfDown], 'KB/s', 'KB/s');
}
}
};
const loadNetworkOptions = async () => {
const res = await getNetworkOptions();
netOptions.value = res.data;
searchInfo.info = netOptions.value && netOptions.value[0];
networkChoose.value = searchInfo.info;
search('all');
};
function initCharts(chartName: string, xDatas: any, yDatas: any, yTitle: string, formatStr: string) {
const lineChart = echarts.init(document.getElementById(chartName) as HTMLElement);
const option = {
zlevel: 1,
z: 1,
tooltip: {
trigger: 'axis',
formatter: function (datas: any) {
let res = datas[0].name + '<br/>';
for (const item of datas) {
res += item.marker + ' ' + item.seriesName + '' + item.data + formatStr + '<br/>';
}
return res;
},
},
legend: {
data: chartName === 'loadNetworkChart' && [i18n.global.t('monitor.up'), i18n.global.t('monitor.down')],
},
grid: { left: '7%', right: '7%', bottom: '20%' },
xAxis: { data: xDatas },
yAxis: { name: '( ' + formatStr + ' )' },
dataZoom: [{ startValue: zoomStart.value }],
series: yDatas,
};
lineChart.setOption(option, true);
}
function initLoadCharts(item: Monitor.MonitorData) {
const lineChart = echarts.init(document.getElementById('loadLoadChart') as HTMLElement);
const option = {
zlevel: 1,
z: 1,
tooltip: {
trigger: 'axis',
formatter: function (datas: any) {
let res = datas[0].name + '<br/>';
for (const item of datas) {
res += item.marker + ' ' + item.seriesName + '' + item.data + '%' + '<br/>';
}
return res;
},
},
legend: {
data: [
'1 ' + i18n.global.t('monitor.min'),
'5 ' + i18n.global.t('monitor.min'),
'15 ' + i18n.global.t('monitor.min'),
i18n.global.t('monitor.resourceUsage'),
],
},
grid: { left: '7%', right: '7%', bottom: '20%' },
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
},
yAxis: {
type: 'value',
data: item.date.map(function (item: any) {
return dateFromatWithoutYear(item);
}),
},
yAxis: [
{ type: 'value', name: i18n.global.t('monitor.loadDetail') + ' ( % )' },
{
type: 'value',
name: i18n.global.t('monitor.resourceUsage') + ' ( % )',
position: 'right',
alignTicks: true,
},
],
dataZoom: [{ startValue: zoomStart.value }],
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
name: '1 ' + i18n.global.t('monitor.min'),
type: 'line',
smooth: true,
showSymbol: false,
data: item.value.map(function (item: any) {
return item.cpuLoad1.toFixed(2);
}),
},
{
name: '5 ' + i18n.global.t('monitor.min'),
type: 'line',
showSymbol: false,
data: item.value.map(function (item: any) {
return item.cpuLoad5.toFixed(2);
}),
},
{
name: '15 ' + i18n.global.t('monitor.min'),
type: 'line',
showSymbol: false,
data: item.value.map(function (item: any) {
return item.cpuLoad15.toFixed(2);
}),
},
{
name: i18n.global.t('monitor.resourceUsage'),
type: 'line',
showSymbol: false,
data: item.value.map(function (item: any) {
return item.loadUsage.toFixed(2);
}),
yAxisIndex: 1,
},
],
};
lineChart.setOption(option, true);
}
function initIOCharts(item: Monitor.MonitorData) {
const lineChart = echarts.init(document.getElementById('loadIOChart') as HTMLElement);
const option = {
zlevel: 1,
z: 1,
tooltip: {
trigger: 'axis',
formatter: function (datas: any) {
let res = datas[0].name + '<br/>';
for (const item of datas) {
if (
item.seriesName === i18n.global.t('monitor.read') ||
item.seriesName === i18n.global.t('monitor.write')
) {
res += item.marker + ' ' + item.seriesName + '' + item.data + ' KB/s' + '<br/>';
}
if (item.seriesName === i18n.global.t('monitor.readWriteCount')) {
res +=
item.marker +
' ' +
item.seriesName +
'' +
item.data +
' ' +
i18n.global.t('monitor.count') +
'/s' +
'<br/>';
}
if (item.seriesName === i18n.global.t('monitor.readWriteTime')) {
res += item.marker + ' ' + item.seriesName + '' + item.data + ' ms' + '<br/>';
}
}
return res;
},
},
legend: {
data: [
i18n.global.t('monitor.read'),
i18n.global.t('monitor.write'),
i18n.global.t('monitor.readWriteCount'),
i18n.global.t('monitor.readWriteTime'),
],
},
grid: { left: '7%', right: '7%', bottom: '20%' },
xAxis: {
data: item.date.map(function (item: any) {
return dateFromatWithoutYear(item);
}),
},
yAxis: [
{ type: 'value', name: '( KB/s )' },
{ type: 'value', position: 'right', alignTicks: true },
],
dataZoom: [{ startValue: zoomStart.value }],
series: [
{
name: i18n.global.t('monitor.read'),
type: 'line',
showSymbol: false,
data: item.value.map(function (item: any) {
return (item.read / 1024).toFixed(2);
}),
},
{
name: i18n.global.t('monitor.write'),
type: 'line',
showSymbol: false,
data: item.value.map(function (item: any) {
return (item.write / 1024).toFixed(2);
}),
},
{
name: i18n.global.t('monitor.readWriteCount'),
type: 'line',
showSymbol: false,
data: item.value.map(function (item: any) {
return item.count;
}),
yAxisIndex: 1,
},
{
name: i18n.global.t('monitor.readWriteTime'),
type: 'line',
showSymbol: false,
data: item.value.map(function (item: any) {
return item.time;
}),
yAxisIndex: 1,
},
],
};
lineChart.setOption(option, true);
}
function changeChartSize() {
echarts.getInstanceByDom(document.getElementById('loadLoadChart') as HTMLElement)?.resize();
echarts.getInstanceByDom(document.getElementById('loadCPUChart') as HTMLElement)?.resize();
echarts.getInstanceByDom(document.getElementById('loadMemoryChart') as HTMLElement)?.resize();
echarts.getInstanceByDom(document.getElementById('loadIOChart') as HTMLElement)?.resize();
echarts.getInstanceByDom(document.getElementById('loadNetworkChart') as HTMLElement)?.resize();
}
onMounted(() => {
for (let i = 1; i < 6; i++) {
initCharts('loadChart' + i);
}
zoomStart.value = dateFromatWithoutYear(new Date(new Date().setHours(0, 0, 0, 0)));
loadNetworkOptions();
window.addEventListener('resize', changeChartSize);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', changeChartSize);
});
</script>