mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
fix: 优化导入备份限制 (#361)
This commit is contained in:
parent
67bb30c10c
commit
fa983bdcc9
@ -519,6 +519,12 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
||||
}
|
||||
|
||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
|
||||
if _, err := os.Stat(path.Dir(dstDir)); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(path.Dir(dstDir), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
|
||||
if err != nil {
|
||||
return err
|
||||
@ -547,7 +553,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/chunkupload [post]
|
||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
|
||||
func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
fileForm, err := c.FormFile("chunk")
|
||||
if err != nil {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -12,6 +12,12 @@
|
||||
<em>{{ $t('database.clickHelper') }}</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<el-progress
|
||||
v-if="isUpload"
|
||||
text-inside
|
||||
:stroke-width="12"
|
||||
:percentage="uploadPrecent"
|
||||
></el-progress>
|
||||
<div v-if="type === 'mysql'" class="el-upload__tip">
|
||||
<span class="input-help">{{ $t('database.supportUpType') }}</span>
|
||||
<span class="input-help">
|
||||
@ -26,7 +32,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-button v-if="uploaderFiles.length === 1" icon="Upload" @click="onSubmit">
|
||||
<el-button :disabled="isUpload" v-if="uploaderFiles.length === 1" icon="Upload" @click="onSubmit">
|
||||
{{ $t('commons.button.upload') }}
|
||||
</el-button>
|
||||
|
||||
@ -82,11 +88,13 @@ import i18n from '@/lang';
|
||||
import { UploadFile, UploadFiles, UploadInstance } from 'element-plus';
|
||||
import { File } from '@/api/interface/file';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { BatchDeleteFile, CheckFile, GetUploadList, UploadFileData } from '@/api/modules/files';
|
||||
import { BatchDeleteFile, CheckFile, ChunkUploadFileData, GetUploadList } from '@/api/modules/files';
|
||||
import { loadBaseDir } from '@/api/modules/setting';
|
||||
import { MsgError, MsgSuccess } from '@/utils/message';
|
||||
|
||||
const loading = ref();
|
||||
const isUpload = ref();
|
||||
const uploadPrecent = ref<number>(0);
|
||||
const selects = ref<any>([]);
|
||||
const baseDir = ref();
|
||||
|
||||
@ -166,20 +174,12 @@ const beforeAvatarUpload = (rawFile) => {
|
||||
MsgError(i18n.global.t('commons.msg.unSupportType'));
|
||||
return false;
|
||||
}
|
||||
if (rawFile.size / 1024 / 1024 > 50) {
|
||||
MsgError(i18n.global.t('commons.msg.unSupportSize', [50]));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!rawFile.name.endsWith('.sql') && !rawFile.name.endsWith('.tar.gz') && !rawFile.name.endsWith('.sql.gz')) {
|
||||
MsgError(i18n.global.t('commons.msg.unSupportType'));
|
||||
return false;
|
||||
}
|
||||
if (rawFile.size / 1024 / 1024 > 10) {
|
||||
MsgError(i18n.global.t('commons.msg.unSupportSize', [10]));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -194,42 +194,72 @@ const handleClose = () => {
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
const formData = new FormData();
|
||||
if (uploaderFiles.value.length !== 1) {
|
||||
return;
|
||||
}
|
||||
if (!uploaderFiles.value[0]!.raw.name) {
|
||||
const file = uploaderFiles.value[0];
|
||||
if (!file.raw.name) {
|
||||
MsgError(i18n.global.t('commons.msg.fileNameErr'));
|
||||
return;
|
||||
}
|
||||
let reg = /^[a-zA-Z0-9\u4e00-\u9fa5]{1}[a-z:A-Z0-9_.\u4e00-\u9fa5-]{0,256}$/;
|
||||
if (!reg.test(uploaderFiles.value[0]!.raw.name)) {
|
||||
if (!reg.test(file.raw.name)) {
|
||||
MsgError(i18n.global.t('commons.msg.fileNameErr'));
|
||||
return;
|
||||
}
|
||||
const res = await CheckFile(baseDir.value + uploaderFiles.value[0]!.raw.name);
|
||||
const res = await CheckFile(baseDir.value + file.raw.name);
|
||||
if (!res.data) {
|
||||
MsgError(i18n.global.t('commons.msg.fileExist'));
|
||||
return;
|
||||
}
|
||||
formData.append('file', uploaderFiles.value[0]!.raw);
|
||||
let isOk = beforeAvatarUpload(uploaderFiles.value[0]!.raw);
|
||||
let isOk = beforeAvatarUpload(file.raw);
|
||||
if (!isOk) {
|
||||
return;
|
||||
}
|
||||
formData.append('path', baseDir.value);
|
||||
loading.value = true;
|
||||
UploadFileData(formData, {})
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
submitUpload(file);
|
||||
};
|
||||
|
||||
const submitUpload = async (file: any) => {
|
||||
isUpload.value = true;
|
||||
const CHUNK_SIZE = 1024 * 1024;
|
||||
const fileSize = file.size;
|
||||
const chunkCount = Math.ceil(fileSize / CHUNK_SIZE);
|
||||
let uploadedChunkCount = 0;
|
||||
|
||||
for (let i = 0; i < chunkCount; i++) {
|
||||
const start = i * CHUNK_SIZE;
|
||||
const end = Math.min(start + CHUNK_SIZE, fileSize);
|
||||
const chunk = file.raw.slice(start, end);
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append('filename', file.name);
|
||||
formData.append('path', baseDir.value);
|
||||
formData.append('chunk', chunk);
|
||||
formData.append('chunkIndex', i.toString());
|
||||
formData.append('chunkCount', chunkCount.toString());
|
||||
|
||||
try {
|
||||
await ChunkUploadFileData(formData, {
|
||||
onUploadProgress: (progressEvent) => {
|
||||
const progress = Math.round(
|
||||
((uploadedChunkCount + progressEvent.loaded / progressEvent.total) * 100) / chunkCount,
|
||||
);
|
||||
uploadPrecent.value = progress;
|
||||
},
|
||||
});
|
||||
uploadedChunkCount++;
|
||||
} catch (error) {
|
||||
isUpload.value = false;
|
||||
}
|
||||
if (uploadedChunkCount == chunkCount) {
|
||||
isUpload.value = false;
|
||||
uploadRef.value?.clearFiles();
|
||||
uploaderFiles.value = [];
|
||||
MsgSuccess(i18n.global.t('file.uploadSuccess'));
|
||||
search();
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: File.File | null) => {
|
||||
|
@ -305,7 +305,7 @@ const message = {
|
||||
'This port is the exposed port of the container. You need to save the modification separately and restart the container!',
|
||||
|
||||
selectFile: 'Select file',
|
||||
supportUpType: 'Only sql, sql.gz, and tar.gz files within 10 MB are supported',
|
||||
supportUpType: 'Only sql, sql.gz, and tar.gz files are supported',
|
||||
zipFormat: 'tar.gz compressed package structure: test.tar.gz compressed package must contain test.sql',
|
||||
|
||||
currentStatus: 'Current state',
|
||||
@ -965,7 +965,7 @@ const message = {
|
||||
type: 'Type',
|
||||
static: 'Static',
|
||||
deployment: 'Deployment',
|
||||
supportUpType: 'Only .tar.gz files within 50 MB are supported',
|
||||
supportUpType: 'Only .tar.gz files are supported',
|
||||
zipFormat: '.tar.gz compressed package structure: test.tar.gz compressed package must contain {0} file',
|
||||
proxy: 'Reverse Proxy',
|
||||
alias: 'Path Name',
|
||||
|
@ -311,7 +311,7 @@ const message = {
|
||||
selectFile: '选择文件',
|
||||
dropHelper: '将上传文件拖拽到此处,或者',
|
||||
clickHelper: '点击上传',
|
||||
supportUpType: '仅支持 10M 以内 sql、sql.gz、tar.gz 文件',
|
||||
supportUpType: '仅支持 sql、sql.gz、tar.gz 文件',
|
||||
zipFormat: 'tar.gz 压缩包结构:test.tar.gz 压缩包内,必需包含 test.sql',
|
||||
|
||||
currentStatus: '当前状态',
|
||||
@ -971,7 +971,7 @@ const message = {
|
||||
type: '类型',
|
||||
static: '静态网站',
|
||||
deployment: '一键部署',
|
||||
supportUpType: '仅支持 50M 以内 .tar.gz 文件',
|
||||
supportUpType: '仅支持 .tar.gz 文件',
|
||||
zipFormat: '.tar.gz 压缩包结构:test.tar.gz 压缩包内,必需包含 {0} 文件',
|
||||
proxy: '反向代理',
|
||||
alias: '代号',
|
||||
|
@ -15,7 +15,6 @@
|
||||
:auto-upload="false"
|
||||
ref="uploadRef"
|
||||
:on-change="fileOnChange"
|
||||
v-loading="loading"
|
||||
:limit="1"
|
||||
:on-exceed="handleExceed"
|
||||
>
|
||||
@ -24,8 +23,10 @@
|
||||
{{ $t('database.dropHelper') }}
|
||||
<em>{{ $t('database.clickHelper') }}</em>
|
||||
</div>
|
||||
<template #tip>
|
||||
<el-progress v-if="loading" text-inside :stroke-width="12" :percentage="uploadPrecent"></el-progress>
|
||||
</template>
|
||||
</el-upload>
|
||||
<el-progress v-if="loading" :text-inside="true" :stroke-width="26" :percentage="uploadPrecent"></el-progress>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
|
||||
|
Loading…
x
Reference in New Issue
Block a user