Feat: refactoring FileManager & modify file permissions

This commit is contained in:
alongw 2023-10-15 02:04:37 +08:00
parent 2ad6ab4f4f
commit f4e5079542
7 changed files with 222 additions and 8 deletions

View File

@ -10,6 +10,8 @@ declare module 'vue' {
ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb']
ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem']
AButton: typeof import('ant-design-vue/es')['Button']
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
ACol: typeof import('ant-design-vue/es')['Col']
ActionButton: typeof import('./src/components/ActionButton.vue')['default']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']

View File

@ -5,6 +5,21 @@
justify-content: space-between;
}
.flex-around {
display: flex;
justify-content: space-around;
}
.flex-evenly {
display: flex;
justify-content: space-evenly;
}
.flex-warp {
display: flex;
flex-wrap: wrap;
}
.flex {
display: flex;
}

View File

@ -1,11 +1,11 @@
import { h, ref, createVNode, type Ref } from "vue";
import { h, ref, createVNode, type Ref, reactive } from "vue";
import { t } from "@/lang/i18n";
import type { TableProps, UploadProps } from "ant-design-vue";
import { LoadingOutlined, ExclamationCircleOutlined } from "@ant-design/icons-vue";
import { parseForwardAddress } from "@/tools/protocol";
import { number2permission, permission2number } from "@/tools/permission";
import {
fileList as getFileListApi,
getFileStatus as getFileStatusApi,
@ -17,12 +17,19 @@ import {
compressFile as compressFileApi,
uploadAddress,
uploadFile as uploadFileApi,
downloadAddress
downloadAddress,
changePermission as changePermissionApi
} from "@/services/apis/fileManager";
import { message, Modal } from "ant-design-vue";
import type { DataType, OperationForm, Breadcrumb, FileStatus } from "@/types/fileManager";
import type {
DataType,
OperationForm,
Breadcrumb,
FileStatus,
Permission
} from "@/types/fileManager";
export const useFileManager = (
instanceId: string | undefined,
@ -78,6 +85,9 @@ export const useFileManager = (
if (mode == "unzip") {
dialog.value.mode = "unzip";
}
if (mode == "permission") {
dialog.value.mode = "permission";
}
dialog.value.title = title;
dialog.value.info = info;
@ -88,7 +98,11 @@ export const useFileManager = (
return new Promise((resolve) => {
dialog.value.ok = () => {
if (dialog.value.value == "" && dialog.value.mode != "unzip") {
if (
dialog.value.value == "" &&
dialog.value.mode != "unzip" &&
dialog.value.mode != "permission"
) {
return message.error(t("请输入内容"));
}
resolve(dialog.value.value);
@ -430,6 +444,46 @@ export const useFileManager = (
}
};
const permission = reactive<Permission>({
data: {
owner: [],
usergroup: [],
everyone: []
},
deep: false,
loading: false
});
const changePermission = async (name: string, mode: number) => {
permission.loading = true;
permission.data = number2permission(mode);
permission.loading = false;
await openDialog(t("更改权限"), "", "", "permission");
const { execute } = changePermissionApi();
try {
await execute({
params: {
remote_uuid: daemonId || "",
uuid: instanceId || ""
},
data: {
chmod: permission2number(
permission.data.owner,
permission.data.usergroup,
permission.data.everyone
),
deep: permission.deep,
target: breadcrumbs[breadcrumbs.length - 1].path + name
}
});
message.success(t("更改权限成功"));
await getFileList();
} catch (err: any) {
return message.error(err.message);
}
permission.deep = false;
};
return {
fileStatus,
indicator,
@ -437,6 +491,7 @@ export const useFileManager = (
percentComplete,
spinning,
rowSelection,
permission,
openDialog,
getFileList,
touchFile,
@ -453,6 +508,7 @@ export const useFileManager = (
downloadFile,
handleChangeDir,
handleTableChange,
getFileStatus
getFileStatus,
changePermission
};
};

View File

@ -221,3 +221,22 @@ export const fileContent = useDefineApi<
url: "/api/files",
method: "PUT"
});
// 修改权限
export const changePermission = useDefineApi<
{
params: {
remote_uuid: string;
uuid: string;
};
data: {
chmod: number;
deep: boolean;
target: string;
};
},
boolean
>({
url: "/api/files/chmod",
method: "PUT"
});

View File

@ -0,0 +1,35 @@
export const permission2number = (
owner: string[],
usergroup: string[],
everyone: string[]
): number => {
const calculate = (arr: string[]): number => {
return arr.reduce((acc, cur) => acc + parseInt(cur), 0);
};
return parseInt(`${calculate(owner)}${calculate(usergroup)}${calculate(everyone)}`);
};
export const number2permission = (permission: number) => {
const calculate = (num: number): string[] => {
const arr: string[] = [];
if (num - 4 >= 0) {
arr.push("4");
num -= 4;
}
if (num - 2 >= 0) {
arr.push("2");
num -= 2;
}
if (num - 1 >= 0) {
arr.push("1");
num -= 1;
}
return arr;
};
const str = permission.toString().padStart(3, "0");
return {
owner: calculate(parseInt(str[0])),
usergroup: calculate(parseInt(str[1])),
everyone: calculate(parseInt(str[2]))
};
};

View File

@ -26,3 +26,13 @@ export interface FileStatus {
isGlobalInstance: boolean;
dist: string[];
}
export interface Permission {
data: {
owner: string[];
usergroup: string[];
everyone: string[];
};
deep: boolean;
loading: boolean;
}

View File

@ -117,6 +117,7 @@ const {
rowSelection,
spinning,
fileStatus,
permission,
getFileList,
touchFile,
reloadList,
@ -131,7 +132,8 @@ const {
handleChangeDir,
rowClickTable,
handleTableChange,
getFileStatus
getFileStatus,
changePermission
} = useFileManager(
instanceId,
daemonId,
@ -331,7 +333,11 @@ onMounted(() => {
<a-dropdown>
<template #overlay>
<a-menu>
<a-menu-item v-if="fileStatus?.platform != 'win32'" key="1">
<a-menu-item
v-if="fileStatus?.platform != 'win32'"
key="1"
@click="changePermission(record.name, record.mode)"
>
{{ t("TXT_CODE_16853efe") }}
</a-menu-item>
<a-menu-item
@ -434,6 +440,59 @@ onMounted(() => {
<a-radio-button value="big5">big5</a-radio-button>
</a-radio-group>
</a-space>
<a-space v-if="dialog.mode == 'permission'" direction="vertical" class="w-100">
<a-spin :spinning="permission.loading" :indicator="indicator" size="small">
<div class="flex-around permission">
<a-checkbox-group v-model:value="permission.data.owner">
<a-row class="direction-column son">
<h3 class="m-0">所有者</h3>
<a-col class="m-5 options">
<a-checkbox value="4">读取</a-checkbox>
</a-col>
<a-col class="m-5 options">
<a-checkbox value="2">写入</a-checkbox>
</a-col>
<a-col class="m-5 options">
<a-checkbox value="1">执行</a-checkbox>
</a-col>
</a-row>
</a-checkbox-group>
<a-checkbox-group v-model:value="permission.data.usergroup">
<a-row class="direction-column son">
<h3 class="m-0">用户组</h3>
<a-col class="m-5 options">
<a-checkbox value="4">读取</a-checkbox>
</a-col>
<a-col class="m-5 options">
<a-checkbox value="2">写入</a-checkbox>
</a-col>
<a-col class="m-5 options">
<a-checkbox value="1">执行</a-checkbox>
</a-col>
</a-row>
</a-checkbox-group>
<a-checkbox-group v-model:value="permission.data.everyone">
<a-row class="direction-column son">
<h3 class="m-0">任何人</h3>
<a-col class="m-5 options">
<a-checkbox value="4">读取</a-checkbox>
</a-col>
<a-col class="m-5 options">
<a-checkbox value="2">写入</a-checkbox>
</a-col>
<a-col class="m-5 options">
<a-checkbox value="1">执行</a-checkbox>
</a-col>
</a-row>
</a-checkbox-group>
</div>
<a-checkbox v-model:checked="permission.deep">应用到子目录</a-checkbox>
</a-spin>
</a-space>
</a-modal>
<FileEditor ref="FileEditorDialog" />
@ -482,4 +541,22 @@ onMounted(() => {
background-color: var(--color-gray-4);
}
}
.permission {
.son {
border: 1px solid #dcdfe6;
border-radius: 10px;
padding: 10px 20px;
box-shadow: inset 0 0 0 1px #00000010;
}
}
@media (max-width: 350px) {
.permission {
flex-direction: column;
.son {
width: 100%;
}
}
}
</style>