首页的变更(仪表盘稍后做调整)
This commit is contained in:
@@ -1,450 +1,52 @@
|
||||
<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();
|
||||
import Index from '@/views/index/tenantIndex.vue';
|
||||
import defalutIndex from '@/views/index/defaultIndex.vue';
|
||||
import Dash from '@/views/dashboard/overview/index.vue';
|
||||
import Gold from '@/views/perfManage/goldTarget/index.vue';
|
||||
import { getConfigKey } from '@/api/system/config';
|
||||
|
||||
echarts.use([
|
||||
TooltipComponent,
|
||||
GaugeChart,
|
||||
TitleComponent,
|
||||
LegendComponent,
|
||||
PieChart,
|
||||
CanvasRenderer,
|
||||
LabelLayout,
|
||||
]);
|
||||
import { defineAsyncComponent, onMounted, shallowRef } from 'vue';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
|
||||
/**图DOM节点实例对象 */
|
||||
const statusBar = ref<HTMLElement | undefined>(undefined);
|
||||
const currentComponent = shallowRef(
|
||||
defineAsyncComponent(() => import('@/views/index/defaultIndex.vue'))
|
||||
);
|
||||
|
||||
/**图实例对象 */
|
||||
const statusBarChart = ref<any>(null);
|
||||
// function loadComponent(sysValue: String) {
|
||||
// //PS:import不允许变量形式 也有人说左右都穿插字符串即可---经测试不行
|
||||
|
||||
/**网元状态字典数据 */
|
||||
let indexColor = ref<DictType[]>([
|
||||
{ label: 'Normal', value: 'normal', elTagType: '', elTagClass: '#91cc75' },
|
||||
{
|
||||
label: 'Abnormal',
|
||||
value: 'abnormal',
|
||||
elTagType: '',
|
||||
elTagClass: '#ee6666',
|
||||
},
|
||||
]);
|
||||
// // currentComponent.value = defineAsyncComponent(
|
||||
// // () => import(`@/views/${selectedComponent.value}.vue`)
|
||||
// // );
|
||||
|
||||
/**表格字段列 */
|
||||
//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 #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;
|
||||
// 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.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: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
// switch (sysValue) {
|
||||
// case 'Index':
|
||||
// currentComponent.value = Index;
|
||||
// break;
|
||||
// case 'Gold':
|
||||
// currentComponent.value = Gold;
|
||||
// break;
|
||||
// case 'Dash':
|
||||
// currentComponent.value = Dash;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
onMounted(() => {
|
||||
getDict('index_status')
|
||||
.then(res => {
|
||||
if (res.length > 0) {
|
||||
indexColor.value = res;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
fnLocale();
|
||||
fnGetList(true);
|
||||
timer = setInterval(() => fnGetList(false), 10000); // 每隔10秒执行一次
|
||||
});
|
||||
});
|
||||
// getConfigKey('sys.indexModule').then(res => {
|
||||
// if (res.code === RESULT_CODE_SUCCESS && res.data) {
|
||||
// loadComponent(res.data);
|
||||
// }
|
||||
// });
|
||||
|
||||
// 在组件卸载之前清除定时器
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearInterval(timer);
|
||||
if (useUserStore().roles.includes('tenant')) {
|
||||
currentComponent.value = Index;
|
||||
}
|
||||
});
|
||||
</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>
|
||||
<component :is="currentComponent" />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
450
src/views/index/defaultIndex.vue
Normal file
450
src/views/index/defaultIndex.vue
Normal file
@@ -0,0 +1,450 @@
|
||||
<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', 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.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 #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;
|
||||
// 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.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: {},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
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>
|
||||
393
src/views/index/tenantIndex.vue
Normal file
393
src/views/index/tenantIndex.vue
Normal file
@@ -0,0 +1,393 @@
|
||||
<script setup lang="ts">
|
||||
import * as echarts from 'echarts/core';
|
||||
import {
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
TitleComponent,
|
||||
LegendComponent,
|
||||
DataZoomComponent,
|
||||
} from 'echarts/components';
|
||||
import { LineChart, LineSeriesOption } from 'echarts/charts';
|
||||
import { UniversalTransition } from 'echarts/features';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import { listMain } from '@/api/index';
|
||||
import { PieChart } from 'echarts/charts';
|
||||
import { LabelLayout } from 'echarts/features';
|
||||
import { ref, onMounted, markRaw } from 'vue';
|
||||
import { PageContainer } from 'antdv-pro-layout';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import UPFTEST from './tenantUPF.vue';
|
||||
import { BarChart } from 'echarts/charts';
|
||||
|
||||
const { t } = useI18n();
|
||||
echarts.use([
|
||||
TooltipComponent,
|
||||
LegendComponent,
|
||||
PieChart,
|
||||
CanvasRenderer,
|
||||
BarChart,
|
||||
LabelLayout,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
DataZoomComponent,
|
||||
LineChart,
|
||||
UniversalTransition,
|
||||
TitleComponent,
|
||||
]);
|
||||
|
||||
/**图DOM节点实例对象 */
|
||||
const statusBar = ref<HTMLElement | undefined>(undefined);
|
||||
|
||||
/**图实例对象 */
|
||||
const statusBarChart = ref<any>(null);
|
||||
|
||||
/**查询网元状态列表 */
|
||||
function fnGetList(one: boolean) {
|
||||
listMain().then(res => {
|
||||
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: t('views.dashboard.overview.skim.baseTitle'),
|
||||
textStyle: {
|
||||
//标题内容的样式
|
||||
// color: '#000', //
|
||||
fontStyle: 'normal', //lic主标题文字字体风格,默认normal,有italic(斜体),oblique(斜体)
|
||||
//fontWeight: "700", //可选normal(正常),bold(加粗),bolder(加粗),lighter(变细),100|200|300|400|500...
|
||||
// fontFamily: "PingFangSC-Regular, PingFang SC", //主题文字字体,默认微软雅黑
|
||||
// fontSize: 20 //主题文字字体大小,默认为18px
|
||||
},
|
||||
},
|
||||
// legend: {
|
||||
// top: '10%',
|
||||
// textStyle: {
|
||||
// fontSize: 10
|
||||
// },
|
||||
// data: ['低危', '高位']
|
||||
// },
|
||||
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
top: '10%',
|
||||
left: '3%',
|
||||
right: '3%',
|
||||
bottom: '1%',
|
||||
containLabel: true,
|
||||
},
|
||||
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [
|
||||
t('views.dashboard.overview.skim.gnbBase'),
|
||||
t('views.dashboard.overview.skim.gnbUeNum'),
|
||||
t('views.dashboard.overview.skim.enbBase'),
|
||||
t('views.dashboard.overview.skim.enbUeNum'),
|
||||
],
|
||||
axisTick: {
|
||||
show: false,
|
||||
}, // 取消坐标轴刻度线
|
||||
axisLine: {
|
||||
show: false, // 取消坐标轴线
|
||||
}, // 取消坐标轴线
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisTick: {
|
||||
show: false,
|
||||
}, // 取消坐标轴刻度线
|
||||
axisLine: {
|
||||
show: false, // 取消坐标轴线
|
||||
}, // 取消坐标轴线
|
||||
axisLabel: {
|
||||
show: false,
|
||||
}, // 取消坐标轴刻度线
|
||||
splitLine: {
|
||||
show: false, // 取消网格线
|
||||
}, // 取消网格线
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: [
|
||||
3,
|
||||
{
|
||||
value: 5,
|
||||
// itemStyle: {
|
||||
// color: '#f9d3e3',
|
||||
// },
|
||||
},
|
||||
2,
|
||||
4,
|
||||
],
|
||||
itemStyle: {
|
||||
borderRadius: [10, 10, 0, 0], // 设置四个圆角的半径,顺序为左上、右上、右下、左下
|
||||
},
|
||||
label: {
|
||||
show: true, // 显示数值
|
||||
position: 'inside', // 设置显示位置为柱状图内部
|
||||
fontSize: 15, // 设置字体大小
|
||||
formatter: (params: any) => {
|
||||
if (!params.value) return '';
|
||||
return `${params.value}`;
|
||||
},
|
||||
},
|
||||
type: 'bar',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fnGetList(true);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<PageContainer>
|
||||
<div style="background-color: #f7f8fc; padding: 20px">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="8">
|
||||
<a-card
|
||||
:bordered="false"
|
||||
style="
|
||||
background: linear-gradient(135deg, #17ead9, #6078ea);
|
||||
margin: 'left';
|
||||
"
|
||||
class="cardClass"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="10">
|
||||
<a-avatar
|
||||
:size="76"
|
||||
style="
|
||||
background: linear-gradient(135deg, #17ead9, #6078ea);
|
||||
margin-top: 15px;
|
||||
"
|
||||
>
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</a-col>
|
||||
<a-col :span="14">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="24">
|
||||
<h1
|
||||
style="
|
||||
margin-top: 10px;
|
||||
color: #e1f6e1;
|
||||
font-size: 30px;
|
||||
margin-right: 20px;
|
||||
"
|
||||
>
|
||||
{{ t('views.dashboard.overview.skim.users') }}
|
||||
</h1>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-statistic
|
||||
:value="3000"
|
||||
:value-style="{
|
||||
color: '#e1f6e1',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '32px',
|
||||
marginLeft: '50px',
|
||||
}"
|
||||
style="margin-left: -50px"
|
||||
>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<!-- <a-card-meta
|
||||
:title="t('views.dashboard.overview.skim.users')"
|
||||
description="This is the description"
|
||||
style="margin-top: 20px; color: #f7f8fc"
|
||||
class="my-card-meta1"
|
||||
>
|
||||
<template #avatar>
|
||||
<a-avatar
|
||||
:size="64"
|
||||
style="background: linear-gradient(135deg, #17ead9, #6078ea)"
|
||||
>
|
||||
<template #icon><UserOutlined /></template>
|
||||
</a-avatar>
|
||||
</template>
|
||||
</a-card-meta> -->
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="8">
|
||||
<a-card
|
||||
:bordered="false"
|
||||
style="
|
||||
background: linear-gradient(135deg, #ce9ffc, #7367f0);
|
||||
margin: 'center';
|
||||
"
|
||||
class="cardClass"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="10">
|
||||
<a-avatar
|
||||
:size="76"
|
||||
style="
|
||||
background: linear-gradient(135deg, #ce9ffc, #7367f0);
|
||||
margin-top: 15px;
|
||||
"
|
||||
>
|
||||
<template #icon><comment-outlined /></template>
|
||||
</a-avatar>
|
||||
</a-col>
|
||||
<a-col :span="14">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="24">
|
||||
<h1
|
||||
style="margin-top: 10px; color: #e1f6e1; font-size: 30px"
|
||||
>
|
||||
{{ t('views.dashboard.overview.skim.imsUeNum') }}
|
||||
</h1>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-statistic
|
||||
:value="2"
|
||||
:value-style="{
|
||||
color: '#e1f6e1',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '32px',
|
||||
marginLeft: '50px',
|
||||
}"
|
||||
style="margin-right: 20px"
|
||||
>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="8">
|
||||
<a-card
|
||||
:bordered="false"
|
||||
style="
|
||||
background: linear-gradient(135deg, #ffe985, #fa742b);
|
||||
margin: 'right';
|
||||
"
|
||||
class="cardClass"
|
||||
>
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="10">
|
||||
<a-avatar
|
||||
:size="76"
|
||||
style="
|
||||
background: linear-gradient(135deg, #ffe985, #fa742b);
|
||||
margin-top: 15px;
|
||||
"
|
||||
>
|
||||
<template #icon><database-outlined /></template>
|
||||
</a-avatar>
|
||||
</a-col>
|
||||
<a-col :span="14">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="24">
|
||||
<h1
|
||||
style="margin-top: 10px; color: #e1f6e1; font-size: 30px"
|
||||
>
|
||||
{{ t('views.dashboard.overview.skim.smfUeNum') }}
|
||||
</h1>
|
||||
</a-col>
|
||||
<a-col :span="24">
|
||||
<a-statistic
|
||||
:value="5"
|
||||
:value-style="{
|
||||
color: '#e1f6e1',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '32px',
|
||||
marginLeft: '50px',
|
||||
}"
|
||||
style="margin-right: 20px"
|
||||
>
|
||||
</a-statistic>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<!-- <a-col :span="6">
|
||||
<a-card :bordered="false" class="cardClass">
|
||||
<div style="width: 100%; min-height: 200px" ref="statusBar"></div>
|
||||
到时候画饼图 显示四个options 分别45G基站数/用户数
|
||||
</a-card>
|
||||
</a-col> -->
|
||||
</a-row>
|
||||
</div>
|
||||
<div style="background-color: #f7f8fc; padding: 20px">
|
||||
<a-row :gutter="16">
|
||||
<a-col :span="14">
|
||||
<a-card :bordered="false" class="cardClass"> <UPFTEST /></a-card>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="10">
|
||||
<a-card :bordered="false" class="cardClass">
|
||||
<div style="width: 100%; min-height: 400px" ref="statusBar"></div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.cardClass {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-top: 0.1rem;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
/* 设置图表容器大小和位置 */
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
299
src/views/index/tenantUPF.vue
Normal file
299
src/views/index/tenantUPF.vue
Normal file
@@ -0,0 +1,299 @@
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { listKPIData } from '@/api/perfManage/goldTarget';
|
||||
import * as echarts from 'echarts/core';
|
||||
import {
|
||||
TooltipComponent,
|
||||
TooltipComponentOption,
|
||||
GridComponent,
|
||||
GridComponentOption,
|
||||
LegendComponent,
|
||||
LegendComponentOption,
|
||||
} from 'echarts/components';
|
||||
import { LineChart, LineSeriesOption } from 'echarts/charts';
|
||||
import { UniversalTransition } from 'echarts/features';
|
||||
import { CanvasRenderer } from 'echarts/renderers';
|
||||
import { markRaw } from 'vue';
|
||||
import useI18n from '@/hooks/useI18n';
|
||||
import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||
import {
|
||||
upfFlowData,
|
||||
upfFlowParse,
|
||||
} from '../dashboard/overview/hooks/useUPFTotalFlow';
|
||||
const { t } = useI18n();
|
||||
|
||||
echarts.use([
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
LineChart,
|
||||
CanvasRenderer,
|
||||
UniversalTransition,
|
||||
]);
|
||||
|
||||
type EChartsOption = echarts.ComposeOption<
|
||||
| TooltipComponentOption
|
||||
| GridComponentOption
|
||||
| LegendComponentOption
|
||||
| LineSeriesOption
|
||||
>;
|
||||
|
||||
/**图DOM节点实例对象 */
|
||||
const upfFlow = ref<HTMLElement | undefined>(undefined);
|
||||
|
||||
/**图实例对象 */
|
||||
const upfFlowChart = ref<any>(null);
|
||||
|
||||
function fnDesign(container: HTMLElement | undefined, option: EChartsOption) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
if (!upfFlowChart.value) {
|
||||
upfFlowChart.value = markRaw(echarts.init(container, 'light'));
|
||||
}
|
||||
|
||||
option && upfFlowChart.value.setOption(option);
|
||||
|
||||
// 创建 ResizeObserver 实例
|
||||
var observer = new ResizeObserver(entries => {
|
||||
if (upfFlowChart.value) {
|
||||
upfFlowChart.value.resize();
|
||||
}
|
||||
});
|
||||
// 监听元素大小变化
|
||||
observer.observe(container);
|
||||
}
|
||||
|
||||
//渲染速率图
|
||||
function handleRanderChart() {
|
||||
const { lineXTime, lineYUp, lineYDown } = upfFlowData.value;
|
||||
|
||||
var yAxisSeries: any = [
|
||||
{
|
||||
name: t('views.dashboard.overview.upfFlow.up'),
|
||||
type: 'line',
|
||||
color: 'rgba(250, 219, 20)',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(250, 219, 20, .5)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(250, 219, 20, 0.5)',
|
||||
},
|
||||
]),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10,
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
formatter: '{b}',
|
||||
data: lineYUp,
|
||||
},
|
||||
{
|
||||
name: t('views.dashboard.overview.upfFlow.down'),
|
||||
type: 'line',
|
||||
color: 'rgba(92, 123, 217)',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgba(92, 123, 217, .5)',
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgba(92, 123, 217, 0.5)',
|
||||
},
|
||||
]),
|
||||
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||
shadowBlur: 10,
|
||||
},
|
||||
symbol: 'circle',
|
||||
symbolSize: 5,
|
||||
formatter: '{b}',
|
||||
data: lineYDown,
|
||||
},
|
||||
];
|
||||
|
||||
const optionData: EChartsOption = {
|
||||
tooltip: {
|
||||
show: true, //是否显示提示框组件
|
||||
trigger: 'axis',
|
||||
//formatter:'{a0}:{c0}<br>{a1}:{c1}'
|
||||
formatter: function (param: any) {
|
||||
var tip = '';
|
||||
if (param !== null && param.length > 0) {
|
||||
tip += param[0].name + '<br />';
|
||||
for (var i = 0; i < param.length; i++) {
|
||||
tip +=
|
||||
param[i].marker +
|
||||
param[i].seriesName +
|
||||
': ' +
|
||||
param[i].value +
|
||||
'<br />';
|
||||
}
|
||||
}
|
||||
return tip;
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: yAxisSeries.map((s: any) => s.name),
|
||||
textStyle: {
|
||||
fontSize: 12,
|
||||
},
|
||||
left: 'center', // 设置图例居中
|
||||
},
|
||||
grid: {
|
||||
top: '14%',
|
||||
left: '4%',
|
||||
right: '4%',
|
||||
bottom: '12%',
|
||||
containLabel: true,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: lineXTime,
|
||||
axisLabel: {
|
||||
formatter: function (params: any) {
|
||||
return params.split(' ')[1];
|
||||
},
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {},
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
name: '(Mbps)',
|
||||
nameTextStyle: {
|
||||
fontSize: 12, // 设置文字距离x轴的距离
|
||||
padding: [0, -10, 0, 0], // 设置名称在x轴方向上的偏移
|
||||
},
|
||||
type: 'value',
|
||||
// splitNumber: 4,
|
||||
min: 0,
|
||||
//max: 300,
|
||||
axisLabel: {
|
||||
formatter: '{value}',
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {},
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 90,
|
||||
end: 100,
|
||||
},
|
||||
{
|
||||
start: 90,
|
||||
end: 100,
|
||||
},
|
||||
],
|
||||
series: yAxisSeries,
|
||||
};
|
||||
fnDesign(upfFlow.value, optionData);
|
||||
}
|
||||
|
||||
/**查询初始UPF数据 */
|
||||
function fnGetInitData() {
|
||||
// 查询10分钟前的
|
||||
const nowDate: Date = new Date();
|
||||
const tenMinutesAgo = new Date(nowDate.getTime() - 5 * 60 * 1000);
|
||||
|
||||
listKPIData({
|
||||
neType: 'UPF',
|
||||
neId: '001',
|
||||
startTime: parseDateToStr(tenMinutesAgo),
|
||||
endTime: parseDateToStr(nowDate),
|
||||
// startTime: '2024-03-20 19:50:00',
|
||||
// endTime: '2024-03-20 19:55:00',
|
||||
interval: 5, // 5秒
|
||||
sortField: 'timeGroup',
|
||||
sortOrder: 'asc',
|
||||
})
|
||||
.then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
for (const item of res.data) {
|
||||
upfFlowParse(item);
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
handleRanderChart();
|
||||
});
|
||||
}
|
||||
|
||||
watch(
|
||||
() => upfFlowData.value,
|
||||
v => {
|
||||
if (upfFlowChart.value == null) return;
|
||||
upfFlowChart.value.setOption({
|
||||
xAxis: {
|
||||
data: v.lineXTime,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: v.lineYUp,
|
||||
},
|
||||
{
|
||||
data: v.lineYDown,
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
fnGetInitData();
|
||||
|
||||
// setInterval(() => {
|
||||
// upfFlowData.value.lineXTime.push(parseDateToStr(new Date()));
|
||||
// const upN3 = parseSizeFromKbs(+145452, 5);
|
||||
// upfFlowData.value.lineYUp.push(upN3[0]);
|
||||
// const downN6 = parseSizeFromKbs(+232343, 5);
|
||||
// upfFlowData.value.lineYDown.push(downN6[0]);
|
||||
|
||||
// upfFlowChart.value.setOption({
|
||||
// xAxis: {
|
||||
// data: upfFlowData.value.lineXTime,
|
||||
// },
|
||||
// series: [
|
||||
// {
|
||||
// data: upfFlowData.value.lineYUp,
|
||||
// },
|
||||
// {
|
||||
// data: upfFlowData.value.lineYDown,
|
||||
// },
|
||||
// ],
|
||||
// });
|
||||
// }, 5000);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div ref="upfFlow" class="chart-container"></div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.chart-container {
|
||||
/* 设置图表容器大小和位置 */
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user