feat: 增加创建软链接文件功能
This commit is contained in:
@@ -20,10 +20,13 @@ type FileTree struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type FileCreate struct {
|
type FileCreate struct {
|
||||||
Path string
|
Path string
|
||||||
Content string
|
Content string
|
||||||
IsDir bool
|
IsDir bool
|
||||||
Mode int64
|
Mode int64
|
||||||
|
IsLink bool
|
||||||
|
IsSymlink bool
|
||||||
|
LinkPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileDelete struct {
|
type FileDelete struct {
|
||||||
|
@@ -50,16 +50,18 @@ func (f FileService) GetFileTree(op dto.FileOption) ([]dto.FileTree, error) {
|
|||||||
func (f FileService) Create(op dto.FileCreate) error {
|
func (f FileService) Create(op dto.FileCreate) error {
|
||||||
|
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
|
|
||||||
if fo.Stat(op.Path) {
|
if fo.Stat(op.Path) {
|
||||||
return errors.New("file is exist")
|
return errors.New("file is exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
if op.IsDir {
|
if op.IsDir {
|
||||||
return fo.CreateDir(op.Path, fs.FileMode(op.Mode))
|
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 {
|
func (f FileService) Delete(op dto.FileDelete) error {
|
||||||
|
@@ -25,6 +25,22 @@ func (f FileOp) CreateDir(dst string, mode fs.FileMode) error {
|
|||||||
return f.Fs.MkdirAll(dst, mode)
|
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 {
|
func (f FileOp) DeleteDir(dst string) error {
|
||||||
return f.Fs.RemoveAll(dst)
|
return f.Fs.RemoveAll(dst)
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ type FileInfo struct {
|
|||||||
Size int64 `json:"size"`
|
Size int64 `json:"size"`
|
||||||
IsDir bool `json:"isDir"`
|
IsDir bool `json:"isDir"`
|
||||||
IsSymlink bool `json:"isSymlink"`
|
IsSymlink bool `json:"isSymlink"`
|
||||||
|
LinkPath string `json:"linkPath"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Mode string `json:"mode"`
|
Mode string `json:"mode"`
|
||||||
MimeType string `json:"mimeType"`
|
MimeType string `json:"mimeType"`
|
||||||
@@ -59,6 +60,9 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
|
|||||||
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
|
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
|
||||||
MimeType: GetMimeType(op.Path),
|
MimeType: GetMimeType(op.Path),
|
||||||
}
|
}
|
||||||
|
if file.IsSymlink {
|
||||||
|
file.LinkPath = GetSymlink(op.Path)
|
||||||
|
}
|
||||||
if op.Expand {
|
if op.Expand {
|
||||||
if file.IsDir {
|
if file.IsDir {
|
||||||
if err := file.listChildren(); err != nil {
|
if err := file.listChildren(); err != nil {
|
||||||
@@ -111,6 +115,9 @@ func (f *FileInfo) listChildren() error {
|
|||||||
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
|
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
|
||||||
MimeType: GetMimeType(fPath),
|
MimeType: GetMimeType(fPath),
|
||||||
}
|
}
|
||||||
|
if isSymlink {
|
||||||
|
file.LinkPath = GetSymlink(fPath)
|
||||||
|
}
|
||||||
|
|
||||||
if isInvalidLink {
|
if isInvalidLink {
|
||||||
file.Type = "invalid_link"
|
file.Type = "invalid_link"
|
||||||
|
@@ -34,3 +34,11 @@ func GetMimeType(path string) string {
|
|||||||
}
|
}
|
||||||
return mime.String()
|
return mime.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetSymlink(path string) string {
|
||||||
|
linkPath, err := os.Readlink(path)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return linkPath
|
||||||
|
}
|
||||||
|
@@ -9,6 +9,7 @@ export namespace File {
|
|||||||
size: number;
|
size: number;
|
||||||
isDir: boolean;
|
isDir: boolean;
|
||||||
isSymlink: boolean;
|
isSymlink: boolean;
|
||||||
|
linkPath: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
updateTime: string;
|
updateTime: string;
|
||||||
modTime: string;
|
modTime: string;
|
||||||
@@ -35,6 +36,9 @@ export namespace File {
|
|||||||
path: string;
|
path: string;
|
||||||
isDir: boolean;
|
isDir: boolean;
|
||||||
mode: number;
|
mode: number;
|
||||||
|
isLink?: boolean;
|
||||||
|
isSymlink?: boolean;
|
||||||
|
linkPath?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FileDelete {
|
export interface FileDelete {
|
||||||
|
@@ -192,5 +192,9 @@ export default {
|
|||||||
compressSuccess: '压缩成功',
|
compressSuccess: '压缩成功',
|
||||||
deCompressSuccess: '解压成功',
|
deCompressSuccess: '解压成功',
|
||||||
deCompressDst: '解压路径',
|
deCompressDst: '解压路径',
|
||||||
|
linkType: '链接类型',
|
||||||
|
softLink: '软链接',
|
||||||
|
hardLink: '硬链接',
|
||||||
|
linkPath: '链接路径',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -7,13 +7,29 @@
|
|||||||
@open="onOpen"
|
@open="onOpen"
|
||||||
v-loading="loading"
|
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.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-form-item :label="$t('file.name')" prop="name"> <el-input v-model="addForm.name" /></el-form-item>
|
||||||
<el-checkbox v-model="isLink" :label="$t('file.link')"></el-checkbox>
|
<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-form>
|
||||||
<el-checkbox v-model="setRole" :label="$t('file.setRole')"></el-checkbox>
|
|
||||||
<FileRole v-if="setRole" :mode="'0755'" @get-mode="getMode"></FileRole>
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<span class="dialog-footer">
|
<span class="dialog-footer">
|
||||||
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
@@ -35,15 +51,15 @@ import { Rules } from '@/global/form-rues';
|
|||||||
const fileForm = ref<FormInstance>();
|
const fileForm = ref<FormInstance>();
|
||||||
let loading = ref(false);
|
let loading = ref(false);
|
||||||
let setRole = ref(false);
|
let setRole = ref(false);
|
||||||
let isLink = ref(false);
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
open: Boolean,
|
open: Boolean,
|
||||||
file: Object,
|
file: Object,
|
||||||
});
|
});
|
||||||
const { open, file } = toRefs(props);
|
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 em = defineEmits(['close']);
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
em('close', open);
|
em('close', open);
|
||||||
@@ -52,17 +68,19 @@ const handleClose = () => {
|
|||||||
const rules = reactive<FormRules>({
|
const rules = reactive<FormRules>({
|
||||||
name: [Rules.required],
|
name: [Rules.required],
|
||||||
path: [Rules.required],
|
path: [Rules.required],
|
||||||
|
isSymlink: [Rules.required],
|
||||||
|
linkPath: [Rules.required],
|
||||||
});
|
});
|
||||||
|
|
||||||
const getMode = (val: number) => {
|
const getMode = (val: number) => {
|
||||||
addItem.value.mode = val;
|
addForm.mode = val;
|
||||||
};
|
};
|
||||||
|
|
||||||
let getPath = computed(() => {
|
let getPath = computed(() => {
|
||||||
if (form.value.path === '/') {
|
if (addForm.path === '/') {
|
||||||
return form.value.path + form.value.name;
|
return addForm.path + addForm.name;
|
||||||
} else {
|
} 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) {
|
if (!valid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let addItem = {};
|
||||||
|
Object.assign(addItem, addForm);
|
||||||
|
addItem['path'] = getPath.value;
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
addItem.value.path = getPath.value;
|
CreateFile(addItem as File.FileCreate)
|
||||||
CreateFile(addItem.value)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
|
||||||
handleClose();
|
handleClose();
|
||||||
@@ -87,9 +108,14 @@ const submit = async (formEl: FormInstance | undefined) => {
|
|||||||
|
|
||||||
const onOpen = () => {
|
const onOpen = () => {
|
||||||
const f = file?.value as File.FileCreate;
|
const f = file?.value as File.FileCreate;
|
||||||
addItem.value.isDir = f.isDir;
|
addForm.isDir = f.isDir;
|
||||||
addItem.value.path = f.path;
|
addForm.path = f.path;
|
||||||
form.value.name = '';
|
addForm.name = '';
|
||||||
form.value.path = f.path;
|
addForm.isLink = false;
|
||||||
|
init();
|
||||||
|
};
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
setRole.value = false;
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@@ -64,11 +64,12 @@
|
|||||||
<el-button type="primary" plain> {{ $t('file.terminal') }}</el-button>
|
<el-button type="primary" plain> {{ $t('file.terminal') }}</el-button>
|
||||||
<el-button type="primary" plain> {{ $t('file.shareList') }}</el-button>
|
<el-button type="primary" plain> {{ $t('file.shareList') }}</el-button>
|
||||||
</template>
|
</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 }">
|
<template #default="{ row }">
|
||||||
<svg-icon v-if="row.isDir" className="table-icon" iconName="p-file-folder"></svg-icon>
|
<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>
|
<svg-icon v-else className="table-icon" iconName="p-file-normal"></svg-icon>
|
||||||
<el-link :underline="false" @click="open(row)">{{ row.name }}</el-link>
|
<el-link :underline="false" @click="open(row)">{{ row.name }}</el-link>
|
||||||
|
<span v-if="row.isSymlink"> -> {{ row.linkPath }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column :label="$t('file.mode')" prop="mode">
|
<el-table-column :label="$t('file.mode')" prop="mode">
|
||||||
|
Reference in New Issue
Block a user