1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 16:29:17 +08:00

feat: 适配面包屑长度

This commit is contained in:
zhengkunwang223 2023-02-01 19:02:24 +08:00 committed by zhengkunwang223
parent 3c4dd6249a
commit eb046090a5
6 changed files with 213 additions and 145 deletions

View File

@ -10,6 +10,7 @@ declare module 'vue' {
AppLayout: typeof import('./src/components/app-layout/index.vue')['default'] AppLayout: typeof import('./src/components/app-layout/index.vue')['default']
AppStatus: typeof import('./src/components/app-status/index.vue')['default'] AppStatus: typeof import('./src/components/app-status/index.vue')['default']
BackButton: typeof import('./src/components/back-button/index.vue')['default'] BackButton: typeof import('./src/components/back-button/index.vue')['default']
Bread: typeof import('./src/components/bread-crumbs/bread.vue')['default']
BreadCrumbs: typeof import('./src/components/bread-crumbs/index.vue')['default'] BreadCrumbs: typeof import('./src/components/bread-crumbs/index.vue')['default']
BreadCrumbsItem: typeof import('./src/components/bread-crumbs/bread-crumbs-item.vue')['default'] BreadCrumbsItem: typeof import('./src/components/bread-crumbs/bread-crumbs-item.vue')['default']
CardWithHeader: typeof import('./src/components/card-with-header/index.vue')['default'] CardWithHeader: typeof import('./src/components/card-with-header/index.vue')['default']

View File

@ -1,12 +1,23 @@
<template> <template>
<div class="bread-crumbs-item"> <span class="bread-crumbs-item" ref="item">
<el-link><slot></slot></el-link> <el-link><slot></slot></el-link>
<i v-if="!props.right" :class="'panel p-arrow-right'"></i> <i v-if="!props.right" :class="'panel p-arrow-right'"></i>
</div> </span>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue';
const props = defineProps({ const props = defineProps({
right: Boolean, right: Boolean,
}); });
const item = ref();
defineExpose({ item });
</script> </script>
<style lang="scss" setup>
.bread-crumbs-item {
margin-top: 3px;
}
</style>

View File

@ -1,6 +1,12 @@
<template> <template>
<div class="bread-crumbs"><slot></slot></div> <span class="bread-crumbs" ref="bread"><slot></slot></span>
</template> </template>
<script lang="ts" setup>
import { ref } from 'vue';
const bread = ref();
defineExpose({ bread });
</script>
<style lang="scss"> <style lang="scss">
.bread-crumbs { .bread-crumbs {
display: flex; display: flex;

View File

@ -697,6 +697,7 @@ export default {
downloading: '正在下载...', downloading: '正在下载...',
infoDetail: '文件属性', infoDetail: '文件属性',
type: '类型', type: '类型',
root: '根目录',
}, },
setting: { setting: {
all: '全部', all: '全部',

View File

@ -50,6 +50,7 @@ let form = ref({
const em = defineEmits(['close']); const em = defineEmits(['close']);
const handleClose = () => { const handleClose = () => {
open.value = false;
if (editor) { if (editor) {
editor.dispose(); editor.dispose();
} }

View File

@ -1,24 +1,28 @@
<template> <template>
<div>
<el-row> <el-row>
<el-col :span="2"> <el-col :span="2">
<div> <div>
<el-button :icon="Back" @click="jump(paths.length - 2)" circle :disabled="paths.length == 0" /> <el-button
:icon="Back"
@click="jump(paths[paths.length - 2].url)"
circle
:disabled="paths.length == 0"
/>
<el-button :icon="Refresh" circle @click="search" /> <el-button :icon="Refresh" circle @click="search" />
</div> </div>
</el-col> </el-col>
<el-col :span="22"> <el-col :span="22">
<div class="path"> <div class="path" ref="pathRef">
<BreadCrumbs> <span ref="breadCrumbRef">
<BreadCrumbItem @click="jump(-1)" :right="paths.length == 0">/</BreadCrumbItem> <span class="root">
<BreadCrumbItem <el-link @click="jump('/')">{{ $t('file.root') }}</el-link>
v-for="(item, key) in paths" </span>
:key="key" <span v-for="item in paths" :key="item.url">
@click="jump(key)" <span class="split">></span>
:right="key == paths.length - 1" <el-link @click="jump(item.url)">{{ item.name }}</el-link>
> </span>
{{ item }} </span>
</BreadCrumbItem>
</BreadCrumbs>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -68,7 +72,12 @@
</div> --> </div> -->
</template> </template>
<template #main> <template #main>
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" :data="data" @search="search"> <ComplexTable
:pagination-config="paginationConfig"
v-model:selects="selects"
:data="data"
@search="search"
>
<el-table-column type="selection" width="55" /> <el-table-column type="selection" width="55" />
<el-table-column :label="$t('commons.table.name')" min-width="250" fix show-overflow-tooltip> <el-table-column :label="$t('commons.table.name')" min-width="250" fix show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
@ -129,10 +138,11 @@
<Process :open="processPage.open" @close="closeProcess" /> <Process :open="processPage.open" @close="closeProcess" />
<Detail ref="detailRef" /> <Detail ref="detailRef" />
</LayoutContent> </LayoutContent>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, reactive, ref } from '@vue/runtime-core'; import { nextTick, onMounted, reactive, ref } from '@vue/runtime-core';
import { GetFilesList, DeleteFile, GetFileContent, ComputeDirSize } from '@/api/modules/files'; import { GetFilesList, DeleteFile, GetFileContent, ComputeDirSize } from '@/api/modules/files';
import { computeSize, dateFormat, getIcon, getRandomStr } from '@/utils/util'; import { computeSize, dateFormat, getIcon, getRandomStr } from '@/utils/util';
import { File } from '@/api/interface/file'; import { File } from '@/api/interface/file';
@ -141,8 +151,6 @@ import { ElMessage } from 'element-plus';
import LayoutContent from '@/layout/layout-content.vue'; import LayoutContent from '@/layout/layout-content.vue';
import ComplexTable from '@/components/complex-table/index.vue'; import ComplexTable from '@/components/complex-table/index.vue';
import i18n from '@/lang'; import i18n from '@/lang';
import BreadCrumbs from '@/components/bread-crumbs/index.vue';
import BreadCrumbItem from '@/components/bread-crumbs/bread-crumbs-item.vue';
import CreateFile from './create/index.vue'; import CreateFile from './create/index.vue';
import ChangeRole from './change-role/index.vue'; import ChangeRole from './change-role/index.vue';
import Compress from './compress/index.vue'; import Compress from './compress/index.vue';
@ -159,12 +167,18 @@ import Detail from './detail/index.vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import { Back, Refresh } from '@element-plus/icons-vue'; import { Back, Refresh } from '@element-plus/icons-vue';
interface FilePaths {
url: string;
name: string;
}
const router = useRouter(); const router = useRouter();
const data = ref(); const data = ref();
let selects = ref<any>([]); let selects = ref<any>([]);
let req = reactive({ path: '/', expand: true, showHidden: false, page: 1, pageSize: 100 }); let req = reactive({ path: '/', expand: true, showHidden: false, page: 1, pageSize: 100 });
let loading = ref(false); let loading = ref(false);
const paths = ref<string[]>([]); const paths = ref<FilePaths[]>([]);
let pathWidth = ref(0);
const fileCreate = reactive({ path: '/', isDir: false, mode: 0o755 }); const fileCreate = reactive({ path: '/', isDir: false, mode: 0o755 });
const fileCompress = reactive({ files: [''], name: '', dst: '', operate: 'compress' }); const fileCompress = reactive({ files: [''], name: '', dst: '', operate: 'compress' });
@ -189,6 +203,8 @@ const uploadRef = ref();
const wgetRef = ref(); const wgetRef = ref();
const moveRef = ref(); const moveRef = ref();
const downloadRef = ref(); const downloadRef = ref();
const pathRef = ref();
const breadCrumbRef = ref();
const paginationConfig = reactive({ const paginationConfig = reactive({
currentPage: 1, currentPage: 1,
@ -205,13 +221,6 @@ const search = async () => {
paginationConfig.total = res.data.itemTotal; paginationConfig.total = res.data.itemTotal;
data.value = res.data.items; data.value = res.data.items;
req.path = res.data.path; req.path = res.data.path;
const pathArray = req.path.split('/');
paths.value = [];
for (const p of pathArray) {
if (p != '') {
paths.value.push(p);
}
}
}) })
.finally(() => { .finally(() => {
loading.value = false; loading.value = false;
@ -221,32 +230,58 @@ const search = async () => {
const open = async (row: File.File) => { const open = async (row: File.File) => {
if (row.isDir) { if (row.isDir) {
const name = row.name; const name = row.name;
paths.value.push(name);
if (req.path.endsWith('/')) { if (req.path.endsWith('/')) {
req.path = req.path + name; req.path = req.path + name;
} else { } else {
req.path = req.path + '/' + name; req.path = req.path + '/' + name;
} }
search(); paths.value.push({
url: req.path,
name: name,
});
jump(req.path);
} else { } else {
openCodeEditor(row); openCodeEditor(row);
} }
}; };
const jump = async (index: number) => { const handlePath = () => {
let path = '/'; if (breadCrumbRef.value.offsetWidth > pathWidth.value) {
if (index != -1) { paths.value.splice(0, 1);
const jPaths = paths.value.slice(0, index + 1); paths.value[0].name = '..';
for (let i in jPaths) { nextTick(function () {
if (path.endsWith('/')) { handlePath();
path = path + jPaths[i]; });
}
};
const jump = async (url: string) => {
req.path = url;
await search();
getPaths(req.path);
nextTick(function () {
handlePath();
});
};
const getPaths = (reqPath: string) => {
const pathArray = reqPath.split('/');
paths.value = [];
let base = '/';
for (const p of pathArray) {
if (p != '') {
if (base.endsWith('/')) {
base = base + p;
} else { } else {
path = path + '/' + jPaths[i]; base = base + '/' + p;
}
paths.value.push({
url: base,
name: p,
});
} }
} }
}
req.path = path;
search();
}; };
const handleCreate = (commnad: string) => { const handleCreate = (commnad: string) => {
@ -424,14 +459,27 @@ const buttons = [
onMounted(() => { onMounted(() => {
if (router.currentRoute.value.query.path) { if (router.currentRoute.value.query.path) {
req.path = String(router.currentRoute.value.query.path); req.path = String(router.currentRoute.value.query.path);
getPaths(req.path);
} }
pathWidth.value = pathRef.value.offsetWidth * 0.7;
search(); search();
}); });
</script> </script>
<style> <style scoped lang="scss">
.path { .path {
border: 1px solid #ebeef5;
background-color: #ffffff; background-color: #ffffff;
height: 30px;
border-radius: 2px !important;
.root {
margin-left: 10px;
}
.split {
margin-left: 5px;
margin-right: 5px;
}
} }
.search-button { .search-button {