feat: 看板用户行为事件
This commit is contained in:
@@ -518,18 +518,15 @@ export default {
|
|||||||
topology: {
|
topology: {
|
||||||
title: "Network Topology",
|
title: "Network Topology",
|
||||||
},
|
},
|
||||||
cdrEvent: {
|
userActivity: {
|
||||||
title: "CDR User Activity",
|
title: "User Activity",
|
||||||
id: "Serial",
|
|
||||||
type: "Type",
|
type: "Type",
|
||||||
msg: "Info",
|
duration: "Duration",
|
||||||
|
caller: "Caller",
|
||||||
|
called: "Called",
|
||||||
|
result: "Result",
|
||||||
|
time: "Time",
|
||||||
},
|
},
|
||||||
ueEvent: {
|
|
||||||
title: "UE User Activity",
|
|
||||||
id: "IMSI",
|
|
||||||
type: "Type",
|
|
||||||
msg: "Info",
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
neUser: {
|
neUser: {
|
||||||
|
|||||||
@@ -518,18 +518,15 @@ export default {
|
|||||||
topology: {
|
topology: {
|
||||||
title: "网络拓扑",
|
title: "网络拓扑",
|
||||||
},
|
},
|
||||||
cdrEvent: {
|
userActivity: {
|
||||||
title: "CDR用户活动",
|
title: "用户活动",
|
||||||
id: "编号",
|
|
||||||
type: "类型",
|
type: "类型",
|
||||||
msg: "信息",
|
duration: "时长",
|
||||||
|
caller: "主叫",
|
||||||
|
called: "被叫",
|
||||||
|
result: "结果",
|
||||||
|
time: "时间",
|
||||||
},
|
},
|
||||||
ueEvent: {
|
|
||||||
title: "UE用户活动",
|
|
||||||
id: "IMSI",
|
|
||||||
type: "类型",
|
|
||||||
msg: "信息",
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
neUser: {
|
neUser: {
|
||||||
|
|||||||
@@ -1,134 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import {
|
|
||||||
cdrEventData,
|
|
||||||
cdrEventTotal,
|
|
||||||
cdrEventId,
|
|
||||||
} from '../../hooks/useCDREvent';
|
|
||||||
import useI18n from '@/hooks/useI18n';
|
|
||||||
const { t } = useI18n();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="cdr" style="display: block">
|
|
||||||
<div class="cdr-head">
|
|
||||||
<span class="col">{{ t('views.dashboard.overview.cdrEvent.id') }}</span>
|
|
||||||
<span class="col">{{ t('views.dashboard.overview.cdrEvent.type') }}</span>
|
|
||||||
<span class="col-w">
|
|
||||||
{{ t('views.dashboard.overview.cdrEvent.msg') }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="cdr-marquee-view">
|
|
||||||
<div
|
|
||||||
class="row"
|
|
||||||
:class="{ 'row-new': item.id === cdrEventId }"
|
|
||||||
v-for="item in cdrEventData"
|
|
||||||
:key="item.id"
|
|
||||||
>
|
|
||||||
<span class="col" :title="item.call">{{ item.call }}</span>
|
|
||||||
<span class="col" :title="item.type">{{ item.type }}</span>
|
|
||||||
<span class="col-w" :title="item.msg">{{ item.msg }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.cdr {
|
|
||||||
height: 88%;
|
|
||||||
|
|
||||||
&-head {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
font-size: 0.583rem;
|
|
||||||
padding: 0.5rem 1.5rem;
|
|
||||||
color: #68d8fe;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
line-height: 1.05;
|
|
||||||
& .col {
|
|
||||||
min-width: 3.2rem;
|
|
||||||
width: 30%;
|
|
||||||
margin-right: 1rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
&-w {
|
|
||||||
min-width: 8.4rem;
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-marquee-view {
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
height: 92%;
|
|
||||||
|
|
||||||
/* 修改滚动条的样式 */
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 8px; /* 设置滚动条宽度 */
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background-color: #101129; /* 设置滚动条轨道背景颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #28293f; /* 设置滚动条滑块颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
background-color: #68d8fe; /* 设置鼠标悬停时滚动条滑块颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
& .row {
|
|
||||||
line-height: 1.5;
|
|
||||||
padding: 0 1.5rem;
|
|
||||||
color: #61a8ff;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
cursor: context-menu;
|
|
||||||
&-new {
|
|
||||||
color: #fff;
|
|
||||||
animation: backInRight 0.3s alternate;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
@keyframes backInRight {
|
|
||||||
0% {
|
|
||||||
opacity: 0.7;
|
|
||||||
-webkit-transform: translateX(2000px) scale(0.7);
|
|
||||||
transform: translateX(2000px) scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
80% {
|
|
||||||
opacity: 0.7;
|
|
||||||
-webkit-transform: translateX(0) scale(0.7);
|
|
||||||
transform: translateX(0) scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
-webkit-transform: scale(1);
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .col {
|
|
||||||
min-width: 3.2rem;
|
|
||||||
width: 30%;
|
|
||||||
margin-right: 1rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
&-w {
|
|
||||||
min-width: 8.4rem;
|
|
||||||
width: 60%;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import { ueEventData, ueEventTotal, ueEventId } from '../../hooks/useUEEvent';
|
|
||||||
import useI18n from '@/hooks/useI18n';
|
|
||||||
const { t } = useI18n();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="ue" style="display: block">
|
|
||||||
<div class="ue-head">
|
|
||||||
<span class="col">{{ t('views.dashboard.overview.ueEvent.id') }}</span>
|
|
||||||
<span class="col">{{ t('views.dashboard.overview.ueEvent.type') }}</span>
|
|
||||||
<span class="col-w">{{ t('views.dashboard.overview.ueEvent.msg') }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="ue-marquee-view">
|
|
||||||
<div
|
|
||||||
class="row"
|
|
||||||
:class="{ 'row-new': item.id === ueEventId }"
|
|
||||||
v-for="item in ueEventData"
|
|
||||||
:key="item.id"
|
|
||||||
>
|
|
||||||
<span class="col" :title="item.imsi">{{ item.imsi }}</span>
|
|
||||||
<span class="col" :title="item.type">{{ item.type }}</span>
|
|
||||||
<span class="col-w" :title="item.msg">{{ item.msg }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="less" scoped>
|
|
||||||
.ue {
|
|
||||||
height: 88%;
|
|
||||||
|
|
||||||
&-head {
|
|
||||||
background: rgba(255, 255, 255, 0.1);
|
|
||||||
font-size: 0.583rem;
|
|
||||||
padding: 0.5rem 1.5rem;
|
|
||||||
color: #68d8fe;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
line-height: 1.05;
|
|
||||||
& .col {
|
|
||||||
min-width: 3.2rem;
|
|
||||||
width: 30%;
|
|
||||||
margin-right: 1rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
&-w {
|
|
||||||
min-width: 8.4rem;
|
|
||||||
width: 60%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-marquee-view {
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
height: 92%;
|
|
||||||
|
|
||||||
/* 修改滚动条的样式 */
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
width: 8px; /* 设置滚动条宽度 */
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-track {
|
|
||||||
background-color: #101129; /* 设置滚动条轨道背景颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #28293f; /* 设置滚动条滑块颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-webkit-scrollbar-thumb:hover {
|
|
||||||
background-color: #68d8fe; /* 设置鼠标悬停时滚动条滑块颜色 */
|
|
||||||
}
|
|
||||||
|
|
||||||
& .row {
|
|
||||||
line-height: 1.5;
|
|
||||||
padding: 0 1.5rem;
|
|
||||||
color: #61a8ff;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
cursor: context-menu;
|
|
||||||
&-new {
|
|
||||||
color: #fff;
|
|
||||||
animation: backInRight 0.3s alternate;
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
@keyframes backInRight {
|
|
||||||
0% {
|
|
||||||
opacity: 0.7;
|
|
||||||
-webkit-transform: translateX(2000px) scale(0.7);
|
|
||||||
transform: translateX(2000px) scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
80% {
|
|
||||||
opacity: 0.7;
|
|
||||||
-webkit-transform: translateX(0) scale(0.7);
|
|
||||||
transform: translateX(0) scale(0.7);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
-webkit-transform: scale(1);
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .col {
|
|
||||||
min-width: 3.2rem;
|
|
||||||
width: 30%;
|
|
||||||
margin-right: 1rem;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
&-w {
|
|
||||||
min-width: 8.4rem;
|
|
||||||
width: 60%;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
264
src/views/dashboard/overview/components/UserActivity/index.vue
Normal file
264
src/views/dashboard/overview/components/UserActivity/index.vue
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { eventData, eventId } from '../../hooks/useUserActivity';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="activty">
|
||||||
|
<template v-for="item in eventData" :key="item.eId">
|
||||||
|
<div
|
||||||
|
class="card-cdr"
|
||||||
|
:class="{ active: item.eId === eventId }"
|
||||||
|
v-if="item.eType === 'cdr'"
|
||||||
|
>
|
||||||
|
<div class="card-cdr-item">
|
||||||
|
<div>
|
||||||
|
{{ t('views.dashboard.overview.userActivity.type') }}:
|
||||||
|
<span>{{ item.data.callType }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ t('views.dashboard.overview.userActivity.duration') }}:
|
||||||
|
<span>{{ item.data.callDuration }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-cdr-item">
|
||||||
|
<div>
|
||||||
|
{{ t('views.dashboard.overview.userActivity.caller') }}:
|
||||||
|
<span>{{ item.data.callerParty }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ t('views.dashboard.overview.userActivity.called') }}:
|
||||||
|
<span>{{ item.data.calledParty }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ t('views.dashboard.overview.userActivity.result') }}:
|
||||||
|
<span>{{ item.data.cause }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="card-ue"
|
||||||
|
:class="{ active: item.eId === eventId }"
|
||||||
|
v-if="item.eType === 'ue'"
|
||||||
|
>
|
||||||
|
<div class="card-ue-item">
|
||||||
|
<div>
|
||||||
|
{{ t('views.dashboard.overview.userActivity.type') }}:
|
||||||
|
<span>{{ item.type }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{{ t('views.dashboard.overview.userActivity.time') }}:
|
||||||
|
<span v-if="item.type === 'auth-result'">
|
||||||
|
{{ item.data.authTime }}
|
||||||
|
</span>
|
||||||
|
<span v-if="item.type === 'detach'">
|
||||||
|
{{ item.data.detachTime }}
|
||||||
|
</span>
|
||||||
|
<span v-if="item.type === 'cm-state'">
|
||||||
|
{{ item.data.changeTime }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>IMSI: <span>{{ item.data.imei }}</span></div>
|
||||||
|
<div class="card-ue-auth" v-if="item.type === 'auth-result'">
|
||||||
|
<div>
|
||||||
|
GNB ID: <span>{{ item.data.gNBID }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Cell ID: <span>{{ item.data.cellID }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Tac ID: <span>{{ item.data.tacID }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- <div class="card-cdr active">
|
||||||
|
<div class="card-cdr-item">
|
||||||
|
<div>类型: <span>video</span></div>
|
||||||
|
<div>时长: <span>123s</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-cdr-item">
|
||||||
|
<div>主叫: <span>12307550064</span></div>
|
||||||
|
<div>被叫: <span>12307550064</span></div>
|
||||||
|
</div>
|
||||||
|
<div>结果: <span>200</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-cdr">
|
||||||
|
<div class="card-cdr-item">
|
||||||
|
<div>类型: <span>audio</span></div>
|
||||||
|
<div>时长: <span>123s</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-cdr-item">
|
||||||
|
<div>主叫: <span>12307550064</span></div>
|
||||||
|
<div>被叫: <span>12307550064</span></div>
|
||||||
|
</div>
|
||||||
|
<div>结果: <span>200</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-ue">
|
||||||
|
<div class="card-ue-item">
|
||||||
|
<div>类型: <span>auth-result</span></div>
|
||||||
|
<div>Time: <span>2023-01-16 07:28:11</span></div>
|
||||||
|
</div>
|
||||||
|
<div>IMSI: <span>4600212141</span></div>
|
||||||
|
<div class="card-ue-auth">
|
||||||
|
<div>GNB ID: <span>31</span></div>
|
||||||
|
<div>Cell ID: <span>17</span></div>
|
||||||
|
<div>Tac ID: <span>98</span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-ue">
|
||||||
|
<div class="card-ue-item">
|
||||||
|
<div>类型: <span>cm-state</span></div>
|
||||||
|
<div>Time: <span>2023-01-16 07:28:11</span></div>
|
||||||
|
</div>
|
||||||
|
<div>IMSI: <span>4600212141</span></div>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<!-- <div class="card-cdr">
|
||||||
|
{ "recordType":"MOC", // MOC, MTC, MOSM, MTSM
|
||||||
|
"seqNumber":81,
|
||||||
|
"callReference":"Y6ecb69Bj@10.25.0.210",
|
||||||
|
"callerParty":"7112",
|
||||||
|
"calledParty":"7108",
|
||||||
|
"serviceResult":"ok",
|
||||||
|
"seizureTime":1706515269,
|
||||||
|
"answerTime":1706515273,
|
||||||
|
"releaseTime":1706515294,
|
||||||
|
"callDuration":21
|
||||||
|
"callType":"audio" // audio, video
|
||||||
|
"fwdType": "CFB" // CFU,CFB, CFNR, CFNL
|
||||||
|
"fwdParty":"7999",
|
||||||
|
"cause": 200 // 200, 403, 408, 500 .... }
|
||||||
|
|
||||||
|
主叫:callerParty
|
||||||
|
被叫:calledParty
|
||||||
|
时长:callDuration
|
||||||
|
呼叫类型:callType
|
||||||
|
原因:cause
|
||||||
|
信息: 主叫 -> 被叫
|
||||||
|
</div>
|
||||||
|
<div class="card-ue">ue
|
||||||
|
事件类型:auth-result
|
||||||
|
imei
|
||||||
|
GNB ID
|
||||||
|
Cell ID
|
||||||
|
Tac ID
|
||||||
|
authTime
|
||||||
|
|
||||||
|
事件类型:detach
|
||||||
|
imsi
|
||||||
|
detachTime
|
||||||
|
|
||||||
|
事件类型:cm-state
|
||||||
|
imsi
|
||||||
|
changeTime
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.activty {
|
||||||
|
// background-color: rgb(253, 180, 180);
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
height: 90%;
|
||||||
|
color: #61a8ff;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
& .card-ue {
|
||||||
|
// background-color: rgb(185, 241, 168);
|
||||||
|
border: 1px #61a8ff solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
& span {
|
||||||
|
color: #68d8fe;
|
||||||
|
}
|
||||||
|
&-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
& > div {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&-auth {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
& > div {
|
||||||
|
width: 33%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .card-cdr {
|
||||||
|
// background-color: rgb(184, 168, 241);
|
||||||
|
border: 1px #61a8ff solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 0.2rem 0.5rem;
|
||||||
|
margin-bottom: 0.3rem;
|
||||||
|
line-height: 1rem;
|
||||||
|
& span {
|
||||||
|
color: #68d8fe;
|
||||||
|
}
|
||||||
|
&-item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
& > div {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .active {
|
||||||
|
color: #fff;
|
||||||
|
border: 1px #fff solid;
|
||||||
|
animation: backInRight 0.3s alternate;
|
||||||
|
& span {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 修改滚动条的样式 */
|
||||||
|
&::-webkit-scrollbar {
|
||||||
|
width: 8px; /* 设置滚动条宽度 */
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-track {
|
||||||
|
background-color: #101129; /* 设置滚动条轨道背景颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #28293f; /* 设置滚动条滑块颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
&::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: #68d8fe; /* 设置鼠标悬停时滚动条滑块颜色 */
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes backInRight {
|
||||||
|
0% {
|
||||||
|
opacity: 0.7;
|
||||||
|
-webkit-transform: translateX(2000px) scale(0.7);
|
||||||
|
transform: translateX(2000px) scale(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
80% {
|
||||||
|
opacity: 0.7;
|
||||||
|
-webkit-transform: translateX(0) scale(0.7);
|
||||||
|
transform: translateX(0) scale(0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
/**事件数据 */
|
|
||||||
export const cdrEventData = ref<Record<string, any>[]>([]);
|
|
||||||
|
|
||||||
/**事件总量 */
|
|
||||||
export const cdrEventTotal = ref<number>(0);
|
|
||||||
|
|
||||||
/**事件推送id */
|
|
||||||
export const cdrEventId = ref<string>('');
|
|
||||||
|
|
||||||
/**cdrEvent CDR会话事件 数据解析 */
|
|
||||||
export function cdrEventParse(item: Record<string, any>) {
|
|
||||||
let evData: Record<string, any> = item.cdrJSON || item.CDR;
|
|
||||||
if (typeof evData === 'string') {
|
|
||||||
try {
|
|
||||||
evData = JSON.parse(evData);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (evData.recordType === 'CALL') {
|
|
||||||
return {
|
|
||||||
id: item.id || item.timestamp,
|
|
||||||
type: evData.recordType,
|
|
||||||
time: evData.callDuration,
|
|
||||||
call: evData.callReference,
|
|
||||||
msg: `${evData.calledParty} -> ${evData.callerParty}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
/**事件数据 */
|
|
||||||
export const ueEventData = ref<Record<string, any>[]>([]);
|
|
||||||
|
|
||||||
/**事件总量 */
|
|
||||||
export const ueEventTotal = ref<number>(0);
|
|
||||||
|
|
||||||
/**事件推送id */
|
|
||||||
export const ueEventId = ref<string>('');
|
|
||||||
|
|
||||||
/**ueEvent UE会话事件 数据解析 */
|
|
||||||
export function ueEventParse(item: Record<string, any>) {
|
|
||||||
let evData: Record<string, any> = item.eventJSON;
|
|
||||||
if (typeof evData === 'string') {
|
|
||||||
try {
|
|
||||||
evData = JSON.parse(evData);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.eventType === 'auth-result') {
|
|
||||||
return {
|
|
||||||
id: item.id || item.timestamp,
|
|
||||||
type: item.eventType,
|
|
||||||
time: evData.authTime,
|
|
||||||
imsi: evData.imsi,
|
|
||||||
msg: `${evData.authMessage}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.eventType === 'detach') {
|
|
||||||
return {
|
|
||||||
id: item.id || item.timestamp,
|
|
||||||
type: item.eventType,
|
|
||||||
time: evData.detachTime,
|
|
||||||
imsi: evData.imsi,
|
|
||||||
msg: `${evData.detachResult}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.eventType === 'cm-state') {
|
|
||||||
return {
|
|
||||||
id: item.id || item.timestamp,
|
|
||||||
type: item.eventType,
|
|
||||||
time: evData.changeTime,
|
|
||||||
imsi: evData.imsi,
|
|
||||||
msg: `${evData.onlineNumber}`,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
66
src/views/dashboard/overview/hooks/useUserActivity.ts
Normal file
66
src/views/dashboard/overview/hooks/useUserActivity.ts
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
/**UE事件数据 */
|
||||||
|
export const ueEventData = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
|
/**UE事件总量 */
|
||||||
|
export const ueEventTotal = ref<number>(0);
|
||||||
|
|
||||||
|
/**UE事件推送id */
|
||||||
|
export const ueEventId = ref<string>('');
|
||||||
|
|
||||||
|
/**ueEvent UE会话事件 数据解析 */
|
||||||
|
export function ueEventParse(item: Record<string, any>) {
|
||||||
|
let evData: Record<string, any> = item.eventJSON;
|
||||||
|
if (typeof evData === 'string') {
|
||||||
|
try {
|
||||||
|
evData = JSON.parse(evData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
eType: 'ue',
|
||||||
|
eId: `ue_${item.timestamp}`,
|
||||||
|
id: item.id,
|
||||||
|
type: item.eventType,
|
||||||
|
data: evData,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**CDR事件数据 */
|
||||||
|
export const cdrEventData = ref<Record<string, any>[]>([]);
|
||||||
|
|
||||||
|
/**CDR事件总量 */
|
||||||
|
export const cdrEventTotal = ref<number>(0);
|
||||||
|
|
||||||
|
/**CDR事件推送id */
|
||||||
|
export const cdrEventId = ref<string>('');
|
||||||
|
|
||||||
|
/**cdrEvent CDR会话事件 数据解析 */
|
||||||
|
export function cdrEventParse(item: Record<string, any>) {
|
||||||
|
let evData: Record<string, any> = item.cdrJSON || item.CDR;
|
||||||
|
if (typeof evData === 'string') {
|
||||||
|
try {
|
||||||
|
evData = JSON.parse(evData);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
eType: 'cdr',
|
||||||
|
eId: `cdr_${item.timestamp}`,
|
||||||
|
id: item.id,
|
||||||
|
data: evData,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**CDR+UE事件数据 */
|
||||||
|
export const eventData = ref<Record<string, any>[]>([]);
|
||||||
|
/**CDR+UE事件总量 */
|
||||||
|
export const eventTotal = ref<number>(0);
|
||||||
|
/**CDR/UE事件推送id */
|
||||||
|
export const eventId = ref<string>('');
|
||||||
@@ -2,17 +2,12 @@ import { RESULT_CODE_ERROR } from '@/constants/result-constants';
|
|||||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
import { onBeforeUnmount, onMounted } from 'vue';
|
import { onBeforeUnmount, onMounted } from 'vue';
|
||||||
import {
|
import {
|
||||||
ueEventData,
|
|
||||||
ueEventId,
|
|
||||||
ueEventTotal,
|
|
||||||
ueEventParse,
|
ueEventParse,
|
||||||
} from './useUEEvent';
|
|
||||||
import {
|
|
||||||
cdrEventData,
|
|
||||||
cdrEventTotal,
|
|
||||||
cdrEventId,
|
|
||||||
cdrEventParse,
|
cdrEventParse,
|
||||||
} from './useCDREvent';
|
eventData,
|
||||||
|
eventTotal,
|
||||||
|
eventId,
|
||||||
|
} from './useUserActivity';
|
||||||
import { upfTotalFlow, upfTFParse } from './useUPFTotalFlow';
|
import { upfTotalFlow, upfTFParse } from './useUPFTotalFlow';
|
||||||
import { neStateParse } from './useTopology';
|
import { neStateParse } from './useTopology';
|
||||||
|
|
||||||
@@ -28,21 +23,20 @@ export default function useWS() {
|
|||||||
/**接收数据后回调 */
|
/**接收数据后回调 */
|
||||||
function wsError(ev: any) {
|
function wsError(ev: any) {
|
||||||
// 接收数据后回调
|
// 接收数据后回调
|
||||||
console.log(ev);
|
console.error(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**接收数据后回调 */
|
/**接收数据后回调 */
|
||||||
function wsMessage(res: Record<string, any>) {
|
function wsMessage(res: Record<string, any>) {
|
||||||
console.log(res);
|
// console.log(res);
|
||||||
const { code, requestId, data } = res;
|
const { code, requestId, data } = res;
|
||||||
if (code === RESULT_CODE_ERROR) {
|
if (code === RESULT_CODE_ERROR) {
|
||||||
console.warn(res.msg);
|
console.warn(res.msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!requestId) return;
|
|
||||||
|
|
||||||
// 网元状态
|
// 网元状态
|
||||||
if (requestId.startsWith('neState')) {
|
if (requestId && requestId.startsWith('neState')) {
|
||||||
const neType = requestId.split('_')[1];
|
const neType = requestId.split('_')[1];
|
||||||
neStateParse(neType, data);
|
neStateParse(neType, data);
|
||||||
return;
|
return;
|
||||||
@@ -53,35 +47,27 @@ export default function useWS() {
|
|||||||
// ueEvent UE会话事件
|
// ueEvent UE会话事件
|
||||||
case '1010':
|
case '1010':
|
||||||
if (Array.isArray(data.rows)) {
|
if (Array.isArray(data.rows)) {
|
||||||
ueEventTotal.value = data.total;
|
eventTotal.value += data.total;
|
||||||
const evDataArr: Record<string, any>[] = [];
|
|
||||||
for (const item of data.rows) {
|
for (const item of data.rows) {
|
||||||
const v = ueEventParse(item);
|
const v = ueEventParse(item);
|
||||||
if (v) {
|
if (v) {
|
||||||
evDataArr.push(v);
|
eventData.value.push(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ueEventData.value = evDataArr;
|
eventId.value = eventData.value[0].eId;
|
||||||
if (evDataArr.length > 0) {
|
|
||||||
ueEventId.value = evDataArr[0].id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
//cdrEvent CDR会话事件
|
//cdrEvent CDR会话事件
|
||||||
case '1005':
|
case '1005':
|
||||||
if (Array.isArray(data.rows)) {
|
if (Array.isArray(data.rows)) {
|
||||||
cdrEventTotal.value = data.total;
|
eventTotal.value += data.total;
|
||||||
const evDataArr: Record<string, any>[] = [];
|
|
||||||
for (const item of data.rows) {
|
for (const item of data.rows) {
|
||||||
const v = cdrEventParse(item);
|
const v = cdrEventParse(item);
|
||||||
if (v) {
|
if (v) {
|
||||||
evDataArr.push(v);
|
eventData.value.push(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cdrEventData.value = evDataArr;
|
eventId.value = eventData.value[0].eId;
|
||||||
if (evDataArr.length > 0) {
|
|
||||||
cdrEventId.value = evDataArr[0].id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
//UPF-总流量数
|
//UPF-总流量数
|
||||||
@@ -112,8 +98,12 @@ export default function useWS() {
|
|||||||
if (data.data) {
|
if (data.data) {
|
||||||
const v = ueEventParse(data.data);
|
const v = ueEventParse(data.data);
|
||||||
if (v) {
|
if (v) {
|
||||||
ueEventData.value.unshift(v);
|
eventData.value.unshift(v);
|
||||||
ueEventId.value = v.id;
|
eventTotal.value += 1;
|
||||||
|
eventId.value = v.eId;
|
||||||
|
if (eventData.value.length > 50) {
|
||||||
|
eventData.value.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -122,8 +112,12 @@ export default function useWS() {
|
|||||||
if (data.data) {
|
if (data.data) {
|
||||||
const v = cdrEventParse(data.data);
|
const v = cdrEventParse(data.data);
|
||||||
if (v) {
|
if (v) {
|
||||||
cdrEventData.value.unshift(v);
|
eventData.value.unshift(v);
|
||||||
cdrEventId.value = v.id;
|
eventTotal.value += 1;
|
||||||
|
eventId.value = v.eId;
|
||||||
|
if (eventData.value.length > 50) {
|
||||||
|
eventData.value.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -154,7 +148,7 @@ export default function useWS() {
|
|||||||
sortField: 'timestamp',
|
sortField: 'timestamp',
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 50,
|
pageSize: 25,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -170,7 +164,7 @@ export default function useWS() {
|
|||||||
sortField: 'timestamp',
|
sortField: 'timestamp',
|
||||||
sortOrder: 'desc',
|
sortOrder: 'desc',
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 50,
|
pageSize: 25,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import { onBeforeUnmount, onMounted, reactive, ref } from 'vue';
|
|||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import Topology from './components/Topology/index.vue';
|
import Topology from './components/Topology/index.vue';
|
||||||
import NeResources from './components/NeResources/index.vue';
|
import NeResources from './components/NeResources/index.vue';
|
||||||
import UEEvent from './components/UEEvent/index.vue';
|
import UserActivity from './components/UserActivity/index.vue';
|
||||||
import CDREvent from './components/CDREvent/index.vue';
|
|
||||||
import AlarnDayLine from './components/AlarnDayLine/index.vue';
|
import AlarnDayLine from './components/AlarnDayLine/index.vue';
|
||||||
import AlarnTypeBar from './components/AlarnTypeBar/index.vue';
|
import AlarnTypeBar from './components/AlarnTypeBar/index.vue';
|
||||||
import UPFFlow from './components/UPFFlow/index.vue';
|
import UPFFlow from './components/UPFFlow/index.vue';
|
||||||
@@ -75,6 +74,7 @@ async function fnGetState() {
|
|||||||
stateTimeout.value = setTimeout(() => fnGetState(), 5_000);
|
stateTimeout.value = setTimeout(() => fnGetState(), 5_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**初始数据函数 */
|
||||||
function InitData() {
|
function InitData() {
|
||||||
cdrEventSend();
|
cdrEventSend();
|
||||||
ueEventSend();
|
ueEventSend();
|
||||||
@@ -188,32 +188,22 @@ onBeforeUnmount(() => {
|
|||||||
<div class="item">
|
<div class="item">
|
||||||
<h4>{{ onlineInfo.nbNum }}</h4>
|
<h4>{{ onlineInfo.nbNum }}</h4>
|
||||||
<span>
|
<span>
|
||||||
<WifiOutlined style="color: #edcb35" />
|
<GlobalOutlined style="color: #edcb35"/>
|
||||||
{{ t('views.dashboard.overview.skim.base') }}
|
{{ t('views.dashboard.overview.skim.base') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--告警统计-->
|
<!-- 用户行为 -->
|
||||||
<div class="alarmType panel">
|
<div class="userActivity panel">
|
||||||
<div class="inner">
|
|
||||||
<h3>{{ t('views.dashboard.overview.alarmType.title') }}</h3>
|
|
||||||
<div class="chart">
|
|
||||||
<AlarnTypeBar />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- CDR会话 -->
|
|
||||||
<div class="cdrEvent panel">
|
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<h3>
|
<h3>
|
||||||
<WhatsAppOutlined style="color: #68d8fe" />
|
<WhatsAppOutlined style="color: #68d8fe" />
|
||||||
{{ t('views.dashboard.overview.cdrEvent.title') }}
|
{{ t('views.dashboard.overview.userActivity.title') }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="chart">
|
<div class="chart">
|
||||||
<CDREvent />
|
<UserActivity />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -305,15 +295,21 @@ onBeforeUnmount(() => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- UE会话 -->
|
<!--告警统计-->
|
||||||
<div class="ueEvent panel">
|
<div class="alarmType panel">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<h3>
|
<h3>{{ t('views.dashboard.overview.alarmType.title') }}</h3>
|
||||||
<WhatsAppOutlined style="color: #68d8fe" />
|
|
||||||
{{ t('views.dashboard.overview.ueEvent.title') }}
|
|
||||||
</h3>
|
|
||||||
<div class="chart">
|
<div class="chart">
|
||||||
<UEEvent />
|
<AlarnTypeBar />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!--告警Top-->
|
||||||
|
<div class="alarmType panel">
|
||||||
|
<div class="inner">
|
||||||
|
<h3>{{ t('views.dashboard.overview.alarmType.title') }}</h3>
|
||||||
|
<div class="chart">
|
||||||
|
<AlarnDayLine />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user