ref: 统一ftp操作功能,备份文件查看下载删除功能

This commit is contained in:
TsMask
2025-04-25 16:16:09 +08:00
parent 71b4943816
commit 204d198819
8 changed files with 473 additions and 609 deletions

View File

@@ -53,43 +53,3 @@ export function delFile(query: Record<string, any>) {
params: query, params: query,
}); });
} }
/**
* 更新FTP信息
* @param data 数据
* @returns object
*/
export function updateFTPInfo(data: Record<string, any>) {
return request({
url: `/lm/table/ftp`,
method: 'POST',
data: data,
crypto: sessionGet(CACHE_SESSION_CRYPTO_API) !== 'false',
});
}
/**
* 获取FTP信息
* @param data 数据
* @returns object
*/
export function getFTPInfo() {
return request({
url: `/lm/table/ftp`,
method: 'GET',
crypto: sessionGet(CACHE_SESSION_CRYPTO_API) !== 'false',
});
}
/**
* 发送FTP文件
* @param data 数据
* @returns object
*/
export function putFTPInfo(filePath: string, fileName: string) {
return request({
url: `/lm/table/ftp`,
method: 'PUT',
data: { filePath, fileName },
});
}

View File

@@ -83,43 +83,3 @@ export function importNeConfigBackup(data: Record<string, any>) {
data: data, data: data,
}); });
} }
/**
* 更新FTP信息
* @param data 数据
* @returns object
*/
export function updateFTPInfo(data: Record<string, any>) {
return request({
url: `/ne/config/backup/ftp`,
method: 'POST',
data: data,
crypto: sessionGet(CACHE_SESSION_CRYPTO_API) !== 'false',
});
}
/**
* 获取FTP信息
* @param data 数据
* @returns object
*/
export function getFTPInfo() {
return request({
url: `/ne/config/backup/ftp`,
method: 'GET',
crypto: sessionGet(CACHE_SESSION_CRYPTO_API) !== 'false',
});
}
/**
* 发送FTP文件
* @param data 数据
* @returns object
*/
export function putFTPInfo(path: string) {
return request({
url: `/ne/config/backup/ftp`,
method: 'PUT',
data: { path },
});
}

38
src/api/neData/backup.ts Normal file
View File

@@ -0,0 +1,38 @@
import { request } from '@/plugins/http-fetch';
/**
* 备份文件-获取FTP配置
* @returns object
*/
export function getBackupFTP() {
return request({
url: '/neData/backup/ftp',
method: 'GET',
});
}
/**
* 备份文件-文件FTP发送
* @param data 对象
* @returns object
*/
export function pushBackupFTP(data: Record<string, any>) {
return request({
url: '/neData/backup/ftp',
method: 'POST',
data,
});
}
/**
* 备份文件-更新FTP配置
* @param data 对象
* @returns object
*/
export function updateBackupFTP(data: Record<string, any>) {
return request({
url: '/neData/backup/ftp',
method: 'PUT',
data,
});
}

View File

@@ -210,6 +210,50 @@ export function chunkUpload(data: FormData) {
}); });
} }
/**
* 本地文件列表
* @param path 文件路径
* @param search search prefix
* @returns object
*/
export async function listFile(query: Record<string, any>) {
return request({
url: `/file/list`,
method: 'GET',
params: query,
});
}
/**
* 本地文件获取下载
* @param path 文件路径
* @param fileName 文件名
* @returns object
*/
export async function getFile(path: string, fileName: string) {
return request({
url: `/file`,
method: 'GET',
params: { path, fileName },
responseType: 'blob',
timeout: 60_000,
});
}
/**
* 本地文件删除
* @param path 文件路径
* @param fileName 文件名
* @returns object
*/
export async function delFile(path: string, fileName: string) {
return request({
url: `/file`,
method: 'DELETE',
params: { path, fileName },
});
}
/** /**
* 转存上传文件到静态资源 * 转存上传文件到静态资源
* @returns object * @returns object

View File

@@ -101,7 +101,14 @@ export function parseObjLineToHump(obj: any): any {
* @param decimalPlaces 保留小数位,默认2位 * @param decimalPlaces 保留小数位,默认2位
* @returns 单位 xB * @returns 单位 xB
*/ */
export function parseSizeFromFile(bytes: number, decimalPlaces: number = 2) { export function parseSizeFromFile(
bytes: number,
decimalPlaces: number = 2
): string {
if (typeof bytes !== 'number' || isNaN(bytes) || bytes < 0) {
return `${bytes}`;
}
if (bytes === 0) return '0 B';
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
let i = 0; let i = 0;
while (bytes >= 1024 && i < units.length - 1) { while (bytes >= 1024 && i < units.length - 1) {

View File

@@ -1,38 +1,57 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted, toRaw } from 'vue'; import { reactive, ref, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout'; import { PageContainer } from 'antdv-pro-layout';
import { ProModal } from 'antdv-pro-modal';
import { SizeType } from 'ant-design-vue/es/config-provider'; import { SizeType } from 'ant-design-vue/es/config-provider';
import { ColumnsType } from 'ant-design-vue/es/table'; import { ColumnsType } from 'ant-design-vue/es/table';
import { Form, 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 { parseDateToStr } from '@/utils/date-utils';
import {
getBakFile,
getBakFileList,
downFile,
delFile,
updateFTPInfo,
getFTPInfo,
putFTPInfo,
} from '@/api/logManage/exportFile';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
import saveAs from 'file-saver'; import saveAs from 'file-saver';
import { regExpIPv4 } from '@/utils/regular-utils'; import { delFile, getFile, listFile } from '@/api/tool/file';
import { parseSizeFromFile } from '@/utils/parse-utils';
import { pushBackupFTP } from '@/api/neData/backup';
const { t } = useI18n(); const { t } = useI18n();
/**网元参数 */ /**文件来源 */
let logSelect = ref<string[]>([]); let sourceState = reactive({
/**文件列表 */
/**文件列表 */ list: [
let fileList = ref<any>([]); {
value: '/log/operate_log',
label: t('views.logManage.exportFile.operateLog'),
path: '/usr/local/omc/backup',
},
{
value: '/cdr/ims_cdr',
label: t('views.logManage.exportFile.cdrIMS'),
path: '/usr/local/omc/backup',
},
{
value: '/cdr/smf_cdr',
label: t('views.logManage.exportFile.cdrSMF'),
path: '/usr/local/omc/backup',
},
{
value: '/cdr/smsc_cdr',
label: t('views.logManage.exportFile.cdrSMSC'),
path: '/usr/local/omc/backup',
},
{
value: '/cdr/sgwc_cdr',
label: t('views.logManage.exportFile.cdrSGWC'),
path: '/usr/local/omc/backup',
},
],
/**选择value */
value: undefined,
});
/**查询参数 */ /**查询参数 */
let queryParams = reactive({ let queryParams = reactive({
/**读取路径 */ /**读取路径 */
path: '', path: '',
/**表名 */
tableName: '',
/**当前页数 */ /**当前页数 */
pageNum: 1, pageNum: 1,
/**每页条数 */ /**每页条数 */
@@ -80,6 +99,9 @@ let tableColumns: ColumnsType = [
title: t('views.logManage.neFile.size'), title: t('views.logManage.neFile.size'),
dataIndex: 'size', dataIndex: 'size',
align: 'left', align: 'left',
customRender(opt) {
return parseSizeFromFile(opt.value);
},
width: 100, width: 100,
}, },
{ {
@@ -88,9 +110,9 @@ let tableColumns: ColumnsType = [
align: 'left', align: 'left',
customRender(opt) { customRender(opt) {
if (!opt.value) return ''; if (!opt.value) return '';
return parseDateToStr(opt.value * 1000); return parseDateToStr(opt.value);
}, },
width: 150, width: 200,
}, },
{ {
title: t('views.logManage.neFile.fileName'), title: t('views.logManage.neFile.fileName'),
@@ -135,10 +157,6 @@ let tablePagination = reactive({
/**下载触发等待 */ /**下载触发等待 */
let downLoading = ref<boolean>(false); let downLoading = ref<boolean>(false);
/**删除触发等待 */
let delLoading = ref<boolean>(false);
/**信息文件下载 */ /**信息文件下载 */
function fnDownloadFile(row: Record<string, any>) { function fnDownloadFile(row: Record<string, any>) {
if (downLoading.value) return; if (downLoading.value) return;
@@ -150,10 +168,7 @@ function fnDownloadFile(row: Record<string, any>) {
onOk() { onOk() {
downLoading.value = true; downLoading.value = true;
const hide = message.loading(t('common.loading'), 0); const hide = message.loading(t('common.loading'), 0);
downFile({ getFile(queryParams.path, row.fileName)
path: queryParams.path,
fileName: row.fileName,
})
.then(res => { .then(res => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
message.success({ message.success({
@@ -178,6 +193,9 @@ function fnDownloadFile(row: Record<string, any>) {
}); });
} }
/**删除触发等待 */
let delLoading = ref<boolean>(false);
/**信息文件删除 */
function fnRecordDelete(row: Record<string, any>) { function fnRecordDelete(row: Record<string, any>) {
if (delLoading.value) return; if (delLoading.value) return;
Modal.confirm({ Modal.confirm({
@@ -186,30 +204,27 @@ function fnRecordDelete(row: Record<string, any>) {
fileName: row.fileName, fileName: row.fileName,
}), }),
onOk() { onOk() {
const key = 'delFile';
delLoading.value = true; delLoading.value = true;
message.loading({ content: t('common.loading'), key }); const hide = message.loading(t('common.loading'), 0);
delFile({ delFile(queryParams.path, row.fileName)
fileName: row.fileName,
path: queryParams.path,
})
.then(res => { .then(res => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
message.success({ message.success({
content: t('views.system.user.delSuss'), content: t('common.msgSuccess', {
key, msg: t('common.deleteText'),
}),
duration: 2, duration: 2,
}); });
fnGetList(); fnGetList();
} else { } else {
message.error({ message.error({
content: `${res.msg}`, content: t('views.logManage.exportFile.deleteTipErr'),
key: key,
duration: 2, duration: 2,
}); });
} }
}) })
.finally(() => { .finally(() => {
hide();
delLoading.value = false; delLoading.value = false;
}); });
}, },
@@ -217,17 +232,18 @@ function fnRecordDelete(row: Record<string, any>) {
} }
/**网元类型选择对应修改 */ /**网元类型选择对应修改 */
function fnNeChange(keys: any, opt: any) { function fnNeChange(_: any, opt: any) {
queryParams.tableName = keys; queryParams.path = `${opt.path}${opt.value}`;
queryParams.path = opt.path; ftpInfo.path = queryParams.path;
ftpInfo.tag = opt.value;
fnGetList(1); fnGetList(1);
} }
/**查询备份信息列表, pageNum初始页数 */ /**查询备份信息列表, pageNum初始页数 */
function fnGetList(pageNum?: number) { function fnGetList(pageNum?: number) {
if (queryParams.tableName === '') { if (queryParams.path === '') {
message.warning({ message.warning({
content: t('views.logManage.exportFile.selectTip'), content: t('views.logManage.exportFile.fileSourcePlease'),
duration: 2, duration: 2,
}); });
return; return;
@@ -237,7 +253,7 @@ function fnGetList(pageNum?: number) {
if (pageNum) { if (pageNum) {
queryParams.pageNum = pageNum; queryParams.pageNum = pageNum;
} }
getBakFileList(toRaw(queryParams)).then(res => { listFile(toRaw(queryParams)).then(res => {
if (res.code === RESULT_CODE_SUCCESS) { if (res.code === RESULT_CODE_SUCCESS) {
const { total, rows } = res.data; const { total, rows } = res.data;
tablePagination.total = total; tablePagination.total = total;
@@ -259,147 +275,34 @@ function fnGetList(pageNum?: number) {
}); });
} }
onMounted(() => { /**打开FTP配置窗口 */
getBakFile().then(res => { const openFTPModal = ref<boolean>(false);
if (res.code === RESULT_CODE_SUCCESS) { function fnFTPModalOpen() {
res.data.forEach((item: any) => { openFTPModal.value = !openFTPModal.value;
fileList.value.push({ }
value: item.tableName,
label: item.tableDisplay,
path: item.filePath,
});
});
}
});
// .finally(() => {
// fnGetList();
// });
});
/**对象信息状态类型 */ type FTPInfoType = {
type ModalStateType = { path: string;
/**新增框或修改框是否显示 */ tag: string;
openByEdit: boolean; fileName: string;
/**标题 */
title: string;
/**表单数据 */
from: Record<string, any>;
/**确定按钮 loading */
confirmLoading: boolean;
}; };
const ftpInfo = reactive<FTPInfoType>({
/**FTP日志对象信息状态 */ path: '',
let modalState: ModalStateType = reactive({ tag: '',
openByEdit: false, fileName: '',
title: '设置远程备份配置',
from: {
username: '',
password: '',
toIp: '',
toPort: 22,
enable: false,
dir: '',
},
confirmLoading: false,
}); });
/**FTP日志对象信息内表单属性和校验规则 */ /**同步文件到FTP */
const modalStateFrom = Form.useForm( function fnSyncFileToFTP(fileName: string) {
modalState.from, ftpInfo.fileName = fileName;
reactive({ pushBackupFTP(toRaw(ftpInfo)).then(res => {
toIp: [ if (res.code === RESULT_CODE_SUCCESS) {
{ message.success(t('common.operateOk'), 3);
required: true,
pattern: regExpIPv4,
message: 'Please enter the service login IP',
},
],
username: [
{
required: true,
trigger: 'blur',
message: 'Please enter the service login user name',
},
],
dir: [
{
required: true,
trigger: 'blur',
message: 'Please enter the service address target file directory',
},
],
})
);
/**
* 对话框弹出显示为 新增或者修改
* @param configId 参数编号id, 不传为新增
*/
function fnModalVisibleByEdit() {
if (modalState.confirmLoading) return;
const hide = message.loading(t('common.loading'), 0);
modalState.confirmLoading = true;
getFTPInfo().then(res => {
modalState.confirmLoading = false;
hide();
if (res.code === RESULT_CODE_SUCCESS && res.data) {
modalState.from = Object.assign(modalState.from, res.data);
modalState.title = 'Setting Remote Backup';
modalState.openByEdit = true;
} else { } else {
message.error(res.msg, 3); message.warning(res.msg, 3);
modalState.title = 'Setting Remote Backup';
modalState.openByEdit = false;
} }
}); });
} }
/**FTP对象保存 */
function fnModalOk() {
modalStateFrom.validate().then(() => {
modalState.confirmLoading = true;
const from = toRaw(modalState.from);
updateFTPInfo(from)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(`Configuration saved successfully`, 3);
fnModalCancel();
} else {
message.warning(`Configuration save exception`, 3);
}
})
.finally(() => {
modalState.confirmLoading = false;
});
});
}
/**
* 对话框弹出关闭执行函数
* 进行表达规则校验
*/
function fnModalCancel() {
modalState.openByEdit = false;
modalStateFrom.resetFields();
}
/**
* 同步文件到FTP
* @param row
*/
function fnSyncFileToFTP(row: Record<string, any>) {
putFTPInfo(row.filePath, row.fileName)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(t('common.operateOk'), 3);
} else {
message.warning(res.msg, 3);
}
})
.finally(() => {
modalState.confirmLoading = false;
});
}
</script> </script>
<template> <template>
@@ -410,12 +313,14 @@ function fnSyncFileToFTP(row: Record<string, any>) {
<a-form :model="queryParams" name="queryParams" layout="horizontal"> <a-form :model="queryParams" name="queryParams" layout="horizontal">
<a-row :gutter="16" align="middle"> <a-row :gutter="16" align="middle">
<a-col> <a-col>
<span>{{ t('views.logManage.exportFile.fileName') }}:</span>&nbsp; <span>{{ t('views.logManage.exportFile.fileSource') }}:</span
>&nbsp;
<a-select <a-select
v-model:value="logSelect" v-model:value="sourceState.value"
:options="fileList" :options="sourceState.list"
@change="fnNeChange" @change="fnNeChange"
:allow-clear="false" :allow-clear="false"
:placeholder="t('common.selectPlease')"
style="width: 200px" style="width: 200px"
/> />
</a-col> </a-col>
@@ -436,9 +341,11 @@ function fnSyncFileToFTP(row: Record<string, any>) {
<!-- 插槽-卡片右侧 --> <!-- 插槽-卡片右侧 -->
<template #extra> <template #extra>
<a-space :size="8" align="center"> <a-space :size="8" align="center">
<a-tooltip> <a-tooltip placement="topRight">
<template #title>Setting Remote Backup</template> <template #title>
<a-button type="text" @click.prevent="fnModalVisibleByEdit()"> {{ t('views.ne.neConfigBackup.backupModal.title') }}
</template>
<a-button type="text" @click.prevent="fnFTPModalOpen()">
<template #icon><DeliveredProcedureOutlined /></template> <template #icon><DeliveredProcedureOutlined /></template>
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@@ -465,135 +372,45 @@ function fnSyncFileToFTP(row: Record<string, any>) {
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'fileName'"> <template v-if="column.key === 'fileName'">
<a-space :size="8" align="center"> <a-space :size="8" align="center">
<a-button <a-tooltip placement="topRight" v-if="record.fileType === 'file'">
type="link" <template #title>
:loading="downLoading" {{ t('views.ne.neConfigBackup.backupModal.pushFileOper') }}
@click.prevent="fnSyncFileToFTP(record)" </template>
v-if="record.fileType === 'file'" <a-button
> type="link"
<template #icon><CloudServerOutlined /></template> @click.prevent="fnSyncFileToFTP(record.fileName)"
</a-button> >
<a-button <template #icon><CloudServerOutlined /></template>
type="link" </a-button>
:loading="downLoading" </a-tooltip>
@click.prevent="fnDownloadFile(record)" <a-tooltip placement="topRight" v-if="record.fileType === 'file'">
v-if="record.fileType === 'file'" <template #title>{{ t('common.downloadText') }}</template>
> <a-button
<template #icon><DownloadOutlined /></template> type="link"
</a-button> :loading="downLoading"
<a-button @click.prevent="fnDownloadFile(record)"
type="link" >
:loading="delLoading" <template #icon><DownloadOutlined /></template>
@click.prevent="fnRecordDelete(record)" </a-button>
v-if="record.fileType === 'file'" </a-tooltip>
> <a-tooltip placement="topRight" v-if="record.fileType === 'file'">
<template #icon><DeleteOutlined /></template> <template #title>{{ t('common.deleteText') }}</template>
</a-button> <a-button
type="link"
:loading="delLoading"
@click.prevent="fnRecordDelete(record)"
>
<template #icon><DeleteOutlined /></template>
</a-button>
</a-tooltip>
</a-space> </a-space>
</template> </template>
</template> </template>
</a-table> </a-table>
</a-card> </a-card>
<!-- 新增框或修改框 --> <!-- FTP配置窗口 -->
<ProModal <BackupModal v-model:open="openFTPModal"></BackupModal>
:drag="true"
:width="800"
:destroyOnClose="true"
:keyboard="false"
:mask-closable="false"
:open="modalState.openByEdit"
:title="modalState.title"
:confirm-loading="modalState.confirmLoading"
@ok="fnModalOk"
@cancel="fnModalCancel"
>
<a-form
name="modalStateFrom"
layout="horizontal"
:label-col="{ span: 6 }"
:label-wrap="true"
>
<a-form-item label="Enable" name="enable" :label-col="{ span: 3 }">
<a-switch
v-model:checked="modalState.from.enable"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
/>
</a-form-item>
<template v-if="modalState.from.enable">
<a-row>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="Service IP"
name="toIp"
v-bind="modalStateFrom.validateInfos.toIp"
>
<a-input
v-model:value="modalState.from.toIp"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="Service Port"
name="toPort"
v-bind="modalStateFrom.validateInfos.toPort"
>
<a-input-number
v-model:value="modalState.from.toPort"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input-number>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="UserName"
name="username"
v-bind="modalStateFrom.validateInfos.username"
>
<a-input
v-model:value="modalState.from.username"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="Password"
name="password"
v-bind="modalStateFrom.validateInfos.password"
>
<a-input-password
v-model:value="modalState.from.password"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input-password>
</a-form-item>
</a-col>
</a-row>
<a-form-item
label="Save Dir"
name="dir"
v-bind="modalStateFrom.validateInfos.dir"
:label-col="{ span: 3 }"
>
<a-input
v-model:value="modalState.from.dir"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</template>
</a-form>
</ProModal>
</PageContainer> </PageContainer>
</template> </template>

View File

@@ -0,0 +1,230 @@
<script setup lang="ts">
import { reactive, watch, toRaw } from 'vue';
import { ProModal } from 'antdv-pro-modal';
import useI18n from '@/hooks/useI18n';
import { Form, message } from 'ant-design-vue';
import { regExpIPv4 } from '@/utils/regular-utils';
import { getBackupFTP, updateBackupFTP } from '@/api/neData/backup';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
const { t } = useI18n();
const emit = defineEmits(['ok', 'cancel', 'update:open']);
const props = defineProps({
open: {
type: Boolean,
default: false,
required: true,
},
});
/**对话框对象信息状态类型 */
type StateType = {
/**框是否显示 */
open: boolean;
/**标题 */
title: string;
/**查看命令 */
form: Record<string, any>;
/**等待 */
confirmLoading: boolean;
};
/**对话框对象信息状态 */
let state: StateType = reactive({
open: false,
title: '设置远程备份配置',
form: {
username: '',
password: '',
toIp: '',
toPort: 22,
enable: false,
dir: '',
},
confirmLoading: false,
});
/**FTP对象信息内表单属性和校验规则 */
const stateFrom = Form.useForm(
state.form,
reactive({
toIp: [
{
required: true,
pattern: regExpIPv4,
message: t('views.ne.neConfigBackup.backupModal.toIpPleace'),
},
],
username: [
{
required: true,
trigger: 'blur',
message: t('views.ne.neConfigBackup.backupModal.usernamePleace'),
},
],
dir: [
{
required: true,
trigger: 'blur',
message: t('views.ne.neConfigBackup.backupModal.dirPleace'),
},
],
})
);
/**对象保存 */
function fnModalOk() {
stateFrom.validate().then(() => {
state.confirmLoading = true;
const from = toRaw(state.form);
updateBackupFTP(from)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(t('common.operateOk'), 3);
fnModalCancel();
} else {
message.warning(t('common.operateErr'), 3);
}
})
.finally(() => {
state.confirmLoading = false;
});
});
}
/**
* 对话框弹出关闭执行函数
* 进行表达规则校验
*/
function fnModalCancel() {
stateFrom.resetFields();
state.open = false;
emit('cancel');
emit('update:open', false);
}
/**
* 对话框弹出显示为 新增或者修改
*/
function fnModalVisible() {
if (state.confirmLoading) return;
const hide = message.loading(t('common.loading'), 0);
state.confirmLoading = true;
getBackupFTP()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && res.data) {
state.form = Object.assign(state.form, res.data);
}
})
.finally(() => {
state.confirmLoading = false;
hide();
state.title = t('views.ne.neConfigBackup.backupModal.title');
state.open = true;
});
}
/**监听是否显示,初始数据 */
watch(
() => props.open,
val => {
if (val) {
fnModalVisible();
}
}
);
</script>
<template>
<ProModal
:drag="true"
:width="520"
:destroyOnClose="true"
:keyboard="false"
:mask-closable="false"
:open="state.open"
:title="state.title"
:confirm-loading="state.confirmLoading"
@ok="fnModalOk"
@cancel="fnModalCancel"
>
<a-form
name="modalStateFTPFrom"
layout="horizontal"
:label-col="{ span: 6 }"
:label-wrap="true"
>
<a-form-item
:label="t('views.ne.neConfigBackup.backupModal.enable')"
name="enable"
>
<a-switch
v-model:checked="state.form.enable"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
/>
</a-form-item>
<template v-if="state.form.enable">
<a-form-item
:label="t('views.ne.neConfigBackup.backupModal.toIp')"
name="toIp"
v-bind="stateFrom.validateInfos.toIp"
>
<a-input
v-model:value="state.form.toIp"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
<a-form-item
:label="t('views.ne.neConfigBackup.backupModal.toPort')"
name="toPort"
v-bind="stateFrom.validateInfos.toPort"
>
<a-input-number
v-model:value="state.form.toPort"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input-number>
</a-form-item>
<a-form-item
:label="t('views.ne.neConfigBackup.backupModal.username')"
name="username"
v-bind="stateFrom.validateInfos.username"
>
<a-input
v-model:value="state.form.username"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
<a-form-item
:label="t('views.ne.neConfigBackup.backupModal.password')"
name="password"
v-bind="stateFrom.validateInfos.password"
>
<a-input-password
v-model:value="state.form.password"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input-password>
</a-form-item>
<a-form-item
:label="t('views.ne.neConfigBackup.backupModal.dir')"
name="dir"
v-bind="stateFrom.validateInfos.dir"
>
<a-input
v-model:value="state.form.dir"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</template>
</a-form>
</ProModal>
</template>
<style scoped></style>

View File

@@ -5,22 +5,20 @@ import { ProModal } from 'antdv-pro-modal';
import { Form, Modal, TableColumnsType, message } from 'ant-design-vue/es'; import { Form, Modal, TableColumnsType, message } from 'ant-design-vue/es';
import { SizeType } from 'ant-design-vue/es/config-provider'; import { SizeType } from 'ant-design-vue/es/config-provider';
import { MenuInfo } from 'ant-design-vue/es/menu/src/interface'; import { MenuInfo } from 'ant-design-vue/es/menu/src/interface';
import BackupModal from './components/BackupModal.vue';
import useNeInfoStore from '@/store/modules/neinfo'; import useNeInfoStore from '@/store/modules/neinfo';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
import useDictStore from '@/store/modules/dict'; import useDictStore from '@/store/modules/dict';
import { NE_TYPE_LIST } from '@/constants/ne-constants'; import { NE_TYPE_LIST } from '@/constants/ne-constants';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { parseDateToStr } from '@/utils/date-utils'; import { parseDateToStr } from '@/utils/date-utils';
import { regExpIPv4 } from '@/utils/regular-utils';
import { import {
delNeConfigBackup, delNeConfigBackup,
downNeConfigBackup, downNeConfigBackup,
listNeConfigBackup, listNeConfigBackup,
updateNeConfigBackup, updateNeConfigBackup,
getFTPInfo,
putFTPInfo,
updateFTPInfo,
} from '@/api/ne/neConfigBackup'; } from '@/api/ne/neConfigBackup';
import { pushBackupFTP } from '@/api/neData/backup';
import saveAs from 'file-saver'; import saveAs from 'file-saver';
const { t } = useI18n(); const { t } = useI18n();
const { getDict } = useDictStore(); const { getDict } = useDictStore();
@@ -389,119 +387,26 @@ onMounted(() => {
}); });
}); });
/**FTP日志对象信息状态 */ /**打开FTP配置窗口 */
let modalStateFTP: ModalStateType = reactive({ const openFTPModal = ref<boolean>(false);
openByEdit: false, function fnFTPModalOpen() {
title: '设置远程备份配置', openFTPModal.value = !openFTPModal.value;
from: { }
username: '',
password: '',
toIp: '',
toPort: 22,
enable: false,
dir: '',
},
confirmLoading: false,
});
/**FTP日志对象信息内表单属性和校验规则 */ /**同步文件到FTP */
const modalStateFTPFrom = Form.useForm( function fnSyncFileToFTP(row: Record<string, any>) {
modalStateFTP.from, pushBackupFTP({
reactive({ path: row.path.substring(0, row.path.lastIndexOf('/')),
toIp: [ fileName: row.name,
{ tag: 'ne_config',
required: true, }).then(res => {
pattern: regExpIPv4, if (res.code === RESULT_CODE_SUCCESS) {
message: 'Please enter the service login IP', message.success(t('common.operateOk'), 3);
},
],
username: [
{
required: true,
trigger: 'blur',
message: 'Please enter the service login user name',
},
],
dir: [
{
required: true,
trigger: 'blur',
message: 'Please enter the service address target file directory',
},
],
})
);
/**
* 对话框弹出显示为 新增或者修改
* @param configId 参数编号id, 不传为新增
*/
function fnModalFTPVisibleByEdit() {
if (modalStateFTP.confirmLoading) return;
const hide = message.loading(t('common.loading'), 0);
modalStateFTP.confirmLoading = true;
getFTPInfo().then(res => {
modalStateFTP.confirmLoading = false;
hide();
if (res.code === RESULT_CODE_SUCCESS && res.data) {
modalStateFTP.from = Object.assign(modalStateFTP.from, res.data);
modalStateFTP.title = 'Setting Remote Backup';
modalStateFTP.openByEdit = true;
} else { } else {
message.error(res.msg, 3); message.warning(res.msg, 3);
modalStateFTP.title = 'Setting Remote Backup';
modalStateFTP.openByEdit = false;
} }
}); });
} }
/**FTP对象保存 */
function fnModalFTPOk() {
modalStateFTPFrom.validate().then(() => {
modalStateFTP.confirmLoading = true;
const from = toRaw(modalStateFTP.from);
updateFTPInfo(from)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(`Configuration saved successfully`, 3);
fnModalFTPCancel();
} else {
message.warning(`Configuration save exception`, 3);
}
})
.finally(() => {
modalStateFTP.confirmLoading = false;
});
});
}
/**
* 对话框弹出关闭执行函数
* 进行表达规则校验
*/
function fnModalFTPCancel() {
modalStateFTP.openByEdit = false;
modalStateFTPFrom.resetFields();
}
/**
* 同步文件到FTP
* @param row
*/
function fnSyncFileToFTP(row: Record<string, any>) {
modalStateFTP.confirmLoading = true;
putFTPInfo(row.path)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(t('common.operateOk'), 3);
} else {
message.warning(res.msg, 3);
}
})
.finally(() => {
modalStateFTP.confirmLoading = false;
});
}
</script> </script>
<template> <template>
@@ -572,8 +477,10 @@ function fnSyncFileToFTP(row: Record<string, any>) {
<template #extra> <template #extra>
<a-space :size="8" align="center"> <a-space :size="8" align="center">
<a-tooltip placement="topRight"> <a-tooltip placement="topRight">
<template #title>Setting Remote Backup</template> <template #title>
<a-button type="text" @click.prevent="fnModalFTPVisibleByEdit()"> {{ t('views.ne.neConfigBackup.backupModal.title') }}
</template>
<a-button type="text" @click.prevent="fnFTPModalOpen()">
<template #icon><DeliveredProcedureOutlined /></template> <template #icon><DeliveredProcedureOutlined /></template>
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@@ -632,12 +539,10 @@ function fnSyncFileToFTP(row: Record<string, any>) {
<template v-if="column.key === 'id'"> <template v-if="column.key === 'id'">
<a-space :size="8" align="center"> <a-space :size="8" align="center">
<a-tooltip placement="topRight"> <a-tooltip placement="topRight">
<template #title>Send Current File To Remote Backup</template> <template #title>
<a-button {{ t('views.ne.neConfigBackup.backupModal.pushFileOper') }}
type="link" </template>
:loading="modalStateFTP.confirmLoading" <a-button type="link" @click.prevent="fnSyncFileToFTP(record)">
@click.prevent="fnSyncFileToFTP(record)"
>
<template #icon><CloudServerOutlined /></template> <template #icon><CloudServerOutlined /></template>
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@@ -676,7 +581,7 @@ function fnSyncFileToFTP(row: Record<string, any>) {
<!-- 新增框或修改框 --> <!-- 新增框或修改框 -->
<ProModal <ProModal
:drag="true" :drag="true"
:width="512" :width="520"
:destroyOnClose="true" :destroyOnClose="true"
:keyboard="false" :keyboard="false"
:mask-closable="false" :mask-closable="false"
@@ -719,105 +624,8 @@ function fnSyncFileToFTP(row: Record<string, any>) {
</a-form> </a-form>
</ProModal> </ProModal>
<!-- FTP --> <!-- FTP配置窗口 -->
<ProModal <BackupModal v-model:open="openFTPModal"></BackupModal>
:drag="true"
:width="800"
:destroyOnClose="true"
:keyboard="false"
:mask-closable="false"
:open="modalStateFTP.openByEdit"
:title="modalStateFTP.title"
:confirm-loading="modalStateFTP.confirmLoading"
@ok="fnModalFTPOk"
@cancel="fnModalFTPCancel"
>
<a-form
name="modalStateFTPFrom"
layout="horizontal"
:label-col="{ span: 6 }"
:label-wrap="true"
>
<a-form-item label="Enable" name="enable" :label-col="{ span: 3 }">
<a-switch
v-model:checked="modalStateFTP.from.enable"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
/>
</a-form-item>
<template v-if="modalStateFTP.from.enable">
<a-row>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="Service IP"
name="toIp"
v-bind="modalStateFTPFrom.validateInfos.toIp"
>
<a-input
v-model:value="modalStateFTP.from.toIp"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="Service Port"
name="toPort"
v-bind="modalStateFTPFrom.validateInfos.toPort"
>
<a-input-number
v-model:value="modalStateFTP.from.toPort"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input-number>
</a-form-item>
</a-col>
</a-row>
<a-row>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="UserName"
name="username"
v-bind="modalStateFTPFrom.validateInfos.username"
>
<a-input
v-model:value="modalStateFTP.from.username"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="24">
<a-form-item
label="Password"
name="password"
v-bind="modalStateFTPFrom.validateInfos.password"
>
<a-input-password
v-model:value="modalStateFTP.from.password"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input-password>
</a-form-item>
</a-col>
</a-row>
<a-form-item
label="Save Dir"
name="dir"
v-bind="modalStateFTPFrom.validateInfos.dir"
:label-col="{ span: 3 }"
>
<a-input
v-model:value="modalStateFTP.from.dir"
allow-clear
:placeholder="t('common.inputPlease')"
></a-input>
</a-form-item>
</template>
</a-form>
</ProModal>
</PageContainer> </PageContainer>
</template> </template>