fix: CDR数据检查格式,SGWC调试
This commit is contained in:
@@ -421,14 +421,18 @@ export default {
|
||||
resultFail: "Fail",
|
||||
delTip: "Confirm deletion of the data item numbered [{msg}]?",
|
||||
exportTip: "Do you confirm to export the current query conditions of the CDR data? (Maximum 10,000 items can be exported.)",
|
||||
smfChargingID: 'Charging ID',
|
||||
chargingID: 'Charging ID',
|
||||
smfSubscriptionIDData: 'Subscription ID Data',
|
||||
smfSubscriptionIDType: 'Subscription ID Type',
|
||||
smfDataVolumeUplink: 'Data Volume Uplink',
|
||||
smfDataVolumeDownlink: 'Data Volume Downlink',
|
||||
smfDataTotalVolume: 'Data Total Volume',
|
||||
smfDuration: 'Duration',
|
||||
smfInvocationTime: 'Invocation Time',
|
||||
durationTime: 'Duration',
|
||||
invocationTime: 'Invocation Time',
|
||||
sgwcServedIMSI: 'IMSI',
|
||||
sgwcServedMSISDN: 'MSISDN',
|
||||
sgwcVolumeGPRSUplink: 'GPRS Uplink',
|
||||
sgwcVolumeGPRSDownlink: 'GPRS Downlink',
|
||||
},
|
||||
ue: {
|
||||
eventType: "Event Type",
|
||||
|
||||
@@ -421,14 +421,18 @@ export default {
|
||||
resultFail: "失败",
|
||||
delTip: "确认删除编号为【{msg}】的数据项?",
|
||||
exportTip: "确认导出当前查询条件的话单数据吗?(导出最大支持一万条)",
|
||||
smfChargingID: '计费ID',
|
||||
chargingID: '计费ID',
|
||||
smfSubscriptionIDData: '订阅 ID 数据',
|
||||
smfSubscriptionIDType: '订阅 ID 类型',
|
||||
smfDataVolumeUplink: '数据量上行链路',
|
||||
smfDataVolumeDownlink: '数据量下行链路',
|
||||
smfDataTotalVolume: '数据总量',
|
||||
smfDuration: '持续时间',
|
||||
smfInvocationTime: '调用时间',
|
||||
durationTime: '持续时间',
|
||||
invocationTime: '调用时间',
|
||||
sgwcServedIMSI: 'IMSI',
|
||||
sgwcServedMSISDN: 'MSISDN',
|
||||
sgwcVolumeGPRSUplink: 'GPRS 上行链路',
|
||||
sgwcVolumeGPRSDownlink: 'GPRS 下行链路',
|
||||
},
|
||||
ue: {
|
||||
eventType: "事件类型",
|
||||
|
||||
@@ -21,6 +21,8 @@ import { parseDateToStr, parseDuration } from '@/utils/date-utils';
|
||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import saveAs from 'file-saver';
|
||||
import PQueue from 'p-queue';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { t } = useI18n();
|
||||
const { getDict } = useDictStore();
|
||||
const ws = new WS();
|
||||
@@ -307,6 +309,18 @@ function fnRecordDelete(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
@@ -407,7 +421,9 @@ function fnRealTime() {
|
||||
subGroupID: `1005_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
@@ -417,12 +433,6 @@ function fnRealTime() {
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsError(ev: any) {
|
||||
// 接收数据后回调
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
@@ -724,6 +734,17 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import PQueue from 'p-queue';
|
||||
import saveAs from 'file-saver';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { t } = useI18n();
|
||||
const ws = new WS();
|
||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||
@@ -34,7 +36,8 @@ let queryParams = reactive({
|
||||
/**网元类型 */
|
||||
neType: 'SGWC',
|
||||
neId: '001',
|
||||
subscriberID: '',
|
||||
imsi: '',
|
||||
msisdn: '',
|
||||
sortField: 'timestamp',
|
||||
sortOrder: 'desc',
|
||||
/**开始时间 */
|
||||
@@ -50,7 +53,8 @@ let queryParams = reactive({
|
||||
/**查询参数重置 */
|
||||
function fnQueryReset() {
|
||||
queryParams = Object.assign(queryParams, {
|
||||
subscriberID: '',
|
||||
imsi: '',
|
||||
msisdn: '',
|
||||
startTime: '',
|
||||
endTime: '',
|
||||
pageNum: 1,
|
||||
@@ -89,12 +93,12 @@ let tableState: TabeStateType = reactive({
|
||||
let tableColumns: ColumnsType = [
|
||||
{
|
||||
title: t('common.rowId'),
|
||||
dataIndex: 'left',
|
||||
align: 'center',
|
||||
dataIndex: 'id',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfChargingID'), // 计费ID
|
||||
title: t('views.dashboard.cdr.chargingID'), // 计费ID
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
@@ -104,90 +108,71 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfSubscriptionIDType'), // 订阅 ID 类型
|
||||
title: t('views.dashboard.cdr.sgwcServedIMSI'), // IMSI
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.subscriberIdentifier?.subscriptionIDType;
|
||||
return cdrJSON.servedIMSI;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfSubscriptionIDData'), // 订阅 ID 数据
|
||||
title: t('views.dashboard.cdr.sgwcServedMSISDN'), // MSISDN
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.subscriberIdentifier?.subscriptionIDData;
|
||||
return cdrJSON.servedMSISDN;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfDataVolumeUplink'), // 数据量上行链路
|
||||
title: t('views.dashboard.cdr.sgwcVolumeGPRSUplink'), // GPRS 上行链路
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
const listOfMultipleUnitUsage = cdrJSON.listOfMultipleUnitUsage;
|
||||
const listOfTrafficVolumes = cdrJSON.listOfTrafficVolumes;
|
||||
if (
|
||||
!Array.isArray(listOfMultipleUnitUsage) ||
|
||||
listOfMultipleUnitUsage.length < 1
|
||||
!Array.isArray(listOfTrafficVolumes) ||
|
||||
listOfTrafficVolumes.length < 1
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataVolumeGPRSUplink = 0;
|
||||
for (const used of listOfTrafficVolumes) {
|
||||
const v = +used.dataVolumeGPRSUplink;
|
||||
dataVolumeGPRSUplink += isNaN(v) ? 0 : v;
|
||||
}
|
||||
return usedUnitContainer[0].dataVolumeUplink;
|
||||
return dataVolumeGPRSUplink;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfDataVolumeDownlink'), // 数据量下行链路
|
||||
title: t('views.dashboard.cdr.sgwcVolumeGPRSDownlink'), // GPRS 下行链路
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 180,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
const listOfMultipleUnitUsage = cdrJSON.listOfMultipleUnitUsage;
|
||||
const listOfTrafficVolumes = cdrJSON.listOfTrafficVolumes;
|
||||
if (
|
||||
!Array.isArray(listOfMultipleUnitUsage) ||
|
||||
listOfMultipleUnitUsage.length < 1
|
||||
!Array.isArray(listOfTrafficVolumes) ||
|
||||
listOfTrafficVolumes.length < 1
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataVolumeGPRSDownlink = 0;
|
||||
for (const used of listOfTrafficVolumes) {
|
||||
const v = +used.dataVolumeGPRSDownlink;
|
||||
dataVolumeGPRSDownlink += isNaN(v) ? 0 : v;
|
||||
}
|
||||
return usedUnitContainer[0].dataVolumeDownlink;
|
||||
return dataVolumeGPRSDownlink;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfDataTotalVolume'), // 数据总量
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 150,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
const listOfMultipleUnitUsage = cdrJSON.listOfMultipleUnitUsage;
|
||||
if (
|
||||
!Array.isArray(listOfMultipleUnitUsage) ||
|
||||
listOfMultipleUnitUsage.length < 1
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
}
|
||||
return usedUnitContainer[0].dataTotalVolume;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfDuration'), // 持续时间
|
||||
title: t('views.dashboard.cdr.durationTime'), // 持续时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
@@ -197,13 +182,13 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfInvocationTime'), // 调用时间
|
||||
title: t('views.dashboard.cdr.invocationTime'), // 操作时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
customRender(opt) {
|
||||
const cdrJSON = opt.value;
|
||||
return cdrJSON.invocationTimestamp;
|
||||
return cdrJSON.recordOpeningTime;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -306,6 +291,18 @@ function fnRecordDelete(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
@@ -406,7 +403,9 @@ function fnRealTime() {
|
||||
subGroupID: `1008_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
@@ -416,12 +415,6 @@ function fnRealTime() {
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsError(ev: any) {
|
||||
// 接收数据后回调
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
@@ -435,7 +428,7 @@ function wsMessage(res: Record<string, any>) {
|
||||
return;
|
||||
}
|
||||
// cdrEvent CDR会话事件
|
||||
if (data.groupId === `1006_${queryParams.neId}`) {
|
||||
if (data.groupId === `1008_${queryParams.neId}`) {
|
||||
const cdrEvent = data.data;
|
||||
queue.add(async () => {
|
||||
modalState.maxId += 1;
|
||||
@@ -515,17 +508,44 @@ onBeforeUnmount(() => {
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.dashboard.cdr.smfSubscriptionIDData')"
|
||||
name="subscriberID"
|
||||
:label="t('views.dashboard.cdr.sgwcServedIMSI')"
|
||||
name="imsi"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="queryParams.subscriberID"
|
||||
v-model:value="queryParams.imsi"
|
||||
allow-clear
|
||||
:placeholder="t('common.inputPlease')"
|
||||
:maxlength="40"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="6" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.dashboard.cdr.sgwcServedMSISDN')"
|
||||
name="msisdn"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="queryParams.msisdn"
|
||||
allow-clear
|
||||
:placeholder="t('common.inputPlease')"
|
||||
:maxlength="40"
|
||||
></a-input>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="4" :md="12" :xs="24">
|
||||
<a-form-item>
|
||||
<a-space :size="8">
|
||||
<a-button type="primary" @click.prevent="fnGetList(1)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
{{ t('common.search') }}
|
||||
</a-button>
|
||||
<a-button type="default" @click.prevent="fnQueryReset">
|
||||
<template #icon><ClearOutlined /></template>
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="8" :md="12" :xs="24">
|
||||
<a-form-item
|
||||
:label="t('views.dashboard.cdr.time')"
|
||||
@@ -542,20 +562,6 @@ onBeforeUnmount(() => {
|
||||
></a-range-picker>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :lg="4" :md="12" :xs="24">
|
||||
<a-form-item>
|
||||
<a-space :size="8">
|
||||
<a-button type="primary" @click.prevent="fnGetList(1)">
|
||||
<template #icon><SearchOutlined /></template>
|
||||
{{ t('common.search') }}
|
||||
</a-button>
|
||||
<a-button type="default" @click.prevent="fnQueryReset">
|
||||
<template #icon><ClearOutlined /></template>
|
||||
{{ t('common.reset') }}
|
||||
</a-button>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-card>
|
||||
@@ -669,6 +675,17 @@ onBeforeUnmount(() => {
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
@@ -699,15 +716,11 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
<div>
|
||||
<span>{{ t('views.dashboard.cdr.time') }}: </span>
|
||||
<span>{{ record.cdrJSON.invocationTimestamp }}</span>
|
||||
<span>{{ record.cdrJSON.recordOpeningTime }}</span>
|
||||
</div>
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.dashboard.cdr.rowInfo') }}
|
||||
</a-divider>
|
||||
<div>
|
||||
<span>Record Network Function ID: </span>
|
||||
<span>{{ record.cdrJSON.recordingNetworkFunctionID }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Record Type: </span>
|
||||
<span>{{ record.cdrJSON.recordType }}</span>
|
||||
@@ -724,92 +737,66 @@ onBeforeUnmount(() => {
|
||||
<span>Duration: </span>
|
||||
<span>{{ record.cdrJSON.duration }}</span>
|
||||
</div>
|
||||
<a-divider orientation="left"> Subscriber Identifier </a-divider>
|
||||
<div>
|
||||
<span>Subscription ID Type: </span>
|
||||
<span>
|
||||
{{ record.cdrJSON.subscriberIdentifier?.subscriptionIDType }}
|
||||
</span>
|
||||
<span>Record Access Point Name NI: </span>
|
||||
<span>{{ record.cdrJSON.accessPointNameNI }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Subscription ID Data: </span>
|
||||
<span>
|
||||
{{ record.cdrJSON.subscriberIdentifier?.subscriptionIDData }}
|
||||
</span>
|
||||
<span>Record Cause For Rec Closing: </span>
|
||||
<span>{{ record.cdrJSON.causeForRecClosing }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Record Sequence Number: </span>
|
||||
<span>{{ record.cdrJSON.recordSequenceNumber }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Local Record Sequence Number: </span>
|
||||
<span>{{ record.cdrJSON.localRecordSequenceNumber }}</span>
|
||||
</div>
|
||||
</a-col>
|
||||
<a-col :lg="8" :md="12" :xs="24">
|
||||
<a-divider orientation="left">
|
||||
List Of Multiple Unit Usage
|
||||
</a-divider>
|
||||
<div v-for="u in record.cdrJSON.listOfMultipleUnitUsage">
|
||||
<!-- <div>RatingGroup: {{ u.ratingGroup }}</div> -->
|
||||
<div v-for="udata in u.usedUnitContainer">
|
||||
<div>
|
||||
<span>Data Total Volume: </span>
|
||||
<span>{{ udata.dataTotalVolume }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Downlink: </span>
|
||||
<span>{{ udata.dataVolumeDownlink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Uplink: </span>
|
||||
<span>{{ udata.dataVolumeUplink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Time: </span>
|
||||
<span>{{ udata.time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a-divider orientation="left">
|
||||
PDU Session Charging Information
|
||||
</a-divider>
|
||||
<a-divider orientation="left"> Server Information </a-divider>
|
||||
<div>
|
||||
<span>User Identifier: </span>
|
||||
<span>{{
|
||||
record.cdrJSON.pDUSessionChargingInformation?.userIdentifier
|
||||
}}</span>
|
||||
<span>IMSI: </span>
|
||||
<span> {{ record.cdrJSON.servedIMSI }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>MSISDN: </span>
|
||||
<span> {{ record.cdrJSON.servedMSISDN }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PGW Address Used: </span>
|
||||
<span> {{ record.cdrJSON.pGWAddressUsed }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>SGW Address: </span>
|
||||
<span> {{ record.cdrJSON.sGWAddress }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>SSC Mode: </span>
|
||||
<span>{{
|
||||
record.cdrJSON.pDUSessionChargingInformation?.sSCMode
|
||||
}}</span>
|
||||
|
||||
<span>RAT Type: </span>
|
||||
<span>{{
|
||||
record.cdrJSON.pDUSessionChargingInformation?.rATType
|
||||
}}</span>
|
||||
|
||||
<span>DNN ID: </span>
|
||||
<span> {{ record.cdrJSON.rATType }} </span>
|
||||
</div>
|
||||
<a-divider orientation="left"> PDPPD Information </a-divider>
|
||||
<div>
|
||||
<span>PDPPDN Type: </span>
|
||||
<span> {{ record.cdrJSON.pdpPDNType }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PDPPDN Address: </span>
|
||||
<span> {{ record.cdrJSON.servedPDPPDNAddress }} </span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Node Address: </span>
|
||||
<span>
|
||||
{{ record.cdrJSON.pDUSessionChargingInformation?.dNNID }}
|
||||
{{ record.cdrJSON.servingNodeAddress?.join(', ') }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PDU Type: </span>
|
||||
<span>Node Type: </span>
|
||||
<span>
|
||||
{{ record.cdrJSON.pDUSessionChargingInformation?.pDUType }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PDU IPv4 Address: </span>
|
||||
<span>
|
||||
{{
|
||||
record.cdrJSON.pDUSessionChargingInformation?.pDUAddress
|
||||
?.pDUIPv4Address
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>PDU IPv6 Addres Swith Prefix: </span>
|
||||
<span>
|
||||
{{
|
||||
record.cdrJSON.pDUSessionChargingInformation?.pDUAddress
|
||||
?.pDUIPv6AddresswithPrefix
|
||||
}}
|
||||
<template v-for="item in record.cdrJSON.servingNodeType">
|
||||
{{ item.servingNodeType }}
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
</a-col>
|
||||
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import PQueue from 'p-queue';
|
||||
import saveAs from 'file-saver';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { t } = useI18n();
|
||||
const ws = new WS();
|
||||
const queue = new PQueue({ concurrency: 1, autoStart: true });
|
||||
@@ -94,7 +96,7 @@ let tableColumns: ColumnsType = [
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfChargingID'), // 计费ID
|
||||
title: t('views.dashboard.cdr.chargingID'), // 计费ID
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
@@ -137,11 +139,15 @@ let tableColumns: ColumnsType = [
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataVolumeUplink = 0;
|
||||
for (const v of listOfMultipleUnitUsage) {
|
||||
if (Array.isArray(v.usedUnitContainer)) {
|
||||
for (const used of v.usedUnitContainer) {
|
||||
dataVolumeUplink += +used.dataVolumeUplink;
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedUnitContainer[0].dataVolumeUplink;
|
||||
return dataVolumeUplink;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -158,11 +164,15 @@ let tableColumns: ColumnsType = [
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataVolumeDownlink = 0;
|
||||
for (const v of listOfMultipleUnitUsage) {
|
||||
if (Array.isArray(v.usedUnitContainer)) {
|
||||
for (const used of v.usedUnitContainer) {
|
||||
dataVolumeDownlink += +used.dataVolumeDownlink;
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedUnitContainer[0].dataVolumeDownlink;
|
||||
return dataVolumeDownlink;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -179,15 +189,19 @@ let tableColumns: ColumnsType = [
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
const usedUnitContainer = listOfMultipleUnitUsage[0].usedUnitContainer;
|
||||
if (!Array.isArray(usedUnitContainer) || usedUnitContainer.length < 1) {
|
||||
return 0;
|
||||
let dataTotalVolume = 0;
|
||||
for (const v of listOfMultipleUnitUsage) {
|
||||
if (Array.isArray(v.usedUnitContainer)) {
|
||||
for (const used of v.usedUnitContainer) {
|
||||
dataTotalVolume += +used.dataTotalVolume;
|
||||
}
|
||||
}
|
||||
}
|
||||
return usedUnitContainer[0].dataTotalVolume;
|
||||
return dataTotalVolume;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfDuration'), // 持续时间
|
||||
title: t('views.dashboard.cdr.durationTime'), // 持续时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 100,
|
||||
@@ -197,7 +211,7 @@ let tableColumns: ColumnsType = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t('views.dashboard.cdr.smfInvocationTime'), // 调用时间
|
||||
title: t('views.dashboard.cdr.invocationTime'), // 调用时间
|
||||
dataIndex: 'cdrJSON',
|
||||
align: 'left',
|
||||
width: 200,
|
||||
@@ -306,6 +320,18 @@ function fnRecordDelete(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
@@ -406,7 +432,9 @@ function fnRealTime() {
|
||||
subGroupID: `1006_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
@@ -416,12 +444,6 @@ function fnRealTime() {
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsError(ev: any) {
|
||||
// 接收数据后回调
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
@@ -669,6 +691,17 @@ onBeforeUnmount(() => {
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
@@ -742,24 +775,33 @@ onBeforeUnmount(() => {
|
||||
<a-divider orientation="left">
|
||||
List Of Multiple Unit Usage
|
||||
</a-divider>
|
||||
|
||||
<div v-for="u in record.cdrJSON.listOfMultipleUnitUsage">
|
||||
<!-- <div>RatingGroup: {{ u.ratingGroup }}</div> -->
|
||||
<div v-for="udata in u.usedUnitContainer">
|
||||
<div>RatingGroup: {{ u.ratingGroup }}</div>
|
||||
<div
|
||||
v-for="(udata, i) in u.usedUnitContainer"
|
||||
style="display: flex"
|
||||
>
|
||||
<strong style="margin-right: 12px">
|
||||
{{ i }}
|
||||
</strong>
|
||||
<div>
|
||||
<span>Data Total Volume: </span>
|
||||
<span>{{ udata.dataTotalVolume }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Downlink: </span>
|
||||
<span>{{ udata.dataVolumeDownlink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Uplink: </span>
|
||||
<span>{{ udata.dataVolumeUplink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Time: </span>
|
||||
<span>{{ udata.time }}</span>
|
||||
<div>
|
||||
<span>Data Total Volume: </span>
|
||||
<span>{{ udata.dataTotalVolume }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Downlink: </span>
|
||||
<span>{{ udata.dataVolumeDownlink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Data Volume Uplink: </span>
|
||||
<span>{{ udata.dataVolumeUplink }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span>Time: </span>
|
||||
<span>{{ udata.time }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,6 +21,8 @@ import { parseDateToStr } from '@/utils/date-utils';
|
||||
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||
import saveAs from 'file-saver';
|
||||
import PQueue from 'p-queue';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
const { copy } = useClipboard({ legacy: true });
|
||||
const { getDict } = useDictStore();
|
||||
const { t } = useI18n();
|
||||
const ws = new WS();
|
||||
@@ -282,6 +284,18 @@ function fnRecordDelete(id: string) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 复制CDR
|
||||
* @param jsonStr JSON字符串
|
||||
*/
|
||||
function fnRecordCopy(jsonStr: string) {
|
||||
if (!jsonStr) return;
|
||||
const text = JSON.stringify(jsonStr, null, 2);
|
||||
copy(text).then(() => {
|
||||
message.success(t('common.copyOk'), 3);
|
||||
});
|
||||
}
|
||||
|
||||
/**查询列表, pageNum初始页数 */
|
||||
function fnGetList(pageNum?: number) {
|
||||
if (tableState.loading) return;
|
||||
@@ -382,7 +396,9 @@ function fnRealTime() {
|
||||
subGroupID: `1007_${queryParams.neId}`,
|
||||
},
|
||||
onmessage: wsMessage,
|
||||
onerror: wsError,
|
||||
onerror: (ev: any) => {
|
||||
console.error(ev);
|
||||
},
|
||||
};
|
||||
ws.connect(options);
|
||||
} else {
|
||||
@@ -392,12 +408,6 @@ function fnRealTime() {
|
||||
}
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsError(ev: any) {
|
||||
// 接收数据后回调
|
||||
console.error(ev);
|
||||
}
|
||||
|
||||
/**接收数据后回调 */
|
||||
function wsMessage(res: Record<string, any>) {
|
||||
const { code, requestId, data } = res;
|
||||
@@ -665,7 +675,7 @@ onBeforeUnmount(() => {
|
||||
:data-source="tableState.data"
|
||||
:size="tableState.size"
|
||||
:pagination="tablePagination"
|
||||
:scroll="{ x: tableColumns.length * 150, y: 'calc(100vh - 480px)' }"
|
||||
:scroll="{ x: tableColumns.length * 180, y: 'calc(100vh - 480px)' }"
|
||||
:row-selection="{
|
||||
type: 'checkbox',
|
||||
columnWidth: '48px',
|
||||
@@ -689,6 +699,17 @@ onBeforeUnmount(() => {
|
||||
</template>
|
||||
<template v-if="column.key === 'id'">
|
||||
<a-space :size="8" align="center">
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.copyText') }}</template>
|
||||
<a-button
|
||||
type="link"
|
||||
@click.prevent="fnRecordCopy(record.cdrJSON)"
|
||||
>
|
||||
<template #icon>
|
||||
<CopyOutlined />
|
||||
</template>
|
||||
</a-button>
|
||||
</a-tooltip>
|
||||
<a-tooltip>
|
||||
<template #title>{{ t('common.deleteText') }}</template>
|
||||
<a-button
|
||||
|
||||
Reference in New Issue
Block a user