initHeader
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<el-dropdown trigger="click" :teleported="false">
|
||||
<div class="more-button">
|
||||
<i :class="'iconfont icon-xiala'"></i>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="refresh">
|
||||
<el-icon><Refresh /></el-icon>{{ $t("tabs.refresh") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="maximize">
|
||||
<el-icon><FullScreen /></el-icon>{{ $t("tabs.maximize") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided @click="closeCurrentTab">
|
||||
<el-icon><Remove /></el-icon>{{ $t("tabs.closeCurrent") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="tabStore.closeTabsOnSide(route.fullPath, 'left')">
|
||||
<el-icon><DArrowLeft /></el-icon>{{ $t("tabs.closeLeft") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="tabStore.closeTabsOnSide(route.fullPath, 'right')">
|
||||
<el-icon><DArrowRight /></el-icon>{{ $t("tabs.closeRight") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item divided @click="tabStore.closeMultipleTab(route.fullPath)">
|
||||
<el-icon><CircleClose /></el-icon>{{ $t("tabs.closeOther") }}
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="closeAllTab">
|
||||
<el-icon><FolderDelete /></el-icon>{{ $t("tabs.closeAll") }}
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { inject, nextTick } from "vue";
|
||||
import { HOME_URL } from "@/config";
|
||||
import { useTabsStore } from "@/stores/modules/tabs";
|
||||
import { useGlobalStore } from "@/stores/modules/global";
|
||||
import { useKeepAliveStore } from "@/stores/modules/keepAlive";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const tabStore = useTabsStore();
|
||||
const globalStore = useGlobalStore();
|
||||
const keepAliveStore = useKeepAliveStore();
|
||||
|
||||
// refresh current page
|
||||
const refreshCurrentPage: Function = inject("refresh") as Function;
|
||||
const refresh = () => {
|
||||
setTimeout(() => {
|
||||
keepAliveStore.removeKeepAliveName(route.name as string);
|
||||
refreshCurrentPage(false);
|
||||
nextTick(() => {
|
||||
keepAliveStore.addKeepAliveName(route.name as string);
|
||||
refreshCurrentPage(true);
|
||||
});
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// maximize current page
|
||||
const maximize = () => {
|
||||
globalStore.setGlobalState("maximize", true);
|
||||
};
|
||||
|
||||
// Close Current
|
||||
const closeCurrentTab = () => {
|
||||
if (route.meta.isAffix) return;
|
||||
tabStore.removeTabs(route.fullPath);
|
||||
};
|
||||
|
||||
// Close All
|
||||
const closeAllTab = () => {
|
||||
tabStore.closeMultipleTab();
|
||||
router.push(HOME_URL);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../index.scss";
|
||||
</style>
|
||||
69
frontend/src/layouts/components/Tabs/index.scss
Normal file
69
frontend/src/layouts/components/Tabs/index.scss
Normal file
@@ -0,0 +1,69 @@
|
||||
.tabs-box {
|
||||
background-color: var(--el-bg-color);
|
||||
.tabs-menu {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
.el-dropdown {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
.more-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 43px;
|
||||
cursor: pointer;
|
||||
border-left: 1px solid var(--el-border-color-light);
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
background-color: var(--el-color-info-light-9);
|
||||
}
|
||||
.iconfont {
|
||||
font-size: 12.5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
:deep(.el-tabs) {
|
||||
.el-tabs__header {
|
||||
box-sizing: border-box;
|
||||
height: 40px;
|
||||
padding: 0 10px;
|
||||
margin: 0;
|
||||
.el-tabs__nav-wrap {
|
||||
position: absolute;
|
||||
width: calc(100% - 70px);
|
||||
.el-tabs__nav {
|
||||
display: flex;
|
||||
border: none;
|
||||
.el-tabs__item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #afafaf;
|
||||
border: none;
|
||||
.tabs-icon {
|
||||
margin: 1.5px 4px 0 0;
|
||||
font-size: 15px;
|
||||
}
|
||||
.is-icon-close {
|
||||
margin-top: 1px;
|
||||
}
|
||||
&.is-active {
|
||||
color: var(--el-color-primary);
|
||||
&::before {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
content: "";
|
||||
border-bottom: 2px solid var(--el-color-primary) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
108
frontend/src/layouts/components/Tabs/index.vue
Normal file
108
frontend/src/layouts/components/Tabs/index.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div class="tabs-box">
|
||||
<div class="tabs-menu">
|
||||
<el-tabs v-model="tabsMenuValue" type="card" @tab-click="tabClick" @tab-remove="tabRemove">
|
||||
<el-tab-pane v-for="item in tabsMenuList" :key="item.path" :label="item.title" :name="item.path" :closable="item.close">
|
||||
<template #label>
|
||||
<el-icon v-show="item.icon && tabsIcon" class="tabs-icon">
|
||||
<component :is="item.icon"></component>
|
||||
</el-icon>
|
||||
{{ item.title }}
|
||||
</template>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<MoreButton />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Sortable from "sortablejs";
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { useGlobalStore } from "@/stores/modules/global";
|
||||
import { useTabsStore } from "@/stores/modules/tabs";
|
||||
import { useAuthStore } from "@/stores/modules/auth";
|
||||
import { TabsPaneContext, TabPaneName } from "element-plus";
|
||||
import MoreButton from "./components/MoreButton.vue";
|
||||
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const tabStore = useTabsStore();
|
||||
const authStore = useAuthStore();
|
||||
const globalStore = useGlobalStore();
|
||||
|
||||
const tabsMenuValue = ref(route.fullPath);
|
||||
const tabsMenuList = computed(() => tabStore.tabsMenuList);
|
||||
const tabsIcon = computed(() => globalStore.tabsIcon);
|
||||
|
||||
onMounted(() => {
|
||||
tabsDrop();
|
||||
initTabs();
|
||||
});
|
||||
|
||||
// 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue)
|
||||
watch(
|
||||
() => route.fullPath,
|
||||
() => {
|
||||
if (route.meta.isFull) return;
|
||||
tabsMenuValue.value = route.fullPath;
|
||||
const tabsParams = {
|
||||
icon: route.meta.icon as string,
|
||||
title: route.meta.title as string,
|
||||
path: route.fullPath,
|
||||
name: route.name as string,
|
||||
close: !route.meta.isAffix,
|
||||
isKeepAlive: route.meta.isKeepAlive as boolean
|
||||
};
|
||||
tabStore.addTabs(tabsParams);
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
// 初始化需要固定的 tabs
|
||||
const initTabs = () => {
|
||||
authStore.flatMenuListGet.forEach(item => {
|
||||
if (item.meta.isAffix && !item.meta.isHide && !item.meta.isFull) {
|
||||
const tabsParams = {
|
||||
icon: item.meta.icon,
|
||||
title: item.meta.title,
|
||||
path: item.path,
|
||||
name: item.name,
|
||||
close: !item.meta.isAffix,
|
||||
isKeepAlive: item.meta.isKeepAlive
|
||||
};
|
||||
tabStore.addTabs(tabsParams);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// tabs 拖拽排序
|
||||
const tabsDrop = () => {
|
||||
Sortable.create(document.querySelector(".el-tabs__nav") as HTMLElement, {
|
||||
draggable: ".el-tabs__item",
|
||||
animation: 300,
|
||||
onEnd({ newIndex, oldIndex }) {
|
||||
const tabsList = [...tabStore.tabsMenuList];
|
||||
const currRow = tabsList.splice(oldIndex as number, 1)[0];
|
||||
tabsList.splice(newIndex as number, 0, currRow);
|
||||
tabStore.setTabs(tabsList);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Tab Click
|
||||
const tabClick = (tabItem: TabsPaneContext) => {
|
||||
const fullPath = tabItem.props.name as string;
|
||||
router.push(fullPath);
|
||||
};
|
||||
|
||||
// Remove Tab
|
||||
const tabRemove = (fullPath: TabPaneName) => {
|
||||
tabStore.removeTabs(fullPath as string, fullPath == route.fullPath);
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./index.scss";
|
||||
</style>
|
||||
Reference in New Issue
Block a user