1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-21 17:29:17 +08:00

505 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<el-row :gutter="20" class="row-box">
<el-col :span="8">
<el-card class="el-card">
<template #header>
<div class="card-header">
<span>{{ $t('home.overview') }}</span>
</div>
</template>
<el-row :gutter="20">
<el-col :span="12">
<el-card style="font-size: 12px; height: 80px; border-radius: 10px">
<svg-icon style="float: left; margin-left: 5px" iconName="p-website"></svg-icon>
<span style="float: left; margin-left: 5px; margin-top: 10px">
{{ $t('menu.website') }}
</span>
<el-link
style="float: right; font-size: 24px; margin-right: 5px"
@click="goRouter('/websites')"
type="primary"
>
{{ baseInfo?.websiteNumber }}
</el-link>
</el-card>
</el-col>
<el-col :span="12">
<el-card style="font-size: 12px; height: 80px; border-radius: 10px">
<svg-icon style="float: left; margin-left: 5px" iconName="p-database"></svg-icon>
<span style="float: left; margin-left: 5px; margin-top: 10px">
{{ $t('menu.database') }}
</span>
<el-link
style="float: right; font-size: 24px; margin-right: 5px"
@click="goRouter('/databases')"
type="primary"
>
{{ baseInfo?.databaseNumber }}
</el-link>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 20px; margin-top: 30px">
<el-col :span="12">
<el-card style="font-size: 12px; height: 80px; border-radius: 10px">
<svg-icon style="float: left; margin-left: 5px" iconName="p-plan"></svg-icon>
<span style="float: left; margin-left: 5px; margin-top: 10px">
{{ $t('menu.cronjob') }}
</span>
<el-link
style="float: right; font-size: 24px; margin-right: 5px"
@click="goRouter('/cronjobs')"
type="primary"
>
{{ baseInfo?.cronjobNumber }}
</el-link>
</el-card>
</el-col>
<el-col :span="12">
<el-card style="font-size: 12px; height: 80px; border-radius: 10px">
<svg-icon style="float: left; margin-left: 5px" iconName="p-appstore"></svg-icon>
<span style="float: left; margin-left: 5px; margin-top: 10px">
{{ $t('home.appInstalled') }}
</span>
<el-link
style="float: right; font-size: 24px; margin-right: 5px"
@click="goRouter('/apps')"
type="primary"
>
{{ baseInfo?.appInstalldNumber }}
</el-link>
</el-card>
</el-col>
</el-row>
</el-card>
</el-col>
<el-col :span="8">
<el-card class="el-card">
<template #header>
<div class="card-header">
<span>{{ $t('commons.table.status') }}</span>
</div>
</template>
<Status ref="statuRef" />
</el-card>
</el-col>
<el-col :span="8">
<el-card class="el-card">
<template #header>
<div class="card-header">
<span>{{ $t('home.systemInfo') }}</span>
</div>
</template>
<el-form>
<el-form-item :label="$t('home.hostname')">{{ baseInfo.hostname }}</el-form-item>
<el-form-item :label="$t('home.platformVersion')">
{{ baseInfo.platform }}-{{ baseInfo.platformVersion }}
</el-form-item>
<el-form-item :label="$t('home.kernelVersion')">
{{ baseInfo.kernelVersion }}
</el-form-item>
<el-form-item :label="$t('home.kernelArch')">{{ baseInfo.kernelArch }}</el-form-item>
<el-form-item :label="$t('home.uptime')">{{ baseInfo.uptime }}</el-form-item>
<el-form-item :label="$t('home.runningTime')">{{ baseInfo.timeSinceUptime }}</el-form-item>
</el-form>
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 20px" class="row-box">
<el-col :span="12">
<App ref="appRef" />
</el-col>
<el-col :span="12">
<el-card class="el-card">
<el-radio-group v-model="chartOption" @change="changeOption">
<el-radio-button label="network">{{ $t('home.network') }}</el-radio-button>
<el-radio-button label="io">{{ $t('home.io') }}</el-radio-button>
</el-radio-group>
<el-select
v-if="chartOption === 'network'"
@change="onLoadBaseInfo(false, 'network')"
v-model="searchInfo.netOption"
style="float: right"
>
<el-option v-for="item in netOptions" :key="item" :label="item" :value="item" />
</el-select>
<el-select
v-if="chartOption === 'io'"
v-model="searchInfo.ioOption"
@change="onLoadBaseInfo(false, 'io')"
style="float: right"
>
<el-option v-for="item in ioOptions" :key="item" :label="item" :value="item" />
</el-select>
<div style="margin-top: 20px" v-if="chartOption === 'network'">
<el-tag>{{ $t('monitor.up') }}: {{ currentChartInfo.netBytesSent }} KB/s</el-tag>
<el-tag style="margin-left: 20px">
{{ $t('monitor.down') }}: {{ currentChartInfo.netBytesRecv }} KB/s
</el-tag>
<el-tag style="margin-left: 20px">
{{ $t('home.totalSend') }}: {{ computeSize(currentInfo.netBytesSent) }}
</el-tag>
<el-tag style="margin-left: 20px">
{{ $t('home.totalRecv') }}: {{ computeSize(currentInfo.netBytesRecv) }}
</el-tag>
</div>
<div style="margin-top: 20px" v-if="chartOption === 'io'">
<el-tag>{{ $t('monitor.read') }}: {{ currentChartInfo.ioReadBytes }} MB</el-tag>
<el-tag style="margin-left: 20px">
{{ $t('monitor.write') }}: {{ currentChartInfo.ioWriteBytes }} MB
</el-tag>
<el-tag style="margin-left: 20px">
{{ $t('home.rwPerSecond') }}: {{ currentChartInfo.ioCount }} {{ $t('home.time') }}
</el-tag>
<el-tag style="margin-left: 20px">
{{ $t('home.rwPerSecond') }}: {{ currentInfo.ioTime }} ms
</el-tag>
</div>
<div
v-if="chartOption === 'io'"
id="ioChart"
style="margin-top: 20px; width: 100%; height: 320px"
></div>
<div
v-if="chartOption === 'network'"
id="networkChart"
style="margin-top: 20px; width: 100%; height: 320px"
></div>
</el-card>
</el-col>
</el-row>
</div>
</template>
<script lang="ts" setup>
import { onMounted, onBeforeUnmount, ref, reactive } from 'vue';
import * as echarts from 'echarts';
import Status from '@/views/home/status/index.vue';
import App from '@/views/home/app/index.vue';
import i18n from '@/lang';
import { Dashboard } from '@/api/interface/dashboard';
import { dateFromatForSecond, computeSize } from '@/utils/util';
import { useRouter } from 'vue-router';
import { loadBaseInfo, loadCurrentInfo } from '@/api/modules/dashboard';
import { getIOOptions, getNetworkOptions } from '@/api/modules/monitor';
const router = useRouter();
const statuRef = ref();
const appRef = ref();
const chartOption = ref('network');
let timer: NodeJS.Timer | null = null;
let isInit = ref<boolean>(true);
const ioReadBytes = ref<Array<number>>([]);
const ioWriteBytes = ref<Array<number>>([]);
const netBytesSents = ref<Array<number>>([]);
const netBytesRecvs = ref<Array<number>>([]);
const timeIODatas = ref<Array<string>>([]);
const timeNetDatas = ref<Array<string>>([]);
const ioOptions = ref();
const netOptions = ref();
const searchInfo = reactive({
ioOption: 'all',
netOption: 'all',
});
const baseInfo = ref<Dashboard.BaseInfo>({
haloID: 0,
dateeaseID: 0,
jumpserverID: 0,
metersphereID: 0,
kubeoperatorID: 0,
kubepiID: 0,
websiteNumber: 0,
databaseNumber: 0,
cronjobNumber: 0,
appInstalldNumber: 0,
hostname: '',
os: '',
platform: '',
platformFamily: '',
platformVersion: '',
kernelArch: '',
kernelVersion: '',
virtualizationSystem: '',
uptime: '',
timeSinceUptime: '',
cpuCores: 0,
cpuLogicalCores: 0,
cpuModelName: '',
currentInfo: null,
});
const currentInfo = ref<Dashboard.CurrentInfo>({
procs: 0,
load1: 0,
load5: 0,
load15: 0,
loadUsagePercent: 0,
cpuPercent: [] as Array<number>,
cpuUsedPercent: 0,
cpuUsed: 0,
cpuTotal: 0,
memoryTotal: 0,
memoryAvailable: 0,
memoryUsed: 0,
MemoryUsedPercent: 0,
ioReadBytes: 0,
ioWriteBytes: 0,
ioTime: 0,
ioCount: 0,
total: 0,
free: 0,
used: 0,
usedPercent: 0,
inodesTotal: 0,
inodesUsed: 0,
inodesFree: 0,
inodesUsedPercent: 0,
netBytesSent: 0,
netBytesRecv: 0,
shotTime: new Date(),
});
const currentChartInfo = reactive({
ioReadBytes: 0,
ioWriteBytes: 0,
ioCount: 0,
netBytesSent: 0,
netBytesRecv: 0,
});
const changeOption = async () => {
isInit.value = true;
loadData();
};
const goRouter = async (path: string) => {
router.push({ path: path });
};
const onLoadNetworkOptions = async () => {
const res = await getNetworkOptions();
netOptions.value = res.data;
searchInfo.netOption = netOptions.value && netOptions.value[0];
};
const onLoadIOOptions = async () => {
const res = await getIOOptions();
ioOptions.value = res.data;
searchInfo.ioOption = ioOptions.value && ioOptions.value[0];
};
const onLoadBaseInfo = async (isInit: boolean, range: string) => {
if (range === 'all' || range === 'io') {
ioReadBytes.value = [];
ioWriteBytes.value = [];
timeIODatas.value = [];
} else if (range === 'all' || range === 'network') {
netBytesSents.value = [];
netBytesRecvs.value = [];
timeNetDatas.value = [];
}
const res = await loadBaseInfo(searchInfo.ioOption, searchInfo.netOption);
baseInfo.value = res.data;
currentInfo.value = baseInfo.value.currentInfo;
if (baseInfo.value.timeSinceUptime) {
baseInfo.value.timeSinceUptime.replaceAll('days', i18n.global.t('home.Day'));
baseInfo.value.timeSinceUptime.replaceAll('hours', i18n.global.t('home.Hour'));
baseInfo.value.timeSinceUptime.replaceAll('minutes', i18n.global.t('home.Minute'));
}
onLoadCurrentInfo();
statuRef.value.acceptParams(currentInfo.value, baseInfo.value);
appRef.value.acceptParams(baseInfo.value);
if (isInit) {
window.addEventListener('resize', changeChartSize);
timer = setInterval(async () => {
onLoadCurrentInfo();
}, 3000);
}
};
const onLoadCurrentInfo = async () => {
const res = await loadCurrentInfo(searchInfo.ioOption, searchInfo.netOption);
currentChartInfo.netBytesSent = Number(
((res.data.netBytesSent - currentInfo.value.netBytesSent) / 1024 / 3).toFixed(2),
);
netBytesSents.value.push(currentChartInfo.netBytesSent);
if (netBytesSents.value.length > 20) {
netBytesSents.value.splice(0, 1);
}
currentChartInfo.netBytesRecv = Number(
((res.data.netBytesRecv - currentInfo.value.netBytesRecv) / 1024 / 3).toFixed(2),
);
netBytesRecvs.value.push(currentChartInfo.netBytesRecv);
if (netBytesRecvs.value.length > 20) {
netBytesRecvs.value.splice(0, 1);
}
currentChartInfo.ioReadBytes = Number(
((res.data.ioReadBytes - currentInfo.value.ioReadBytes) / 1024 / 1024 / 3).toFixed(2),
);
ioReadBytes.value.push(currentChartInfo.ioReadBytes);
if (ioReadBytes.value.length > 20) {
ioReadBytes.value.splice(0, 1);
}
currentChartInfo.ioWriteBytes = Number(
((res.data.ioWriteBytes - currentInfo.value.ioWriteBytes) / 1024 / 1024 / 3).toFixed(2),
);
ioWriteBytes.value.push(currentChartInfo.ioWriteBytes);
if (ioWriteBytes.value.length > 20) {
ioWriteBytes.value.splice(0, 1);
}
currentChartInfo.ioCount = Number(((res.data.ioCount - currentInfo.value.ioCount) / 3).toFixed(2));
timeIODatas.value.push(dateFromatForSecond(res.data.shotTime));
if (timeIODatas.value.length > 20) {
timeIODatas.value.splice(0, 1);
}
timeNetDatas.value.push(dateFromatForSecond(res.data.shotTime));
if (timeNetDatas.value.length > 20) {
timeNetDatas.value.splice(0, 1);
}
loadData();
currentInfo.value = res.data;
statuRef.value.acceptParams(currentInfo.value, baseInfo.value);
};
const loadData = async () => {
if (chartOption.value === 'io') {
let ioReadYDatas = {
name: i18n.global.t('monitor.read'),
type: 'line',
smooth: true,
areaStyle: {
color: '#ebdee3',
},
data: ioReadBytes.value,
showSymbol: false,
};
let ioWriteYDatas = {
name: i18n.global.t('monitor.write'),
type: 'line',
smooth: true,
areaStyle: {
color: '#ebdee3',
},
data: ioWriteBytes.value,
showSymbol: false,
};
freshChart(
'ioChart',
[i18n.global.t('monitor.read'), i18n.global.t('monitor.write')],
timeIODatas.value,
[ioReadYDatas, ioWriteYDatas],
i18n.global.t('monitor.network'),
'MB',
);
} else {
let netTxYDatas = {
name: i18n.global.t('monitor.up'),
type: 'line',
smooth: true,
areaStyle: {
color: '#ebdee3',
},
data: netBytesRecvs.value,
showSymbol: false,
};
let netRxYDatas = {
name: i18n.global.t('monitor.down'),
type: 'line',
smooth: true,
areaStyle: {
color: '#ebdee3',
},
data: netBytesSents.value,
showSymbol: false,
};
freshChart(
'networkChart',
[i18n.global.t('monitor.up'), i18n.global.t('monitor.down')],
timeNetDatas.value,
[netTxYDatas, netRxYDatas],
i18n.global.t('monitor.network'),
'KB/s',
);
}
};
function freshChart(chartName: string, legendDatas: any, xDatas: any, yDatas: any, yTitle: string, formatStr: string) {
if (isInit.value) {
echarts.init(document.getElementById(chartName) as HTMLElement);
isInit.value = false;
}
let itemChart = echarts.getInstanceByDom(document.getElementById(chartName) as HTMLElement);
const option = {
title: [
{
left: 'center',
text: yTitle,
},
],
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;
},
},
grid: { left: '7%', right: '7%', bottom: '20%' },
legend: {
data: legendDatas,
right: 10,
},
xAxis: { data: xDatas, boundaryGap: false },
yAxis: { name: '( ' + formatStr + ' )' },
series: yDatas,
};
itemChart?.setOption(option, true);
}
function changeChartSize() {
echarts.getInstanceByDom(document.getElementById('ioChart') as HTMLElement)?.resize();
echarts.getInstanceByDom(document.getElementById('networkChart') as HTMLElement)?.resize();
}
onMounted(() => {
onLoadNetworkOptions();
onLoadIOOptions();
onLoadBaseInfo(true, 'all');
});
onBeforeUnmount(() => {
clearInterval(Number(timer));
timer = null;
window.removeEventListener('resize', changeChartSize);
});
</script>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>