2022-04-27 10:59:02 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<div>
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-dialog :title="title" v-model="dialogVisible" :close-on-click-modal="true" :destroy-on-close="true"
|
|
|
|
|
|
:before-close="cancel" width="1050px">
|
2022-04-27 10:59:02 +08:00
|
|
|
|
<el-row :gutter="20">
|
2022-05-05 21:26:55 +08:00
|
|
|
|
<el-col :lg="12" :md="12">
|
2022-04-27 10:59:02 +08:00
|
|
|
|
<el-descriptions size="small" title="基础信息" :column="2" border>
|
|
|
|
|
|
<template #extra>
|
|
|
|
|
|
<el-link @click="onRefresh" icon="refresh" :underline="false" type="success"></el-link>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
<el-descriptions-item label="主机名">
|
|
|
|
|
|
{{ stats.Hostname }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="运行时间">
|
|
|
|
|
|
{{ stats.Uptime }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="总任务">
|
|
|
|
|
|
{{ stats.TotalProcs }}
|
|
|
|
|
|
</el-descriptions-item>
|
|
|
|
|
|
<el-descriptions-item label="运行中任务">
|
|
|
|
|
|
{{ stats.RunningProcs }}
|
|
|
|
|
|
</el-descriptions-item>
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-descriptions-item label="负载"> {{ stats.Load1 }} {{ stats.Load5 }} {{ stats.Load10 }}
|
|
|
|
|
|
</el-descriptions-item>
|
2022-04-27 10:59:02 +08:00
|
|
|
|
</el-descriptions>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
2022-05-05 21:26:55 +08:00
|
|
|
|
<el-col :lg="6" :md="6">
|
2022-04-27 10:59:02 +08:00
|
|
|
|
<div class="card-item-chart" ref="memRef"></div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
2022-05-05 21:26:55 +08:00
|
|
|
|
<el-col :lg="6" :md="6">
|
2022-04-27 10:59:02 +08:00
|
|
|
|
<div class="card-item-chart" ref="cpuRef"></div>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
|
|
|
|
|
|
<el-row :gutter="20">
|
|
|
|
|
|
<el-col :lg="8" :md="8">
|
|
|
|
|
|
<span style="font-size: 16px; font-weight: 700">磁盘</span>
|
|
|
|
|
|
<el-table :data="stats.FSInfos" stripe max-height="250" style="width: 100%" border>
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-table-column prop="MountPoint" label="挂载点" min-width="100" show-overflow-tooltip>
|
|
|
|
|
|
</el-table-column>
|
2022-04-27 10:59:02 +08:00
|
|
|
|
<el-table-column prop="Used" label="可使用" min-width="70" show-overflow-tooltip>
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatByteSize(scope.row.Free) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="Used" label="已使用" min-width="70" show-overflow-tooltip>
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatByteSize(scope.row.Used) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
|
|
|
|
|
|
<el-col :lg="16" :md="16">
|
|
|
|
|
|
<span style="font-size: 16px; font-weight: 700">网卡</span>
|
|
|
|
|
|
<el-table :data="netInter" stripe max-height="250" style="width: 100%" border>
|
|
|
|
|
|
<el-table-column prop="name" label="网卡" min-width="120" show-overflow-tooltip></el-table-column>
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<el-table-column prop="IPv4" label="IPv4" min-width="130" show-overflow-tooltip>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="IPv6" label="IPv6" min-width="130" show-overflow-tooltip>
|
|
|
|
|
|
</el-table-column>
|
2022-04-27 10:59:02 +08:00
|
|
|
|
<el-table-column prop="Rx" label="接收(rx)" min-width="110" show-overflow-tooltip>
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatByteSize(scope.row.Rx) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
<el-table-column prop="Tx" label="发送(tx)" min-width="110" show-overflow-tooltip>
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
{{ formatByteSize(scope.row.Tx) }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
</el-col>
|
|
|
|
|
|
</el-row>
|
|
|
|
|
|
</el-dialog>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
|
import { toRefs, reactive, watch, ref, nextTick } from 'vue';
|
2022-04-27 10:59:02 +08:00
|
|
|
|
import useEcharts from '@/common/echarts/useEcharts.ts';
|
|
|
|
|
|
import tdTheme from '@/common/echarts/theme.json';
|
|
|
|
|
|
import { formatByteSize } from '@/common/utils/format';
|
|
|
|
|
|
import { machineApi } from './api';
|
|
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const props = defineProps({
|
|
|
|
|
|
visible: {
|
|
|
|
|
|
type: Boolean,
|
|
|
|
|
|
},
|
|
|
|
|
|
stats: {
|
|
|
|
|
|
type: Object,
|
|
|
|
|
|
},
|
|
|
|
|
|
machineId: {
|
|
|
|
|
|
type: Number,
|
2022-04-27 10:59:02 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
title: {
|
|
|
|
|
|
type: String,
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const emit = defineEmits(['update:visible', 'cancel', 'update:machineId'])
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const cpuRef: any = ref();
|
|
|
|
|
|
const memRef: any = ref();
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
let cpuChart: any = null;
|
|
|
|
|
|
let memChart: any = null;
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const state = reactive({
|
|
|
|
|
|
dialogVisible: false,
|
|
|
|
|
|
stats: {} as any,
|
|
|
|
|
|
netInter: [] as any,
|
|
|
|
|
|
});
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const {
|
|
|
|
|
|
dialogVisible,
|
|
|
|
|
|
stats,
|
|
|
|
|
|
netInter,
|
|
|
|
|
|
} = toRefs(state)
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
let charts = [] as any
|
|
|
|
|
|
|
|
|
|
|
|
watch(props, async (newValue: any) => {
|
|
|
|
|
|
const visible = newValue.visible;
|
|
|
|
|
|
if (visible) {
|
|
|
|
|
|
await setStats();
|
|
|
|
|
|
}
|
|
|
|
|
|
state.dialogVisible = visible;
|
|
|
|
|
|
if (visible) {
|
|
|
|
|
|
initCharts();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const setStats = async () => {
|
|
|
|
|
|
state.stats = await machineApi.stats.request({ id: props.machineId });
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const onRefresh = async () => {
|
|
|
|
|
|
await setStats();
|
|
|
|
|
|
initCharts();
|
|
|
|
|
|
};
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const initMemStats = () => {
|
|
|
|
|
|
const data = [
|
|
|
|
|
|
{ name: '可用内存', value: state.stats.MemAvailable },
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '已用内存',
|
|
|
|
|
|
value: state.stats.MemTotal - state.stats.MemAvailable,
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
title: {
|
|
|
|
|
|
text: '内存',
|
|
|
|
|
|
x: 'left',
|
|
|
|
|
|
textStyle: { fontSize: 15 },
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'item',
|
|
|
|
|
|
valueFormatter: formatByteSize,
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
top: '15%',
|
|
|
|
|
|
orient: 'vertical',
|
|
|
|
|
|
left: 'left',
|
|
|
|
|
|
textStyle: { fontSize: 12 },
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '内存',
|
|
|
|
|
|
type: 'pie',
|
|
|
|
|
|
radius: ['30%', '60%'], // 饼图内圈和外圈大小
|
|
|
|
|
|
center: ['60%', '50%'], // 饼图位置,0: 左右;1: 上下
|
|
|
|
|
|
avoidLabelOverlap: false,
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: false,
|
|
|
|
|
|
position: 'center',
|
2022-04-27 10:59:02 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
emphasis: {
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
fontSize: '15',
|
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
|
},
|
2022-04-27 10:59:02 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
labelLine: {
|
|
|
|
|
|
show: false,
|
2022-04-27 10:59:02 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
data: data,
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
};
|
|
|
|
|
|
if (memChart) {
|
|
|
|
|
|
memChart.setOption(option, true);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const chart: any = useEcharts(memRef.value, tdTheme, option);
|
|
|
|
|
|
memChart = chart;
|
|
|
|
|
|
charts.push(chart);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const initCpuStats = () => {
|
|
|
|
|
|
const cpu = state.stats.CPU;
|
|
|
|
|
|
const data = [
|
|
|
|
|
|
{ name: 'Idle', value: cpu.Idle },
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'Iowait',
|
|
|
|
|
|
value: cpu.Iowait,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'System',
|
|
|
|
|
|
value: cpu.System,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'User',
|
|
|
|
|
|
value: cpu.User,
|
|
|
|
|
|
},
|
|
|
|
|
|
];
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
title: {
|
|
|
|
|
|
text: 'CPU使用率',
|
|
|
|
|
|
x: 'left',
|
|
|
|
|
|
textStyle: { fontSize: 15 },
|
|
|
|
|
|
},
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'item',
|
|
|
|
|
|
valueFormatter: (value: any) => value + '%',
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
top: '15%',
|
|
|
|
|
|
orient: 'vertical',
|
|
|
|
|
|
left: 'left',
|
|
|
|
|
|
textStyle: { fontSize: 12 },
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: 'CPU',
|
|
|
|
|
|
type: 'pie',
|
|
|
|
|
|
radius: ['30%', '60%'], // 饼图内圈和外圈大小
|
|
|
|
|
|
center: ['60%', '50%'], // 饼图位置,0: 左右;1: 上下
|
|
|
|
|
|
avoidLabelOverlap: false,
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: false,
|
|
|
|
|
|
position: 'center',
|
2022-04-27 10:59:02 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
emphasis: {
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
fontSize: '15',
|
|
|
|
|
|
fontWeight: 'bold',
|
|
|
|
|
|
},
|
2022-04-27 10:59:02 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
labelLine: {
|
|
|
|
|
|
show: false,
|
2022-04-27 10:59:02 +08:00
|
|
|
|
},
|
2022-10-29 20:08:15 +08:00
|
|
|
|
data: data,
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
};
|
|
|
|
|
|
if (cpuChart) {
|
|
|
|
|
|
cpuChart.setOption(option, true);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const chart: any = useEcharts(cpuRef.value, tdTheme, option);
|
|
|
|
|
|
cpuChart = chart;
|
|
|
|
|
|
charts.push(chart);
|
|
|
|
|
|
};
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const initCharts = () => {
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
initMemStats();
|
|
|
|
|
|
initCpuStats();
|
|
|
|
|
|
});
|
|
|
|
|
|
parseNetInter();
|
|
|
|
|
|
initEchartsResize();
|
|
|
|
|
|
};
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const initEchartResizeFun = () => {
|
|
|
|
|
|
nextTick(() => {
|
|
|
|
|
|
for (let i = 0; i < charts.length; i++) {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
charts[i].resize();
|
|
|
|
|
|
}, i * 1000);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
};
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const initEchartsResize = () => {
|
|
|
|
|
|
window.addEventListener('resize', initEchartResizeFun);
|
|
|
|
|
|
};
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const parseNetInter = () => {
|
|
|
|
|
|
state.netInter = [];
|
|
|
|
|
|
const netInter = state.stats.NetIntf;
|
|
|
|
|
|
const keys = Object.keys(netInter);
|
|
|
|
|
|
const values = Object.values(netInter);
|
|
|
|
|
|
for (let i = 0; i < values.length; i++) {
|
|
|
|
|
|
let value: any = values[i];
|
|
|
|
|
|
// 将网卡名称赋值新属性值name
|
|
|
|
|
|
value.name = keys[i];
|
|
|
|
|
|
state.netInter.push(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
const cancel = () => {
|
|
|
|
|
|
emit('update:visible', false);
|
|
|
|
|
|
emit('cancel');
|
2022-04-27 10:59:02 +08:00
|
|
|
|
|
2022-10-29 20:08:15 +08:00
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
cpuChart = null;
|
|
|
|
|
|
memChart = null;
|
|
|
|
|
|
}, 200);
|
|
|
|
|
|
};
|
2022-04-27 10:59:02 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss">
|
|
|
|
|
|
.card-item-chart {
|
|
|
|
|
|
height: 200px;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|