mirror of https://github.com/1Panel-dev/1Panel
feat: 文件管理页面
parent
2964f83d68
commit
07af78758f
File diff suppressed because it is too large
Load Diff
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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>
|
||||
|
|
|
@ -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: '压缩',
|
||||
},
|
||||
};
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -189,4 +189,4 @@
|
|||
margin-right: 20px;
|
||||
border: 0;
|
||||
// box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue