Browse Source

fix: 优化导入备份限制 (#361)

pull/369/head
ssongliu 2 years ago committed by GitHub
parent
commit
fa983bdcc9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      backend/app/api/v1/file.go
  2. 353
      cmd/server/docs/docs.go
  3. 282
      cmd/server/docs/swagger.json
  4. 277
      cmd/server/docs/swagger.yaml
  5. 80
      frontend/src/components/upload/index.vue
  6. 4
      frontend/src/lang/modules/en.ts
  7. 4
      frontend/src/lang/modules/zh.ts
  8. 5
      frontend/src/views/host/file-management/upload/index.vue

7
backend/app/api/v1/file.go

@ -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 {

353
cmd/server/docs/docs.go

File diff suppressed because it is too large Load Diff

282
cmd/server/docs/swagger.json

File diff suppressed because it is too large Load Diff

277
cmd/server/docs/swagger.yaml

File diff suppressed because it is too large Load Diff

80
frontend/src/components/upload/index.vue

@ -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) => {

4
frontend/src/lang/modules/en.ts

@ -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',

4
frontend/src/lang/modules/zh.ts

@ -311,7 +311,7 @@ const message = {
selectFile: '选择文件',
dropHelper: '将上传文件拖拽到此处或者',
clickHelper: '点击上传',
supportUpType: '仅支持 10M 以内 sqlsql.gztar.gz 文件',
supportUpType: '仅支持 sqlsql.gztar.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: '代号',

5
frontend/src/views/host/file-management/upload/index.vue

@ -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…
Cancel
Save