feat: 支持下载UDM Auth, UDM sub, User PCC导入模板

This commit is contained in:
TsMask
2025-05-09 18:48:27 +08:00
parent f1aec581c7
commit 8664e72189
11 changed files with 323 additions and 115 deletions

View File

@@ -0,0 +1,2 @@
imsi,msisdn,sess_rules,pcc_rules,hdr_enrich,rfsp,sar,qos_audio,qos_video
001012082101039,1234,internet|ims_sig,internet|ims_sig,321321,255,321312,32131,32131

View File

@@ -0,0 +1,2 @@
001011100001157,1234567890ABCDEF1234567890ABCDEF,0,8000,11111111111111111111111111111111
001011100001158,1234567890ABCDEF1234567890ABCDEF,0,8000,11111111111111111111111111111111

View File

@@ -0,0 +1,2 @@
001011100001157,62357000583,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&internet&ims,1,64,24,65,def_eps,1,010200000000,-
001011100001158,62357000585,def_ambr,def_nssai,def_arfb,def_sar,0,3,def_snssai,1-000001&internet&ims,1,64,24,65,def_eps,1,010200000000,-

View File

@@ -0,0 +1,3 @@
#username,password
62357000580,123456
62357000581,123456

View File

@@ -0,0 +1,4 @@
#vlote=0 MSISDN and IMSI need to be filled in the same way.
#imsi,msisdn,vlote,vni
460996650000580,62357000580,1,ims.mnc000.mcc460.3gppnetwork.org
62357000581,62357000581,0,ims.mnc000.mcc460.3gppnetwork.org

View File

@@ -716,6 +716,26 @@ function fnModalUploadImportUpload(file: File) {
});
}
/**对话框表格信息导入模板 */
function fnModalDownloadImportTemplate() {
const hide = message.loading(t('common.loading'), 0);
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
const templateUrl = `${
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
? ''
: baseUrl.indexOf('/') === -1
? '/' + baseUrl
: baseUrl
}/neDataImput`;
saveAs(
`${templateUrl}/udm_auth_template.txt`,
`import_udmauth_template_${Date.now()}.txt`
);
hide();
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
@@ -1227,11 +1247,24 @@ onMounted(() => {
:size="10"
>
<template #default>
<a-radio-group
v-model:value="uploadImportState.from.typeVal"
:options="uploadImportState.typeOptions"
@change="fnModalUploadImportTypeChange"
/>
<a-row justify="space-between" align="middle">
<a-col :span="12">
<a-radio-group
v-model:value="uploadImportState.from.typeVal"
:options="uploadImportState.typeOptions"
@change="fnModalUploadImportTypeChange"
/>
</a-col>
<a-col>
<a-button
type="link"
:title="t('views.neData.common.importTemplate')"
@click.prevent="fnModalDownloadImportTemplate"
>
{{ t('views.neData.common.importTemplate') }}
</a-button>
</a-col>
</a-row>
<a-input-password
v-if="uploadImportState.from.typeVal === 'k4'"
v-model:value="uploadImportState.from.typeData"

View File

@@ -1,33 +1,52 @@
<script setup lang="ts">
import { reactive, ref, onMounted, toRaw } from 'vue';
import { reactive, ref, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { SizeType } from 'ant-design-vue/es/config-provider';
import { ColumnsType } from 'ant-design-vue/es/table';
import { Modal, message } from 'ant-design-vue/es';
import { Modal, message } from 'ant-design-vue/es';
import BackupModal from '@/views/ne/neConfigBackup/components/BackupModal.vue';
import { parseDateToStr } from '@/utils/date-utils';
import {
getBakFile,
getBakFileList,
downFile,
delFile,
} from '@/api/neUser/exportFile';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useI18n from '@/hooks/useI18n';
import saveAs from 'file-saver';
import { delFile, getFile, listFile } from '@/api/tool/file';
import { parseSizeFromFile } from '@/utils/parse-utils';
import { pushBackupFTP } from '@/api/neData/backup';
const { t } = useI18n();
/**网元参数 */
let logSelect = ref<string[]>([]);
/**文件列表 */
let fileList = ref<any>([]);
/**文件来源 */
let sourceState = reactive({
/**文件列表 */
list: [
{
value: '/auth',
label: t('views.neData.backupData.auth'),
path: '/usr/local/omc/backup/udm_data',
},
{
value: '/sub',
label: t('views.neData.backupData.sub'),
path: '/usr/local/omc/backup/udm_data',
},
{
value: '/voip',
label: t('views.neData.backupData.voip'),
path: '/usr/local/omc/backup/udm_data',
},
{
value: '/volte',
label: t('views.neData.backupData.volte'),
path: '/usr/local/omc/backup/udm_data',
},
],
/**选择value */
value: undefined,
});
/**查询参数 */
let queryParams = reactive({
/**读取路径 */
path: '',
/**表名 */
tableName: '',
/**当前页数 */
pageNum: 1,
/**每页条数 */
@@ -75,6 +94,9 @@ let tableColumns: ColumnsType = [
title: t('views.logManage.neFile.size'),
dataIndex: 'size',
align: 'left',
customRender(opt) {
return parseSizeFromFile(opt.value);
},
width: 100,
},
{
@@ -83,9 +105,9 @@ let tableColumns: ColumnsType = [
align: 'left',
customRender(opt) {
if (!opt.value) return '';
return parseDateToStr(opt.value * 1000);
return parseDateToStr(opt.value);
},
width: 250,
width: 200,
},
{
title: t('views.logManage.neFile.fileName'),
@@ -130,10 +152,6 @@ let tablePagination = reactive({
/**下载触发等待 */
let downLoading = ref<boolean>(false);
/**删除触发等待 */
let delLoading = ref<boolean>(false);
/**信息文件下载 */
function fnDownloadFile(row: Record<string, any>) {
if (downLoading.value) return;
@@ -145,10 +163,7 @@ function fnDownloadFile(row: Record<string, any>) {
onOk() {
downLoading.value = true;
const hide = message.loading(t('common.loading'), 0);
downFile({
path: queryParams.path,
fileName: row.fileName,
})
getFile(queryParams.path, row.fileName)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
@@ -173,6 +188,9 @@ function fnDownloadFile(row: Record<string, any>) {
});
}
/**删除触发等待 */
let delLoading = ref<boolean>(false);
/**信息文件删除 */
function fnRecordDelete(row: Record<string, any>) {
if (delLoading.value) return;
Modal.confirm({
@@ -181,30 +199,27 @@ function fnRecordDelete(row: Record<string, any>) {
fileName: row.fileName,
}),
onOk() {
const key = 'delFile';
delLoading.value = true;
message.loading({ content: t('common.loading'), key });
delFile({
fileName: row.fileName,
path: queryParams.path,
})
const hide = message.loading(t('common.loading'), 0);
delFile(queryParams.path, row.fileName)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('views.system.user.delSuss'),
key,
content: t('common.msgSuccess', {
msg: t('common.deleteText'),
}),
duration: 2,
});
fnGetList();
} else {
message.error({
content: `${res.msg}`,
key: key,
content: t('views.logManage.exportFile.deleteTipErr'),
duration: 2,
});
}
})
.finally(() => {
hide();
delLoading.value = false;
});
},
@@ -212,17 +227,18 @@ function fnRecordDelete(row: Record<string, any>) {
}
/**网元类型选择对应修改 */
function fnNeChange(keys: any, opt: any) {
queryParams.tableName = keys;
queryParams.path = opt.path;
function fnNeChange(_: any, opt: any) {
queryParams.path = `${opt.path}${opt.value}`;
ftpInfo.path = queryParams.path;
ftpInfo.tag = opt.value;
fnGetList(1);
}
/**查询备份信息列表, pageNum初始页数 */
function fnGetList(pageNum?: number) {
if (queryParams.tableName === '') {
if (queryParams.path === '') {
message.warning({
content: t('views.logManage.exportFile.selectTip'),
content: t('views.logManage.exportFile.fileSourcePlease'),
duration: 2,
});
return;
@@ -232,13 +248,14 @@ function fnGetList(pageNum?: number) {
if (pageNum) {
queryParams.pageNum = pageNum;
}
getBakFileList(toRaw(queryParams)).then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
tablePagination.total = res.total;
tableState.data = res.data;
listFile(toRaw(queryParams)).then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
const { total, rows } = res.data;
tablePagination.total = total;
tableState.data = rows;
if (
tablePagination.total <=
(queryParams.pageNum - 1) * tablePagination.pageSize &&
(queryParams.pageNum - 1) * tablePagination.pageSize &&
queryParams.pageNum !== 1
) {
tableState.loading = false;
@@ -253,23 +270,34 @@ function fnGetList(pageNum?: number) {
});
}
onMounted(() => {
getBakFile().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
res.data.forEach((item: any) => {
fileList.value.push({
value: item.tableName,
label: item.tableDisplay,
path: item.filePath,
});
});
}
});
// .finally(() => {
// fnGetList();
// });
/**打开FTP配置窗口 */
const openFTPModal = ref<boolean>(false);
function fnFTPModalOpen() {
openFTPModal.value = !openFTPModal.value;
}
type FTPInfoType = {
path: string;
tag: string;
fileName: string;
};
const ftpInfo = reactive<FTPInfoType>({
path: '',
tag: '',
fileName: '',
});
/**同步文件到FTP */
function fnSyncFileToFTP(fileName: string) {
ftpInfo.fileName = fileName;
pushBackupFTP(toRaw(ftpInfo)).then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(t('common.operateOk'), 3);
} else {
message.warning(res.msg, 3);
}
});
}
</script>
<template>
@@ -280,12 +308,14 @@ onMounted(() => {
<a-form :model="queryParams" name="queryParams" layout="horizontal">
<a-row :gutter="16" align="middle">
<a-col>
<span>{{ t('views.logManage.exportFile.fileName') }}:</span>&nbsp;
<span>{{ t('views.logManage.exportFile.fileSource') }}:</span
>&nbsp;
<a-select
v-model:value="logSelect"
:options="fileList"
v-model:value="sourceState.value"
:options="sourceState.list"
@change="fnNeChange"
:allow-clear="false"
:placeholder="t('common.selectPlease')"
style="width: 200px"
/>
</a-col>
@@ -306,6 +336,14 @@ onMounted(() => {
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-tooltip placement="topRight">
<template #title>
{{ t('views.ne.neConfigBackup.backupModal.title') }}
</template>
<a-button type="text" @click.prevent="fnFTPModalOpen()">
<template #icon><DeliveredProcedureOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.reloadText') }}</template>
<a-button type="text" @click.prevent="fnGetList()">
@@ -329,33 +367,45 @@ onMounted(() => {
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'fileName'">
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.downloadText') }}</template>
<a-button
type="link"
:loading="downLoading"
@click.prevent="fnDownloadFile(record)"
v-if="record.fileType === 'file'"
>
<template #icon><DownloadOutlined /></template>
</a-button>
<a-tooltip placement="topRight" v-if="record.fileType === 'file'">
<template #title>
{{ t('views.ne.neConfigBackup.backupModal.pushFileOper') }}
</template>
<a-button
type="link"
@click.prevent="fnSyncFileToFTP(record.fileName)"
>
<template #icon><CloudServerOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip>
<a-tooltip placement="topRight" v-if="record.fileType === 'file'">
<template #title>{{ t('common.downloadText') }}</template>
<a-button
type="link"
:loading="downLoading"
@click.prevent="fnDownloadFile(record)"
>
<template #icon><DownloadOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip placement="topRight" v-if="record.fileType === 'file'">
<template #title>{{ t('common.deleteText') }}</template>
<a-button
type="link"
:loading="delLoading"
@click.prevent="fnRecordDelete(record)"
v-if="record.fileType === 'file'"
>
<template #icon><DeleteOutlined /></template>
</a-button>
<a-button
type="link"
:loading="delLoading"
@click.prevent="fnRecordDelete(record)"
>
<template #icon><DeleteOutlined /></template>
</a-button>
</a-tooltip>
</a-space>
</template>
</template>
</a-table>
</a-card>
<!-- FTP配置窗口 -->
<BackupModal v-model:open="openFTPModal"></BackupModal>
</PageContainer>
</template>

View File

@@ -770,6 +770,26 @@ function fnModalUploadImportUpload(file: File) {
});
}
/**对话框表格信息导入模板 */
function fnModalDownloadImportTemplate() {
const hide = message.loading(t('common.loading'), 0);
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
const templateUrl = `${
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
? ''
: baseUrl.indexOf('/') === -1
? '/' + baseUrl
: baseUrl
}/neDataImput`;
saveAs(
`${templateUrl}/udm_volte_template.txt`,
`import_udmvolte_template_${Date.now()}.txt`
);
hide();
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
@@ -1251,23 +1271,25 @@ onMounted(() => {
:size="10"
>
<template #default>
<a-alert
:message="uploadImportState.msg"
:type="uploadImportState.hasFail ? 'warning' : 'info'"
v-show="uploadImportState.msg.length > 0"
>
<template #action>
<a-row justify="space-between" align="middle">
<a-col :span="12"> </a-col>
<a-col>
<a-button
size="small"
type="link"
danger
@click="fnModalUploadImportFailReason"
v-if="uploadImportState.hasFail"
:title="t('views.neData.common.importTemplate')"
@click.prevent="fnModalDownloadImportTemplate"
>
{{ t('views.neUser.auth.importFail') }}
{{ t('views.neData.common.importTemplate') }}
</a-button>
</template>
</a-alert>
</a-col>
</a-row>
<a-textarea
:disabled="true"
:hidden="!uploadImportState.msg"
:value="uploadImportState.msg"
:auto-size="{ minRows: 2, maxRows: 8 }"
style="background-color: transparent; color: rgba(0, 0, 0, 0.85)"
/>
</template>
</UploadModal>
</PageContainer>

View File

@@ -635,6 +635,26 @@ function filterOption(value: any, option: any) {
return option.value.toUpperCase().indexOf(value.toUpperCase()) >= 0;
}
/**对话框表格信息导入模板 */
function fnModalDownloadImportTemplate() {
const hide = message.loading(t('common.loading'), 0);
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
const templateUrl = `${
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
? ''
: baseUrl.indexOf('/') === -1
? '/' + baseUrl
: baseUrl
}/neDataImput`;
saveAs(
`${templateUrl}/pcf_template.txt`,
`import_pcfrule_template_${Date.now()}.txt`
);
hide();
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
@@ -1156,6 +1176,18 @@ onMounted(() => {
:ext="['.txt']"
>
<template #default>
<a-row justify="space-between" align="middle">
<a-col :span="12"> </a-col>
<a-col>
<a-button
type="link"
:title="t('views.neData.common.importTemplate')"
@click.prevent="fnModalDownloadImportTemplate"
>
{{ t('views.neData.common.importTemplate') }}
</a-button>
</a-col>
</a-row>
<a-textarea
:disabled="true"
:hidden="!uploadImportState.msg"

View File

@@ -1180,6 +1180,26 @@ function fnTenantNameFocus() {
});
}
/**对话框表格信息导入模板 */
async function fnModalDownloadImportTemplate() {
const hide = message.loading(t('common.loading'), 0);
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
const templateUrl = `${
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
? ''
: baseUrl.indexOf('/') === -1
? '/' + baseUrl
: baseUrl
}/neDataImput`;
saveAs(
`${templateUrl}/udm_sub_template.txt`,
`import_udmsub_template_${Date.now()}.txt`
);
hide();
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
@@ -1257,8 +1277,12 @@ onMounted(() => {
<a-col :lg="8" :md="12" :xs="24">
<a-form-item label="MSISDN" name="msisdn">
<a-input v-model:value="queryParams.msisdn" allow-clear :maxlength="32"
:placeholder="t('common.inputPlease')"></a-input>
<a-input
v-model:value="queryParams.msisdn"
allow-clear
:maxlength="32"
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :xs="24">
@@ -2198,6 +2222,18 @@ onMounted(() => {
:size="10"
>
<template #default>
<a-row justify="space-between" align="middle">
<a-col :span="12"> </a-col>
<a-col>
<a-button
type="link"
:title="t('views.neData.common.importTemplate')"
@click.prevent="fnModalDownloadImportTemplate"
>
{{ t('views.neData.common.importTemplate') }}
</a-button>
</a-col>
</a-row>
<a-alert
:message="uploadImportState.msg"
:type="uploadImportState.hasFail ? 'warning' : 'info'"

View File

@@ -652,6 +652,26 @@ function fnModalUploadImportUpload(file: File) {
});
}
/**对话框表格信息导入模板 */
function fnModalDownloadImportTemplate() {
const hide = message.loading(t('common.loading'), 0);
const baseUrl = import.meta.env.VITE_HISTORY_BASE_URL;
const templateUrl = `${
baseUrl.length === 1 && baseUrl.indexOf('/') === 0
? ''
: baseUrl.indexOf('/') === -1
? '/' + baseUrl
: baseUrl
}/neDataImput`;
saveAs(
`${templateUrl}/udm_voip_template.txt`,
`import_udmvoip_template_${Date.now()}.txt`
);
hide();
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
@@ -1042,23 +1062,25 @@ onMounted(() => {
:size="10"
>
<template #default>
<a-alert
:message="uploadImportState.msg"
:type="uploadImportState.hasFail ? 'warning' : 'info'"
v-show="uploadImportState.msg.length > 0"
>
<template #action>
<a-row justify="space-between" align="middle">
<a-col :span="12"> </a-col>
<a-col>
<a-button
size="small"
type="link"
danger
@click="fnModalUploadImportFailReason"
v-if="uploadImportState.hasFail"
:title="t('views.neData.common.importTemplate')"
@click.prevent="fnModalDownloadImportTemplate"
>
{{ t('views.neUser.auth.importFail') }}
{{ t('views.neData.common.importTemplate') }}
</a-button>
</template>
</a-alert>
</a-col>
</a-row>
<a-textarea
:disabled="true"
:hidden="!uploadImportState.msg"
:value="uploadImportState.msg"
:auto-size="{ minRows: 2, maxRows: 8 }"
style="background-color: transparent; color: rgba(0, 0, 0, 0.85)"
/>
</template>
</UploadModal>
</PageContainer>