feat: 看板用户行为添加MME的UE事件

This commit is contained in:
TsMask
2024-06-17 11:21:44 +08:00
parent 1b1a56e49b
commit ee10119d77
4 changed files with 212 additions and 174 deletions

View File

@@ -19,12 +19,18 @@ let dict: {
ueEventType: DictType[]; ueEventType: DictType[];
/**UE 事件CM状态 */ /**UE 事件CM状态 */
ueEventCmState: DictType[]; ueEventCmState: DictType[];
/**UE 事件类型MME */
ueEventTypeMME: DictType[];
/**UE 事件结果MME */
ueEventResultMME: DictType[];
} = reactive({ } = reactive({
cdrSipCode: [], cdrSipCode: [],
cdrCallType: [], cdrCallType: [],
ueAauthCode: [], ueAauthCode: [],
ueEventType: [], ueEventType: [],
ueEventCmState: [], ueEventCmState: [],
ueEventTypeMME: [],
ueEventResultMME: [],
}); });
onMounted(() => { onMounted(() => {
@@ -35,6 +41,8 @@ onMounted(() => {
getDict('ue_auth_code'), getDict('ue_auth_code'),
getDict('ue_event_type'), getDict('ue_event_type'),
getDict('ue_event_cm_state'), getDict('ue_event_cm_state'),
getDict('ue_event_mme_type'),
getDict('ue_event_mme_result'),
]).then(resArr => { ]).then(resArr => {
if (resArr[0].status === 'fulfilled') { if (resArr[0].status === 'fulfilled') {
dict.cdrSipCode = resArr[0].value; dict.cdrSipCode = resArr[0].value;
@@ -51,6 +59,12 @@ onMounted(() => {
if (resArr[4].status === 'fulfilled') { if (resArr[4].status === 'fulfilled') {
dict.ueEventCmState = resArr[4].value; dict.ueEventCmState = resArr[4].value;
} }
if (resArr[5].status === 'fulfilled') {
dict.ueEventTypeMME = resArr[5].value;
}
if (resArr[6].status === 'fulfilled') {
dict.ueEventResultMME = resArr[6].value;
}
}); });
}); });
</script> </script>
@@ -58,11 +72,11 @@ onMounted(() => {
<template> <template>
<div class="activty"> <div class="activty">
<template v-for="item in eventData" :key="item.eId"> <template v-for="item in eventData" :key="item.eId">
<!-- CDR事件 --> <!-- CDR事件IMS -->
<div <div
class="card-cdr" class="card-cdr"
:class="{ active: item.eId === eventId }" :class="{ active: item.eId === eventId }"
v-if="item.eType === 'cdr'" v-if="item.eType === 'ims_cdr'"
> >
<div class="card-cdr-item"> <div class="card-cdr-item">
<div> <div>
@@ -104,18 +118,22 @@ onMounted(() => {
<div> <div>
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp; {{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span v-if="item.data.callType !== 'sms'"> <span v-if="item.data.callType !== 'sms'">
<DictTag :options="dict.cdrSipCode" :value="item.data.cause" value-option="0" /> <DictTag
:options="dict.cdrSipCode"
:value="item.data.cause"
value-option="0"
/>
</span> </span>
<span v-else> <span v-else>
{{ t('views.dashboard.overview.userActivity.resultOK') }} {{ t('views.dashboard.overview.userActivity.resultOK') }}
</span> </span>
</div> </div>
</div> </div>
<!-- UE事件 --> <!-- UE事件AMF -->
<div <div
class="card-ue" class="card-ue"
:class="{ active: item.eId === eventId }" :class="{ active: item.eId === eventId }"
v-if="item.eType === 'ue'" v-if="item.eType === 'amf_ue'"
> >
<div class="card-ue-item"> <div class="card-ue-item">
<div> <div>
@@ -172,96 +190,62 @@ onMounted(() => {
</span> </span>
</div> </div>
</div> </div>
<!-- UE事件MME -->
<div
class="card-ue"
:class="{ active: item.eId === eventId }"
v-if="item.eType === 'mme_ue'"
>
<div class="card-ue-item">
<div>
{{ t('views.dashboard.overview.userActivity.type') }}:&nbsp;
<span>
<DictTag :options="dict.ueEventTypeMME" :value="item.type" />
</span>
</div>
<div>
IMSI: <span :title="item.data.imsi">{{ item.data.imsi }}</span>
</div>
<div>
{{ t('views.dashboard.overview.userActivity.time') }}:
<span :title="item.data.timestamp">
{{ parseDateToStr(+item.data.timestamp * 1000) }}
</span>
</div>
</div>
<div class="card-ue-w33" 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 v-if="item.type === 'auth-result'">
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span>
<DictTag :options="dict.ueAauthCode" :value="item.data.authCode" />
</span>
</div>
<div v-if="item.type === 'detach'">
{{ t('views.dashboard.overview.userActivity.result') }}:
<span>{{ t('views.dashboard.overview.userActivity.resultOK') }}</span>
</div>
<div class="card-ue-w33">
{{ t('views.dashboard.overview.userActivity.result') }}:&nbsp;
<span>
<DictTag
:options="dict.ueEventResultMME"
:value="item.data.result"
/>
</span>
</div>
</div>
</template> </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 .... }
{"neType":"IMS","neName":"IMS_001","rmUID":"4400HX1IMS001","timestamp":1707124616,
"CDR":{"recordType":"MOSM","seqNumber":1,"callReference":"IIocbkeoj@10.10.91.22",
"callerParty":"12307551241","calledParty":"+8613800755000","serviceResult":"ok",
"seizureTime":1707124616,"answerTime":1707124616,"releaseTime":1707124616,
"callDuration":0,"callType":"text","fwdType":"","fwdParty":"","cause":200}}
https://telnyx.com/resources/sip-response-codes-need-know-2-minutes
主叫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> </div>
</template> </template>

View File

@@ -1,7 +1,9 @@
import { ref } from 'vue'; import { ref } from 'vue';
/**ueEvent UE会话事件 数据解析 */ /**ueEventAMFParse UE会话事件AMF 数据解析 */
export function ueEventParse(item: Record<string, any>) { function ueEventAMFParse(
item: Record<string, any>
): false | Record<string, any> {
let evData: Record<string, any> = item.eventJSON; let evData: Record<string, any> = item.eventJSON;
if (typeof evData === 'string') { if (typeof evData === 'string') {
try { try {
@@ -12,8 +14,8 @@ export function ueEventParse(item: Record<string, any>) {
} }
return { return {
eType: 'ue', eType: 'amf_ue',
eId: `ue_${item.id}_${Date.now()}`, eId: `amf_ue_${item.id}_${Date.now()}`,
eTime: +item.timestamp, eTime: +item.timestamp,
id: item.id, id: item.id,
type: item.eventType, type: item.eventType,
@@ -21,8 +23,33 @@ export function ueEventParse(item: Record<string, any>) {
}; };
} }
/**cdrEvent CDR会话事件 数据解析 */ /**ueEventMMEParse UE会话事件MME 数据解析 */
export function cdrEventParse(item: Record<string, any>) { function ueEventMMEParse(
item: Record<string, any>
): false | 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: 'mme_ue',
eId: `mme_ue_${item.id}_${Date.now()}`,
eTime: +item.timestamp,
id: item.id,
type: item.eventType,
data: evData,
};
}
/**cdrEventIMSParse CDR会话事件IMS 数据解析 */
function cdrEventIMSParse(
item: Record<string, any>
): false | Record<string, any> {
let evData: Record<string, any> = item.cdrJSON || item.CDR; let evData: Record<string, any> = item.cdrJSON || item.CDR;
if (typeof evData === 'string') { if (typeof evData === 'string') {
try { try {
@@ -39,14 +66,73 @@ export function cdrEventParse(item: Record<string, any>) {
} }
return { return {
eType: 'cdr', eType: 'ims_cdr',
eId: `cdr_${item.id}_${Date.now()}`, eId: `ims_cdr_${item.id}_${Date.now()}`,
eTime: +item.timestamp, eTime: +item.timestamp,
id: item.id, id: item.id,
data: evData, data: evData,
}; };
} }
/**eventListParse 事件列表解析 */
export function eventListParse(
type: 'ims_cdr' | 'amf_ue' | 'mme_ue',
data: any
) {
eventTotal.value += data.total;
for (const item of data.rows) {
let v: false | Record<string, any> = false;
if (type === 'ims_cdr') {
v = cdrEventIMSParse(item);
}
if (type === 'amf_ue') {
v = ueEventAMFParse(item);
}
if (type === 'mme_ue') {
v = ueEventMMEParse(item);
}
if (v) {
eventData.value.push(v);
}
}
// 有数据进行排序
if (eventData.value.length > 5) {
eventData.value.sort((a, b) => b.eTime - a.eTime);
}
if (eventData.value.length > 0) {
eventId.value = eventData.value[0].eId;
}
}
/**eventItemParseAndPush 事件项解析并添加 */
export async function eventItemParseAndPush(
type: 'ims_cdr' | 'amf_ue' | 'mme_ue',
item: any
) {
let v: false | Record<string, any> = false;
if (type === 'ims_cdr') {
v = cdrEventIMSParse(item);
}
if (type === 'amf_ue') {
v = ueEventAMFParse(item);
}
if (type === 'mme_ue') {
v = ueEventMMEParse(item);
}
if (v) {
eventData.value.unshift(v);
eventTotal.value += 1;
eventId.value = v.eId;
await new Promise(resolve => setTimeout(resolve, 800));
if (eventData.value.length > 20) {
eventData.value.pop();
}
}
}
/**CDR+UE事件数据 */ /**CDR+UE事件数据 */
export const eventData = ref<Record<string, any>[]>([]); export const eventData = ref<Record<string, any>[]>([]);
/**CDR+UE事件总量 */ /**CDR+UE事件总量 */

View File

@@ -2,11 +2,8 @@ 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 {
ueEventParse, eventListParse,
cdrEventParse, eventItemParseAndPush,
eventData,
eventTotal,
eventId,
userActivityReset, userActivityReset,
} from './useUserActivity'; } from './useUserActivity';
import { import {
@@ -55,41 +52,19 @@ export default function useWS() {
// AMF_UE会话事件 // AMF_UE会话事件
case '1010': case '1010':
if (Array.isArray(data.rows)) { if (Array.isArray(data.rows)) {
eventTotal.value += data.total; eventListParse('amf_ue', data);
for (const item of data.rows) {
const v = ueEventParse(item);
if (v) {
eventData.value.push(v);
}
}
// 有数据进行排序
if (eventData.value.length > 10) {
eventData.value.sort((a, b) => b.eTime - a.eTime);
}
if (eventData.value.length > 0) {
eventId.value = eventData.value[0].eId;
} }
break;
// MME_UE会话事件
case '1011':
if (Array.isArray(data.rows)) {
eventListParse('mme_ue', data);
} }
break; break;
// IMS_CDR会话事件 // IMS_CDR会话事件
case '1005': case '1005':
if (Array.isArray(data.rows)) { if (Array.isArray(data.rows)) {
eventTotal.value += data.total; eventListParse('ims_cdr', data);
for (const item of data.rows) {
const v = cdrEventParse(item);
if (v) {
eventData.value.push(v);
}
}
// 有数据进行排序
if (eventData.value.length > 10) {
eventData.value.sort((a, b) => b.eTime - a.eTime);
}
if (eventData.value.length > 0) {
eventId.value = eventData.value[0].eId;
}
} }
break; break;
//UPF-总流量数 //UPF-总流量数
@@ -127,35 +102,19 @@ export default function useWS() {
// AMF_UE会话事件 // AMF_UE会话事件
case '1010': case '1010':
if (data.data) { if (data.data) {
queue.add(async () => { queue.add(() => eventItemParseAndPush('amf_ue', data.data));
const v = ueEventParse(data.data);
if (v) {
eventData.value.unshift(v);
eventTotal.value += 1;
eventId.value = v.eId;
await new Promise(resolve => setTimeout(resolve, 800));
if (eventData.value.length > 20) {
eventData.value.pop();
} }
} break;
}); // MME_UE会话事件
case '1011':
if (data.data) {
queue.add(() => eventItemParseAndPush('mme_ue', data.data));
} }
break; break;
// IMS_CDR会话事件 // IMS_CDR会话事件
case '1005': case '1005':
if (data.data) { if (data.data) {
queue.add(async () => { queue.add(() => eventItemParseAndPush('ims_cdr', data.data));
const v = cdrEventParse(data.data);
if (v) {
eventData.value.unshift(v);
eventTotal.value += 1;
eventId.value = v.eId;
await new Promise(resolve => setTimeout(resolve, 800));
if (eventData.value.length > 20) {
eventData.value.pop();
}
}
});
} }
break; break;
} }
@@ -188,8 +147,9 @@ export default function useWS() {
}); });
} }
/**ueEvent UE会话事件 发消息*/ /**userActivitySend 用户行为事件基础列表数据 发消息*/
function ueEventSend() { function userActivitySend() {
// AMF_UE会话事件
ws.send({ ws.send({
requestId: '1010', requestId: '1010',
type: 'amf_ue', type: 'amf_ue',
@@ -199,13 +159,23 @@ export default function useWS() {
sortField: 'timestamp', sortField: 'timestamp',
sortOrder: 'desc', sortOrder: 'desc',
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 5,
}, },
}); });
} // MME_UE会话事件
ws.send({
/**cdrEvent CDR会话事件 发消息*/ requestId: '1011',
function cdrEventSend() { type: 'mme_ue',
data: {
neType: 'MME',
neId: '001',
sortField: 'timestamp',
sortOrder: 'desc',
pageNum: 1,
pageSize: 5,
},
});
// IMS_CDR会话事件
ws.send({ ws.send({
requestId: '1005', requestId: '1005',
type: 'ims_cdr', type: 'ims_cdr',
@@ -216,7 +186,7 @@ export default function useWS() {
sortField: 'timestamp', sortField: 'timestamp',
sortOrder: 'desc', sortOrder: 'desc',
pageNum: 1, pageNum: 1,
pageSize: 10, pageSize: 5,
}, },
}); });
} }
@@ -248,8 +218,7 @@ export default function useWS() {
return { return {
wsSend, wsSend,
cdrEventSend, userActivitySend,
ueEventSend,
upfTFSend, upfTFSend,
}; };
} }

View File

@@ -29,7 +29,7 @@ import { useRouter } from 'vue-router';
const router = useRouter(); const router = useRouter();
const appStore = useAppStore(); const appStore = useAppStore();
const { t } = useI18n(); const { t } = useI18n();
const { wsSend, cdrEventSend, ueEventSend, upfTFSend } = useWS(); const { wsSend, userActivitySend, upfTFSend } = useWS();
/**概览状态类型 */ /**概览状态类型 */
type SkimStateType = { type SkimStateType = {
@@ -155,8 +155,7 @@ async function fnGetSkim() {
/**初始数据函数 */ /**初始数据函数 */
function loadData() { function loadData() {
fnGetNeState(); // 获取网元状态 fnGetNeState(); // 获取网元状态
cdrEventSend(); userActivitySend();
ueEventSend();
upfTFSend(0); upfTFSend(0);
upfTFSend(7); upfTFSend(7);
upfTFSend(30); upfTFSend(30);