perf: 网元备份导入导出弹窗表单重构

This commit is contained in:
TsMask
2024-07-26 18:27:15 +08:00
parent 8e9498ec83
commit ab0d26513c
5 changed files with 212 additions and 86 deletions

View File

@@ -0,0 +1,83 @@
import { request } from '@/plugins/http-fetch';
/**
* 网元配置文件备份记录列表
* @param query 查询参数
* @returns object
*/
export function listNeConfigBackup(query: Record<string, any>) {
return request({
url: '/ne/config/backup/list',
method: 'get',
params: query,
});
}
/**
* 网元配置文件备份记录修改
* @param data 数据 { id, name, remark }
* @returns object
*/
export function updateNeConfigBackup(data: Record<string, any>) {
return request({
url: '/ne/config/backup',
method: 'put',
data: data,
});
}
/**
* 网元配置文件备份记录下载
* @param id 记录ID
* @returns object
*/
export async function downNeConfigBackup(id: string) {
return await request({
url: '/ne/config/backup/download',
method: 'get',
params: { id },
responseType: 'blob',
timeout: 180_000,
});
}
/**
* 网元配置文件备份记录删除
* @param id 记录ID
* @returns object
*/
export async function delNeConfigBackup(id: string) {
return request({
url: '/ne/config/backup',
method: 'delete',
params: { id },
});
}
/**
* 网元配置文件备份导出
* @param data 数据 { neType, neId }
* @returns object
*/
export function exportNeConfigBackup(data: Record<string, any>) {
return request({
url: '/ne/config/backup/export',
method: 'post',
data: data,
responseType: 'blob',
timeout: 180_000,
});
}
/**
* 网元配置文件备份导入
* @param data 数据 { neType, neId, type, path }
* @returns object
*/
export function importNeConfigBackup(data: Record<string, any>) {
return request({
url: '/ne/config/backup/import',
method: 'post',
data: data,
});
}

View File

@@ -668,9 +668,8 @@ export default {
local:'Local File', local:'Local File',
localUpload:'Local Upload', localUpload:'Local Upload',
exportTip:'Confirm that you want to export the network element configuration file?', exportTip:'Confirm that you want to export the network element configuration file?',
exportMsg:'Exported successfully, please download from [Backup Management].', exportMsg:'Exporting Network Element Configuration Information to a File Succeeded',
filePlease: "Please upload a file", pathPlease: 'No Backup File Found',
fileNamePlease: 'Please select the server file',
}, },
}, },
neHost: { neHost: {
@@ -781,6 +780,11 @@ export default {
syncNeDone: 'Synchronization to network element terminals complete', syncNeDone: 'Synchronization to network element terminals complete',
saveOk: 'Save Success!', saveOk: 'Save Success!',
}, },
neConfigBackup: {
name: "Name",
downTip: 'Confirmed to download the backup file [{txt}]?',
title: "Modify Backup {txt}",
},
neQuickSetup: { neQuickSetup: {
stepPrev: 'Previous', stepPrev: 'Previous',
stepPrevTip: 'Confirm that you want to abandon the current change and return to the previous step?', stepPrevTip: 'Confirm that you want to abandon the current change and return to the previous step?',

View File

@@ -668,9 +668,8 @@ export default {
local:'本地文件', local:'本地文件',
localUpload:'本地上传', localUpload:'本地上传',
exportTip:'确认要导出网元配置信息到文件?', exportTip:'确认要导出网元配置信息到文件?',
exportMsg:'导出成功,请到【备份管理】进行下载', exportMsg:'导出网元配置信息到文件成功',
filePlease: "请上传文件", pathPlease: '未发现文件',
fileNamePlease: '请选择服务器文件',
}, },
}, },
neHost: { neHost: {
@@ -781,6 +780,11 @@ export default {
syncNeDone: '同步到网元终端完成', syncNeDone: '同步到网元终端完成',
saveOk: '保存成功!', saveOk: '保存成功!',
}, },
neConfigBackup: {
name: "名称",
downTip: '确认要下载备份文件【{txt}】吗?',
title: "修改备份信息 {txt}",
},
neQuickSetup: { neQuickSetup: {
stepPrev: '上一步', stepPrev: '上一步',
stepPrevTip: '确认要放弃当前变更返回上一步吗?', stepPrevTip: '确认要放弃当前变更返回上一步吗?',

View File

@@ -1,15 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, toRaw, watch } from 'vue'; import { reactive, toRaw, watch } from 'vue';
import { Form, Modal, Upload, message } from 'ant-design-vue/lib'; import { Form, Modal, Upload, message, notification } from 'ant-design-vue/lib';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface'; import { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
import { FileType } from 'ant-design-vue/lib/upload/interface'; import { FileType, UploadFile } from 'ant-design-vue/lib/upload/interface';
import { import {
exportSet, exportNeConfigBackup,
importFile, importNeConfigBackup,
listServerFile, listNeConfigBackup,
} from '@/api/configManage/neManage'; } from '@/api/ne/neConfigBackup';
import saveAs from 'file-saver';
import { uploadFile } from '@/api/tool/file';
const { t } = useI18n(); const { t } = useI18n();
const emit = defineEmits(['ok', 'cancel', 'update:visible']); const emit = defineEmits(['ok', 'cancel', 'update:visible']);
const props = defineProps({ const props = defineProps({
@@ -28,32 +30,49 @@ const props = defineProps({
}, },
}); });
/**表格所需option */ /**导入状态数据 */
const neManageOption = reactive({ const importState = reactive({
importType: [ typeOption: [
{ label: t('views.ne.neInfo.backConf.server'), value: 'server' }, { label: t('views.ne.neInfo.backConf.server'), value: 'backup' },
{ label: t('views.ne.neInfo.backConf.local'), value: 'local' }, { label: t('views.ne.neInfo.backConf.local'), value: 'upload' },
], ],
serverFileName: <any[]>[], backupData: <any[]>[],
}); });
/**查询网元远程服务器备份文件 */ /**查询网元远程服务器备份文件 */
function typeChange(value: any) { function backupSearch(name?: string) {
if (value === 'server') { const { neType, neId } = modalState.from;
modalState.from.fileName = undefined; listNeConfigBackup({
listServerFile(modalState.from).then(res => { neType,
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) { neId,
neManageOption.serverFileName = []; name,
res.data.forEach((item: any) => { pageNum: 1,
neManageOption.serverFileName.push({ pageSize: 20,
label: item.fileName, }).then(res => {
value: item.fileName, if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
}); importState.backupData = [];
res.rows.forEach((item: any) => {
importState.backupData.push({
label: item.name,
value: item.path,
}); });
} });
}); }
} else { });
modalState.from.file = null; }
/**服务器备份文件选择切换 */
function backupChange(value: any) {
if (!value) {
backupSearch();
}
}
/**类型切换 */
function typeChange(value: any) {
modalState.from.path = undefined;
if (value === 'backup') {
backupSearch();
} }
} }
@@ -67,9 +86,8 @@ type ModalStateType = {
from: { from: {
neType: string; neType: string;
neId: string; neId: string;
importType: 'local' | 'server'; type: 'upload' | 'backup';
file: File | null; path: string | undefined;
fileName: string | undefined;
}; };
/**确定按钮 loading */ /**确定按钮 loading */
confirmLoading: boolean; confirmLoading: boolean;
@@ -84,9 +102,8 @@ let modalState: ModalStateType = reactive({
from: { from: {
neType: '', neType: '',
neId: '', neId: '',
importType: 'local', type: 'upload',
file: null, path: undefined,
fileName: undefined,
}, },
confirmLoading: false, confirmLoading: false,
uploadFiles: [], uploadFiles: [],
@@ -96,16 +113,10 @@ let modalState: ModalStateType = reactive({
const modalStateFrom = Form.useForm( const modalStateFrom = Form.useForm(
modalState.from, modalState.from,
reactive({ reactive({
file: [ path: [
{ {
required: true, required: true,
message: t('views.ne.neInfo.backConf.filePlease'), message: t('views.ne.neInfo.backConf.pathPlease'),
},
],
fileName: [
{
required: true,
message: t('views.ne.neInfo.backConf.fileNamePlease'),
}, },
], ],
}) })
@@ -117,21 +128,13 @@ const modalStateFrom = Form.useForm(
*/ */
function fnModalOk() { function fnModalOk() {
if (modalState.confirmLoading) return; if (modalState.confirmLoading) return;
const from = toRaw(modalState.from); const from = toRaw(modalState.from);
let validateName = ['importType'];
if (from.importType === 'local') {
validateName.push('file');
} else {
validateName.push('fileName');
}
modalStateFrom modalStateFrom
.validate(validateName) .validate()
.then(e => { .then(e => {
modalState.confirmLoading = true; modalState.confirmLoading = true;
const hide = message.loading(t('common.loading'), 0); const hide = message.loading(t('common.loading'), 0);
importFile(from) importNeConfigBackup(from)
.then(res => { .then(res => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
message.success(t('common.operateOk'), 3); message.success(t('common.operateOk'), 3);
@@ -168,6 +171,12 @@ function fnModalCancel() {
emit('update:visible', false); emit('update:visible', false);
} }
/**表单上传前删除 */
function fnBeforeRemoveFile(file: UploadFile) {
modalState.from.path = undefined;
return true;
}
/**表单上传前检查或转换压缩 */ /**表单上传前检查或转换压缩 */
function fnBeforeUploadFile(file: FileType) { function fnBeforeUploadFile(file: FileType) {
if (modalState.confirmLoading) return false; if (modalState.confirmLoading) return false;
@@ -187,12 +196,30 @@ function fnBeforeUploadFile(file: FileType) {
/**表单上传文件 */ /**表单上传文件 */
function fnUploadFile(up: UploadRequestOption) { function fnUploadFile(up: UploadRequestOption) {
// 改为完成状态 // 发送请求
const file = modalState.uploadFiles[0]; const hide = message.loading(t('common.loading'), 0);
file.percent = 100; modalState.confirmLoading = true;
file.status = 'done'; let formData = new FormData();
// 预置到表单 formData.append('file', up.file);
modalState.from.file = up.file as File; formData.append('subPath', 'import');
uploadFile(formData)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
// 改为完成状态
const file = modalState.uploadFiles[0];
file.percent = 100;
file.status = 'done';
// 预置到表单
const { fileName } = res.data;
modalState.from.path = fileName;
} else {
message.error(res.msg, 3);
}
})
.finally(() => {
hide();
modalState.confirmLoading = false;
});
} }
/**监听是否显示,初始数据 */ /**监听是否显示,初始数据 */
@@ -220,10 +247,17 @@ function fnExportConf(neType: string, neId: string) {
content: t('views.ne.neInfo.backConf.exportTip'), content: t('views.ne.neInfo.backConf.exportTip'),
onOk() { onOk() {
const hide = message.loading(t('common.loading'), 0); const hide = message.loading(t('common.loading'), 0);
exportSet({ neType, neId }) exportNeConfigBackup({ neType, neId })
.then(res => { .then(res => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
message.success(t('views.ne.neInfo.backConf.exportMsg'), 3); notification.success({
message: t('common.tipTitle'),
description: t('views.ne.neInfo.backConf.exportMsg'),
});
saveAs(
res.data,
`${neType}_${neId}_config_backup_${Date.now()}.zip`
);
} else { } else {
message.error(`${res.msg}`, 3); message.error(`${res.msg}`, 3);
} }
@@ -258,44 +292,44 @@ defineExpose({
<a-form name="modalStateFrom" layout="horizontal" :label-col="{ span: 6 }"> <a-form name="modalStateFrom" layout="horizontal" :label-col="{ span: 6 }">
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :lg="12" :md="12" :xs="24"> <a-col :lg="12" :md="12" :xs="24">
<a-form-item <a-form-item :label="t('views.ne.common.neType')" name="neType">
:label="t('views.ne.common.neType')"
name="neType"
v-bind="modalStateFrom.validateInfos.neType"
>
{{ modalState.from.neType }} {{ modalState.from.neType }}
</a-form-item> </a-form-item>
<a-form-item <a-form-item
:label="t('views.ne.neInfo.backConf.importType')" :label="t('views.ne.neInfo.backConf.importType')"
name="importType" name="type"
> >
<a-select <a-select
v-model:value="modalState.from.importType" v-model:value="modalState.from.type"
default-value="server" default-value="server"
:options="neManageOption.importType" :options="importState.typeOption"
@change="typeChange" @change="typeChange"
> >
</a-select> </a-select>
</a-form-item> </a-form-item>
</a-col> </a-col>
<a-col :lg="12" :md="12" :xs="24"> <a-col :lg="12" :md="12" :xs="24">
<a-form-item <a-form-item :label="t('views.ne.common.neId')" name="neId">
:label="t('views.ne.common.neId')"
name="neId"
v-bind="modalStateFrom.validateInfos.neId"
>
{{ modalState.from.neId }} {{ modalState.from.neId }}
</a-form-item> </a-form-item>
<a-form-item <a-form-item
:label="t('views.ne.neInfo.backConf.server')" :label="t('views.ne.neInfo.backConf.server')"
name="fileName" name="fileName"
v-bind="modalStateFrom.validateInfos.fileName" v-bind="modalStateFrom.validateInfos.path"
v-if="modalState.from.importType === 'server'" v-if="modalState.from.type === 'backup'"
> >
<a-select <a-select
v-model:value="modalState.from.fileName" v-model:value="modalState.from.path"
:options="neManageOption.serverFileName" :options="importState.backupData"
:placeholder="t('common.selectPlease')" :placeholder="t('common.selectPlease')"
:show-search="true"
:default-active-first-option="false"
:show-arrow="false"
:allow-clear="true"
:filter-option="false"
:not-found-content="null"
@search="backupSearch"
@change="backupChange"
> >
</a-select> </a-select>
</a-form-item> </a-form-item>
@@ -303,8 +337,8 @@ defineExpose({
<a-form-item <a-form-item
:label="t('views.ne.neInfo.backConf.local')" :label="t('views.ne.neInfo.backConf.local')"
name="file" name="file"
v-bind="modalStateFrom.validateInfos.file" v-bind="modalStateFrom.validateInfos.path"
v-if="modalState.from.importType === 'local'" v-if="modalState.from.type === 'upload'"
> >
<a-upload <a-upload
name="file" name="file"
@@ -314,9 +348,10 @@ defineExpose({
:max-count="1" :max-count="1"
:show-upload-list="{ :show-upload-list="{
showPreviewIcon: false, showPreviewIcon: false,
showRemoveIcon: false, showRemoveIcon: true,
showDownloadIcon: false, showDownloadIcon: false,
}" }"
:remove="fnBeforeRemoveFile"
:before-upload="fnBeforeUploadFile" :before-upload="fnBeforeUploadFile"
:custom-request="fnUploadFile" :custom-request="fnUploadFile"
:disabled="modalState.confirmLoading" :disabled="modalState.confirmLoading"

View File

@@ -558,7 +558,7 @@ onMounted(() => {
:data-source="tableState.data" :data-source="tableState.data"
:size="tableState.size" :size="tableState.size"
:pagination="tablePagination" :pagination="tablePagination"
:scroll="{ x: tableColumns.length * 150 }" :scroll="{ x: tableColumns.length * 120 }"
:row-selection="{ :row-selection="{
type: 'checkbox', type: 'checkbox',
columnWidth: '48px', columnWidth: '48px',