535 lines
14 KiB
Vue
535 lines
14 KiB
Vue
<script setup lang="ts">
|
||
import { PageContainer } from 'antdv-pro-layout';
|
||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||
import { message } from 'ant-design-vue/lib';
|
||
import { reactive, toRaw, ref, onMounted, onBeforeUnmount } from 'vue';
|
||
import { listMain } from '@/api/index';
|
||
import useI18n from '@/hooks/useI18n';
|
||
import { TooltipComponent } from 'echarts/components';
|
||
import { GaugeChart } from 'echarts/charts';
|
||
import { CanvasRenderer } from 'echarts/renderers';
|
||
import * as echarts from 'echarts/core';
|
||
import { TitleComponent, LegendComponent } from 'echarts/components';
|
||
import { PieChart } from 'echarts/charts';
|
||
import { LabelLayout } from 'echarts/features';
|
||
import { useRoute } from 'vue-router';
|
||
import useAppStore from '@/store/modules/app';
|
||
import useDictStore from '@/store/modules/dict';
|
||
const { getDict } = useDictStore();
|
||
const appStore = useAppStore();
|
||
const route = useRoute();
|
||
const { t } = useI18n();
|
||
|
||
echarts.use([
|
||
TooltipComponent,
|
||
GaugeChart,
|
||
TitleComponent,
|
||
LegendComponent,
|
||
PieChart,
|
||
CanvasRenderer,
|
||
LabelLayout,
|
||
]);
|
||
|
||
/**字典数据 */
|
||
/**用户性别字典 */
|
||
let indexColor = ref<DictType[]>([
|
||
{ label: 'normal', value: 'normal', elTagType: '', elTagClass: '#91cc75' },
|
||
{ label: 'abnormal', value: 'abnormal', elTagType: '', elTagClass: '#ee6666' },
|
||
]);
|
||
|
||
/**表格字段列 */
|
||
//customRender(){} ----单元格处理
|
||
let tableColumns: ColumnsType = [
|
||
{
|
||
title: t('views.index.object'),
|
||
dataIndex: 'name',
|
||
align: 'center',
|
||
key: 'status',
|
||
},
|
||
{
|
||
title: t('views.index.realNeStatus'),
|
||
dataIndex: 'status',
|
||
align: 'center',
|
||
customRender(opt) {
|
||
if (opt.value == 'Normal') return t('views.index.normal');
|
||
return t('views.index.abnormal');
|
||
},
|
||
},
|
||
{
|
||
title: t('views.index.reloadTime'),
|
||
dataIndex: 'refresh',
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: t('views.index.version'),
|
||
dataIndex: 'version',
|
||
align: 'center',
|
||
},
|
||
{
|
||
title: t('views.index.ipAddress'),
|
||
dataIndex: 'ipAddress',
|
||
key: 'groupName',
|
||
align: 'center',
|
||
},
|
||
];
|
||
/**表格状态类型 */
|
||
type TabeStateType = {
|
||
/**加载等待 */
|
||
loading: boolean;
|
||
/**紧凑型 */
|
||
size: string;
|
||
/**斑马纹 */
|
||
striped: boolean;
|
||
/**搜索栏 */
|
||
seached: boolean;
|
||
/**记录数据 */
|
||
data: object[];
|
||
/**勾选记录 */
|
||
selectedRowKeys: (string | number)[];
|
||
};
|
||
|
||
/**表格状态 */
|
||
let tableState: TabeStateType = reactive({
|
||
loading: false,
|
||
size: 'middle',
|
||
striped: false,
|
||
seached: false,
|
||
data: [],
|
||
selectedRowKeys: [],
|
||
});
|
||
|
||
/**表格状态 */
|
||
let nfInfo: any = reactive({
|
||
obj: 'OMC',
|
||
version: '2.2312.8',
|
||
status: t('views.index.normal'),
|
||
number: '',
|
||
outTimeDate: '',
|
||
});
|
||
|
||
/**表格状态类型 */
|
||
type nfStateType = {
|
||
/**主机名 */
|
||
hostName: string;
|
||
/**操作系统信息 */
|
||
osInfo: string;
|
||
/**数据库信息 */
|
||
dbInfo: string;
|
||
/**IP地址 */
|
||
ipAddress: string;
|
||
/**端口 */
|
||
port: number;
|
||
/**版本 */
|
||
version: string;
|
||
/**CPU利用率 */
|
||
cpuUse: string;
|
||
/**内存使用 */
|
||
memoryUse: string;
|
||
/**用户容量 */
|
||
capability: number;
|
||
/**序列号 */
|
||
serialNum: string;
|
||
/**许可证到期日期 */
|
||
/* selectedRowKeys: (string | number)[];*/
|
||
expiryDate: string;
|
||
};
|
||
/**网元详细信息 */
|
||
let pronInfo: nfStateType = reactive({
|
||
hostName: '5gc',
|
||
osInfo:
|
||
'Linux 5gc 4.15.0-112-generic #113-Ubuntu SMP Thu Jul 9 23:41:39 UTC 2020 x86_64 GNU/Linux',
|
||
dbInfo: 'adb v1.0.1',
|
||
ipAddress: '-',
|
||
port: 3030,
|
||
version: '-',
|
||
cpuUse: '-',
|
||
memoryUse: '-',
|
||
capability: 0,
|
||
serialNum: '-',
|
||
expiryDate: '-',
|
||
});
|
||
|
||
/**查询网元状态列表 */
|
||
function fnGetList(one: boolean) {
|
||
if (tableState.loading) return;
|
||
one && (tableState.loading = true);
|
||
listMain().then(res => {
|
||
tableState.data = res;
|
||
tableState.loading = false;
|
||
var rightNum = 0;
|
||
var errorNum = 0;
|
||
|
||
for (let i = 0; i < res.length; i++) {
|
||
if (res[i].status == '正常' || res[i].status == 'Normal') {
|
||
rightNum++;
|
||
} else {
|
||
errorNum++;
|
||
}
|
||
}
|
||
echarts.init(document.getElementById('echarts-records')).clear();
|
||
var chartDom = document.getElementById('echarts-records');
|
||
var myChart = echarts.init(chartDom);
|
||
|
||
var option = {
|
||
title: {
|
||
text: '',
|
||
subtext: '',
|
||
left: 'center',
|
||
},
|
||
tooltip: {
|
||
trigger: 'item',
|
||
},
|
||
legend: {
|
||
orient: 'vertical',
|
||
left: 'left',
|
||
},
|
||
color: [
|
||
'' + indexColor.value[0]['elTagClass'],
|
||
'' + indexColor.value[1]['elTagClass'],
|
||
],
|
||
series: [
|
||
{
|
||
name: t('views.index.realNeStatus'),
|
||
type: 'pie',
|
||
radius: '70%',
|
||
center: ['50%', '50%'],
|
||
data: [
|
||
{ value: rightNum, name: t('views.index.normal') },
|
||
{ value: errorNum, name: t('views.index.abnormal') },
|
||
],
|
||
emphasis: {
|
||
itemStyle: {
|
||
shadowBlur: 10,
|
||
shadowOffsetX: 0,
|
||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||
},
|
||
},
|
||
|
||
label: {},
|
||
},
|
||
],
|
||
};
|
||
|
||
option && myChart.setOption(option);
|
||
window.onresize = function () {
|
||
// echarts 窗口缩放自适应 随着div--echarts-records的大小来适应
|
||
myChart.resize();
|
||
};
|
||
});
|
||
}
|
||
|
||
/**點擊網元名 */
|
||
function init(e: any) {
|
||
let realData = toRaw(e);
|
||
var chartDom = document.getElementById('echarts-records');
|
||
var myChart = echarts.init(chartDom);
|
||
myChart.clear(); //怕遗留以前得元素
|
||
|
||
let cpuUsage = realData.cpuUsage;
|
||
let memUsage = realData.memUsage;
|
||
var nfMenUsage =
|
||
Math.round((memUsage?.nfUsedMem / memUsage?.totalMem) * 10000) / 100.0;
|
||
let partitionInfo = realData.diskSpace?.partitionInfo[1];
|
||
var nfMaxDiskSpace =
|
||
Math.round((partitionInfo?.used / partitionInfo?.total) * 10000) / 100.0;
|
||
let option = {
|
||
tooltip: {
|
||
formatter: '{a} <br/>{b} : {c}%',
|
||
},
|
||
series: [
|
||
{
|
||
name: 'Nf Memory usage',
|
||
center: ['17%', '50%'],
|
||
radius: '80%',
|
||
type: 'gauge',
|
||
progress: {
|
||
show: true,
|
||
},
|
||
pointer: {
|
||
//仪表盘的指针
|
||
//这个show属性好像有问题,因为在这次开发中,需要去掉指正,我设置false的时候,还是显示指针,估计是BUG吧,我用的echarts-3.2.3;希望改进。最终,我把width属性设置为0,成功搞定!
|
||
show: true,
|
||
//指针长度
|
||
length: '60%',
|
||
},
|
||
title: {
|
||
offsetCenter: [0, '90%'],
|
||
},
|
||
detail: {
|
||
valueAnimation: true,
|
||
formatter: '{value}',
|
||
textStyle: {
|
||
fontSize: 18,
|
||
},
|
||
offsetCenter: [0, '60%'],
|
||
},
|
||
data: [
|
||
{
|
||
value: nfMenUsage,
|
||
name: 'MEM',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
center: ['50%', '50%'],
|
||
name: 'Nf CPU usage',
|
||
radius: '80%',
|
||
type: 'gauge',
|
||
progress: {
|
||
show: true,
|
||
},
|
||
|
||
title: {
|
||
offsetCenter: [0, '90%'],
|
||
},
|
||
detail: {
|
||
valueAnimation: true,
|
||
formatter: '{value}',
|
||
textStyle: {
|
||
fontSize: 18,
|
||
},
|
||
offsetCenter: [0, '60%'],
|
||
},
|
||
data: [
|
||
{
|
||
value: cpuUsage?.nfCpuUsage / 100,
|
||
name: 'CPU',
|
||
},
|
||
],
|
||
},
|
||
{
|
||
center: ['83%', '50%'],
|
||
name: 'NF maximum disk usage',
|
||
radius: '80%',
|
||
type: 'gauge',
|
||
progress: {
|
||
show: true,
|
||
},
|
||
title: {
|
||
offsetCenter: [0, '90%'],
|
||
},
|
||
detail: {
|
||
valueAnimation: true,
|
||
formatter: '{value}',
|
||
textStyle: {
|
||
fontSize: 18,
|
||
},
|
||
offsetCenter: [0, '60%'],
|
||
},
|
||
data: [
|
||
{
|
||
value: nfMaxDiskSpace,
|
||
name: 'DiskSpace',
|
||
},
|
||
],
|
||
},
|
||
],
|
||
};
|
||
|
||
option && myChart.setOption(option);
|
||
window.onresize = function () {
|
||
// echarts 窗口缩放自适应 随着div--echarts-records的大小来适应
|
||
myChart.resize();
|
||
};
|
||
|
||
nfInfo.obj = realData.name;
|
||
nfInfo.number = realData.serialNum;
|
||
nfInfo.outTimeDate = realData.expiryDate;
|
||
}
|
||
|
||
/**抽屉 网元详细信息 */
|
||
const visible = ref(false);
|
||
const closeDrawer = () => {
|
||
visible.value = false;
|
||
};
|
||
/**抽屉 网元详细信息 */
|
||
|
||
/**监听表格行事件*/
|
||
function rowClick(record: any, index: any) {
|
||
return {
|
||
onClick: (event: any) => {
|
||
if (
|
||
toRaw(record).status == '异常' ||
|
||
toRaw(record).status == 'Abnormal'
|
||
) {
|
||
message.error(t('views.index.neStatus'), 2);
|
||
return false;
|
||
} else {
|
||
let pronData = toRaw(record);
|
||
//渲染详细信息
|
||
pronInfo = {
|
||
hostName: pronData.hostName,
|
||
osInfo: pronData.osInfo,
|
||
dbInfo: pronData.dbInfo,
|
||
ipAddress: pronData.ipAddress,
|
||
port: pronData.port,
|
||
version: pronData.version,
|
||
cpuUse:
|
||
pronData.name +
|
||
':' +
|
||
pronData.cpuUsage?.nfCpuUsage / 100 +
|
||
'%; ' +
|
||
'SYS:' +
|
||
pronData.cpuUsage?.sysCpuUsage / 100 +
|
||
'%',
|
||
memoryUse:
|
||
'Total:' +
|
||
pronData.memUsage?.totalMem +
|
||
'KB; ' +
|
||
pronData.name +
|
||
':' +
|
||
pronData.memUsage?.nfUsedMem +
|
||
'KB; SYS:' +
|
||
pronData.memUsage?.sysMemUsage +
|
||
'KB',
|
||
capability: pronData.capability,
|
||
serialNum: pronData.serialNum,
|
||
expiryDate: pronData.expiryDate,
|
||
};
|
||
}
|
||
visible.value = true;
|
||
},
|
||
};
|
||
}
|
||
let timer: any;
|
||
|
||
/**
|
||
* 国际化翻译转换
|
||
*/
|
||
function fnLocale() {
|
||
let title = route.meta.title as string;
|
||
if (title.indexOf('router.') !== -1) {
|
||
title = t(title);
|
||
}
|
||
appStore.setTitle(title);
|
||
}
|
||
|
||
onMounted(() => {
|
||
getDict('index_status').then(res => {
|
||
if (res.length > 0) {
|
||
indexColor.value = res;
|
||
}
|
||
});
|
||
//console.log(indexColor)
|
||
fnLocale();
|
||
fnGetList(true);
|
||
timer = setInterval(() => fnGetList(false), 10000); // 每隔10秒执行一次
|
||
});
|
||
|
||
// 在组件卸载之前清除定时器
|
||
|
||
onBeforeUnmount(() => {
|
||
clearInterval(timer);
|
||
});
|
||
</script>
|
||
|
||
<template>
|
||
<PageContainer :breadcrumb="false">
|
||
<div>
|
||
<a-drawer :visible="visible" @close="closeDrawer" :width="700">
|
||
<a-descriptions bordered :column="1" :label-style="{ width: '160px' }">
|
||
<a-descriptions-item :label="t('views.index.hostName')">{{
|
||
pronInfo.hostName
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.osInfo')">{{
|
||
pronInfo.osInfo
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.dbInfo')">{{
|
||
pronInfo.dbInfo
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.ipAddress')">{{
|
||
pronInfo.ipAddress
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.port')">{{
|
||
pronInfo.port
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.version')">{{
|
||
pronInfo.version
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.cpuUse')">{{
|
||
pronInfo.cpuUse
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.memoryUse')">{{
|
||
pronInfo.memoryUse
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.capability')">{{
|
||
pronInfo.capability
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.serialNum')">{{
|
||
pronInfo.serialNum
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.expiryDate')">{{
|
||
pronInfo.expiryDate
|
||
}}</a-descriptions-item>
|
||
</a-descriptions>
|
||
</a-drawer>
|
||
</div>
|
||
|
||
<a-row :gutter="16">
|
||
<a-col :lg="14" :md="16" :xs="24">
|
||
<!-- 表格列表 -->
|
||
<a-table
|
||
class="table"
|
||
row-key="id"
|
||
:columns="tableColumns"
|
||
:loading="tableState.loading"
|
||
:data-source="tableState.data"
|
||
:pagination="false"
|
||
:scroll="{ x: true }"
|
||
:customRow="rowClick"
|
||
>
|
||
<template #bodyCell="{ column, record }">
|
||
<template v-if="column.key === 'status'">
|
||
<div v-if="record.status == '正常' || record.status == 'Normal'">
|
||
<a-tag color="blue" @click="init(record)">{{
|
||
record.name
|
||
}}</a-tag>
|
||
</div>
|
||
<div v-else>
|
||
<a-tag color="pink">{{ record.name }}</a-tag>
|
||
</div>
|
||
</template>
|
||
</template>
|
||
</a-table>
|
||
</a-col>
|
||
<a-col :lg="10" :md="8" :xs="24">
|
||
<a-card :title="t('views.index.runStatus')" style="margin-bottom: 16px">
|
||
<div
|
||
id="echarts-records"
|
||
style="width: 100%; min-height: 200px"
|
||
></div>
|
||
</a-card>
|
||
<a-card :title="t('views.index.mark')" style="margin-top: 16px">
|
||
<a-descriptions
|
||
bordered
|
||
:column="1"
|
||
:label-style="{ width: '160px' }"
|
||
>
|
||
<a-descriptions-item :label="t('views.index.object')">{{
|
||
nfInfo.obj
|
||
}}</a-descriptions-item>
|
||
<template v-if="nfInfo.obj === 'OMC'">
|
||
<a-descriptions-item :label="t('views.index.versionNum')">{{
|
||
nfInfo.version
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.systemStatus')">{{
|
||
nfInfo.status
|
||
}}</a-descriptions-item>
|
||
</template>
|
||
<template v-else>
|
||
<a-descriptions-item :label="t('views.index.serialNum')">{{
|
||
nfInfo.number
|
||
}}</a-descriptions-item>
|
||
<a-descriptions-item :label="t('views.index.expiryDate')">{{
|
||
nfInfo.outTimeDate
|
||
}}</a-descriptions-item>
|
||
</template>
|
||
</a-descriptions>
|
||
</a-card>
|
||
</a-col>
|
||
</a-row>
|
||
</PageContainer>
|
||
</template>
|
||
|
||
<style lang="less" scoped></style>
|