185 lines
4.5 KiB
TypeScript
185 lines
4.5 KiB
TypeScript
![]() |
import type { IContextMenuItem } from '@vben-core/tabs-ui';
|
||
|
import type { TabItem } from '@vben-core/typings';
|
||
|
|
||
|
import {
|
||
|
IcRoundClose,
|
||
|
IcRoundMultipleStop,
|
||
|
IcRoundRefresh,
|
||
|
MdiArrowExpandHorizontal,
|
||
|
MdiFormatHorizontalAlignLeft,
|
||
|
MdiFormatHorizontalAlignRight,
|
||
|
MdiPin,
|
||
|
MdiPinOff,
|
||
|
} from '@vben-core/iconify';
|
||
|
import { filterTree } from '@vben-core/toolkit';
|
||
|
|
||
|
import { storeToRefs, useAccessStore, useTabsStore } from '@vben/stores';
|
||
|
import { computed, watch } from 'vue';
|
||
|
import { useRoute, useRouter } from 'vue-router';
|
||
|
|
||
|
function useTabs() {
|
||
|
const router = useRouter();
|
||
|
const route = useRoute();
|
||
|
const accessStore = useAccessStore();
|
||
|
const tabsStore = useTabsStore();
|
||
|
const { accessMenus } = storeToRefs(accessStore);
|
||
|
|
||
|
const currentActive = computed(() => {
|
||
|
return route.path;
|
||
|
});
|
||
|
|
||
|
const currentTabs = computed(() => {
|
||
|
return tabsStore.getTabs;
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
* 初始化固定标签页
|
||
|
*/
|
||
|
const initAffixTabs = () => {
|
||
|
const affixTabs = filterTree(router.getRoutes(), (route) => {
|
||
|
return !!route.meta?.affixTab;
|
||
|
});
|
||
|
tabsStore.setAffixTabs(affixTabs);
|
||
|
};
|
||
|
|
||
|
// 点击tab,跳转路由
|
||
|
const handleClick = (key: string) => {
|
||
|
router.push(key);
|
||
|
};
|
||
|
|
||
|
// 关闭tab
|
||
|
const handleClose = async (key: string) => {
|
||
|
await tabsStore.closeTabByKey(key, router);
|
||
|
};
|
||
|
|
||
|
watch(
|
||
|
() => accessMenus.value,
|
||
|
() => {
|
||
|
initAffixTabs();
|
||
|
},
|
||
|
{ immediate: true },
|
||
|
);
|
||
|
|
||
|
watch(
|
||
|
() => route.path,
|
||
|
() => {
|
||
|
tabsStore.addTab(route);
|
||
|
},
|
||
|
{ immediate: true },
|
||
|
);
|
||
|
|
||
|
const createContextMenus = (tab: TabItem) => {
|
||
|
const tabs = tabsStore.getTabs;
|
||
|
const affixTabs = tabsStore.affixTabs;
|
||
|
const index = tabs.findIndex((item) => item.path === tab.path);
|
||
|
|
||
|
const disabled = tabs.length <= 1;
|
||
|
|
||
|
const { meta } = tab;
|
||
|
const affixTab = meta?.affixTab ?? false;
|
||
|
const isCurrentTab = route.path === tab.path;
|
||
|
|
||
|
// 当前处于最左侧或者减去固定标签页的数量等于0
|
||
|
const closeLeftDisabled =
|
||
|
index === 0 || index - affixTabs.length <= 0 || !isCurrentTab;
|
||
|
|
||
|
const closeRightDisabled = !isCurrentTab || index === tabs.length - 1;
|
||
|
|
||
|
const closeOtherDisabled =
|
||
|
disabled || !isCurrentTab || tabs.length - affixTabs.length <= 1;
|
||
|
|
||
|
const menus: IContextMenuItem[] = [
|
||
|
{
|
||
|
disabled: !isCurrentTab,
|
||
|
handler: async () => {
|
||
|
await tabsStore.refreshTab(router);
|
||
|
},
|
||
|
icon: IcRoundRefresh,
|
||
|
key: 'reload',
|
||
|
text: '重新加载',
|
||
|
},
|
||
|
{
|
||
|
disabled: !!affixTab || disabled,
|
||
|
handler: async () => {
|
||
|
await tabsStore.closeTab(tab, router);
|
||
|
},
|
||
|
icon: IcRoundClose,
|
||
|
key: 'close',
|
||
|
text: '关闭标签页',
|
||
|
},
|
||
|
{
|
||
|
handler: async () => {
|
||
|
await (affixTab
|
||
|
? tabsStore.unPushPinTab(tab)
|
||
|
: tabsStore.pushPinTab(tab));
|
||
|
},
|
||
|
icon: affixTab ? MdiPinOff : MdiPin,
|
||
|
key: 'affix',
|
||
|
separator: true,
|
||
|
text: affixTab ? '取消固定标签页' : '固定标签页',
|
||
|
},
|
||
|
{
|
||
|
disabled: closeLeftDisabled,
|
||
|
handler: async () => {
|
||
|
await tabsStore.closeLeftTabs(tab);
|
||
|
},
|
||
|
icon: MdiFormatHorizontalAlignLeft,
|
||
|
key: 'close-left',
|
||
|
text: '关闭左侧标签页',
|
||
|
},
|
||
|
{
|
||
|
disabled: closeRightDisabled,
|
||
|
handler: async () => {
|
||
|
await tabsStore.closeRightTabs(tab);
|
||
|
},
|
||
|
icon: MdiFormatHorizontalAlignRight,
|
||
|
key: 'close-right',
|
||
|
separator: true,
|
||
|
text: '关闭右侧标签页',
|
||
|
},
|
||
|
{
|
||
|
disabled: closeOtherDisabled,
|
||
|
handler: async () => {
|
||
|
await tabsStore.closeOtherTabs(tab);
|
||
|
},
|
||
|
icon: MdiArrowExpandHorizontal,
|
||
|
key: 'close-other',
|
||
|
text: '关闭其他标签页',
|
||
|
},
|
||
|
{
|
||
|
disabled,
|
||
|
handler: async () => {
|
||
|
await tabsStore.closeAllTabs(router);
|
||
|
},
|
||
|
icon: IcRoundMultipleStop,
|
||
|
key: 'close-all',
|
||
|
text: '关闭全部标签页',
|
||
|
},
|
||
|
// {
|
||
|
// icon: 'icon-[material-symbols--back-to-tab-sharp]',
|
||
|
// key: 'close-all',
|
||
|
// text: '新窗口打开',
|
||
|
// },
|
||
|
];
|
||
|
return menus;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* 取消固定标签页
|
||
|
*/
|
||
|
const handleUnPushPin = async (tab: TabItem) => {
|
||
|
await tabsStore.unPushPinTab(tab);
|
||
|
};
|
||
|
|
||
|
return {
|
||
|
createContextMenus,
|
||
|
currentActive,
|
||
|
currentTabs,
|
||
|
handleClick,
|
||
|
handleClose,
|
||
|
handleUnPushPin,
|
||
|
};
|
||
|
}
|
||
|
|
||
|
export { useTabs };
|