320 lines
8.8 KiB
Vue
320 lines
8.8 KiB
Vue
<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" />
|
||
{{ 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" />
|
||
{{ 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" />
|
||
{{ 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" />
|
||
{{ 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" />
|
||
{{ 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>
|