370 lines
8.8 KiB
Vue
370 lines
8.8 KiB
Vue
<script setup lang="ts">
|
|
import { onMounted, ref, nextTick, watch } from 'vue';
|
|
import * as echarts from 'echarts/core';
|
|
import { GridComponent, TooltipComponent } from 'echarts/components';
|
|
import { CanvasRenderer } from 'echarts/renderers';
|
|
import { graphNodeClickID, graphNodeState } from '../../hooks/useTopology';
|
|
import useI18n from '@/hooks/useI18n';
|
|
import { markRaw } from 'vue';
|
|
// 引入液体填充图表
|
|
import 'echarts-liquidfill';
|
|
|
|
const { t } = useI18n();
|
|
|
|
echarts.use([GridComponent, TooltipComponent, CanvasRenderer]);
|
|
|
|
/**图DOM节点实例对象 */
|
|
const neResourcesDom = ref<HTMLElement | undefined>(undefined);
|
|
|
|
/**图实例对象 */
|
|
const neResourcesChart = ref<any>(null);
|
|
|
|
// 当前选中的网元ID
|
|
const currentNeId = ref('');
|
|
|
|
// 资源数据
|
|
const resourceData = ref({
|
|
neCpu: 1,
|
|
sysCpu: 1,
|
|
sysMem: 1,
|
|
sysDisk: 1,
|
|
});
|
|
|
|
// 获取颜色
|
|
function getColorByValue(value: number) {
|
|
if (value >= 70) {
|
|
return ['#f5222d', '#ff7875']; // 红色
|
|
} else if (value >= 30) {
|
|
return ['#2f54eb', '#597ef7']; // 蓝色
|
|
} else {
|
|
return ['#52c41a', '#95de64']; // 绿色
|
|
}
|
|
}
|
|
|
|
/**图数据 */
|
|
const optionData: any = {
|
|
tooltip: {
|
|
trigger: 'item',
|
|
// formatter: '{a}: {c}%',
|
|
formatter: (params: any) => {
|
|
return `${params.seriesName}: ${(params.value * 100).toFixed(2)}%`;
|
|
},
|
|
},
|
|
grid: {
|
|
top: '10%',
|
|
bottom: '5%',
|
|
left: '5%',
|
|
right: '5%',
|
|
containLabel: true,
|
|
},
|
|
series: [
|
|
{
|
|
type: 'liquidFill',
|
|
radius: '50%',
|
|
center: ['15%', '35%'],
|
|
data: [resourceData.value.neCpu / 100],
|
|
name: t('views.dashboard.overview.resources.neCpu'),
|
|
color: getColorByValue(resourceData.value.neCpu),
|
|
backgroundStyle: {
|
|
color: 'rgba(10, 60, 160, 0.1)',
|
|
},
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.neCpu')}\n${
|
|
resourceData.value.neCpu
|
|
}%`;
|
|
},
|
|
textStyle: {
|
|
fontSize: 12,
|
|
color: '#fff',
|
|
},
|
|
},
|
|
},
|
|
outline: {
|
|
show: true,
|
|
borderDistance: 2,
|
|
itemStyle: {
|
|
borderColor: '#0a3ca0',
|
|
borderWidth: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
type: 'liquidFill',
|
|
radius: '50%',
|
|
center: ['85%', '35%'],
|
|
data: [resourceData.value.sysCpu / 100],
|
|
name: t('views.dashboard.overview.resources.sysCpu'),
|
|
color: getColorByValue(resourceData.value.sysCpu),
|
|
backgroundStyle: {
|
|
color: 'rgba(10, 60, 160, 0.1)',
|
|
},
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.sysCpu')}\n${
|
|
resourceData.value.sysCpu
|
|
}%`;
|
|
},
|
|
textStyle: {
|
|
fontSize: 12,
|
|
color: '#fff',
|
|
},
|
|
},
|
|
},
|
|
outline: {
|
|
show: true,
|
|
borderDistance: 2,
|
|
itemStyle: {
|
|
borderColor: '#0a3ca0',
|
|
borderWidth: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
type: 'liquidFill',
|
|
radius: '50%',
|
|
center: ['35%', '65%'],
|
|
data: [resourceData.value.sysMem / 100],
|
|
name: t('views.dashboard.overview.resources.sysMem'),
|
|
color: getColorByValue(resourceData.value.sysMem),
|
|
backgroundStyle: {
|
|
color: 'rgba(10, 60, 160, 0.1)',
|
|
},
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.sysMem')}\n${
|
|
resourceData.value.sysMem
|
|
}%`;
|
|
},
|
|
textStyle: {
|
|
fontSize: 12,
|
|
color: '#fff',
|
|
},
|
|
},
|
|
},
|
|
outline: {
|
|
show: true,
|
|
borderDistance: 2,
|
|
itemStyle: {
|
|
borderColor: '#0a3ca0',
|
|
borderWidth: 1,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
type: 'liquidFill',
|
|
radius: '50%',
|
|
center: ['65%', '65%'],
|
|
data: [resourceData.value.sysDisk / 100],
|
|
name: t('views.dashboard.overview.resources.sysDisk'),
|
|
color: getColorByValue(resourceData.value.sysDisk),
|
|
backgroundStyle: {
|
|
color: 'rgba(10, 60, 160, 0.1)',
|
|
},
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.sysDisk')}\n${
|
|
resourceData.value.sysDisk
|
|
}%`;
|
|
},
|
|
textStyle: {
|
|
fontSize: 12,
|
|
color: '#fff',
|
|
},
|
|
},
|
|
},
|
|
outline: {
|
|
show: true,
|
|
borderDistance: 2,
|
|
itemStyle: {
|
|
borderColor: '#0a3ca0',
|
|
borderWidth: 1,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
};
|
|
|
|
/**图数据渲染 */
|
|
function handleRanderChart(container: HTMLElement | undefined, option: any) {
|
|
if (!container) return;
|
|
neResourcesChart.value = markRaw(echarts.init(container));
|
|
option && neResourcesChart.value.setOption(option);
|
|
|
|
// 创建 ResizeObserver 实例
|
|
var observer = new ResizeObserver(entries => {
|
|
if (neResourcesChart.value) {
|
|
neResourcesChart.value.resize();
|
|
}
|
|
});
|
|
// 监听元素大小变化
|
|
observer.observe(container);
|
|
}
|
|
|
|
function fnChangeData(data: any[], itemID: string) {
|
|
const neType = itemID.split('_')[0];
|
|
const neID = itemID.split('_')[1];
|
|
currentNeId.value = neID;
|
|
|
|
let info = data.find((item: any) => item.id === neType);
|
|
if (!info || !info.neStateMap[neID]?.online) return;
|
|
|
|
let sysCpuUsage = 0;
|
|
let nfCpuUsage = 0;
|
|
if (info.neStateMap[neID].cpu) {
|
|
nfCpuUsage = info.neStateMap[neID].cpu.nfCpuUsage;
|
|
const nfCpu = +(info.neStateMap[neID].cpu.nfCpuUsage / 100);
|
|
nfCpuUsage = +nfCpu.toFixed(2);
|
|
if (nfCpuUsage > 100) {
|
|
nfCpuUsage = 100;
|
|
}
|
|
|
|
sysCpuUsage = info.neStateMap[neID].cpu.sysCpuUsage;
|
|
let sysCpu = +(info.neStateMap[neID].cpu.sysCpuUsage / 100);
|
|
sysCpuUsage = +sysCpu.toFixed(2);
|
|
if (sysCpuUsage > 100) {
|
|
sysCpuUsage = 100;
|
|
}
|
|
}
|
|
|
|
let sysMemUsage = 0;
|
|
if (info.neStateMap[neID].mem) {
|
|
const men = info.neStateMap[neID].mem.sysMemUsage;
|
|
sysMemUsage = +(men / 100).toFixed(2);
|
|
if (sysMemUsage > 100) {
|
|
sysMemUsage = 100;
|
|
}
|
|
}
|
|
|
|
let sysDiskUsage = 0;
|
|
if (
|
|
info.neStateMap[neID].disk &&
|
|
Array.isArray(info.neStateMap[neID].disk.partitionInfo)
|
|
) {
|
|
let disks: any[] = info.neStateMap[neID].disk.partitionInfo;
|
|
disks = disks.sort((a, b) => +b.used - +a.used);
|
|
if (disks.length > 0) {
|
|
const { total, used } = disks[0];
|
|
sysDiskUsage = +((used / total) * 100).toFixed(2);
|
|
}
|
|
}
|
|
|
|
resourceData.value = {
|
|
neCpu: nfCpuUsage,
|
|
sysCpu: sysCpuUsage,
|
|
sysMem: sysMemUsage,
|
|
sysDisk: sysDiskUsage,
|
|
};
|
|
|
|
// 更新图表数据
|
|
neResourcesChart.value.setOption({
|
|
series: [
|
|
{
|
|
data: [resourceData.value.neCpu / 100],
|
|
color: getColorByValue(resourceData.value.neCpu),
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.neCpu')}\n${
|
|
resourceData.value.neCpu
|
|
}%`;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
data: [resourceData.value.sysCpu / 100],
|
|
color: getColorByValue(resourceData.value.sysCpu),
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.sysCpu')}\n${
|
|
resourceData.value.sysCpu
|
|
}%`;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
data: [resourceData.value.sysMem / 100],
|
|
color: getColorByValue(resourceData.value.sysMem),
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.sysMem')}\n${
|
|
resourceData.value.sysMem
|
|
}%`;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
data: [resourceData.value.sysDisk / 100],
|
|
color: getColorByValue(resourceData.value.sysDisk),
|
|
label: {
|
|
normal: {
|
|
formatter: () => {
|
|
return `${t('views.dashboard.overview.resources.sysDisk')}\n${
|
|
resourceData.value.sysDisk
|
|
}%`;
|
|
},
|
|
},
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
watch(
|
|
graphNodeState,
|
|
v => {
|
|
fnChangeData(v, graphNodeClickID.value);
|
|
},
|
|
{
|
|
deep: true,
|
|
}
|
|
);
|
|
|
|
watch(graphNodeClickID, v => {
|
|
fnChangeData(graphNodeState.value, v);
|
|
});
|
|
|
|
onMounted(() => {
|
|
nextTick(() => {
|
|
handleRanderChart(neResourcesDom.value, optionData);
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="resource-panel">
|
|
<div ref="neResourcesDom" class="chart"></div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang="less" scoped>
|
|
.resource-panel {
|
|
width: 100%;
|
|
height: 100%;
|
|
margin-top: -32px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
.panel-title {
|
|
font-size: 14px;
|
|
color: #00fcff;
|
|
padding: 8px;
|
|
border-bottom: 1px solid rgba(10, 115, 255, 0.3);
|
|
}
|
|
|
|
.chart {
|
|
flex: 1;
|
|
width: 100%;
|
|
}
|
|
}
|
|
</style>
|