feat: 增加单独修改文件权限页面

This commit is contained in:
zhengkunwang223 2022-08-29 15:26:36 +08:00
parent 9db23ed649
commit 12527de2ba
11 changed files with 169 additions and 60 deletions

View File

@ -62,3 +62,17 @@ func (b *BaseApi) DeleteFile(c *gin.Context) {
}
helper.SuccessWithData(c, nil)
}
func (b *BaseApi) ChangeFileMode(c *gin.Context) {
var req dto.FileCreate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
err := fileService.ChangeMode(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@ -5,6 +5,7 @@ import (
"fmt"
"github.com/1Panel-dev/1Panel/app/dto"
"github.com/1Panel-dev/1Panel/utils/files"
"github.com/pkg/errors"
"io"
"io/fs"
)
@ -48,6 +49,11 @@ 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))
}
@ -64,6 +70,11 @@ func (f FileService) Delete(op dto.FileDelete) error {
}
}
func (f FileService) ChangeMode(op dto.FileCreate) error {
fo := files.NewFileOp()
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
}
func getUuid() string {
b := make([]byte, 16)
io.ReadFull(rand.Reader, b)

View File

@ -19,6 +19,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
fileRouter.POST("/tree", baseApi.GetFileTree)
fileRouter.POST("", baseApi.CreateFile)
fileRouter.POST("/del", baseApi.DeleteFile)
fileRouter.POST("/mode", baseApi.ChangeFileMode)
}
}

View File

@ -26,6 +26,14 @@ func (f FileOp) DeleteDir(dst string) error {
return f.Fs.RemoveAll(dst)
}
func (f FileOp) Stat(dst string) bool {
info, _ := f.Fs.Stat(dst)
if info != nil {
return true
}
return false
}
func (f FileOp) DeleteFile(dst string) error {
return f.Fs.Remove(dst)
}
@ -50,3 +58,7 @@ func (f FileOp) WriteFile(dst string, in io.Reader, mode fs.FileMode) error {
}
return nil
}
func (f FileOp) Chmod(dst string, mode fs.FileMode) error {
return f.Fs.Chmod(dst, mode)
}

View File

@ -1,26 +0,0 @@
{
"code": 200,
"data": {
"items": [
{
"name": "var",
"isDir": true,
"mode": 775,
"user": "root",
"group": "root",
"size": 2048,
"updateTime": "2022-08-11T11:05:22.001+08:00"
},
{
"name": "test.txt",
"isDir": false,
"mode": 775,
"user": "root",
"group": "root",
"size": 4096,
"updateTime": "2022-08-11T11:05:22.001+08:00"
}
],
"total": 2
}
}

View File

@ -16,3 +16,7 @@ export const CreateFile = (form: File.FileCreate) => {
export const DeleteFile = (form: File.FileDelete) => {
return http.post<File.File>('files/del', form);
};
export const ChangeFileMode = (form: File.FileCreate) => {
return http.post<File.File>('files/mode', form);
};

View File

@ -44,7 +44,7 @@ interface Props {
const roles = ref<string[]>(['0', '1', '2', '3', '4', '5', '6', '7']);
const props = withDefaults(defineProps<Props>(), {
mode: '0775',
mode: '0755',
});
const { mode } = toRefs(props);
@ -53,7 +53,7 @@ let form = ref<RoleForm>({
owner: { r: true, w: true, x: true },
group: { r: true, w: true, x: true },
public: { r: true, w: false, x: true },
mode: '0775',
mode: '0755',
});
const em = defineEmits(['getMode']);

View File

@ -7,6 +7,7 @@ import i18n from '@/lang';
* @param {Function} api 操作数据接口的api方法(必传)
* @param {Object} params 携带的操作数据参数 {id,params}(必传)
* @param {String} message 提示信息(必传)
* @param {String} loading 页面loading
* @param {String} confirmType icon类型(不必传,默认为 warning)
* @return Promise
*/
@ -14,22 +15,28 @@ export const useDeleteData = <P = any, R = any>(
api: (params: P) => Promise<R>,
params: Parameters<typeof api>[0],
message: string,
loading: boolean,
confirmType: HandleData.MessageType = 'error',
) => {
return new Promise((resolve, reject) => {
loading = true;
ElMessageBox.confirm(i18n.global.t(`${message}`) + '?', i18n.global.t('commons.msg.deleteTitle'), {
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: confirmType,
draggable: true,
}).then(async () => {
const res = await api(params);
if (!res) return reject(false);
ElMessage({
type: 'success',
message: i18n.global.t('commons.msg.deleteSuccess'),
})
.then(async () => {
const res = await api(params);
if (!res) return reject(false);
ElMessage({
type: 'success',
message: i18n.global.t('commons.msg.deleteSuccess'),
});
resolve(true);
})
.finally(() => {
loading = false;
});
resolve(true);
});
});
};

View File

@ -0,0 +1,64 @@
<template>
<el-dialog
v-model="open"
:before-close="handleClose"
:title="$t('file.setRole')"
width="30%"
@open="onOpen"
v-loading="loading"
>
<FileRole :mode="mode" @get-mode="getMode"></FileRole>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
<el-button type="primary" @click="submit()">{{ $t('commons.button.confirm') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { File } from '@/api/interface/file';
import { ChangeFileMode } from '@/api/modules/files';
import i18n from '@/lang';
import { ElMessage } from 'element-plus';
import FileRole from '@/components/file-role/index.vue';
interface Props {
open: boolean;
file: Object;
}
const props = withDefaults(defineProps<Props>(), {});
let form = ref<File.FileCreate>({ path: '', isDir: false, mode: 0o755 });
let loading = ref<Boolean>(false);
let mode = ref('0755');
const em = defineEmits(['close']);
const handleClose = () => {
em('close', false);
};
const onOpen = () => {
const f = props.file as File.FileCreate;
form.value.isDir = f.isDir;
form.value.path = f.path;
mode.value = String(f.mode);
};
const getMode = (val: number) => {
form.value.mode = val;
};
const submit = async () => {
loading.value = true;
ChangeFileMode(form.value)
.then(() => {
ElMessage.success(i18n.global.t('commons.msg.updateSuccess'));
handleClose();
})
.finally(() => {
loading.value = false;
});
};
</script>

View File

@ -7,12 +7,13 @@
@open="onOpen"
v-loading="loading"
>
<el-form ref="fileForm" label-position="left" :model="form" label-width="100px">
<el-form-item :label="$t('file.path')"> <el-input v-model="form.path" /></el-form-item>
<el-form ref="fileForm" label-position="left" :model="form" label-width="100px" :rules="rules">
<el-form-item :label="$t('file.path')"> <el-input v-model="getPath" disabled /></el-form-item>
<el-form-item :label="$t('file.name')"> <el-input v-model="name" /></el-form-item>
<el-checkbox v-model="isLink" :label="$t('file.link')"></el-checkbox>
</el-form>
<el-checkbox v-model="setRole" :label="$t('file.setRole')"></el-checkbox>
<FileRole v-if="setRole" :mode="'0775'" @get-mode="getMode"></FileRole>
<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>
@ -23,17 +24,20 @@
</template>
<script setup lang="ts">
import { toRefs, ref } from 'vue';
import { toRefs, ref, reactive, computed } from 'vue';
import { File } from '@/api/interface/file';
import { ElMessage, FormInstance } from 'element-plus';
import { ElMessage, FormInstance, FormRules } from 'element-plus';
import { CreateFile } from '@/api/modules/files';
import i18n from '@/lang';
import FileRole from '@/components/file-role/index.vue';
import { Rules } from '@/global/form-rues';
const fileForm = ref<FormInstance>();
let loading = ref<Boolean>(false);
let setRole = ref<Boolean>(false);
let isLink = ref<Boolean>(false);
let loading = ref(false);
let setRole = ref(false);
let isLink = ref(false);
let name = ref('');
let path = ref('');
const props = defineProps({
open: Boolean,
@ -46,10 +50,18 @@ const handleClose = () => {
em('close', open);
};
const rules = reactive<FormRules>({
name: [Rules.required],
});
const getMode = (val: number) => {
form.value.mode = val;
};
let getPath = computed(() => {
return path.value + '/' + name.value;
});
const submit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid) => {
@ -57,6 +69,7 @@ const submit = async (formEl: FormInstance | undefined) => {
return;
}
loading.value = true;
form.value.path = getPath.value;
CreateFile(form.value)
.then(() => {
ElMessage.success(i18n.global.t('commons.msg.createSuccess'));
@ -72,5 +85,7 @@ const onOpen = () => {
const f = file?.value as File.FileCreate;
form.value.isDir = f.isDir;
form.value.path = f.path;
path.value = f.path;
name.value = '';
};
</script>

View File

@ -54,9 +54,6 @@
<el-dropdown-item command="file">
<svg-icon iconName="p-file-normal"></svg-icon>{{ $t('file.file') }}
</el-dropdown-item>
<el-dropdown-item command="link">
<svg-icon iconName="p-file-normal"></svg-icon>{{ $t('file.linkFile') }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@ -74,7 +71,11 @@
<el-link :underline="false" @click="open(row)">{{ row.name }}</el-link>
</template>
</el-table-column>
<el-table-column :label="$t('file.mode')" prop="mode"> </el-table-column>
<el-table-column :label="$t('file.mode')" prop="mode">
<template #default="{ row }">
<el-link :underline="false" @click="openMode(row)">{{ row.mode }}</el-link>
</template>
</el-table-column>
<el-table-column :label="$t('file.user')" prop="user"> </el-table-column>
<el-table-column :label="$t('file.group')" prop="group"> </el-table-column>
<el-table-column :label="$t('file.size')" prop="size"> </el-table-column>
@ -95,7 +96,8 @@
/>
</ComplexTable>
</el-col>
<CreateFile :open="openCreate" :file="fileCreate" @close="close"></CreateFile>
<CreateFile :open="openCreate" :file="fileCreate" @close="closeCreate"></CreateFile>
<ChangeRole :open="openModePage" :file="modeForm" @close="closeMode"></ChangeRole>
</el-row>
</LayoutContent>
</template>
@ -111,6 +113,7 @@ import { File } from '@/api/interface/file';
import BreadCrumbs from '@/components/bread-crumbs/index.vue';
import BreadCrumbItem from '@/components/bread-crumbs/bread-crumbs-item.vue';
import CreateFile from './create.vue';
import ChangeRole from './change-role.vue';
import { useDeleteData } from '@/hooks/use-delete-data';
let data = ref();
@ -123,6 +126,8 @@ let fileTree = ref<File.FileTree[]>([]);
let expandKeys = ref<string[]>([]);
let openCreate = ref<boolean>(false);
let fileCreate = ref<File.FileCreate>({ path: '/', isDir: false, mode: 0o755 });
let openModePage = ref<boolean>(false);
let modeForm = ref<File.FileCreate>({ path: '/', isDir: false, mode: 0o755 });
const defaultProps = {
children: 'children',
@ -228,24 +233,25 @@ const handleCreate = (commnad: string) => {
};
const delFile = async (row: File.File | null) => {
// let ids: Array<number> = [];
// if (row === null) {
// selects.value.forEach((item: File.File) => {
// ids.push(item.id);
// });
// } else {
// ids.push(row.id);
// }
await useDeleteData(DeleteFile, row as File.FileDelete, 'commons.msg.delete');
await useDeleteData(DeleteFile, row as File.FileDelete, 'commons.msg.delete', loading.value);
search(req);
};
const close = () => {
const closeCreate = () => {
openCreate.value = false;
search(req);
};
const openMode = (item: File.File) => {
modeForm.value = item;
openModePage.value = true;
};
const closeMode = () => {
openModePage.value = false;
search(req);
};
onMounted(() => {
search(req);
});
@ -257,6 +263,7 @@ const buttons = [
},
{
label: i18n.global.t('file.mode'),
click: openMode,
},
{
label: i18n.global.t('file.zip'),