123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- <script lang="ts" setup>
- import type { TabPaneName } from 'element-plus'
- import config from '@/config/defaultSetting'
- import { useMenuStore } from '@/stores/menu'
- interface Tab {
- name: string
- fullPath: string
- params: object
- query: object
- title: string
- }
- const router = useRouter()
- const route = useRoute()
- const routeToTab = (route: any) => {
- return (
- route && {
- name: route.name,
- fullPath: route.fullPath || route.path,
- params: route.params,
- query: route.query,
- title: route.meta?.title
- }
- )
- }
- const defaultTabs = [routeToTab(router.getRoutes().find(item => item.name === config.homeRouteName))]
- route.name !== config.homeRouteName && defaultTabs.push(routeToTab(route))
- const tabs = useStorage<any[]>('globalTabs', defaultTabs, sessionStorage)
- const activeValue = ref(route.fullPath)
- const activeIndex = ref(0)
- const findActiveIndex = (fullPath: string | number) => {
- return tabs.value.findIndex(item => item.fullPath === fullPath)
- }
- const setTab = (tab: Tab) => {
- if (tab.name === 'login' || tabs.value.find(item => item.name === tab.name)) {
- return
- }
- tabs.value.push(tab)
- }
- const menuStore = useMenuStore()
- const activeMenu = ref({})
- const findActiveMenu = (path: any) => {
- const findDeep = (list: any): boolean => {
- let flag = false
- for (let index = 0; index < list.length; index++) {
- const element = list[index]
- if (element.path === path) {
- flag = true
- break
- }
- if (element.children?.length) {
- flag = findDeep(element.children)
- }
- }
- return flag
- }
- for (let index = 0; index < menuStore.allMenuList.length; index++) {
- const element = menuStore.allMenuList[index]
- if (element.path === path) {
- activeMenu.value = element
- break
- }
- if (element.children?.length && findDeep(element.children)) {
- activeMenu.value = element
- break
- }
- }
- }
- const changeTab = (name: TabPaneName) => {
- activeIndex.value = findActiveIndex(name)
- const menu = tabs.value.find(item => item.fullPath === name)
- router.push(menu)
- menuStore.activeRoutePath = name
- findActiveMenu(name)
- menuStore.setActiveTopMenu(activeMenu.value)
- }
- const removeTab = (name: TabPaneName) => {
- const index = findActiveIndex(name)
- activeIndex.value = index < tabs.value.length - 1 ? index + 1 : index - 1
- router.push(tabs.value[activeIndex.value])
- tabs.value.splice(index, 1)
- }
- watch(
- () => route,
- to => {
- setTab(routeToTab(to))
- activeValue.value = to.fullPath
- activeIndex.value = findActiveIndex(to.fullPath)
- },
- {
- deep: true
- }
- )
- const contextMenuVisible = ref(false)
- const left = ref(0)
- const top = ref(0)
- const contextMenuIndex = ref(0)
- const contextMenuItem = computed(() => tabs.value[contextMenuIndex.value]) as any
- const findContextMenuItemIndex = (fullPath: string) => tabs.value.findIndex(item => item.fullPath === fullPath)
- const openContextMenu = (e: any) => {
- const id = e.target?.offsetParent?.id || e.target?.id
- if (id) {
- const fullPath = id.split('tab-')[1]
- contextMenuIndex.value = findContextMenuItemIndex(fullPath)
- left.value = e.clientX + 1
- top.value = e.clientY + 1
- contextMenuVisible.value = true
- }
- }
- const closeContextMenu = () => {
- contextMenuVisible.value = false
- }
- const closeAll = () => {
- router.push(tabs.value[0])
- tabs.value.splice(1)
- closeContextMenu()
- }
- const closeLeft = () => {
- if (activeIndex.value < contextMenuIndex.value) {
- router.push(contextMenuItem.value)
- }
- tabs.value.splice(1, contextMenuIndex.value - 1)
- closeContextMenu()
- }
- const closeRight = () => {
- if (activeIndex.value > contextMenuIndex.value) {
- router.push(contextMenuItem.value)
- }
- tabs.value.splice(contextMenuIndex.value + 1)
- closeContextMenu()
- }
- const closeOther = () => {
- router.push(contextMenuItem.value)
- if (contextMenuIndex.value) {
- tabs.value = [tabs.value[0], contextMenuItem.value]
- } else {
- tabs.value = [tabs.value[0]]
- }
- contextMenuVisible.value = false
- }
- watch(contextMenuVisible, val => {
- if (val) {
- document.body.addEventListener('click', closeContextMenu)
- } else {
- document.body.removeEventListener('click', closeContextMenu)
- }
- })
- const refresh = () => {
- router.go(0)
- }
- </script>
- <template>
- <div class="bg-white" style="border-top: 1px solid var(--el-border-color-light)">
- <el-tabs
- v-model="activeValue"
- type="card"
- @tab-change="changeTab"
- @tab-remove="removeTab"
- @contextmenu.prevent="openContextMenu($event)"
- @dblclick="refresh"
- >
- <el-tab-pane
- v-for="item in tabs"
- :key="item.name"
- :label="item.title"
- :name="item.fullPath"
- :tab="item"
- :closable="item.name !== config.homeRouteName"
- >
- </el-tab-pane>
- </el-tabs>
-
- <ul v-show="contextMenuVisible" :style="{ left: left + 'px', top: top + 'px' }" class="context-menu">
- <li @click="closeAll">关闭所有</li>
- <li @click="closeLeft">关闭左侧</li>
- <li @click="closeRight">关闭右侧</li>
- <li @click="closeOther">关闭其他</li>
- </ul>
- </div>
- </template>
- <style lang="scss" scoped>
- :deep(.el-tabs__header) {
- margin: 0;
- // border-top: 1px solid var(--el-border-color-light);
- }
- :deep(.el-tabs__nav) {
- border-top: none !important;
- border-radius: 0 !important;
- }
- :deep(.el-tabs__item.is-active) {
- background-color: var(--el-color-primary-light-9);
- border-bottom-color: var(--el-border-color) !important;
- }
- .context-menu {
- position: fixed;
- width: 100px;
- margin: 0;
- border-radius: 4px;
- background: var(--el-bg-color-overlay);
- border: 1px solid var(--el-border-color-light);
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
- z-index: 3000;
- list-style-type: none;
- padding: 0;
- li {
- margin: 0;
- padding: 7px 16px;
- cursor: pointer;
- &:hover {
- background: #f2f2f2;
- }
- }
- }
- </style>
|