feat: 增加文件移动功能

This commit is contained in:
zhengkunwang223 2022-09-06 10:35:35 +08:00
parent 16b9adfefe
commit f4eead9cc2
14 changed files with 201 additions and 6 deletions

View File

@ -180,3 +180,16 @@ func (b *BaseApi) Download(c *gin.Context) {
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) Move(c *gin.Context) {
var req dto.FileMove
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := fileService.MvFile(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@ -63,3 +63,9 @@ type FileDownload struct {
Path string `json:"path" validate:"required"`
Name string `json:"name" validate:"required"`
}
type FileMove struct {
Type string `json:"type" validate:"required"`
OldPaths []string `json:"oldPaths" validate:"required"`
NewPath string `json:"newPath" validate:"required"`
}

View File

@ -125,6 +125,14 @@ func (f FileService) Download(c dto.FileDownload) error {
return fo.DownloadFile(c.Url, filepath.Join(c.Path, c.Name))
}
func (f FileService) MvFile(c dto.FileMove) error {
fo := files.NewFileOp()
if c.Type == "cut" {
return fo.Cut(c.OldPaths, c.NewPath)
}
return nil
}
func getUuid() string {
b := make([]byte, 16)
io.ReadFull(rand.Reader, b)

View File

@ -27,6 +27,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
fileRouter.POST("/upload", baseApi.UploadFiles)
fileRouter.POST("/rename", baseApi.ChangeName)
fileRouter.POST("/download", baseApi.Download)
fileRouter.POST("/move", baseApi.Move)
}
}

View File

@ -105,6 +105,17 @@ func (f FileOp) DownloadFile(url, dst string) error {
return nil
}
func (f FileOp) Cut(oldPaths []string, dst string) error {
for _, p := range oldPaths {
base := filepath.Base(p)
dstPath := filepath.Join(dst, base)
if err := f.Fs.Rename(p, dstPath); err != nil {
return err
}
}
return nil
}
type CompressType string
const (

View File

@ -36,6 +36,7 @@ type FileOption struct {
Path string `json:"path"`
Search string `json:"search"`
Expand bool `json:"expand"`
Dir bool `json:"dir"`
}
func NewFileInfo(op FileOption) (*FileInfo, error) {
@ -69,7 +70,7 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
}
if op.Expand {
if file.IsDir {
if err := file.listChildren(); err != nil {
if err := file.listChildren(op.Dir); err != nil {
return nil, err
}
return file, nil
@ -82,14 +83,18 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
return file, nil
}
func (f *FileInfo) listChildren() error {
func (f *FileInfo) listChildren(dir bool) error {
afs := &afero.Afero{Fs: f.Fs}
dir, err := afs.ReadDir(f.Path)
files, err := afs.ReadDir(f.Path)
if err != nil {
return err
}
var items []*FileInfo
for _, df := range dir {
for _, df := range files {
if dir && !df.IsDir() {
continue
}
name := df.Name()
fPath := path.Join(f.Path, df.Name())

View File

@ -22,6 +22,7 @@ export namespace File {
path: string;
search?: string;
expand: boolean;
dir?: boolean;
}
export interface FileTree {
@ -75,4 +76,10 @@ export namespace File {
name: string;
url: string;
}
export interface FileMove {
oldPaths: string[];
newPath: string;
type: string;
}
}

View File

@ -48,3 +48,7 @@ export const RenameRile = (params: File.FileRename) => {
export const DownloadFile = (params: File.FileDownload) => {
return http.post<File.File>('files/download', params);
};
export const MoveFile = (params: File.FileMove) => {
return http.post<File.File>('files/move', params);
};

View File

@ -54,6 +54,10 @@ const props = defineProps({
type: String,
default: '/',
},
dir: {
type: Boolean,
default: false,
},
});
const em = defineEmits(['choose']);
@ -89,6 +93,7 @@ const jump = async (index: number) => {
};
const search = async (req: File.ReqFile) => {
req.dir = props.dir;
loading.value = true;
await GetFilesList(req)
.then((res) => {

View File

@ -200,5 +200,8 @@ export default {
downloadSuccess: '下载成功',
downloadUrl: '下载地址',
downloadStart: '下载开始!',
moveStart: '移动成功',
move: '移动',
copy: '复制',
},
};

View File

@ -60,10 +60,17 @@
<el-button type="primary" plain @click="openUpload"> {{ $t('file.upload') }}</el-button>
<!-- <el-button type="primary" plain> {{ $t('file.search') }}</el-button> -->
<el-button type="primary" plain @click="openDownload"> {{ $t('file.remoteFile') }}</el-button>
<el-button type="primary" plain @click="openMove('copy')" :disabled="selects.length === 0">
{{ $t('file.copy') }}</el-button
>
<el-button type="primary" plain @click="openMove('cut')" :disabled="selects.length === 0">
{{ $t('file.move') }}</el-button
>
<!-- <el-button type="primary" plain> {{ $t('file.sync') }}</el-button>
<el-button type="primary" plain> {{ $t('file.terminal') }}</el-button>
<el-button type="primary" plain> {{ $t('file.shareList') }}</el-button> -->
</template>
<el-table-column type="selection" width="55" />
<el-table-column :label="$t('commons.table.name')" min-width="250" fix show-overflow-tooltip>
<template #default="{ row }">
<svg-icon v-if="row.isDir" className="table-icon" iconName="p-file-folder"></svg-icon>
@ -132,6 +139,7 @@
></FileRename>
<Upload :open="uploadPage.open" :path="uploadPage.path" @close="closeUpload"></Upload>
<FileDown :open="downloadPage.open" :path="downloadPage.path" @close="closeDownload"></FileDown>
<Move :open="movePage.open" :oldPaths="movePage.oldPaths" :type="movePage.type" @close="clodeMove"></Move>
</el-row>
</LayoutContent>
</template>
@ -151,11 +159,12 @@ import ChangeRole from './change-role/index.vue';
import Compress from './compress/index.vue';
import Decompress from './decompress/index.vue';
import Upload from './upload/index.vue';
import FileRename from './file-rename/index.vue';
import FileRename from './rename/index.vue';
import { useDeleteData } from '@/hooks/use-delete-data';
import CodeEditor from './code-editor/index.vue';
import { ElMessage } from 'element-plus';
import FileDown from './file-down/index.vue';
import FileDown from './download/index.vue';
import Move from './move/index.vue';
let data = ref();
let selects = ref<any>([]);
@ -175,6 +184,7 @@ const codeReq = reactive({ path: '', expand: false });
const uploadPage = reactive({ open: false, path: '' });
const renamePage = reactive({ open: false, path: '', oldName: '' });
const downloadPage = reactive({ open: false, path: '' });
const movePage = reactive({ open: false, oldPaths: [''], type: '' });
const defaultProps = {
children: 'children',
@ -370,6 +380,21 @@ const closeRename = () => {
search(req);
};
const openMove = (type: string) => {
movePage.type = type;
movePage.open = true;
const oldpaths = [];
for (const s of selects.value) {
oldpaths.push(s['path']);
}
movePage.oldPaths = oldpaths;
};
const clodeMove = () => {
movePage.open = false;
search(req);
};
const saveContent = (content: string) => {
editorPage.loading = true;
SaveFileContent({ path: codeReq.path, content: content }).finally(() => {

View File

@ -0,0 +1,107 @@
<template>
<el-dialog v-model="open" :title="title" :before-close="handleClose" width="30%" @open="onOpen">
<el-form
ref="fileForm"
label-position="left"
:model="addForm"
label-width="100px"
:rules="rules"
v-loading="loading"
>
<el-form-item :label="$t('file.path')" prop="newPath">
<el-input v-model="addForm.newPath">
<template #append> <FileList @choose="getPath" :dir="true"></FileList> </template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose" :disabled="loading">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="submit(fileForm)" :disabled="loading">{{
$t('commons.button.confirm')
}}</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { MoveFile } from '@/api/modules/files';
import { Rules } from '@/global/form-rues';
import i18n from '@/lang';
import { ElMessage, FormInstance, FormRules } from 'element-plus';
import { toRefs, ref, reactive, PropType, computed } from 'vue';
import FileList from '@/components/file-list/index.vue';
const props = defineProps({
open: {
type: Boolean,
default: false,
},
oldPaths: {
type: Array as PropType<string[]>,
default: () => {
return [];
},
},
type: {
type: String,
default: '',
},
});
const { open } = toRefs(props);
const fileForm = ref<FormInstance>();
const loading = ref(false);
const title = computed(() => {
if (props.type === 'cut') {
return i18n.global.t('file.move');
} else {
return i18n.global.t('file.copy');
}
});
const addForm = reactive({
oldPaths: [] as string[],
newPath: '',
type: '',
});
const rules = reactive<FormRules>({
newPath: [Rules.requiredInput],
});
const em = defineEmits(['close']);
const handleClose = () => {
em('close', open);
};
const getPath = (path: string) => {
addForm.newPath = path;
};
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid) => {
if (!valid) {
return;
}
loading.value = true;
MoveFile(addForm)
.then(() => {
ElMessage.success(i18n.global.t('file.moveStart'));
handleClose();
})
.finally(() => {
loading.value = false;
});
});
};
const onOpen = () => {
addForm.oldPaths = props.oldPaths;
addForm.type = props.type;
};
</script>