447 lines
12 KiB
Vue
447 lines
12 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, markRaw } 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,
|
|
]);
|
|
|
|
/**图DOM节点实例对象 */
|
|
const statusBar = ref<HTMLElement | undefined>(undefined);
|
|
|
|
/**图实例对象 */
|
|
const statusBarChart = ref<any>(null);
|
|
|
|
/**网元状态字典数据 */
|
|
let indexColor = ref<DictType[]>([
|
|
{ label: 'Normal', value: 'normal', tagType: '', tagClass: '#91cc75' },
|
|
{
|
|
label: 'Abnormal',
|
|
value: 'abnormal',
|
|
tagType: '',
|
|
tagClass: '#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.serialNum'),
|
|
dataIndex: 'serialNum',
|
|
align: 'center',
|
|
},
|
|
{
|
|
title: t('views.index.expiryDate'),
|
|
dataIndex: 'expiryDate',
|
|
align: 'center',
|
|
},
|
|
{
|
|
title: t('views.index.ipAddress'),
|
|
dataIndex: 'ipAddress',
|
|
key: 'groupName',
|
|
align: 'center',
|
|
},
|
|
];
|
|
/**表格状态类型 */
|
|
type TabeStateType = {
|
|
/**加载等待 */
|
|
loading: boolean;
|
|
/**紧凑型 */
|
|
size: string;
|
|
/**搜索栏 */
|
|
seached: boolean;
|
|
/**记录数据 */
|
|
data: object[];
|
|
/**勾选记录 */
|
|
selectedRowKeys: (string | number)[];
|
|
};
|
|
|
|
/**表格状态 */
|
|
let tableState: TabeStateType = reactive({
|
|
loading: false,
|
|
size: 'middle',
|
|
seached: false,
|
|
data: [],
|
|
selectedRowKeys: [],
|
|
});
|
|
|
|
/**表格状态 */
|
|
let nfInfo: any = reactive({
|
|
obj: 'OMC',
|
|
version: appStore.version,
|
|
status: t('views.index.normal'),
|
|
outTimeDate: '',
|
|
serialNum: appStore.serialNum,
|
|
});
|
|
|
|
/**表格状态类型 */
|
|
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 2020 x86_64 GNU/Linux',
|
|
dbInfo: 'db v9.9.9',
|
|
ipAddress: '-',
|
|
port: 33030,
|
|
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;
|
|
// if (res.length) nfInfo.serialNum = res[0].serialNum;
|
|
for (let i = 0; i < res.length; i++) {
|
|
if (res[i].status == '正常' || res[i].status == 'Normal') {
|
|
rightNum++;
|
|
} else {
|
|
errorNum++;
|
|
}
|
|
}
|
|
|
|
const optionData: any = {
|
|
title: {
|
|
text: '',
|
|
subtext: '',
|
|
left: 'center',
|
|
},
|
|
tooltip: {
|
|
trigger: 'item',
|
|
},
|
|
legend: {
|
|
orient: 'vertical',
|
|
left: 'left',
|
|
},
|
|
color: indexColor.value.map(item => item.tagClass),
|
|
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: {},
|
|
},
|
|
],
|
|
};
|
|
|
|
fnDesign(statusBar.value, optionData);
|
|
});
|
|
}
|
|
|
|
function fnDesign(container: HTMLElement | undefined, option: any) {
|
|
if (!container) return;
|
|
|
|
if (!statusBarChart.value) {
|
|
statusBarChart.value = markRaw(echarts.init(container, 'light'));
|
|
}
|
|
option && statusBarChart.value.setOption(option);
|
|
|
|
// 创建 ResizeObserver 实例
|
|
var observer = new ResizeObserver(entries => {
|
|
if (statusBarChart.value) {
|
|
statusBarChart.value.resize();
|
|
}
|
|
});
|
|
// 监听元素大小变化
|
|
observer.observe(container);
|
|
}
|
|
|
|
/**抽屉 网元详细信息 */
|
|
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);
|
|
const totalMemInKB = pronData.memUsage?.totalMem;
|
|
const nfUsedMemInKB = pronData.memUsage?.nfUsedMem;
|
|
const sysMemUsageInKB = pronData.memUsage?.sysMemUsage;
|
|
|
|
// 将KB转换为MB
|
|
const totalMemInMB = Math.round((totalMemInKB / 1024) * 100) / 100;
|
|
const nfUsedMemInMB = Math.round((nfUsedMemInKB / 1024) * 100) / 100;
|
|
const sysMemUsageInMB =
|
|
Math.round((sysMemUsageInKB / 1024) * 100) / 100;
|
|
|
|
//渲染详细信息
|
|
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:' +
|
|
totalMemInMB +
|
|
'MB; ' +
|
|
pronData.name +
|
|
':' +
|
|
nfUsedMemInMB +
|
|
'MB; SYS:' +
|
|
sysMemUsageInMB +
|
|
'MB',
|
|
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;
|
|
}
|
|
})
|
|
.finally(() => {
|
|
fnLocale();
|
|
fnGetList(true);
|
|
timer = setInterval(() => fnGetList(false), 10000); // 每隔10秒执行一次
|
|
});
|
|
});
|
|
|
|
// 在组件卸载之前清除定时器
|
|
|
|
onBeforeUnmount(() => {
|
|
clearInterval(timer);
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<PageContainer :breadcrumb="{}">
|
|
<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">{{ 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 style="width: 100%; min-height: 200px" ref="statusBar"></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.serialNum
|
|
}}</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>
|