feat: 信令分析

This commit is contained in:
TsMask
2023-09-25 15:04:45 +08:00
parent 3525d7567e
commit 21a4ad986d
3 changed files with 101 additions and 57 deletions

View File

@@ -54,21 +54,15 @@ export async function listTraceData(query: Record<string, any>) {
return result; return result;
} }
// 网元抓包pcap文件下载 /**
export function tcpdumpPcapDownload(data: Record<string, string>) { * 信令数据解析HTML
* @param id 任务ID
* @returns
*/
export function getTraceRawInfo(id: Record<string, string>) {
return request({ return request({
url: '/traceManagement/v1/tcpdumpPcapDownload', url: `/traceManagement/v1/decMessage/${id}`,
method: 'post', method: 'get',
data: data, responseType: 'text',
responseType: 'blob',
});
}
// 网元抓包生成pcap
export function tcpdumpNeUPFTask(data: Record<string, string>) {
return request({
url: '/traceManagement/v1/tcpdumpNeUPFTask',
method: 'post',
data: data,
}); });
} }

View File

@@ -11,7 +11,7 @@ import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { downloadNeBackup } from '@/api/configManage/backupManage'; import { downloadNeBackup } from '@/api/configManage/backupManage';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
import { listTraceData } from '@/api/trace/analysis'; import { getTraceRawInfo, listTraceData } from '@/api/trace/analysis';
const { t } = useI18n(); const { t } = useI18n();
const route = useRoute(); const route = useRoute();
@@ -151,34 +151,6 @@ function fnTableSize({ key }: MenuInfo) {
tableState.size = key as SizeType; tableState.size = key as SizeType;
} }
/**信息文件下载 */
function fnDownloadFile(row: Record<string, any>) {
Modal.confirm({
title: '提示',
content: `确认下载记录编号为 【${row.id}】 的数据项文件?`,
onOk() {
const key = 'downloadNeBackup';
message.loading({ content: t('common.loading'), key });
downloadNeBackup(toRaw(row)).then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: `已完成下载`,
key,
duration: 2,
});
saveAs(res.data, `user_${Date.now()}.xlsx`);
} else {
message.error({
content: `${res.msg}`,
key,
duration: 2,
});
}
});
},
});
}
/**查询备份信息列表 */ /**查询备份信息列表 */
function fnGetList() { function fnGetList() {
if (tableState.loading) return; if (tableState.loading) return;
@@ -209,6 +181,7 @@ let modalState: ModalStateType = reactive({
title: '信令信息', title: '信令信息',
from: { from: {
rawData: '', rawData: '',
rawDataHTML: '',
}, },
}); });
@@ -221,7 +194,28 @@ function fnModalVisible(row: Record<string, any>) {
const hexString = parseBase64Data(row.rawMsg); const hexString = parseBase64Data(row.rawMsg);
const rawData = convertToReadableFormat(hexString); const rawData = convertToReadableFormat(hexString);
modalState.from.rawData = rawData; modalState.from.rawData = rawData;
modalState.title = `任务 ${row.taskId} 信令信息`; // RAW解析HTML
getTraceRawInfo(row.id).then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
const htmlString = res.msg;
// 删除所有 <a> 标签
const withoutATags = htmlString.replace(/<a\b[^>]*>(.*?)<\/a>/gi, '');
// 删除所有 <script> 标签
const withoutScriptTags = withoutATags.replace(
/<script\b[^>]*>([\s\S]*?)<\/script>/gi,
''
);
// 默认全展开
const withoutHiddenElements = withoutScriptTags.replace(
/style="display:none"/gi,
'style="background:#ffffff"'
);
modalState.from.rawDataHTML = withoutHiddenElements;
} else {
modalState.from.rawDataHTML = '无信息';
}
});
modalState.title = `任务 ${row.imsi}`;
modalState.visible = true; modalState.visible = true;
} }
@@ -255,7 +249,7 @@ function convertToReadableFormat(hexString: string) {
let result = ''; let result = '';
let asciiResult = ''; let asciiResult = '';
let arr = []; let arr = [];
let row = 0; let row = 100;
for (let i = 0; i < hexString.length; i += 2) { for (let i = 0; i < hexString.length; i += 2) {
const hexChars = hexString.substring(i, i + 2); const hexChars = hexString.substring(i, i + 2);
const decimal = parseInt(hexChars, 16); const decimal = parseInt(hexChars, 16);
@@ -289,6 +283,20 @@ function convertToReadableFormat(hexString: string) {
return arr; return arr;
} }
/**信息文件下载 */
function fnDownloadFile() {
Modal.confirm({
title: '提示',
content: `确认下载信令详情HTML文件?`,
onOk() {
const blob = new Blob([modalState.from.rawDataHTML], {
type: 'text/plain',
});
saveAs(blob, `${modalState.title}_${Date.now()}.html`);
},
});
}
onMounted(() => { onMounted(() => {
// 获取列表数据 // 获取列表数据
fnGetList(); fnGetList();
@@ -409,18 +417,38 @@ onMounted(() => {
<!-- 新增框或修改框 --> <!-- 新增框或修改框 -->
<a-modal <a-modal
width="1200px" width="800px"
:title="modalState.title" :title="modalState.title"
:visible="modalState.visible" :visible="modalState.visible"
@cancel="fnModalVisibleClose" @cancel="fnModalVisibleClose"
> >
<h4>信令数据</h4> <div class="raw-title">信令数据</div>
<div v-for="v in modalState.from.rawData" :key="v.row"> <a-row
<div>{{ v.code }}</div> class="raw"
<div>{{ v.asciiText }}</div> :gutter="16"
</div> v-for="v in modalState.from.rawData"
:key="v.row"
>
<a-col class="num" :span="2">{{ v.row }}</a-col>
<a-col class="code" :span="12">{{ v.code }}</a-col>
<a-col class="txt" :span="10">{{ v.asciiText }}</a-col>
</a-row>
<a-divider /> <a-divider />
<h4>信令信息</h4> <div class="raw-title">
信令详情
<a-button
type="dashed"
size="small"
@click.prevent="fnDownloadFile"
v-if="modalState.from.rawDataHTML !== '无信息'"
>
<template #icon>
<DownloadOutlined />
</template>
下载HTML
</a-button>
</div>
<div class="raw-html" v-html="modalState.from.rawDataHTML"></div>
</a-modal> </a-modal>
</PageContainer> </PageContainer>
</template> </template>
@@ -429,4 +457,26 @@ onMounted(() => {
.table :deep(.ant-pagination) { .table :deep(.ant-pagination) {
padding: 0 24px; padding: 0 24px;
} }
.raw {
&-title {
color: #000000d9;
font-size: 24px;
line-height: 1.8;
}
.num {
background-color: #e5e5e5;
}
.code {
background-color: #e7e6ff;
}
.txt {
background-color: #ffe3e5;
}
&-html {
max-height: 300px;
overflow-y: scroll;
}
}
</style> </style>

View File

@@ -307,11 +307,11 @@ onMounted(() => {
v-model:value="modalState.from.upfStart" v-model:value="modalState.from.upfStart"
allow-clear allow-clear
placeholder="upf pacp 命令" placeholder="upf pacp 命令"
style="width: 80%" style="width: 75%"
/> />
<a-button <a-button
type="primary" type="primary"
style="width: 20%" style="width: 25%"
:disabled="modalState.confirmLoading" :disabled="modalState.confirmLoading"
:loading="modalState.confirmLoading" :loading="modalState.confirmLoading"
@click.prevent="fnUPF('start')" @click.prevent="fnUPF('start')"
@@ -330,11 +330,11 @@ onMounted(() => {
v-model:value="modalState.from.upfStop" v-model:value="modalState.from.upfStop"
allow-clear allow-clear
placeholder="upf pacp 命令" placeholder="upf pacp 命令"
style="width: 80%" style="width: 75%"
/> />
<a-button <a-button
type="primary" type="primary"
style="width: 20%" style="width: 25%"
:disabled="modalState.confirmLoading" :disabled="modalState.confirmLoading"
:loading="modalState.confirmLoading" :loading="modalState.confirmLoading"
@click.prevent="fnUPF('stop')" @click.prevent="fnUPF('stop')"