Files
fe.ems.vue3/src/views/dashboard/overview/index.vue
2024-01-31 16:17:03 +08:00

320 lines
8.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { onBeforeUnmount, onMounted, reactive, ref } from 'vue';
import useI18n from '@/hooks/useI18n';
import Topology from './components/Topology/index.vue';
import NeResources from './components/NeResources/index.vue';
import UserActivity from './components/UserActivity/index.vue';
import AlarnTypeBar from './components/AlarnTypeBar/index.vue';
import UPFFlow from './components/UPFFlow/index.vue';
import { listSub } from '@/api/neUser/sub';
import { listUENum } from '@/api/neUser/ue';
import { listBase5G } from '@/api/neUser/base5G';
import {
graphNodeClickID,
graphState,
notNeNodes,
graphNodeStateNum,
} from './hooks/useTopology';
import { upfTotalFlow, upfTFActive } from './hooks/useUPFTotalFlow';
import { useFullscreen } from '@vueuse/core';
import useWS from './hooks/useWS';
import useAppStore from '@/store/modules/app';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
const appStore = useAppStore();
const { t } = useI18n();
const { wsSend, cdrEventSend, ueEventSend, upfTFSend } = useWS();
/**用户在线信息 */
let onlineInfo: {
/**签约用户数量 */
subNum: number;
/**在线用户数 */
ueNum: any;
/**基站数量 */
nbNum: number;
/**原始严重程度 */
activeAlarmSeverity: DictType[];
} = reactive({
subNum: 0,
ueNum: 0,
nbNum: 0,
activeAlarmSeverity: [],
});
/**总览节点 */
const viewportDom = ref<HTMLElement | null>(null);
const { isFullscreen, toggle } = useFullscreen(viewportDom);
/**10s调度器 */
const stateInterval = ref<any>(null);
/**网元状态定时器 */
const stateTimeout = ref<any>(null);
/**查询网元状态 */
async function fnGetState() {
clearTimeout(stateTimeout.value);
// 获取节点状态
for (const node of graphState.data.nodes) {
if (notNeNodes.includes(node.id)) continue;
const { neType, neId } = node.neInfo;
if (!neType || !neId) continue;
wsSend({
requestId: `neState_${neType}_${neId}`,
type: 'ne_state',
data: {
neType: neType,
neId: neId,
},
});
}
// stateTimeout.value = setTimeout(() => fnGetState(), 5_000);
}
/**初始数据函数 */
function InitData() {
cdrEventSend();
ueEventSend();
upfTFSend(0);
upfTFSend(7);
upfTFSend(30);
fnGetState(); // 获取网元状态
stateInterval.value = setInterval(() => {
upfTFActive.value = upfTFActive.value >= 2 ? 0 : upfTFActive.value + 1;
if (upfTFActive.value === 0) {
upfTFSend(7);
} else if (upfTFActive.value === 1) {
upfTFSend(30);
} else if (upfTFActive.value === 2) {
upfTFSend(0);
}
}, 10_000);
}
onMounted(() => {
Promise.allSettled([
listSub({
neid: '003',
sortField: 'imsi',
sortOrder: 'asc',
pageNum: '1',
pageSize: '20',
}),
listBase5G({
//
neType: 'AMF',
neId: '001',
id: '',
pageNum: 1,
/**每页条数 */
pageSize: 20,
}),
listUENum('001'),
])
.then(resArr => {
if (resArr[0].status === 'fulfilled') {
onlineInfo.subNum = resArr[0].value.total;
}
if (
resArr[1].status === 'fulfilled' &&
resArr[1].value.code === RESULT_CODE_SUCCESS &&
Array.isArray(resArr[1].value.rows)
) {
onlineInfo.nbNum = resArr[1].value.rows.length;
}
if (
resArr[2].status === 'fulfilled' &&
resArr[2].value?.code === RESULT_CODE_SUCCESS
) {
onlineInfo.ueNum = resArr[2].value?.data;
}
})
.finally(() => {
InitData();
});
});
onBeforeUnmount(() => {
clearTimeout(stateTimeout.value);
clearTimeout(stateInterval.value);
});
</script>
<template>
<div class="viewport" ref="viewportDom">
<div class="brand">
<div
class="brand-title"
@click="toggle"
:title="t('views.dashboard.overview.fullscreen')"
>
{{ t('views.dashboard.overview.title') }}
<FullscreenExitOutlined v-if="isFullscreen" />
<FullscreenOutlined v-else />
</div>
<div class="brand-desc">{{ appStore.appName }}</div>
</div>
<div class="column">
<!--概览-->
<div class="skim panel">
<div class="inner">
<div class="item">
<h4>{{ onlineInfo.subNum }}</h4>
<span>
<UserOutlined style="color: #006cff" />
{{ t('views.dashboard.overview.skim.users') }}
</span>
</div>
<div class="item">
<h4>{{ onlineInfo.nbNum }}</h4>
<span>
<GlobalOutlined style="color: #edcb35" />
{{ t('views.dashboard.overview.skim.base') }}
</span>
</div>
<div class="item">
<h4>{{ onlineInfo.ueNum }}</h4>
<span>
<UserSwitchOutlined style="color: #6acca3" />
Data {{ t('views.dashboard.overview.skim.session') }}
</span>
</div>
<div class="item">
<h4>0</h4>
<span>
<UserSwitchOutlined style="color: #6acca3" />
IMS {{ t('views.dashboard.overview.skim.session') }}
</span>
</div>
</div>
</div>
<!-- 用户行为 -->
<div class="userActivity panel">
<div class="inner">
<h3>
<WhatsAppOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.userActivity.title') }}
</h3>
<div class="chart">
<UserActivity />
</div>
</div>
</div>
</div>
<div class="column" style="flex: 4; margin: 1.333rem 0.833rem 0">
<!-- 实时流量 -->
<div class="upfFlow panel">
<div class="inner">
<h3>
<AreaChartOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.upfFlow.title') }}
</h3>
<div class="chart">
<UPFFlow />
</div>
</div>
</div>
<!-- 网络拓扑 -->
<div class="topology panel">
<div class="inner">
<h3>
<span>
<ApartmentOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.topology.title') }}
</span>
<span>
{{ t('views.dashboard.overview.topology.normal') }}:
<span class="normal"> {{ graphNodeStateNum[0] }} </span>
{{ t('views.dashboard.overview.topology.abnormal') }}:
<span class="abnormal"> {{ graphNodeStateNum[1] }} </span>
</span>
</h3>
<div class="chart">
<Topology />
</div>
</div>
</div>
</div>
<div class="column">
<!-- UPF总流量 -->
<div class="upfFlowTotal panel">
<div class="inner">
<!-- 筛选 -->
<div class="filter">
<span
:data-key="v"
:class="{ active: upfTFActive === i }"
v-for="(v, i) in ['0', '7', '30']"
:key="v"
@click="
() => {
upfTFActive = i;
}
"
>
{{
v === '0'
? '24' + t('common.units.hour')
: v + t('common.units.day')
}}
</span>
</div>
<!-- 数据 -->
<div class="data">
<div class="item">
<h4>{{ upfTotalFlow[upfTFActive].up }}</h4>
<span>
<ArrowUpOutlined style="color: #597ef7" />
{{ t('views.dashboard.overview.upfFlowTotal.up') }}
</span>
</div>
<div class="item">
<h4>{{ upfTotalFlow[upfTFActive].down }}</h4>
<span>
<ArrowDownOutlined style="color: #52c41a" />
{{ t('views.dashboard.overview.upfFlowTotal.down') }}
</span>
</div>
</div>
</div>
</div>
<!-- 资源情况 -->
<div class="resources panel">
<div class="inner">
<h3>
<DashboardOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.resources.title') }}
{{ graphNodeClickID }}
</h3>
<div class="chart">
<NeResources />
</div>
</div>
</div>
<!-- 告警统计 -->
<div class="alarmType panel">
<div class="inner">
<h3>
<PieChartOutlined style="color: #68d8fe" />&nbsp;&nbsp;
{{ t('views.dashboard.overview.alarmTypeBar.alarmSum') }}
</h3>
<div class="chart">
<AlarnTypeBar />
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
@import url('./css/index.css');
</style>