feat: 数据库备份增加压缩功能

This commit is contained in:
写意 2025-04-19 22:34:59 +08:00
parent cc6085f06d
commit 472fd5b753
3 changed files with 149 additions and 6 deletions

View File

@ -4,6 +4,7 @@
// //
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System.IO.Compression;
using DbType = SqlSugar.DbType; using DbType = SqlSugar.DbType;
namespace Admin.NET.Core.Service; namespace Admin.NET.Core.Service;
@ -176,7 +177,7 @@ public class SysDbBackupService : IDynamicApiController, ITransient
/// <summary> /// <summary>
/// 下载备份 🔖 /// 下载备份 🔖
/// </summary> /// </summary>
/// <param name="fileName"></param> /// <param name="fileName">备份文件名</param>
[ApiDescriptionSettings(Name = "Download"), HttpGet] [ApiDescriptionSettings(Name = "Download"), HttpGet]
[DisplayName("下载备份")] [DisplayName("下载备份")]
[AllowAnonymous] [AllowAnonymous]
@ -187,4 +188,45 @@ public class SysDbBackupService : IDynamicApiController, ITransient
var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return new FileStreamResult(fs, "application/octet-stream") { FileDownloadName = fileName }; return new FileStreamResult(fs, "application/octet-stream") { FileDownloadName = fileName };
} }
/// <summary>
/// 压缩备份 🔖
/// </summary>
/// <param name="fileName">备份文件名</param>
/// <returns>压缩后的文件路径</returns>
[ApiDescriptionSettings(Name = "Compress"), HttpPost]
[DisplayName("压缩备份文件")]
public async Task Compress([FromQuery] string fileName)
{
var sourcePath = Path.Combine(_backupDir, fileName);
if (!File.Exists(sourcePath)) return;
// 生成临时文件路径
var tempPath = Path.Combine(Path.GetTempPath(), $"{Path.GetFileNameWithoutExtension(fileName)}.zip");
var finalPath = Path.Combine(_backupDir, $"{Path.GetFileNameWithoutExtension(fileName)}.zip");
try
{
// 使用临时路径进行压缩
await Task.Run(() =>
{
using var zip = new ZipArchive(new FileStream(tempPath, FileMode.Create), ZipArchiveMode.Create);
var entry = zip.CreateEntry(fileName);
using var entryStream = entry.Open();
using var fileStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read);
fileStream.CopyTo(entryStream);
});
// 压缩成功后,将临时文件移动到目标路径
File.Move(tempPath, finalPath);
}
catch (Exception ex)
{
// 清理临时文件
if (File.Exists(tempPath))
File.Delete(tempPath);
throw;
}
}
} }

View File

@ -72,6 +72,54 @@ export const SysDbBackupApiAxiosParamCreator = function (configuration?: Configu
options: localVarRequestOptions, options: localVarRequestOptions,
}; };
}, },
/**
*
* @summary 🔖
* @param {string} [fileName]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
apiSysDbBackupCompressPost: async (fileName?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
const localVarPath = `/api/sysDbBackup/compress`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
// authentication Bearer required
// http bearer authentication required
if (configuration && configuration.accessToken) {
const accessToken = typeof configuration.accessToken === 'function'
? await configuration.accessToken()
: await configuration.accessToken;
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
}
if (fileName !== undefined) {
localVarQueryParameter['fileName'] = fileName;
}
const query = new URLSearchParams(localVarUrlObj.search);
for (const key in localVarQueryParameter) {
query.set(key, localVarQueryParameter[key]);
}
for (const key in options.params) {
query.set(key, options.params[key]);
}
localVarUrlObj.search = (new URLSearchParams(query)).toString();
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
options: localVarRequestOptions,
};
},
/** /**
* *
* @summary 🔖 * @summary 🔖
@ -123,7 +171,7 @@ export const SysDbBackupApiAxiosParamCreator = function (configuration?: Configu
/** /**
* *
* @summary 🔖 * @summary 🔖
* @param {string} fileName * @param {string} fileName
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
@ -235,6 +283,20 @@ export const SysDbBackupApiFp = function(configuration?: Configuration) {
return axios.request(axiosRequestArgs); return axios.request(axiosRequestArgs);
}; };
}, },
/**
*
* @summary 🔖
* @param {string} [fileName]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysDbBackupCompressPost(fileName?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
const localVarAxiosArgs = await SysDbBackupApiAxiosParamCreator(configuration).apiSysDbBackupCompressPost(fileName, options);
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
return axios.request(axiosRequestArgs);
};
},
/** /**
* *
* @summary 🔖 * @summary 🔖
@ -252,7 +314,7 @@ export const SysDbBackupApiFp = function(configuration?: Configuration) {
/** /**
* *
* @summary 🔖 * @summary 🔖
* @param {string} fileName * @param {string} fileName
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
@ -295,6 +357,16 @@ export const SysDbBackupApiFactory = function (configuration?: Configuration, ba
async apiSysDbBackupAddPost(configId?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> { async apiSysDbBackupAddPost(configId?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysDbBackupApiFp(configuration).apiSysDbBackupAddPost(configId, options).then((request) => request(axios, basePath)); return SysDbBackupApiFp(configuration).apiSysDbBackupAddPost(configId, options).then((request) => request(axios, basePath));
}, },
/**
*
* @summary 🔖
* @param {string} [fileName]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async apiSysDbBackupCompressPost(fileName?: string, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
return SysDbBackupApiFp(configuration).apiSysDbBackupCompressPost(fileName, options).then((request) => request(axios, basePath));
},
/** /**
* *
* @summary 🔖 * @summary 🔖
@ -308,7 +380,7 @@ export const SysDbBackupApiFactory = function (configuration?: Configuration, ba
/** /**
* *
* @summary 🔖 * @summary 🔖
* @param {string} fileName * @param {string} fileName
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
*/ */
@ -345,6 +417,17 @@ export class SysDbBackupApi extends BaseAPI {
public async apiSysDbBackupAddPost(configId?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> { public async apiSysDbBackupAddPost(configId?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysDbBackupApiFp(this.configuration).apiSysDbBackupAddPost(configId, options).then((request) => request(this.axios, this.basePath)); return SysDbBackupApiFp(this.configuration).apiSysDbBackupAddPost(configId, options).then((request) => request(this.axios, this.basePath));
} }
/**
*
* @summary 🔖
* @param {string} [fileName]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof SysDbBackupApi
*/
public async apiSysDbBackupCompressPost(fileName?: string, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
return SysDbBackupApiFp(this.configuration).apiSysDbBackupCompressPost(fileName, options).then((request) => request(this.axios, this.basePath));
}
/** /**
* *
* @summary 🔖 * @summary 🔖
@ -359,7 +442,7 @@ export class SysDbBackupApi extends BaseAPI {
/** /**
* *
* @summary 🔖 * @summary 🔖
* @param {string} fileName * @param {string} fileName
* @param {*} [options] Override http request option. * @param {*} [options] Override http request option.
* @throws {RequiredError} * @throws {RequiredError}
* @memberof SysDbBackupApi * @memberof SysDbBackupApi

View File

@ -28,6 +28,7 @@
</template> </template>
<template #row_buttons="{ row }"> <template #row_buttons="{ row }">
<el-button icon="ele-Delete" text type="danger" v-auth="'dbBackup/delete'" @click="handleDelete(row)"> 删除 </el-button> <el-button icon="ele-Delete" text type="danger" v-auth="'dbBackup/delete'" @click="handleDelete(row)"> 删除 </el-button>
<el-button icon="ele-Files" text type="primary" @click="handleCompress(row)" v-if="!row.fileName.endsWith('.zip')"> 压缩 </el-button>
<el-button icon="ele-Download" text type="primary" @click="handleDownload(row)"> 下载 </el-button> <el-button icon="ele-Download" text type="primary" @click="handleDownload(row)"> 下载 </el-button>
</template> </template>
</vxe-grid> </vxe-grid>
@ -63,7 +64,7 @@ const options = useVxeTable(
{ field: 'fileName', title: '文件名称', minWidth: 200, showOverflow: 'tooltip' }, { field: 'fileName', title: '文件名称', minWidth: 200, showOverflow: 'tooltip' },
{ field: 'size', title: '文件大小', width: 150, showOverflow: 'tooltip', slots: { default: 'row_size' } }, { field: 'size', title: '文件大小', width: 150, showOverflow: 'tooltip', slots: { default: 'row_size' } },
{ field: 'createTime', title: '备份时间', width: 200, showOverflow: 'tooltip', slots: { default: 'row_createTime' } }, { field: 'createTime', title: '备份时间', width: 200, showOverflow: 'tooltip', slots: { default: 'row_createTime' } },
{ field: 'buttons', title: '操作', fixed: 'right', width: 150, showOverflow: true, slots: { default: 'row_buttons' } }, { field: 'buttons', title: '操作', fixed: 'right', width: 200, showOverflow: true, slots: { default: 'row_buttons' } },
], ],
}, },
{ {
@ -145,6 +146,23 @@ const handleDownload = (row: any) => {
tempLink.click(); tempLink.click();
document.body.removeChild(tempLink); document.body.removeChild(tempLink);
}; };
//
const handleCompress = async (row: any) => {
try {
await ElMessageBox.confirm(`确定要压缩备份:【${row.fileName}】吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'info',
});
state.loading = true;
await getAPI(SysDbBackupApi).apiSysDbBackupCompressPost(row.fileName, { timeout: 0 /**永不超时 */ });
await xGrid.value?.commitProxy('reload');
} finally {
state.loading = false;
}
};
</script> </script>
<style scoped></style> <style scoped></style>