mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-12-18 11:17:49 +08:00
feat: 增加创建软链接文件功能
This commit is contained in:
parent
245f5fb68a
commit
1b0660f4a3
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -192,5 +192,9 @@ export default {
|
||||
compressSuccess: '压缩成功',
|
||||
deCompressSuccess: '解压成功',
|
||||
deCompressDst: '解压路径',
|
||||
linkType: '链接类型',
|
||||
softLink: '软链接',
|
||||
hardLink: '硬链接',
|
||||
linkPath: '链接路径',
|
||||
},
|
||||
};
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
|
Loading…
Reference in New Issue
Block a user