fix: layout error
This commit is contained in:
3
packages/business/layouts/src/basic/tabbar/index.ts
Normal file
3
packages/business/layouts/src/basic/tabbar/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default as LayoutTabbar } from './tabbar.vue';
|
||||
export { default as LayoutTabbarTools } from './tabbar-tools.vue';
|
||||
export * from './use-tabs';
|
39
packages/business/layouts/src/basic/tabbar/tabbar-tools.vue
Normal file
39
packages/business/layouts/src/basic/tabbar/tabbar-tools.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { preferences, updatePreferences } from '@vben-core/preferences';
|
||||
import { TabsToolMore, TabsToolScreen } from '@vben-core/tabs-ui';
|
||||
|
||||
import { useTabs } from './use-tabs';
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
const { createContextMenus } = useTabs();
|
||||
|
||||
const menus = computed(() => {
|
||||
return createContextMenus(route);
|
||||
});
|
||||
|
||||
function handleScreenChange(screen: boolean) {
|
||||
updatePreferences({
|
||||
header: {
|
||||
hidden: !!screen,
|
||||
},
|
||||
sidebar: {
|
||||
hidden: !!screen,
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-center h-full">
|
||||
<TabsToolMore :menus="menus" />
|
||||
<TabsToolScreen
|
||||
:screen="preferences.sidebar.hidden"
|
||||
@change="handleScreenChange"
|
||||
@update:screen="handleScreenChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
32
packages/business/layouts/src/basic/tabbar/tabbar.vue
Normal file
32
packages/business/layouts/src/basic/tabbar/tabbar.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<script lang="ts" setup>
|
||||
import { TabsView } from '@vben-core/tabs-ui';
|
||||
|
||||
import { useTabs } from './use-tabs';
|
||||
|
||||
defineOptions({
|
||||
name: 'LayoutTabbar',
|
||||
});
|
||||
|
||||
defineProps<{ showIcon?: boolean }>();
|
||||
|
||||
const {
|
||||
createContextMenus,
|
||||
currentActive,
|
||||
currentTabs,
|
||||
handleClick,
|
||||
handleClose,
|
||||
handleUnPushPin,
|
||||
} = useTabs();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TabsView
|
||||
:active="currentActive"
|
||||
:menus="createContextMenus"
|
||||
:show-icon="showIcon"
|
||||
:tabs="currentTabs"
|
||||
@close="handleClose"
|
||||
@un-push-pin="handleUnPushPin"
|
||||
@update:active="handleClick"
|
||||
/>
|
||||
</template>
|
204
packages/business/layouts/src/basic/tabbar/use-tabs.ts
Normal file
204
packages/business/layouts/src/basic/tabbar/use-tabs.ts
Normal file
@@ -0,0 +1,204 @@
|
||||
import type { IContextMenuItem } from '@vben-core/tabs-ui';
|
||||
import type { TabItem } from '@vben-core/typings';
|
||||
import type {
|
||||
RouteLocationNormalized,
|
||||
RouteRecordNormalized,
|
||||
} from 'vue-router';
|
||||
|
||||
import { computed, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { $t } from '@vben/locales';
|
||||
import {
|
||||
IcRoundClose,
|
||||
IcRoundMultipleStop,
|
||||
IcRoundRefresh,
|
||||
MdiArrowExpandHorizontal,
|
||||
MdiFormatHorizontalAlignLeft,
|
||||
MdiFormatHorizontalAlignRight,
|
||||
MdiPin,
|
||||
MdiPinOff,
|
||||
} from '@vben-core/iconify';
|
||||
import { storeToRefs, useAccessStore, useTabsStore } from '@vben-core/stores';
|
||||
import { filterTree } from '@vben-core/toolkit';
|
||||
|
||||
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;
|
||||
});
|
||||
affixTabs.forEach((tab) => {
|
||||
Object.assign(tab, wrapperTabLocale(tab));
|
||||
});
|
||||
tabsStore.setAffixTabs(affixTabs);
|
||||
};
|
||||
|
||||
// 点击tab,跳转路由
|
||||
const handleClick = (key: string) => {
|
||||
router.push(key);
|
||||
};
|
||||
|
||||
// 关闭tab
|
||||
const handleClose = async (key: string) => {
|
||||
await tabsStore.closeTabByKey(key, router);
|
||||
};
|
||||
|
||||
function wrapperTabLocale(
|
||||
tab: RouteLocationNormalized | RouteRecordNormalized,
|
||||
) {
|
||||
return {
|
||||
...tab,
|
||||
meta: {
|
||||
...tab.meta,
|
||||
title: $t(tab.meta.title as string),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
watch(
|
||||
() => accessMenus.value,
|
||||
() => {
|
||||
initAffixTabs();
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => route.path,
|
||||
() => {
|
||||
tabsStore.addTab(wrapperTabLocale(route) as RouteLocationNormalized);
|
||||
},
|
||||
{ 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 };
|
Reference in New Issue
Block a user