|
|
<script setup lang="ts">
|
|
|
import { storeToRefs } from 'pinia'
|
|
|
import type { RouteLocationNormalized } from 'vue-router'
|
|
|
import TabRedo from './components/tab-redo.vue'
|
|
|
import TabQuick from './components/tab-quick.vue'
|
|
|
import TabFoldButton from './components/tab-foldbutton.vue'
|
|
|
import TabDropDown from './components/tab-dropdown.vue'
|
|
|
import type { TabDropDownInst } from './components/types'
|
|
|
import { REDIRECT_NAME } from '~/constants'
|
|
|
import { Sortable, listenerRouteChange } from '~/utils'
|
|
|
|
|
|
const router = useRouter()
|
|
|
const go = useGo()
|
|
|
const { close } = useTabs()
|
|
|
|
|
|
const multipleTabStore = useMultipleTabStore()
|
|
|
const { tabList } = storeToRefs(multipleTabStore)
|
|
|
const { getShowFold, getShowQuick, getShowRedo } = useMultipleTabSetting()
|
|
|
|
|
|
let activeTabName = $ref<string>('')
|
|
|
const tabDropdownRef = $ref<TabDropDownInst | null>(null)
|
|
|
const tabListRef = computed(() => {
|
|
|
return unref(tabList).filter(item => !item.meta?.hideInTab && router.hasRoute(item.name!))
|
|
|
})
|
|
|
|
|
|
listenerRouteChange((route) => {
|
|
|
const { name } = route
|
|
|
// TODO accessToken
|
|
|
if (name === REDIRECT_NAME || !route) {
|
|
|
return
|
|
|
}
|
|
|
const { path, fullPath, meta = {} } = route
|
|
|
const { currentActiveMenu, hideInTab } = meta
|
|
|
const isHide = !hideInTab ? null : currentActiveMenu
|
|
|
const p = isHide || fullPath || path
|
|
|
if (activeTabName !== p) {
|
|
|
activeTabName = p as string
|
|
|
}
|
|
|
if (isHide) {
|
|
|
const findParentRoute = router.getRoutes().find(item => item.path === currentActiveMenu)
|
|
|
findParentRoute && multipleTabStore.checkTab(findParentRoute as unknown as RouteLocationNormalized)
|
|
|
}
|
|
|
else {
|
|
|
multipleTabStore.checkTab(unref(route))
|
|
|
}
|
|
|
})
|
|
|
|
|
|
function handleChange(value: string) {
|
|
|
go(value, false)
|
|
|
}
|
|
|
|
|
|
// 获取tabs内dom,拖拽
|
|
|
nextTick(() => {
|
|
|
const selection = document.querySelector(
|
|
|
'#drag > div > div > div > div > div.n-tabs-wrapper',
|
|
|
)
|
|
|
Sortable.create(selection as HTMLElement, {
|
|
|
animation: 150,
|
|
|
})
|
|
|
})
|
|
|
|
|
|
function handleContextMenu(e: MouseEvent, tabItem: RouteLocationNormalized) {
|
|
|
e.preventDefault()
|
|
|
if (!tabItem) {
|
|
|
return
|
|
|
}
|
|
|
unref(tabDropdownRef)?.openDropdown(e, tabItem)
|
|
|
}
|
|
|
|
|
|
function handleClose(e: MouseEvent, route: RouteLocationNormalized) {
|
|
|
e.stopPropagation()
|
|
|
close(route)
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<NEl class="mt-2">
|
|
|
<NTabs
|
|
|
id="drag"
|
|
|
v-model:value="activeTabName"
|
|
|
type="card"
|
|
|
:tabs-padding="8"
|
|
|
animated
|
|
|
@update:value="handleChange"
|
|
|
>
|
|
|
<NTab
|
|
|
v-for="(item, index) in tabListRef"
|
|
|
:key="item.query ? item.fullPath : item.path"
|
|
|
:name="item.fullPath"
|
|
|
style="--n-tab-padding: 0"
|
|
|
>
|
|
|
<div
|
|
|
class="group py-4px pl-12px hover:text-[var(--n-tab-text-color-active)]"
|
|
|
:class="[index === 0 ? 'pr-12px' : 'pr-18px']"
|
|
|
@contextmenu="handleContextMenu($event, item)"
|
|
|
>
|
|
|
<span>{{ $t(item.meta.title || '') }}</span>
|
|
|
<LIcon
|
|
|
v-if="index !== 0"
|
|
|
icon="ant-design:close-outlined"
|
|
|
class="hover:nt--7px absolute top-1/2 ml-2px mt--6px inline-flex !transition-all hover:!text-14px"
|
|
|
:class="{ ['!hidden']: activeTabName !== item.fullPath }"
|
|
|
size="14"
|
|
|
@click="handleClose($event, item)"
|
|
|
/>
|
|
|
</div>
|
|
|
</NTab>
|
|
|
<template #suffix>
|
|
|
<TabRedo v-if="getShowRedo" />
|
|
|
<TabQuick v-if="getShowQuick" :tab-item="$route" />
|
|
|
<TabFoldButton v-if="getShowFold" />
|
|
|
</template>
|
|
|
</NTabs>
|
|
|
<TabDropDown ref="tabDropdownRef" />
|
|
|
</NEl>
|
|
|
</template>
|