feat: 文件管理页面

pull/18/head^2
zhengkunwang223 2022-08-19 16:02:58 +08:00
parent 2964f83d68
commit 07af78758f
13 changed files with 10598 additions and 205 deletions

10462
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -25,9 +25,9 @@
"axios": "^0.27.2",
"echarts": "^5.3.0",
"echarts-liquidfill": "^3.1.0",
"element-plus": "^2.2.6",
"fit2cloud-ui-plus": "^0.0.1-beta.12",
"js-base64": "^3.7.2",
"element-plus": "^2.2.13",
"fit2cloud-ui-plus": "^0.0.1-beta.15",
"js-md5": "^0.7.3",
"nprogress": "^0.2.0",
"pinia": "^2.0.12",

View File

@ -0,0 +1,16 @@
import { CommonModel } from '.';
export namespace File {
export interface File extends CommonModel {
name: string;
mode: number;
user: string;
group: string;
updateDate: string;
isDir: boolean;
isLink: boolean;
path: string;
size: number;
accessTime: string;
changeTime: string;
}
}

View File

@ -0,0 +1,26 @@
{
"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

@ -0,0 +1,7 @@
// import { File } from '@/api/interface/file';
import files from '@/api/interface/files.json';
export const GetFilesList = () => {
// return http.post<Login.ResLogin>(`/auth/login`, params);
return files;
};

View File

@ -43,4 +43,11 @@ const svgClass = computed(() => {
padding-left: 0.3em;
padding-right: 0.3em;
}
.table-icon {
width: 1.5em;
height: 1.5em;
position: relative;
fill: currentColor;
vertical-align: middle;
}
</style>

View File

@ -1,6 +1,7 @@
export default {
commons: {
button: {
create: '',
create: '',
add: '',
delete: '',
@ -151,4 +152,27 @@ export default {
request: '',
response: '',
},
file: {
dir: '',
upload: '',
download: '',
fileName: '',
search: '',
mode: '',
owner: '',
file: '',
remoteFile: '',
share: '',
sync: '',
size: '',
updateTime: '',
open: '',
rename: '',
role: '',
info: '',
linkFile: '',
terminal: '',
shareList: '',
zip: '',
},
};

View File

@ -9,7 +9,7 @@
:header="header"
v-if="showBack"
></back-button>
{{ header }}
<span v-else> {{ header }}</span>
</slot>
</div>
<div class="content-container__toolbar" v-if="slots.toolbar">

View File

@ -7,10 +7,11 @@ import '@/assets/iconfont/iconfont.js';
import ElementPlus from 'element-plus';
import Fit2CloudPlus from 'fit2cloud-ui-plus';
import * as Icons from '@element-plus/icons-vue';
import 'element-plus/dist/index.css';
import 'element-plus/theme-chalk/dark/css-vars.css';
import '@/styles/element-dark.scss';
import '@/styles/element.scss';
import 'element-plus/dist/index.css';
import 'element-plus/theme-chalk/dark/css-vars.css';
import 'fit2cloud-ui-plus/src/styles/index.scss';
import directives from '@/directives/index';
import router from '@/routers/index';
import I18n from '@/lang/index';

View File

@ -140,6 +140,20 @@ html.dark {
}
}
.el-table {
--el-table-border-color: #696969;
//fit2cloud-ui
--el-table-text-color: #cfcfcf;
// $table-header-bgColor: #f5f6f7 !default;
.fu-table-header th {
border-top: 1px solid var(--el-table-border-color);
font-weight: 500 !important;
color: var(--el-text-color-regular) !important;
background-color: var(--el-bg-color) !important;
}
}
// el-drawer
.el-drawer {
.el-drawer__header {

View File

@ -189,4 +189,4 @@
margin-right: 20px;
border: 0;
// box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
}
}

View File

@ -1,5 +1,190 @@
<template>
<LayoutContent></LayoutContent>
<LayoutContent :header="$t('menu.files')">
<el-row :gutter="20">
<el-col :span="6">
<el-tree :data="dataSource" show-checkbox node-key="id">
<template #default="{ node }">
<el-icon v-if="node.data.isDir && node.expanded"><FolderOpened /></el-icon>
<el-icon v-if="node.data.isDir && !node.expanded"><Folder /></el-icon>
<el-icon v-if="!node.data.isDir"><Document /></el-icon>
<span class="custom-tree-node">
<span>{{ node.data.label }}</span>
</span>
</template>
</el-tree>
</el-col>
<el-col :span="18">
<div class="path">
<el-breadcrumb class="child" :separator-icon="ArrowRight">
<el-breadcrumb-item>root</el-breadcrumb-item>
<el-breadcrumb-item>var</el-breadcrumb-item>
<el-breadcrumb-item>log</el-breadcrumb-item>
</el-breadcrumb>
</div>
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data">
<template #toolbar>
<el-dropdown split-button type="primary">
{{ $t('commons.button.create') }}
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item>
<svg-icon iconName="p-file-folder"></svg-icon>{{ $t('file.dir') }}
</el-dropdown-item>
<el-dropdown-item>
<svg-icon iconName="p-file-normal"></svg-icon>{{ $t('file.file') }}
</el-dropdown-item>
<el-dropdown-item>
<svg-icon iconName="p-file-normal"></svg-icon>{{ $t('file.linkFile') }}
</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>
<el-table-column :label="$t('commons.table.name')" min-width="120" fix>
<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">{{ 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.owner')" prop="user"> </el-table-column>
<el-table-column :label="$t('file.size')" prop="size"> </el-table-column>
<el-table-column :label="$t('file.updateTime')" prop="updateTime" :formatter="dateFromat">
</el-table-column>
<fu-table-operations
min-width="300"
:ellipsis="4"
:buttons="buttons"
:label="$t('commons.table.operate')"
fixed="right"
fix
/>
</ComplexTable>
</el-col>
</el-row>
</LayoutContent>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { onMounted, reactive, ref } from '@vue/runtime-core';
import LayoutContent from '@/layout/layout-content.vue';
import ComplexTable from '@/components/complex-table/index.vue';
import i18n from '@/lang';
import { GetFilesList } from '@/api/modules/files';
import { dateFromat } from '@/utils/util';
import { ArrowRight } from '@element-plus/icons-vue';
interface Tree {
id: number;
label: string;
isDir: Boolean;
children?: Tree[];
}
let data = ref();
let selects = ref<any>([]);
const paginationConfig = reactive({
page: 1,
pageSize: 5,
total: 0,
});
const buttons = [
{
label: i18n.global.t('file.open'),
},
{
label: i18n.global.t('file.mode'),
},
{
label: i18n.global.t('file.zip'),
},
{
label: i18n.global.t('file.rename'),
},
{
label: i18n.global.t('commons.button.delete'),
},
{
label: i18n.global.t('file.info'),
},
];
const search = async () => {
const res = await GetFilesList();
data.value = res.data.items;
paginationConfig.total = res.data.total;
};
const dataSource = ref<Tree[]>([
{
id: 1,
label: 'var',
isDir: true,
children: [
{
id: 4,
label: 'log',
isDir: true,
children: [
{
id: 9,
isDir: false,
label: 'ko.log',
},
{
id: 10,
isDir: false,
label: 'kubepi.log',
},
],
},
],
},
{
id: 2,
label: 'opt',
isDir: true,
children: [
{
id: 5,
isDir: false,
label: 'app.conf',
},
{
id: 6,
isDir: false,
label: 'test.txt',
},
],
},
]);
onMounted(() => {
search();
});
</script>
<style>
.path {
margin-top: -50px;
height: 30px;
width: 800px;
background-color: #f1f1f1;
margin-bottom: 5px;
border: 1px solid #e8e8e8;
}
.child {
position: relative;
top: 50%;
transform: translateY(-50%);
width: 80%;
}
</style>

View File

@ -8,10 +8,7 @@ import viteCompression from 'vite-plugin-compression';
import VueSetupExtend from 'vite-plugin-vue-setup-extend';
import eslintPlugin from 'vite-plugin-eslint';
import vueJsx from '@vitejs/plugin-vue-jsx';
import importToCDN from 'vite-plugin-cdn-import';
// import AutoImport from "unplugin-auto-import/vite";
// import Components from "unplugin-vue-components/vite";
// import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
import DefineOptions from 'unplugin-vue-define-options/vite';
// @see: https://vitejs.dev/config/
@ -59,37 +56,14 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
}),
DefineOptions(),
// * EsLint 报错信息显示在浏览器界面上
eslintPlugin(),
eslintPlugin({
exclude: ['**/*.js'],
}),
// * vite 可以使用 jsx/tsx 语法
vueJsx(),
// * name 可以写在 script 标签上
VueSetupExtend(),
// * demand import element(如果使用了cdn引入,没必要使用element自动导入了)
// AutoImport({
// resolvers: [ElementPlusResolver()]
// }),
// Components({
// resolvers: [ElementPlusResolver()]
// }),
// * cdn 引入vue、element-plus
importToCDN({
modules: [
// vue按需引入会导致依赖vue的插件出现问题(列如:pinia/vuex)
// {
// name: "vue",
// var: "Vue",
// path: "https://unpkg.com/vue@next"
// },
// 使用cdn引入element-plus时,开发环境还是需要在main.js中引入element-plus,可以不用引入css
// {
// name: "element-plus",
// var: "ElementPlus",
// path: "https://unpkg.com/element-plus",
// css: "https://unpkg.com/element-plus/dist/index.css"
// }
],
}),
// * 是否生成包预览
viteEnv.VITE_REPORT && visualizer(),
// * gzip compress
viteEnv.VITE_BUILD_GZIP &&
@ -104,18 +78,9 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
esbuild: {
pure: viteEnv.VITE_DROP_CONSOLE ? ['console.log', 'debugger'] : [],
},
// build configure
build: {
outDir: 'dist',
// esbuild 打包更快,但是不能去除 console.log
minify: 'esbuild',
// minify: "terser",
// terserOptions: {
// compress: {
// drop_console: viteEnv.VITE_DROP_CONSOLE,
// drop_debugger: true
// }
// },
rollupOptions: {
output: {
// Static resource classification and packaging