1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-02-09 10:00:06 +08:00

573 lines
19 KiB
Vue
Raw Normal View History

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">
2022-09-03 18:41:52 +08:00
<el-scrollbar height="80vh">
2022-08-24 17:34:21 +08:00
<el-tree
:data="fileTree"
:props="defaultProps"
:load="loadNode"
lazy
v-loading="treeLoading"
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">
<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"
>
2022-09-09 11:20:02 +08:00
{{ 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"
@search="search"
2022-08-24 11:10:50 +08:00
>
2022-08-19 16:02:58 +08:00
<template #toolbar>
<el-dropdown @command="handleCreate">
<el-button type="primary" icon="Plus">
2022-09-09 11:20:02 +08:00
{{ $t('commons.button.create') }}
<el-icon class="el-icon--right"><arrow-down /></el-icon>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item command="dir">
<svg-icon iconName="p-file-folder"></svg-icon>
{{ $t('file.dir') }}
</el-dropdown-item>
<el-dropdown-item command="file">
<svg-icon iconName="p-file-normal"></svg-icon>
{{ $t('file.file') }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
2022-09-09 11:20:02 +08:00
<el-button-group style="margin-left: 5px">
<el-button plain @click="openUpload">{{ $t('file.upload') }}</el-button>
2022-09-09 11:20:02 +08:00
<!-- <el-button type="primary" plain> {{ $t('file.search') }}</el-button> -->
<el-button plain @click="openWget">{{ $t('file.remoteFile') }}</el-button>
<el-button plain @click="openMove('copy')" :disabled="selects.length === 0">
2022-09-09 11:20:02 +08:00
{{ $t('file.copy') }}
</el-button>
<el-button plain @click="openMove('cut')" :disabled="selects.length === 0">
2022-09-09 11:20:02 +08:00
{{ $t('file.move') }}
</el-button>
<el-button plain @click="openCompress(selects)" :disabled="selects.length === 0">
2022-09-09 11:20:02 +08:00
{{ $t('file.compress') }}
</el-button>
<el-button plain @click="openDownload" :disabled="selects.length === 0">
2022-09-09 11:20:02 +08:00
{{ $t('file.download') }}
</el-button>
</el-button-group>
2022-08-19 16:02:58 +08:00
</template>
2022-09-06 10:35:35 +08:00
<el-table-column type="selection" width="55" />
<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>
2022-09-09 18:27:50 +08:00
<svg-icon v-else className="table-icon" :iconName="getIconName(row.extension)"></svg-icon>
<el-link :underline="false" @click="open(row)">{{ row.name }}</el-link>
2022-09-09 11:20:02 +08:00
<span v-if="row.isSymlink">-> {{ row.linkPath }}</span>
2022-08-19 16:02:58 +08:00
</template>
</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>
2022-09-09 11:20:02 +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>
<el-table-column :label="$t('file.size')" prop="size">
<template #default="{ row }">
<span v-if="row.isDir">
<el-button type="primary" link small @click="getDirSize(row)">
<span v-if="row.dirSize == undefined">
{{ $t('file.calculate') }}
</span>
<span v-else>{{ getFileSize(row.dirSize) }}</span>
</el-button>
</span>
<span v-else>{{ getFileSize(row.size) }}</span>
</template>
</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-09-03 18:41:52 +08:00
show-overflow-tooltip
2022-09-09 11:20:02 +08:00
></el-table-column>
2022-08-19 16:02:58 +08:00
<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-09-01 19:02:33 +08:00
<CodeEditor
:open="editorPage.open"
:language="'json'"
:content="editorPage.content"
2022-09-03 18:41:52 +08:00
:loading="editorPage.loading"
2022-09-01 19:02:33 +08:00
@close="closeCodeEditor"
2022-09-03 18:41:52 +08:00
@qsave="quickSave"
2022-09-01 19:02:33 +08:00
@save="saveContent"
></CodeEditor>
2022-09-03 22:22:40 +08:00
<FileRename
:open="renamePage.open"
:path="renamePage.path"
:oldName="renamePage.oldName"
@close="closeRename"
></FileRename>
2022-09-03 18:41:52 +08:00
<Upload :open="uploadPage.open" :path="uploadPage.path" @close="closeUpload"></Upload>
2022-09-06 17:48:49 +08:00
<Wget :open="wgetPage.open" :path="wgetPage.path" @close="closeWget"></Wget>
2022-09-06 10:35:35 +08:00
<Move :open="movePage.open" :oldPaths="movePage.oldPaths" :type="movePage.type" @close="clodeMove"></Move>
2022-09-06 17:48:49 +08:00
<Download
:open="downloadPage.open"
:paths="downloadPage.paths"
:name="downloadPage.name"
@close="closeDownload"
></Download>
2022-09-14 19:09:39 +08:00
<Process :open="processPage.open" @close="closeProcess"></Process>
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';
import {
GetFilesList,
GetFilesTree,
DeleteFile,
GetFileContent,
SaveFileContent,
ComputeDirSize,
} from '@/api/modules/files';
2022-09-09 18:27:50 +08:00
import { computeSize, dateFromat, getIcon, getRandomStr } from '@/utils/util';
2022-09-06 17:48:49 +08:00
import { File } from '@/api/interface/file';
import { useDeleteData } from '@/hooks/use-delete-data';
import { ElMessage } from 'element-plus';
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';
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-09-03 18:41:52 +08:00
import Upload from './upload/index.vue';
2022-09-06 10:35:35 +08:00
import FileRename from './rename/index.vue';
2022-09-01 19:02:33 +08:00
import CodeEditor from './code-editor/index.vue';
2022-09-06 17:48:49 +08:00
import Wget from './wget/index.vue';
2022-09-06 10:35:35 +08:00
import Move from './move/index.vue';
2022-09-06 17:48:49 +08:00
import Download from './download/index.vue';
2022-09-09 18:39:56 +08:00
import { Mimetypes } from '@/global/mimetype';
2022-09-14 19:09:39 +08:00
import Process from './process/index.vue';
2022-08-24 17:34:21 +08:00
2022-09-06 17:48:49 +08:00
const data = ref();
let selects = ref<any>([]);
2022-09-15 10:44:43 +08:00
let req = reactive({ path: '/', expand: true, showHidden: false, page: 1, pageSize: 100 });
let loading = ref(false);
let treeLoading = ref(false);
2022-09-06 17:48:49 +08:00
const paths = ref<string[]>([]);
const fileTree = ref<File.FileTree[]>([]);
const expandKeys = ref<string[]>([]);
2022-08-24 17:34:21 +08:00
2022-09-03 22:22:40 +08:00
const filePage = reactive({ open: false, createForm: { path: '/', isDir: false, mode: 0o755 } });
const modePage = reactive({ open: false, modeForm: { path: '/', isDir: false, mode: 0o755 } });
const compressPage = reactive({ open: false, files: [''], name: '', dst: '' });
const deCompressPage = reactive({ open: false, path: '', name: '', dst: '', mimeType: '' });
const editorPage = reactive({ open: false, content: '', loading: false });
2022-09-15 10:44:43 +08:00
const codeReq = reactive({ path: '', expand: false, page: 1, pageSize: 100 });
2022-09-03 18:41:52 +08:00
const uploadPage = reactive({ open: false, path: '' });
2022-09-03 22:22:40 +08:00
const renamePage = reactive({ open: false, path: '', oldName: '' });
2022-09-06 17:48:49 +08:00
const wgetPage = reactive({ open: false, path: '' });
2022-09-06 10:35:35 +08:00
const movePage = reactive({ open: false, oldPaths: [''], type: '' });
2022-09-06 17:48:49 +08:00
const downloadPage = reactive({ open: false, paths: [''], name: '' });
2022-09-14 19:09:39 +08:00
const processPage = reactive({ open: false });
2022-08-30 17:59:59 +08:00
2022-08-24 17:34:21 +08:00
const defaultProps = {
children: 'children',
label: 'name',
id: 'id',
2022-08-24 17:34:21 +08:00
};
2022-08-19 16:02:58 +08:00
const paginationConfig = reactive({
currentPage: 1,
2022-09-15 10:44:43 +08:00
pageSize: 100,
2022-08-19 16:02:58 +08:00
total: 0,
});
const search = async () => {
2022-08-24 11:10:50 +08:00
loading.value = true;
req.page = paginationConfig.currentPage;
2022-09-15 10:44:43 +08:00
req.pageSize = paginationConfig.pageSize;
2022-08-24 17:34:21 +08:00
await GetFilesList(req)
2022-08-24 11:10:50 +08:00
.then((res) => {
2022-09-15 10:44:43 +08:00
paginationConfig.total = res.data.itemTotal;
2022-08-24 11:10:50 +08:00
data.value = res.data.items;
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;
});
};
const open = async (row: File.File) => {
if (row.isDir) {
const name = row.name;
paths.value.push(name);
2022-09-01 19:02:33 +08:00
if (req.path.endsWith('/')) {
req.path = req.path + name;
} else {
req.path = req.path + '/' + name;
}
search();
2022-09-01 19:02:33 +08:00
} else {
openCodeEditor(row);
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) {
2022-09-06 17:48:49 +08:00
if (path.endsWith('/')) {
path = path + jPaths[i];
} else {
path = path + '/' + jPaths[i];
}
2022-08-24 11:10:50 +08:00
}
}
req.path = path;
search();
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;
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();
2022-08-25 18:48:03 +08:00
}
};
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) => {
await useDeleteData(DeleteFile, row as File.FileDelete, 'commons.msg.delete', loading.value);
search();
2022-08-25 18:48:03 +08:00
};
const getFileSize = (size: number) => {
return computeSize(size);
};
const getDirSize = async (row: any) => {
const req = {
path: row.path,
};
loading.value = true;
await ComputeDirSize(req)
.then(async (res) => {
row.dirSize = res.data.size;
})
.finally(() => {
loading.value = false;
});
};
2022-09-09 18:27:50 +08:00
const getIconName = (extension: string) => {
return getIcon(extension);
};
const closeCreate = () => {
2022-08-31 13:59:02 +08:00
filePage.open = false;
search();
2022-08-25 17:54:52 +08:00
};
const openMode = (item: File.File) => {
2022-08-31 13:59:02 +08:00
modePage.modeForm = item;
modePage.open = true;
};
const closeMode = () => {
2022-08-31 13:59:02 +08:00
modePage.open = false;
search();
};
2022-09-06 17:48:49 +08:00
const openCompress = (items: File.File[]) => {
2022-08-30 17:59:59 +08:00
compressPage.open = true;
2022-09-06 17:48:49 +08:00
const paths = [];
for (const item of items) {
paths.push(item.path);
}
compressPage.files = paths;
if (paths.length === 1) {
compressPage.name = items[0].name;
} else {
compressPage.name = getRandomStr(6);
}
2022-08-30 17:59:59 +08:00
compressPage.dst = req.path;
};
const closeCompress = () => {
compressPage.open = false;
search();
2022-08-30 17:59:59 +08:00
};
2022-08-31 13:59:02 +08:00
const openDeCompress = (item: File.File) => {
2022-09-09 18:39:56 +08:00
if (Mimetypes.get(item.mimeType) == undefined) {
ElMessage.warning(i18n.global.t('file.canNotDeCompress'));
return;
}
2022-08-31 13:59:02 +08:00
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();
2022-08-31 13:59:02 +08:00
};
2022-09-01 19:02:33 +08:00
const openCodeEditor = (row: File.File) => {
codeReq.path = row.path;
codeReq.expand = true;
GetFileContent(codeReq).then((res) => {
editorPage.content = res.data.content;
});
editorPage.open = true;
};
const closeCodeEditor = () => {
editorPage.open = false;
};
2022-09-03 18:41:52 +08:00
const openUpload = () => {
uploadPage.open = true;
uploadPage.path = req.path;
};
const closeUpload = () => {
uploadPage.open = false;
search();
2022-09-03 18:41:52 +08:00
};
2022-09-06 17:48:49 +08:00
const openWget = () => {
wgetPage.open = true;
wgetPage.path = req.path;
2022-09-05 16:25:26 +08:00
};
2022-09-14 19:09:39 +08:00
const closeWget = (submit: any) => {
console.log(submit);
2022-09-06 17:48:49 +08:00
wgetPage.open = false;
search();
2022-09-14 19:09:39 +08:00
if (submit) {
openProcess();
}
};
const openProcess = () => {
processPage.open = true;
};
const closeProcess = () => {
processPage.open = false;
2022-09-05 16:25:26 +08:00
};
2022-09-03 22:22:40 +08:00
const openRename = (item: File.File) => {
renamePage.open = true;
renamePage.path = req.path;
renamePage.oldName = item.name;
};
const closeRename = () => {
renamePage.open = false;
search();
2022-09-03 22:22:40 +08:00
};
2022-09-06 10:35:35 +08:00
const openMove = (type: string) => {
movePage.type = type;
const oldpaths = [];
for (const s of selects.value) {
oldpaths.push(s['path']);
}
movePage.oldPaths = oldpaths;
2022-09-06 17:48:49 +08:00
movePage.open = true;
2022-09-06 10:35:35 +08:00
};
const clodeMove = () => {
movePage.open = false;
search();
2022-09-06 10:35:35 +08:00
};
2022-09-06 17:48:49 +08:00
const openDownload = () => {
const paths = [];
for (const s of selects.value) {
paths.push(s['path']);
}
downloadPage.paths = paths;
downloadPage.name = getRandomStr(6);
downloadPage.open = true;
};
const closeDownload = () => {
downloadPage.open = false;
search();
2022-09-06 17:48:49 +08:00
};
2022-09-01 19:02:33 +08:00
const saveContent = (content: string) => {
2022-09-03 18:41:52 +08:00
editorPage.loading = true;
SaveFileContent({ path: codeReq.path, content: content }).finally(() => {
editorPage.loading = false;
2022-09-01 19:02:33 +08:00
editorPage.open = false;
2022-09-03 18:41:52 +08:00
ElMessage.success(i18n.global.t('commons.msg.updateSuccess'));
});
};
const quickSave = (content: string) => {
editorPage.loading = true;
SaveFileContent({ path: codeReq.path, content: content }).finally(() => {
editorPage.loading = false;
ElMessage.success(i18n.global.t('commons.msg.updateSuccess'));
2022-09-01 19:02:33 +08:00
});
};
2022-08-25 18:48:03 +08:00
onMounted(() => {
search();
2022-08-25 18:48:03 +08:00
});
2022-08-31 13:59:02 +08:00
//TODO button增加v-if判断
//openDeCompress 增加是否可以解压判断
const buttons = [
{
label: i18n.global.t('file.open'),
click: open,
},
{
label: i18n.global.t('file.mode'),
click: openMode,
},
{
2022-08-31 13:59:02 +08:00
label: i18n.global.t('file.compress'),
2022-09-06 17:48:49 +08:00
click: (row: File.File) => {
openCompress([row]);
},
},
2022-08-31 13:59:02 +08:00
{
label: i18n.global.t('file.deCompress'),
click: openDeCompress,
2022-09-09 18:39:56 +08:00
disabled: (row: File.File) => {
return row.isDir;
},
2022-08-31 13:59:02 +08:00
},
{
label: i18n.global.t('file.rename'),
2022-09-03 22:22:40 +08:00
click: openRename,
},
{
label: i18n.global.t('commons.button.delete'),
2022-08-25 18:48:03 +08:00
click: delFile,
},
{
label: i18n.global.t('file.info'),
},
];
2022-08-19 16:02:58 +08:00
</script>
<style>
.path {
height: 30px;
margin-bottom: 5px;
}
</style>