1
0
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:
ssongliu 2023-03-22 15:20:30 +08:00 committed by GitHub
parent 67bb30c10c
commit fa983bdcc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 513 additions and 499 deletions

View File

@ -519,6 +519,12 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
} }
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error { 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)) targetFile, err := os.Create(filepath.Join(dstDir, fileName))
if err != nil { if err != nil {
return err return err
@ -547,7 +553,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
// @Success 200 // @Success 200
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /files/chunkupload [post] // @Router /files/chunkupload [post]
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
func (b *BaseApi) UploadChunkFiles(c *gin.Context) { func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
fileForm, err := c.FormFile("chunk") fileForm, err := c.FormFile("chunk")
if err != nil { 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

View File

@ -12,6 +12,12 @@
<em>{{ $t('database.clickHelper') }}</em> <em>{{ $t('database.clickHelper') }}</em>
</div> </div>
<template #tip> <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"> <div v-if="type === 'mysql'" class="el-upload__tip">
<span class="input-help">{{ $t('database.supportUpType') }}</span> <span class="input-help">{{ $t('database.supportUpType') }}</span>
<span class="input-help"> <span class="input-help">
@ -26,7 +32,7 @@
</div> </div>
</template> </template>
</el-upload> </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') }} {{ $t('commons.button.upload') }}
</el-button> </el-button>
@ -82,11 +88,13 @@ import i18n from '@/lang';
import { UploadFile, UploadFiles, UploadInstance } from 'element-plus'; import { UploadFile, UploadFiles, UploadInstance } from 'element-plus';
import { File } from '@/api/interface/file'; import { File } from '@/api/interface/file';
import DrawerHeader from '@/components/drawer-header/index.vue'; 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 { loadBaseDir } from '@/api/modules/setting';
import { MsgError, MsgSuccess } from '@/utils/message'; import { MsgError, MsgSuccess } from '@/utils/message';
const loading = ref(); const loading = ref();
const isUpload = ref();
const uploadPrecent = ref<number>(0);
const selects = ref<any>([]); const selects = ref<any>([]);
const baseDir = ref(); const baseDir = ref();
@ -166,20 +174,12 @@ const beforeAvatarUpload = (rawFile) => {
MsgError(i18n.global.t('commons.msg.unSupportType')); MsgError(i18n.global.t('commons.msg.unSupportType'));
return false; return false;
} }
if (rawFile.size / 1024 / 1024 > 50) {
MsgError(i18n.global.t('commons.msg.unSupportSize', [50]));
return false;
}
return true; return true;
} }
if (!rawFile.name.endsWith('.sql') && !rawFile.name.endsWith('.tar.gz') && !rawFile.name.endsWith('.sql.gz')) { if (!rawFile.name.endsWith('.sql') && !rawFile.name.endsWith('.tar.gz') && !rawFile.name.endsWith('.sql.gz')) {
MsgError(i18n.global.t('commons.msg.unSupportType')); MsgError(i18n.global.t('commons.msg.unSupportType'));
return false; return false;
} }
if (rawFile.size / 1024 / 1024 > 10) {
MsgError(i18n.global.t('commons.msg.unSupportSize', [10]));
return false;
}
return true; return true;
}; };
@ -194,42 +194,72 @@ const handleClose = () => {
}; };
const onSubmit = async () => { const onSubmit = async () => {
const formData = new FormData();
if (uploaderFiles.value.length !== 1) { if (uploaderFiles.value.length !== 1) {
return; return;
} }
if (!uploaderFiles.value[0]!.raw.name) { const file = uploaderFiles.value[0];
if (!file.raw.name) {
MsgError(i18n.global.t('commons.msg.fileNameErr')); MsgError(i18n.global.t('commons.msg.fileNameErr'));
return; return;
} }
let reg = /^[a-zA-Z0-9\u4e00-\u9fa5]{1}[a-z:A-Z0-9_.\u4e00-\u9fa5-]{0,256}$/; 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')); MsgError(i18n.global.t('commons.msg.fileNameErr'));
return; return;
} }
const res = await CheckFile(baseDir.value + uploaderFiles.value[0]!.raw.name); const res = await CheckFile(baseDir.value + file.raw.name);
if (!res.data) { if (!res.data) {
MsgError(i18n.global.t('commons.msg.fileExist')); MsgError(i18n.global.t('commons.msg.fileExist'));
return; return;
} }
formData.append('file', uploaderFiles.value[0]!.raw); let isOk = beforeAvatarUpload(file.raw);
let isOk = beforeAvatarUpload(uploaderFiles.value[0]!.raw);
if (!isOk) { if (!isOk) {
return; return;
} }
formData.append('path', baseDir.value); submitUpload(file);
loading.value = true; };
UploadFileData(formData, {})
.then(() => { const submitUpload = async (file: any) => {
loading.value = false; 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(); uploadRef.value?.clearFiles();
uploaderFiles.value = []; uploaderFiles.value = [];
MsgSuccess(i18n.global.t('file.uploadSuccess')); MsgSuccess(i18n.global.t('file.uploadSuccess'));
search(); search();
}) }
.catch(() => { }
loading.value = false;
});
}; };
const onBatchDelete = async (row: File.File | null) => { const onBatchDelete = async (row: File.File | null) => {

View File

@ -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!', 'This port is the exposed port of the container. You need to save the modification separately and restart the container!',
selectFile: 'Select file', 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', zipFormat: 'tar.gz compressed package structure: test.tar.gz compressed package must contain test.sql',
currentStatus: 'Current state', currentStatus: 'Current state',
@ -965,7 +965,7 @@ const message = {
type: 'Type', type: 'Type',
static: 'Static', static: 'Static',
deployment: 'Deployment', 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', zipFormat: '.tar.gz compressed package structure: test.tar.gz compressed package must contain {0} file',
proxy: 'Reverse Proxy', proxy: 'Reverse Proxy',
alias: 'Path Name', alias: 'Path Name',

View File

@ -311,7 +311,7 @@ const message = {
selectFile: '选择文件', selectFile: '选择文件',
dropHelper: '将上传文件拖拽到此处或者', dropHelper: '将上传文件拖拽到此处或者',
clickHelper: '点击上传', clickHelper: '点击上传',
supportUpType: '仅支持 10M 以内 sqlsql.gztar.gz 文件', supportUpType: '仅支持 sqlsql.gztar.gz 文件',
zipFormat: 'tar.gz 压缩包结构test.tar.gz 压缩包内必需包含 test.sql', zipFormat: 'tar.gz 压缩包结构test.tar.gz 压缩包内必需包含 test.sql',
currentStatus: '当前状态', currentStatus: '当前状态',
@ -971,7 +971,7 @@ const message = {
type: '类型', type: '类型',
static: '静态网站', static: '静态网站',
deployment: '一键部署', deployment: '一键部署',
supportUpType: '仅支持 50M 以内 .tar.gz 文件', supportUpType: '仅支持 .tar.gz 文件',
zipFormat: '.tar.gz 压缩包结构test.tar.gz 压缩包内必需包含 {0} 文件', zipFormat: '.tar.gz 压缩包结构test.tar.gz 压缩包内必需包含 {0} 文件',
proxy: '反向代理', proxy: '反向代理',
alias: '代号', alias: '代号',

View File

@ -15,7 +15,6 @@
:auto-upload="false" :auto-upload="false"
ref="uploadRef" ref="uploadRef"
:on-change="fileOnChange" :on-change="fileOnChange"
v-loading="loading"
:limit="1" :limit="1"
:on-exceed="handleExceed" :on-exceed="handleExceed"
> >
@ -24,8 +23,10 @@
{{ $t('database.dropHelper') }} {{ $t('database.dropHelper') }}
<em>{{ $t('database.clickHelper') }}</em> <em>{{ $t('database.clickHelper') }}</em>
</div> </div>
<template #tip>
<el-progress v-if="loading" text-inside :stroke-width="12" :percentage="uploadPrecent"></el-progress>
</template>
</el-upload> </el-upload>
<el-progress v-if="loading" :text-inside="true" :stroke-width="26" :percentage="uploadPrecent"></el-progress>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button> <el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>