mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-31 14:08:06 +08:00
feat: 增加文件解压功能
This commit is contained in:
parent
20129c7d0b
commit
245f5fb68a
@ -90,3 +90,17 @@ func (b *BaseApi) CompressFile(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) DeCompressFile(c *gin.Context) {
|
||||||
|
var req dto.FileDeCompress
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := fileService.DeCompress(req)
|
||||||
|
if err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
@ -38,3 +38,9 @@ type FileCompress struct {
|
|||||||
Name string
|
Name string
|
||||||
Replace bool
|
Replace bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileDeCompress struct {
|
||||||
|
Dst string
|
||||||
|
Type string
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
@ -85,6 +85,11 @@ func (f FileService) Compress(c dto.FileCompress) error {
|
|||||||
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type))
|
return fo.Compress(c.Files, c.Dst, c.Name, files.CompressType(c.Type))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f FileService) DeCompress(c dto.FileDeCompress) error {
|
||||||
|
fo := files.NewFileOp()
|
||||||
|
return fo.Decompress(c.Path, c.Dst, files.CompressType(c.Type))
|
||||||
|
}
|
||||||
|
|
||||||
func getUuid() string {
|
func getUuid() string {
|
||||||
b := make([]byte, 16)
|
b := make([]byte, 16)
|
||||||
io.ReadFull(rand.Reader, b)
|
io.ReadFull(rand.Reader, b)
|
||||||
|
@ -21,6 +21,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
|||||||
fileRouter.POST("/del", baseApi.DeleteFile)
|
fileRouter.POST("/del", baseApi.DeleteFile)
|
||||||
fileRouter.POST("/mode", baseApi.ChangeFileMode)
|
fileRouter.POST("/mode", baseApi.ChangeFileMode)
|
||||||
fileRouter.POST("/compress", baseApi.CompressFile)
|
fileRouter.POST("/compress", baseApi.CompressFile)
|
||||||
|
fileRouter.POST("/decompress", baseApi.DeCompressFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -49,4 +49,10 @@ export namespace File {
|
|||||||
name: string;
|
name: string;
|
||||||
replace: boolean;
|
replace: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FileDeCompress {
|
||||||
|
path: string;
|
||||||
|
dst: string;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,3 +24,6 @@ export const ChangeFileMode = (form: File.FileCreate) => {
|
|||||||
export const CompressFile = (form: File.FileCompress) => {
|
export const CompressFile = (form: File.FileCompress) => {
|
||||||
return http.post<File.FileCompress>('files/compress', form);
|
return http.post<File.FileCompress>('files/compress', form);
|
||||||
};
|
};
|
||||||
|
export const DeCompressFile = (form: File.FileDeCompress) => {
|
||||||
|
return http.post<File.FileCompress>('files/decompress', form);
|
||||||
|
};
|
||||||
|
17
frontend/src/global/mimetype.ts
Normal file
17
frontend/src/global/mimetype.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { CompressType } from '@/enums/files';
|
||||||
|
|
||||||
|
export const Mimetypes = new Map([
|
||||||
|
['application/zip', CompressType.Zip],
|
||||||
|
['application/x-zip', CompressType.Zip],
|
||||||
|
['application/x-zip-compressed', CompressType.Zip],
|
||||||
|
['application/x-tar', CompressType.Tar],
|
||||||
|
['application/x-bzip2', CompressType.Bz2],
|
||||||
|
['application/gzip', CompressType.TarGz],
|
||||||
|
['application/x-gzip', CompressType.TarGz],
|
||||||
|
['application/x-gunzip', CompressType.TarGz],
|
||||||
|
['application/gzipped', CompressType.TarGz],
|
||||||
|
['application/gzip-compressed', CompressType.TarGz],
|
||||||
|
['application/x-gzip-compressed', CompressType.TarGz],
|
||||||
|
['gzip/document', CompressType.TarGz],
|
||||||
|
['application/x-xz', CompressType.Xz],
|
||||||
|
]);
|
@ -33,7 +33,6 @@ export default {
|
|||||||
sureLogOut: '您是否确认退出登录?',
|
sureLogOut: '您是否确认退出登录?',
|
||||||
createSuccess: '新建成功',
|
createSuccess: '新建成功',
|
||||||
updateSuccess: '更新成功',
|
updateSuccess: '更新成功',
|
||||||
compressSuccess: '压缩成功',
|
|
||||||
},
|
},
|
||||||
login: {
|
login: {
|
||||||
captchaHelper: '请输入验证码',
|
captchaHelper: '请输入验证码',
|
||||||
@ -190,5 +189,8 @@ export default {
|
|||||||
compressType: '压缩格式',
|
compressType: '压缩格式',
|
||||||
compressDst: '压缩路径',
|
compressDst: '压缩路径',
|
||||||
replace: '覆盖已存在的文件',
|
replace: '覆盖已存在的文件',
|
||||||
|
compressSuccess: '压缩成功',
|
||||||
|
deCompressSuccess: '解压成功',
|
||||||
|
deCompressDst: '解压路径',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -110,10 +110,10 @@ const submit = async (formEl: FormInstance | undefined) => {
|
|||||||
let addItem = {};
|
let addItem = {};
|
||||||
Object.assign(addItem, form.value);
|
Object.assign(addItem, form.value);
|
||||||
addItem['name'] = form.value.name + extension.value;
|
addItem['name'] = form.value.name + extension.value;
|
||||||
|
loading.value = true;
|
||||||
CompressFile(addItem as File.FileCompress)
|
CompressFile(addItem as File.FileCompress)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
ElMessage.success(i18n.global.t('commons.msg.compressSuccess'));
|
ElMessage.success(i18n.global.t('file.compressSuccess'));
|
||||||
handleClose();
|
handleClose();
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
107
frontend/src/views/file-management/decompress/index.vue
Normal file
107
frontend/src/views/file-management/decompress/index.vue
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="open"
|
||||||
|
:title="$t('file.deCompress')"
|
||||||
|
:before-close="handleClose"
|
||||||
|
width="30%"
|
||||||
|
@open="onOpen"
|
||||||
|
v-loading="loading"
|
||||||
|
>
|
||||||
|
<el-form ref="fileForm" label-position="left" :model="form" label-width="100px" :rules="rules">
|
||||||
|
<el-form-item :label="$t('file.name')">
|
||||||
|
<el-input v-model="name" disabled></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('file.deCompressDst')" prop="dst">
|
||||||
|
<el-input v-model="form.dst"></el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="submit(fileForm)">{{ $t('commons.button.confirm') }}</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { reactive, ref, toRefs } from 'vue';
|
||||||
|
import { File } from '@/api/interface/file';
|
||||||
|
import { ElMessage, FormInstance, FormRules } from 'element-plus';
|
||||||
|
import { Rules } from '@/global/form-rues';
|
||||||
|
import { DeCompressFile } from '@/api/modules/files';
|
||||||
|
import { Mimetypes } from '@/global/mimetype';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
open: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
dst: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
mimeType: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
dst: [Rules.required],
|
||||||
|
});
|
||||||
|
|
||||||
|
const { open, dst, path, name, mimeType } = toRefs(props);
|
||||||
|
const fileForm = ref<FormInstance>();
|
||||||
|
let loading = ref(false);
|
||||||
|
let form = ref<File.FileDeCompress>({ type: 'zip', dst: '', path: '' });
|
||||||
|
|
||||||
|
const em = defineEmits(['close']);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
em('close', open);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFileType = (mime: string): string => {
|
||||||
|
if (Mimetypes.get(mime) != undefined) {
|
||||||
|
return String(Mimetypes.get(mime));
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const onOpen = () => {
|
||||||
|
form.value = {
|
||||||
|
dst: dst.value,
|
||||||
|
type: getFileType(mimeType.value),
|
||||||
|
path: path.value,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
DeCompressFile(form.value)
|
||||||
|
.then(() => {
|
||||||
|
ElMessage.success(i18n.global.t('file.deCompressSuccess'));
|
||||||
|
handleClose();
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
@ -96,8 +96,8 @@
|
|||||||
/>
|
/>
|
||||||
</ComplexTable>
|
</ComplexTable>
|
||||||
</el-col>
|
</el-col>
|
||||||
<CreateFile :open="openCreate" :file="fileCreate" @close="closeCreate"></CreateFile>
|
<CreateFile :open="filePage.open" :file="filePage.createForm" @close="closeCreate"></CreateFile>
|
||||||
<ChangeRole :open="openModePage" :file="modeForm" @close="closeMode"></ChangeRole>
|
<ChangeRole :open="modePage.open" :file="modePage.modeForm" @close="closeMode"></ChangeRole>
|
||||||
<Compress
|
<Compress
|
||||||
:open="compressPage.open"
|
:open="compressPage.open"
|
||||||
:files="compressPage.files"
|
:files="compressPage.files"
|
||||||
@ -105,6 +105,14 @@
|
|||||||
:name="compressPage.name"
|
:name="compressPage.name"
|
||||||
@close="closeCompress"
|
@close="closeCompress"
|
||||||
></Compress>
|
></Compress>
|
||||||
|
<Decompress
|
||||||
|
:open="deCompressPage.open"
|
||||||
|
:dst="deCompressPage.dst"
|
||||||
|
:path="deCompressPage.path"
|
||||||
|
:name="deCompressPage.name"
|
||||||
|
:mimeType="deCompressPage.mimeType"
|
||||||
|
@close="closeDeCompress"
|
||||||
|
></Decompress>
|
||||||
</el-row>
|
</el-row>
|
||||||
</LayoutContent>
|
</LayoutContent>
|
||||||
</template>
|
</template>
|
||||||
@ -119,9 +127,10 @@ import { dateFromat } from '@/utils/util';
|
|||||||
import { File } from '@/api/interface/file';
|
import { File } from '@/api/interface/file';
|
||||||
import BreadCrumbs from '@/components/bread-crumbs/index.vue';
|
import BreadCrumbs from '@/components/bread-crumbs/index.vue';
|
||||||
import BreadCrumbItem from '@/components/bread-crumbs/bread-crumbs-item.vue';
|
import BreadCrumbItem from '@/components/bread-crumbs/bread-crumbs-item.vue';
|
||||||
import CreateFile from './create.vue';
|
import CreateFile from './create/index.vue';
|
||||||
import ChangeRole from './change-role.vue';
|
import ChangeRole from './change-role/index.vue';
|
||||||
import Compress from './compress.vue';
|
import Compress from './compress/index.vue';
|
||||||
|
import Decompress from './decompress/index.vue';
|
||||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||||
|
|
||||||
let data = ref();
|
let data = ref();
|
||||||
@ -132,12 +141,11 @@ let treeLoading = ref(false);
|
|||||||
let paths = ref<string[]>([]);
|
let paths = ref<string[]>([]);
|
||||||
let fileTree = ref<File.FileTree[]>([]);
|
let fileTree = ref<File.FileTree[]>([]);
|
||||||
let expandKeys = ref<string[]>([]);
|
let expandKeys = ref<string[]>([]);
|
||||||
let openCreate = ref(false);
|
|
||||||
let fileCreate = ref<File.FileCreate>({ path: '/', isDir: false, mode: 0o755 });
|
|
||||||
let openModePage = ref(false);
|
|
||||||
let modeForm = ref<File.FileCreate>({ path: '/', isDir: false, mode: 0o755 });
|
|
||||||
|
|
||||||
|
let filePage = reactive({ open: false, createForm: { path: '/', isDir: false, mode: 0o755 } });
|
||||||
|
let modePage = reactive({ open: false, modeForm: { path: '/', isDir: false, mode: 0o755 } });
|
||||||
let compressPage = reactive({ open: false, files: [''], name: '', dst: '' });
|
let compressPage = reactive({ open: false, files: [''], name: '', dst: '' });
|
||||||
|
let deCompressPage = reactive({ open: false, path: '', name: '', dst: '', mimeType: '' });
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
children: 'children',
|
children: 'children',
|
||||||
@ -234,12 +242,12 @@ const loadNode = (node: any, resolve: (data: File.FileTree[]) => void) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleCreate = (commnad: string) => {
|
const handleCreate = (commnad: string) => {
|
||||||
fileCreate.value.path = req.path;
|
filePage.createForm.path = req.path;
|
||||||
fileCreate.value.isDir = false;
|
filePage.createForm.isDir = false;
|
||||||
if (commnad === 'dir') {
|
if (commnad === 'dir') {
|
||||||
fileCreate.value.isDir = true;
|
filePage.createForm.isDir = true;
|
||||||
}
|
}
|
||||||
openCreate.value = true;
|
filePage.open = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const delFile = async (row: File.File | null) => {
|
const delFile = async (row: File.File | null) => {
|
||||||
@ -248,17 +256,17 @@ const delFile = async (row: File.File | null) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const closeCreate = () => {
|
const closeCreate = () => {
|
||||||
openCreate.value = false;
|
filePage.open = false;
|
||||||
search(req);
|
search(req);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openMode = (item: File.File) => {
|
const openMode = (item: File.File) => {
|
||||||
modeForm.value = item;
|
modePage.modeForm = item;
|
||||||
openModePage.value = true;
|
modePage.open = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const closeMode = () => {
|
const closeMode = () => {
|
||||||
openModePage.value = false;
|
modePage.open = false;
|
||||||
search(req);
|
search(req);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -273,10 +281,26 @@ const closeCompress = () => {
|
|||||||
compressPage.open = false;
|
compressPage.open = false;
|
||||||
search(req);
|
search(req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openDeCompress = (item: File.File) => {
|
||||||
|
deCompressPage.open = true;
|
||||||
|
deCompressPage.name = item.name;
|
||||||
|
deCompressPage.path = item.path;
|
||||||
|
deCompressPage.dst = req.path;
|
||||||
|
deCompressPage.mimeType = item.mimeType;
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeDeCompress = () => {
|
||||||
|
deCompressPage.open = false;
|
||||||
|
search(req);
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
search(req);
|
search(req);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//TODO button增加v-if判断
|
||||||
|
//openDeCompress 增加是否可以解压判断
|
||||||
const buttons = [
|
const buttons = [
|
||||||
{
|
{
|
||||||
label: i18n.global.t('file.open'),
|
label: i18n.global.t('file.open'),
|
||||||
@ -287,9 +311,13 @@ const buttons = [
|
|||||||
click: openMode,
|
click: openMode,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: i18n.global.t('file.zip'),
|
label: i18n.global.t('file.compress'),
|
||||||
click: openCompress,
|
click: openCompress,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: i18n.global.t('file.deCompress'),
|
||||||
|
click: openDeCompress,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: i18n.global.t('file.rename'),
|
label: i18n.global.t('file.rename'),
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user