feat: 增加创建软链接文件功能

This commit is contained in:
zhengkunwang223 2022-08-31 16:00:51 +08:00
parent 245f5fb68a
commit 1b0660f4a3
9 changed files with 98 additions and 27 deletions

View File

@ -20,10 +20,13 @@ type FileTree struct {
}
type FileCreate struct {
Path string
Content string
IsDir bool
Mode int64
Path string
Content string
IsDir bool
Mode int64
IsLink bool
IsSymlink bool
LinkPath string
}
type FileDelete struct {

View File

@ -50,16 +50,18 @@ func (f FileService) GetFileTree(op dto.FileOption) ([]dto.FileTree, error) {
func (f FileService) Create(op dto.FileCreate) error {
fo := files.NewFileOp()
if fo.Stat(op.Path) {
return errors.New("file is exist")
}
if op.IsDir {
return fo.CreateDir(op.Path, fs.FileMode(op.Mode))
} else {
if op.IsLink {
return fo.LinkFile(op.LinkPath, op.Path, op.IsSymlink)
} else {
return fo.CreateFile(op.Path)
}
}
return nil
}
func (f FileService) Delete(op dto.FileDelete) error {

View File

@ -25,6 +25,22 @@ func (f FileOp) CreateDir(dst string, mode fs.FileMode) error {
return f.Fs.MkdirAll(dst, mode)
}
func (f FileOp) CreateFile(dst string) error {
if _, err := f.Fs.Create(dst); err != nil {
return err
}
return nil
}
func (f FileOp) LinkFile(source string, dst string, isSymlink bool) error {
if isSymlink {
osFs := afero.OsFs{}
return osFs.SymlinkIfPossible(source, dst)
} else {
return os.Link(source, dst)
}
}
func (f FileOp) DeleteDir(dst string) error {
return f.Fs.RemoveAll(dst)
}

View File

@ -21,6 +21,7 @@ type FileInfo struct {
Size int64 `json:"size"`
IsDir bool `json:"isDir"`
IsSymlink bool `json:"isSymlink"`
LinkPath string `json:"linkPath"`
Type string `json:"type"`
Mode string `json:"mode"`
MimeType string `json:"mimeType"`
@ -59,6 +60,9 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
MimeType: GetMimeType(op.Path),
}
if file.IsSymlink {
file.LinkPath = GetSymlink(op.Path)
}
if op.Expand {
if file.IsDir {
if err := file.listChildren(); err != nil {
@ -111,6 +115,9 @@ func (f *FileInfo) listChildren() error {
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
MimeType: GetMimeType(fPath),
}
if isSymlink {
file.LinkPath = GetSymlink(fPath)
}
if isInvalidLink {
file.Type = "invalid_link"

View File

@ -34,3 +34,11 @@ func GetMimeType(path string) string {
}
return mime.String()
}
func GetSymlink(path string) string {
linkPath, err := os.Readlink(path)
if err != nil {
return ""
}
return linkPath
}

View File

@ -9,6 +9,7 @@ export namespace File {
size: number;
isDir: boolean;
isSymlink: boolean;
linkPath: boolean;
type: string;
updateTime: string;
modTime: string;
@ -35,6 +36,9 @@ export namespace File {
path: string;
isDir: boolean;
mode: number;
isLink?: boolean;
isSymlink?: boolean;
linkPath?: boolean;
}
export interface FileDelete {

View File

@ -192,5 +192,9 @@ export default {
compressSuccess: '压缩成功',
deCompressSuccess: '解压成功',
deCompressDst: '解压路径',
linkType: '链接类型',
softLink: '软链接',
hardLink: '硬链接',
linkPath: '链接路径',
},
};

View File

@ -7,13 +7,29 @@
@open="onOpen"
v-loading="loading"
>
<el-form ref="fileForm" label-position="left" :model="form" label-width="100px" :rules="rules">
<el-form ref="fileForm" label-position="left" :model="addForm" label-width="100px" :rules="rules">
<el-form-item :label="$t('file.path')" prop="path"> <el-input v-model="getPath" disabled /></el-form-item>
<el-form-item :label="$t('file.name')" prop="name"> <el-input v-model="form.name" /></el-form-item>
<el-checkbox v-model="isLink" :label="$t('file.link')"></el-checkbox>
<el-form-item :label="$t('file.name')" prop="name"> <el-input v-model="addForm.name" /></el-form-item>
<el-form-item v-if="!addForm.isDir">
<el-checkbox v-model="addForm.isLink" :label="$t('file.link')"></el-checkbox
></el-form-item>
<el-form-item :label="$t('file.linkType')" v-if="addForm.isLink" prop="linkType">
<el-radio-group v-model="addForm.isSymlink">
<el-radio :label="true">{{ $t('file.softLink') }}</el-radio>
<el-radio :label="false">{{ $t('file.hardLink') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="addForm.isLink" :label="$t('file.linkPath')" prop="linkPath">
<el-input v-model="addForm.linkPath"
/></el-form-item>
<el-form-item>
<el-checkbox v-if="addForm.isDir" v-model="setRole" :label="$t('file.setRole')"></el-checkbox>
</el-form-item>
<el-form-item>
<FileRole v-if="setRole" :mode="'0755'" @get-mode="getMode"></FileRole>
</el-form-item>
</el-form>
<el-checkbox v-model="setRole" :label="$t('file.setRole')"></el-checkbox>
<FileRole v-if="setRole" :mode="'0755'" @get-mode="getMode"></FileRole>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
@ -35,15 +51,15 @@ import { Rules } from '@/global/form-rues';
const fileForm = ref<FormInstance>();
let loading = ref(false);
let setRole = ref(false);
let isLink = ref(false);
const props = defineProps({
open: Boolean,
file: Object,
});
const { open, file } = toRefs(props);
let addItem = ref<File.FileCreate>({ path: '', isDir: false, mode: 0o755 });
let form = ref({ name: '', path: '' });
let addForm = reactive({ path: '', name: '', isDir: false, mode: 0o755, isLink: false, isSymlink: true, linkPath: '' });
const em = defineEmits(['close']);
const handleClose = () => {
em('close', open);
@ -52,17 +68,19 @@ const handleClose = () => {
const rules = reactive<FormRules>({
name: [Rules.required],
path: [Rules.required],
isSymlink: [Rules.required],
linkPath: [Rules.required],
});
const getMode = (val: number) => {
addItem.value.mode = val;
addForm.mode = val;
};
let getPath = computed(() => {
if (form.value.path === '/') {
return form.value.path + form.value.name;
if (addForm.path === '/') {
return addForm.path + addForm.name;
} else {
return form.value.path + '/' + form.value.name;
return addForm.path + '/' + addForm.name;
}
});
@ -72,9 +90,12 @@ const submit = async (formEl: FormInstance | undefined) => {
if (!valid) {
return;
}
let addItem = {};
Object.assign(addItem, addForm);
addItem['path'] = getPath.value;
loading.value = true;
addItem.value.path = getPath.value;
CreateFile(addItem.value)
CreateFile(addItem as File.FileCreate)
.then(() => {
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
handleClose();
@ -87,9 +108,14 @@ const submit = async (formEl: FormInstance | undefined) => {
const onOpen = () => {
const f = file?.value as File.FileCreate;
addItem.value.isDir = f.isDir;
addItem.value.path = f.path;
form.value.name = '';
form.value.path = f.path;
addForm.isDir = f.isDir;
addForm.path = f.path;
addForm.name = '';
addForm.isLink = false;
init();
};
const init = () => {
setRole.value = false;
};
</script>

View File

@ -64,11 +64,12 @@
<el-button type="primary" plain> {{ $t('file.terminal') }}</el-button>
<el-button type="primary" plain> {{ $t('file.shareList') }}</el-button>
</template>
<el-table-column :label="$t('commons.table.name')" min-width="150" fix>
<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>
<svg-icon v-else className="table-icon" iconName="p-file-normal"></svg-icon>
<el-link :underline="false" @click="open(row)">{{ row.name }}</el-link>
<span v-if="row.isSymlink"> -> {{ row.linkPath }}</span>
</template>
</el-table-column>
<el-table-column :label="$t('file.mode')" prop="mode">