feat: 添加UPF N3 Ping测试功能

This commit is contained in:
TsMask
2025-09-12 15:22:54 +08:00
parent 6b45194c65
commit 5cbe885d7e
2 changed files with 100 additions and 4 deletions

View File

@@ -8,3 +8,12 @@ export function pingV(data: Record<string, string>) {
params: data,
});
}
// ping RTT 时延抖动
export function pingRTT(data: Record<string, string>) {
return request({
url: '/tool/ping/rtt',
method: 'POST',
data: data,
});
}

View File

@@ -12,12 +12,13 @@ import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import TableColumnsDnd from '@/components/TableColumnsDnd/index.vue';
import { listTenant } from '@/api/system/tenant';
import useUserStore from '@/store/modules/user';
import { pingRTT } from '@/api/tool/ping';
const { t } = useI18n();
/**网元参数 */
let neOtions = ref<Record<string, any>[]>([]);
let upfOtions = ref<Record<string, any>[]>([]);
/**查询参数 */
let queryParams = reactive({
@@ -188,6 +189,9 @@ type ModalStateType = {
from: Record<string, any>;
/**确定按钮 loading */
confirmLoading: boolean;
/**ping测试参数 */
pingArgs: Record<string, any>;
pingResult: Record<string, any>[];
};
/**对话框对象信息状态 */
@@ -198,10 +202,24 @@ let modalState: ModalStateType = reactive({
from: {
imsi: '',
msisdn: '',
pduSessionInfo: undefined,
pduSessionInfo: [],
ratType: '',
},
confirmLoading: false,
pingArgs: {
neType: 'UPF',
neId: '001',
ping: {
desAddr: '',
srcAddr: '',
interval: 1,
ttl: 255,
count: 5,
size: 56,
timeout: 2,
},
},
pingResult: [],
});
/**
@@ -233,6 +251,7 @@ function fnModalVisibleByVive(row: Record<string, any>) {
function fnModalCancel() {
modalState.openByEdit = false;
modalState.openByView = false;
modalState.pingResult = [];
}
/**查询列表, pageNum初始页数 */
@@ -262,7 +281,36 @@ function fnGetList(pageNum?: number) {
});
}
/**
* 测试ping
*/
function fnPingTest() {
modalState.pingResult = [];
modalState.confirmLoading = true;
let args = [];
for (const v of modalState.from.pduSessionInfo) {
const data = Object.assign({}, modalState.pingArgs);
data.ping.desAddr = v.ipv4;
data.ping.srcAddr = v.upfN3IP;
args.push(data);
}
Promise.all(args.map(v => pingRTT(v)))
.then(resArr => {
resArr.forEach((v, i) => {
if (v.code === RESULT_CODE_SUCCESS) {
v.data.dnn = modalState.from.pduSessionInfo[i].dnn;
v.data.latency = Number(v.data.avg_rtt || 0).toFixed(3);
v.data.jitter = Number(v.data.max_rtt - v.data.min_rtt || 0).toFixed(
3
);
modalState.pingResult.push(v.data);
}
});
})
.finally(() => {
modalState.confirmLoading = false;
});
}
onMounted(() => {
// 获取网元网元列表
@@ -276,6 +324,9 @@ onMounted(() => {
if (i.neType === 'SMF') {
arr.push({ value: i.neId, label: i.neName });
}
if (i.neType === 'UPF') {
upfOtions.value.push({ value: i.neId, label: i.neName });
}
});
neOtions.value = arr;
if (arr.length > 0) {
@@ -437,7 +488,7 @@ onMounted(() => {
:scroll="{ x: true, y: 400 }"
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'imsi'">
<template v-if="column?.key === 'imsi'">
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.viewText') }}</template>
@@ -458,6 +509,7 @@ onMounted(() => {
<ProModal
:drag="true"
:width="800"
:body-style="{ maxHeight: '600px', 'overflow-y': 'auto' }"
:open="modalState.openByView"
:title="modalState.title"
@cancel="fnModalCancel"
@@ -512,6 +564,41 @@ onMounted(() => {
{{ v.activeTime }}
</a-descriptions-item>
</a-descriptions>
<a-divider orientation="left">Ping Test UPF N3 -> IPv4</a-divider>
<a-form-item label="Select UPF" name="ping">
<a-input-group compact>
<a-select
v-model:value="modalState.pingArgs.neId"
:options="upfOtions"
:placeholder="t('common.selectPlease')"
:disabled="modalState.confirmLoading"
/>
<a-button
type="primary"
@click="fnPingTest()"
:loading="modalState.confirmLoading"
>
Ping
</a-button>
</a-input-group>
</a-form-item>
<a-descriptions
:title="v.dnn"
:column="2"
size="small"
bordered
v-if="modalState.pingResult.length > 0"
v-for="v in modalState.pingResult"
:key="v.dnn"
>
<a-descriptions-item label="Latency">
{{ v.latency }} ms
</a-descriptions-item>
<a-descriptions-item label="Jitter">
{{ v.jitter }} ms
</a-descriptions-item>
</a-descriptions>
</a-form>
</ProModal>
</PageContainer>