初始化
This commit is contained in:
121
frontend/src/layouts/components/Tabs/index.vue
Normal file
121
frontend/src/layouts/components/Tabs/index.vue
Normal file
@@ -0,0 +1,121 @@
|
||||
<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 { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { TabPaneName, TabsPaneContext } from 'element-plus'
|
||||
import { HOME_URL } from '@/config'
|
||||
import { useGlobalStore } from '@/stores/modules/global'
|
||||
import { useTabsStore } from '@/stores/modules/tabs'
|
||||
import MoreButton from './components/MoreButton.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const tabStore = useTabsStore()
|
||||
const globalStore = useGlobalStore()
|
||||
|
||||
const tabsMenuValue = ref(route.fullPath)
|
||||
const tabsMenuList = computed(() => tabStore.tabsMenuList)
|
||||
const tabsIcon = computed(() => globalStore.tabsIcon)
|
||||
|
||||
onMounted(() => {
|
||||
tabsDrop()
|
||||
initTabs()
|
||||
})
|
||||
|
||||
watch(
|
||||
() => route.fullPath,
|
||||
() => {
|
||||
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)
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
const initTabs = () => {
|
||||
const affixTabs = router
|
||||
.getRoutes()
|
||||
.filter(item => item.meta.isAffix && !item.meta.isHide && !item.meta.isFull && item.name && item.path)
|
||||
.sort((a, b) => {
|
||||
if (a.path === HOME_URL) return -1
|
||||
if (b.path === HOME_URL) return 1
|
||||
return 0
|
||||
})
|
||||
|
||||
for (let index = affixTabs.length - 1; index >= 0; index -= 1) {
|
||||
const item = affixTabs[index]
|
||||
const tabsParams = {
|
||||
icon: item.meta.icon as string,
|
||||
title: item.meta.title as string,
|
||||
path: item.path,
|
||||
name: item.name as string,
|
||||
close: !item.meta.isAffix,
|
||||
isKeepAlive: item.meta.isKeepAlive as boolean,
|
||||
unshift: true
|
||||
}
|
||||
tabStore.addTabs(tabsParams)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const tabClick = (tabItem: TabsPaneContext) => {
|
||||
const fullPath = tabItem.props.name as string
|
||||
router.push(fullPath)
|
||||
}
|
||||
|
||||
const tabRemove = (fullPath: TabPaneName) => {
|
||||
tabStore.removeTabs(fullPath as string, fullPath == route.fullPath)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use './index.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user