2022-08-17 17:46:49 +08:00
|
|
|
<template>
|
2022-08-30 17:59:59 +08:00
|
|
|
<LayoutContent>
|
2022-08-19 16:02:58 +08:00
|
|
|
<el-row :gutter="20">
|
2022-08-24 17:34:21 +08:00
|
|
|
<el-col :span="5">
|
|
|
|
<el-scrollbar height="800px">
|
|
|
|
<el-tree
|
|
|
|
:data="fileTree"
|
|
|
|
:props="defaultProps"
|
|
|
|
:load="loadNode"
|
|
|
|
lazy
|
|
|
|
v-loading="treeLoading"
|
2022-08-24 17:58:58 +08:00
|
|
|
node-key="id"
|
|
|
|
:default-expanded-keys="expandKeys"
|
2022-08-25 18:48:03 +08:00
|
|
|
@node-click="clickNode"
|
2022-08-24 17:34:21 +08:00
|
|
|
>
|
|
|
|
<template #default="{ node }">
|
|
|
|
<el-icon v-if="node.expanded"><FolderOpened /></el-icon>
|
|
|
|
<el-icon v-else><Folder /></el-icon>
|
|
|
|
<span class="custom-tree-node">
|
|
|
|
<span>{{ node.data.name }}</span>
|
|
|
|
</span>
|
|
|
|
</template>
|
|
|
|
</el-tree>
|
|
|
|
</el-scrollbar>
|
2022-08-19 16:02:58 +08:00
|
|
|
</el-col>
|
2022-08-24 17:34:21 +08:00
|
|
|
|
|
|
|
<el-col :span="19">
|
2022-08-19 16:02:58 +08:00
|
|
|
<div class="path">
|
2022-08-24 15:33:38 +08:00
|
|
|
<BreadCrumbs>
|
|
|
|
<BreadCrumbItem @click="jump(-1)" :right="paths.length == 0">root</BreadCrumbItem>
|
|
|
|
<BreadCrumbItem
|
|
|
|
v-for="(item, key) in paths"
|
|
|
|
:key="key"
|
|
|
|
@click="jump(key)"
|
|
|
|
:right="key == paths.length - 1"
|
|
|
|
>{{ item }}</BreadCrumbItem
|
|
|
|
>
|
|
|
|
</BreadCrumbs>
|
2022-08-19 16:02:58 +08:00
|
|
|
</div>
|
2022-08-24 11:10:50 +08:00
|
|
|
<ComplexTable
|
|
|
|
:pagination-config="paginationConfig"
|
|
|
|
v-model:selects="selects"
|
|
|
|
:data="data"
|
2022-08-24 17:34:21 +08:00
|
|
|
v-loading="loading"
|
2022-08-24 11:10:50 +08:00
|
|
|
>
|
2022-08-19 16:02:58 +08:00
|
|
|
<template #toolbar>
|
2022-08-25 17:54:52 +08:00
|
|
|
<el-dropdown split-button type="primary" @command="handleCreate">
|
2022-08-19 16:02:58 +08:00
|
|
|
{{ $t('commons.button.create') }}
|
|
|
|
<template #dropdown>
|
|
|
|
<el-dropdown-menu>
|
2022-08-25 17:54:52 +08:00
|
|
|
<el-dropdown-item command="dir">
|
2022-08-19 16:02:58 +08:00
|
|
|
<svg-icon iconName="p-file-folder"></svg-icon>{{ $t('file.dir') }}
|
|
|
|
</el-dropdown-item>
|
2022-08-25 17:54:52 +08:00
|
|
|
<el-dropdown-item command="file">
|
2022-08-19 16:02:58 +08:00
|
|
|
<svg-icon iconName="p-file-normal"></svg-icon>{{ $t('file.file') }}
|
|
|
|
</el-dropdown-item>
|
|
|
|
</el-dropdown-menu>
|
|
|
|
</template>
|
|
|
|
</el-dropdown>
|
|
|
|
<el-button type="primary" plain> {{ $t('file.upload') }}</el-button>
|
|
|
|
<el-button type="primary" plain> {{ $t('file.search') }}</el-button>
|
|
|
|
<el-button type="primary" plain> {{ $t('file.remoteFile') }}</el-button>
|
|
|
|
<el-button type="primary" plain> {{ $t('file.sync') }}</el-button>
|
|
|
|
<el-button type="primary" plain> {{ $t('file.terminal') }}</el-button>
|
|
|
|
<el-button type="primary" plain> {{ $t('file.shareList') }}</el-button>
|
|
|
|
</template>
|
2022-08-31 16:00:51 +08:00
|
|
|
<el-table-column :label="$t('commons.table.name')" min-width="250" fix show-overflow-tooltip>
|
2022-08-19 16:02:58 +08:00
|
|
|
<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>
|
2022-08-24 17:58:58 +08:00
|
|
|
<el-link :underline="false" @click="open(row)">{{ row.name }}</el-link>
|
2022-08-31 16:00:51 +08:00
|
|
|
<span v-if="row.isSymlink"> -> {{ row.linkPath }}</span>
|
2022-08-19 16:02:58 +08:00
|
|
|
</template>
|
|
|
|
</el-table-column>
|
2022-08-29 15:26:36 +08:00
|
|
|
<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>
|
2022-08-24 11:10:50 +08:00
|
|
|
<el-table-column :label="$t('file.user')" prop="user"> </el-table-column>
|
|
|
|
<el-table-column :label="$t('file.group')" prop="group"> </el-table-column>
|
2022-08-19 16:02:58 +08:00
|
|
|
<el-table-column :label="$t('file.size')" prop="size"> </el-table-column>
|
2022-08-24 11:10:50 +08:00
|
|
|
<el-table-column
|
|
|
|
:label="$t('file.updateTime')"
|
|
|
|
prop="modTime"
|
|
|
|
:formatter="dateFromat"
|
2022-08-25 18:48:03 +08:00
|
|
|
min-width="100"
|
2022-08-24 11:10:50 +08:00
|
|
|
>
|
2022-08-19 16:02:58 +08:00
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<fu-table-operations
|
2022-08-24 11:10:50 +08:00
|
|
|
:ellipsis="1"
|
2022-08-19 16:02:58 +08:00
|
|
|
:buttons="buttons"
|
|
|
|
:label="$t('commons.table.operate')"
|
|
|
|
fixed="right"
|
|
|
|
fix
|
|
|
|
/>
|
|
|
|
</ComplexTable>
|
|
|
|
</el-col>
|
2022-08-31 13:59:02 +08:00
|
|
|
<CreateFile :open="filePage.open" :file="filePage.createForm" @close="closeCreate"></CreateFile>
|
|
|
|
<ChangeRole :open="modePage.open" :file="modePage.modeForm" @close="closeMode"></ChangeRole>
|
2022-08-30 17:59:59 +08:00
|
|
|
<Compress
|
|
|
|
:open="compressPage.open"
|
|
|
|
:files="compressPage.files"
|
|
|
|
:dst="compressPage.dst"
|
|
|
|
:name="compressPage.name"
|
|
|
|
@close="closeCompress"
|
|
|
|
></Compress>
|
2022-08-31 13:59:02 +08:00
|
|
|
<Decompress
|
|
|
|
:open="deCompressPage.open"
|
|
|
|
:dst="deCompressPage.dst"
|
|
|
|
:path="deCompressPage.path"
|
|
|
|
:name="deCompressPage.name"
|
|
|
|
:mimeType="deCompressPage.mimeType"
|
|
|
|
@close="closeDeCompress"
|
|
|
|
></Decompress>
|
2022-08-19 16:02:58 +08:00
|
|
|
</el-row>
|
|
|
|
</LayoutContent>
|
2022-08-17 17:46:49 +08:00
|
|
|
</template>
|
|
|
|
|
2022-08-19 16:02:58 +08:00
|
|
|
<script setup lang="ts">
|
2022-08-25 18:48:03 +08:00
|
|
|
import { onMounted, reactive, ref } from '@vue/runtime-core';
|
2022-08-19 16:02:58 +08:00
|
|
|
import LayoutContent from '@/layout/layout-content.vue';
|
|
|
|
import ComplexTable from '@/components/complex-table/index.vue';
|
|
|
|
import i18n from '@/lang';
|
2022-08-25 18:48:03 +08:00
|
|
|
import { GetFilesList, GetFilesTree, DeleteFile } from '@/api/modules/files';
|
2022-08-19 16:02:58 +08:00
|
|
|
import { dateFromat } from '@/utils/util';
|
2022-08-24 11:10:50 +08:00
|
|
|
import { File } from '@/api/interface/file';
|
2022-08-24 15:33:38 +08:00
|
|
|
import BreadCrumbs from '@/components/bread-crumbs/index.vue';
|
|
|
|
import BreadCrumbItem from '@/components/bread-crumbs/bread-crumbs-item.vue';
|
2022-08-31 13:59:02 +08:00
|
|
|
import CreateFile from './create/index.vue';
|
|
|
|
import ChangeRole from './change-role/index.vue';
|
|
|
|
import Compress from './compress/index.vue';
|
|
|
|
import Decompress from './decompress/index.vue';
|
2022-08-25 18:48:03 +08:00
|
|
|
import { useDeleteData } from '@/hooks/use-delete-data';
|
2022-08-24 17:34:21 +08:00
|
|
|
|
2022-08-19 16:02:58 +08:00
|
|
|
let data = ref();
|
|
|
|
let selects = ref<any>([]);
|
2022-08-24 11:10:50 +08:00
|
|
|
let req = reactive({ path: '/', expand: true });
|
2022-08-30 17:59:59 +08:00
|
|
|
let loading = ref(false);
|
|
|
|
let treeLoading = ref(false);
|
2022-08-24 11:10:50 +08:00
|
|
|
let paths = ref<string[]>([]);
|
2022-08-24 17:34:21 +08:00
|
|
|
let fileTree = ref<File.FileTree[]>([]);
|
2022-08-24 17:58:58 +08:00
|
|
|
let expandKeys = ref<string[]>([]);
|
2022-08-24 17:34:21 +08:00
|
|
|
|
2022-08-31 13:59:02 +08:00
|
|
|
let filePage = reactive({ open: false, createForm: { path: '/', isDir: false, mode: 0o755 } });
|
|
|
|
let modePage = reactive({ open: false, modeForm: { path: '/', isDir: false, mode: 0o755 } });
|
2022-08-30 17:59:59 +08:00
|
|
|
let compressPage = reactive({ open: false, files: [''], name: '', dst: '' });
|
2022-08-31 13:59:02 +08:00
|
|
|
let deCompressPage = reactive({ open: false, path: '', name: '', dst: '', mimeType: '' });
|
2022-08-30 17:59:59 +08:00
|
|
|
|
2022-08-24 17:34:21 +08:00
|
|
|
const defaultProps = {
|
|
|
|
children: 'children',
|
|
|
|
label: 'name',
|
2022-08-24 17:58:58 +08:00
|
|
|
id: 'id',
|
2022-08-24 17:34:21 +08:00
|
|
|
};
|
|
|
|
|
2022-08-19 16:02:58 +08:00
|
|
|
const paginationConfig = reactive({
|
|
|
|
page: 1,
|
|
|
|
pageSize: 5,
|
|
|
|
total: 0,
|
|
|
|
});
|
|
|
|
|
2022-08-24 17:34:21 +08:00
|
|
|
const search = async (req: File.ReqFile) => {
|
2022-08-24 11:10:50 +08:00
|
|
|
loading.value = true;
|
2022-08-24 17:34:21 +08:00
|
|
|
await GetFilesList(req)
|
2022-08-24 11:10:50 +08:00
|
|
|
.then((res) => {
|
|
|
|
data.value = res.data.items;
|
2022-08-24 15:33:38 +08:00
|
|
|
req.path = res.data.path;
|
|
|
|
const pathArray = req.path.split('/');
|
|
|
|
paths.value = [];
|
|
|
|
for (const p of pathArray) {
|
|
|
|
if (p != '') {
|
|
|
|
paths.value.push(p);
|
|
|
|
}
|
|
|
|
}
|
2022-08-24 11:10:50 +08:00
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
loading.value = false;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2022-08-24 17:58:58 +08:00
|
|
|
const open = async (row: File.File) => {
|
|
|
|
if (row.isDir) {
|
|
|
|
const name = row.name;
|
|
|
|
paths.value.push(name);
|
|
|
|
if (req.path === '/') {
|
|
|
|
req.path = req.path + name;
|
|
|
|
} else {
|
|
|
|
req.path = req.path + '/' + name;
|
|
|
|
}
|
|
|
|
search(req);
|
2022-08-24 11:10:50 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const jump = async (index: number) => {
|
|
|
|
let path = '/';
|
|
|
|
if (index != -1) {
|
|
|
|
const jPaths = paths.value.slice(0, index + 1);
|
|
|
|
for (let i in jPaths) {
|
|
|
|
path = path + '/' + jPaths[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
req.path = path;
|
|
|
|
search(req);
|
2022-08-19 16:02:58 +08:00
|
|
|
};
|
|
|
|
|
2022-08-24 17:34:21 +08:00
|
|
|
const getTree = async (req: File.ReqFile, node: File.FileTree | null) => {
|
|
|
|
treeLoading.value = true;
|
|
|
|
await GetFilesTree(req)
|
|
|
|
.then((res) => {
|
|
|
|
if (node) {
|
|
|
|
if (res.data.length > 0) {
|
|
|
|
node.children = res.data[0].children;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fileTree.value = res.data;
|
2022-08-24 17:58:58 +08:00
|
|
|
expandKeys.value = [];
|
|
|
|
expandKeys.value.push(fileTree.value[0].id);
|
2022-08-24 17:34:21 +08:00
|
|
|
}
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
treeLoading.value = false;
|
|
|
|
});
|
|
|
|
};
|
2022-08-19 16:02:58 +08:00
|
|
|
|
2022-08-25 18:48:03 +08:00
|
|
|
const clickNode = async (node: any) => {
|
|
|
|
if (node.path) {
|
|
|
|
req.path = node.path;
|
|
|
|
search(req);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-08-24 17:34:21 +08:00
|
|
|
const loadNode = (node: any, resolve: (data: File.FileTree[]) => void) => {
|
|
|
|
if (!node.hasChildNodes) {
|
|
|
|
if (node.data.path) {
|
|
|
|
req.path = node.data.path;
|
|
|
|
getTree(req, node.data);
|
|
|
|
} else {
|
|
|
|
getTree(req, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
resolve([]);
|
|
|
|
};
|
2022-08-25 17:54:52 +08:00
|
|
|
|
|
|
|
const handleCreate = (commnad: string) => {
|
2022-08-31 13:59:02 +08:00
|
|
|
filePage.createForm.path = req.path;
|
|
|
|
filePage.createForm.isDir = false;
|
2022-08-25 17:54:52 +08:00
|
|
|
if (commnad === 'dir') {
|
2022-08-31 13:59:02 +08:00
|
|
|
filePage.createForm.isDir = true;
|
2022-08-25 17:54:52 +08:00
|
|
|
}
|
2022-08-31 13:59:02 +08:00
|
|
|
filePage.open = true;
|
2022-08-25 17:54:52 +08:00
|
|
|
};
|
|
|
|
|
2022-08-25 18:48:03 +08:00
|
|
|
const delFile = async (row: File.File | null) => {
|
2022-08-29 15:26:36 +08:00
|
|
|
await useDeleteData(DeleteFile, row as File.FileDelete, 'commons.msg.delete', loading.value);
|
2022-08-25 18:48:03 +08:00
|
|
|
search(req);
|
|
|
|
};
|
|
|
|
|
2022-08-29 15:26:36 +08:00
|
|
|
const closeCreate = () => {
|
2022-08-31 13:59:02 +08:00
|
|
|
filePage.open = false;
|
2022-08-25 17:54:52 +08:00
|
|
|
search(req);
|
|
|
|
};
|
|
|
|
|
2022-08-29 15:26:36 +08:00
|
|
|
const openMode = (item: File.File) => {
|
2022-08-31 13:59:02 +08:00
|
|
|
modePage.modeForm = item;
|
|
|
|
modePage.open = true;
|
2022-08-29 15:26:36 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
const closeMode = () => {
|
2022-08-31 13:59:02 +08:00
|
|
|
modePage.open = false;
|
2022-08-29 15:26:36 +08:00
|
|
|
search(req);
|
|
|
|
};
|
|
|
|
|
2022-08-30 17:59:59 +08:00
|
|
|
const openCompress = (item: File.File) => {
|
|
|
|
compressPage.open = true;
|
|
|
|
compressPage.files = [item.path];
|
|
|
|
compressPage.name = item.name;
|
|
|
|
compressPage.dst = req.path;
|
|
|
|
};
|
|
|
|
|
|
|
|
const closeCompress = () => {
|
|
|
|
compressPage.open = false;
|
|
|
|
search(req);
|
|
|
|
};
|
2022-08-31 13:59:02 +08:00
|
|
|
|
|
|
|
const openDeCompress = (item: File.File) => {
|
|
|
|
deCompressPage.open = true;
|
|
|
|
deCompressPage.name = item.name;
|
|
|
|
deCompressPage.path = item.path;
|
|
|
|
deCompressPage.dst = req.path;
|
|
|
|
deCompressPage.mimeType = item.mimeType;
|
|
|
|
};
|
|
|
|
|
|
|
|
const closeDeCompress = () => {
|
|
|
|
deCompressPage.open = false;
|
|
|
|
search(req);
|
|
|
|
};
|
|
|
|
|
2022-08-25 18:48:03 +08:00
|
|
|
onMounted(() => {
|
|
|
|
search(req);
|
|
|
|
});
|
|
|
|
|
2022-08-31 13:59:02 +08:00
|
|
|
//TODO button增加v-if判断
|
|
|
|
//openDeCompress 增加是否可以解压判断
|
2022-08-24 17:58:58 +08:00
|
|
|
const buttons = [
|
|
|
|
{
|
|
|
|
label: i18n.global.t('file.open'),
|
|
|
|
click: open,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: i18n.global.t('file.mode'),
|
2022-08-29 15:26:36 +08:00
|
|
|
click: openMode,
|
2022-08-24 17:58:58 +08:00
|
|
|
},
|
|
|
|
{
|
2022-08-31 13:59:02 +08:00
|
|
|
label: i18n.global.t('file.compress'),
|
2022-08-30 17:59:59 +08:00
|
|
|
click: openCompress,
|
2022-08-24 17:58:58 +08:00
|
|
|
},
|
2022-08-31 13:59:02 +08:00
|
|
|
{
|
|
|
|
label: i18n.global.t('file.deCompress'),
|
|
|
|
click: openDeCompress,
|
|
|
|
},
|
2022-08-24 17:58:58 +08:00
|
|
|
{
|
|
|
|
label: i18n.global.t('file.rename'),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
label: i18n.global.t('commons.button.delete'),
|
2022-08-25 18:48:03 +08:00
|
|
|
click: delFile,
|
2022-08-24 17:58:58 +08:00
|
|
|
},
|
|
|
|
{
|
|
|
|
label: i18n.global.t('file.info'),
|
|
|
|
},
|
|
|
|
];
|
2022-08-19 16:02:58 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<style>
|
|
|
|
.path {
|
|
|
|
height: 30px;
|
|
|
|
margin-bottom: 5px;
|
|
|
|
}
|
|
|
|
</style>
|