2024-08-22 11:27:06 +08:00
|
|
|
|
<template>
|
2024-10-22 14:47:25 +08:00
|
|
|
|
<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'>
|
2024-08-22 11:27:06 +08:00
|
|
|
|
<template #label>
|
2024-10-22 14:47:25 +08:00
|
|
|
|
<el-icon v-show='item.icon && tabsIcon' class='tabs-icon'>
|
|
|
|
|
|
<component :is='item.icon'></component>
|
2024-08-22 11:27:06 +08:00
|
|
|
|
</el-icon>
|
|
|
|
|
|
{{ item.title }}
|
|
|
|
|
|
</template>
|
|
|
|
|
|
</el-tab-pane>
|
|
|
|
|
|
</el-tabs>
|
|
|
|
|
|
<MoreButton />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
2024-10-22 14:47:25 +08:00
|
|
|
|
<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'
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
2024-10-22 14:47:25 +08:00
|
|
|
|
const route = useRoute()
|
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
|
const tabStore = useTabsStore()
|
|
|
|
|
|
const authStore = useAuthStore()
|
|
|
|
|
|
const globalStore = useGlobalStore()
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
2024-10-22 14:47:25 +08:00
|
|
|
|
const tabsMenuValue = ref(route.fullPath)
|
|
|
|
|
|
const tabsMenuList = computed(() => tabStore.tabsMenuList)
|
|
|
|
|
|
const tabsIcon = computed(() => globalStore.tabsIcon)
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
|
|
|
|
|
onMounted(() => {
|
2024-10-22 14:47:25 +08:00
|
|
|
|
tabsDrop()
|
|
|
|
|
|
initTabs()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听路由的变化(防止浏览器后退/前进不变化 tabsMenuValue)
|
|
|
|
|
|
watch(
|
|
|
|
|
|
() => route.fullPath,
|
|
|
|
|
|
() => {
|
2024-10-22 14:47:25 +08:00
|
|
|
|
if (route.meta.isFull) return
|
|
|
|
|
|
if (route.meta.hideTab){
|
|
|
|
|
|
tabsMenuValue.value = route.meta.parentPath as string
|
|
|
|
|
|
}else{
|
|
|
|
|
|
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)
|
|
|
|
|
|
}
|
2024-08-22 11:27:06 +08:00
|
|
|
|
},
|
2024-10-22 14:47:25 +08:00
|
|
|
|
{ immediate: true },
|
|
|
|
|
|
)
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化需要固定的 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,
|
2024-10-22 14:47:25 +08:00
|
|
|
|
isKeepAlive: item.meta.isKeepAlive,
|
2025-01-15 09:07:12 +08:00
|
|
|
|
unshift:true
|
2024-10-22 14:47:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
tabStore.addTabs(tabsParams)
|
2024-08-22 11:27:06 +08:00
|
|
|
|
}
|
2024-10-22 14:47:25 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
|
|
|
|
|
// tabs 拖拽排序
|
|
|
|
|
|
const tabsDrop = () => {
|
2024-10-22 14:47:25 +08:00
|
|
|
|
Sortable.create(document.querySelector('.el-tabs__nav') as HTMLElement, {
|
|
|
|
|
|
draggable: '.el-tabs__item',
|
2024-08-22 11:27:06 +08:00
|
|
|
|
animation: 300,
|
|
|
|
|
|
onEnd({ newIndex, oldIndex }) {
|
2024-10-22 14:47:25 +08:00
|
|
|
|
const tabsList = [...tabStore.tabsMenuList]
|
|
|
|
|
|
const currRow = tabsList.splice(oldIndex as number, 1)[0]
|
|
|
|
|
|
tabsList.splice(newIndex as number, 0, currRow)
|
|
|
|
|
|
tabStore.setTabs(tabsList)
|
|
|
|
|
|
},
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
|
|
|
|
|
// Tab Click
|
|
|
|
|
|
const tabClick = (tabItem: TabsPaneContext) => {
|
2024-10-22 14:47:25 +08:00
|
|
|
|
const fullPath = tabItem.props.name as string
|
2025-01-15 09:07:12 +08:00
|
|
|
|
console.log("🚀 ~ tabClick ~ fullPath:", tabItem)
|
2024-10-22 14:47:25 +08:00
|
|
|
|
router.push(fullPath)
|
|
|
|
|
|
}
|
2024-08-22 11:27:06 +08:00
|
|
|
|
|
|
|
|
|
|
// Remove Tab
|
|
|
|
|
|
const tabRemove = (fullPath: TabPaneName) => {
|
2024-10-22 14:47:25 +08:00
|
|
|
|
tabStore.removeTabs(fullPath as string, fullPath == route.fullPath)
|
|
|
|
|
|
}
|
2024-08-22 11:27:06 +08:00
|
|
|
|
</script>
|
|
|
|
|
|
|
2024-10-22 14:47:25 +08:00
|
|
|
|
<style scoped lang='scss'>
|
2024-08-22 11:27:06 +08:00
|
|
|
|
@import "./index.scss";
|
|
|
|
|
|
</style>
|