wms-antdvue/.svn/pristine/57/577ea94621cfd108bb1d5298f97cbc7d6f7436c2.svn-base
2024-11-07 16:33:03 +08:00

318 lines
8.8 KiB
Plaintext

<template>
<div class="tags-view" :class="{ 'dark-tags-view': settingStore.darkTheme }">
<a-tabs
v-model:activeKey="activeKey"
hide-add
type="editable-card"
@change="goPage"
@edit="onEdit"
size="small"
:tabBarGutter="6"
:tabBarStyle="{
margin: 0,
}"
>
<a-tab-pane
v-for="item in tabsList"
:key="item.key"
:tab="item.title"
:closable="!item.meta?.affix"
/>
<template #rightExtra>
<div class="tabs-close">
<a-dropdown placement="bottomLeft">
<div class="tabs-close-btn">
<DownOutlined />
</div>
<template #overlay>
<a-menu>
<a-menu-item @click="fullScreen">
<a-space>
<ExpandOutlined v-if="!getPageFullScreen" />
<CompressOutlined v-else />
<span>{{ getPageFullScreen ? '退出全屏' : '内容全屏' }}</span>
</a-space>
</a-menu-item>
<a-menu-item @click="reloadPage">
<a-space>
<SyncOutlined />
<span>刷新当前</span>
</a-space>
</a-menu-item>
<a-menu-item :disabled="currentRoute.meta?.affix" @click="closeCurrentTabItem">
<a-space>
<MinusOutlined />
<span>关闭当前</span>
</a-space>
</a-menu-item>
<a-menu-item @click="closeOther">
<a-space>
<SwapOutlined />
<span>关闭其他</span>
</a-space>
</a-menu-item>
<a-menu-item @click="closeLeft">
<a-space>
<DoubleLeftOutlined />
<span>关闭左侧</span>
</a-space>
</a-menu-item>
<a-menu-item @click="closeRight">
<a-space>
<DoubleRightOutlined />
<span>关闭右侧</span>
</a-space>
</a-menu-item>
<a-menu-item @click="closeAll">
<a-space>
<CloseOutlined />
<span>关闭全部</span>
</a-space>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</template>
</a-tabs>
</div>
</template>
<script lang="ts" setup>
import { computed, ref, watch, inject } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { storage } from '@/utils/Storage';
import { RouteItem } from '@/store/modules/tabsView';
import { TABS_ROUTES,FIRST_ROUTE } from '@/store/mutation-types';
import { useGo, useRedo } from '@/hooks/web/usePage';
import { PageEnum } from '@/enums/pageEnum';
import { useTabsViewStore } from '@/store/modules/tabsView';
import {
DownOutlined,
SyncOutlined,
CloseOutlined,
MinusOutlined,
SwapOutlined,
DoubleLeftOutlined,
DoubleRightOutlined,
ExpandOutlined,
CompressOutlined,
} from '@ant-design/icons-vue';
import { useProjectSettingStore } from '@/store/modules/projectSetting';
import { useAsyncRouteStore } from '@/store/modules/asyncRoute';
// 获取简易的路由对象
const getSimpleRoute = (route): RouteItem => {
const { fullPath, hash, meta, name, params, path, query } = route;
return { fullPath, hash, meta, name, params, path, query };
};
const emit = defineEmits(['pageFullScreen']);
const route = useRoute();
const router = useRouter();
const go = useGo();
const currentTabRoute = ref(null);
const refreshCurrent = ref(true);
const currentRoute = ref(route);
const activeKey = ref(route.name);
const tabsViewStore = useTabsViewStore();
const settingStore = useProjectSettingStore();
const asyncRouteStore = useAsyncRouteStore();
let routes: RouteItem[] = [];
try {
const routesStr = storage.get(TABS_ROUTES) as string | null | undefined;
routes = routesStr ? JSON.parse(routesStr) : [getSimpleRoute(route)];
} catch (e) {
routes = [getSimpleRoute(route)];
}
// 初始化标签页
tabsViewStore.initTabs(routes);
const getPageFullScreen = inject('isPageFullScreen');
//当前路由对象 或者 右键选择tab路由对象
const getCurrentTabRoute = computed(() =>
currentTabRoute.value ? currentTabRoute.value : route,
);
// 移除缓存组件名称
const delKeepAliveCompName = () => {
if (route.meta.keepAlive) {
const name = router.currentRoute.value.matched.find((item) => item.name == route.name)
?.components?.default.name;
if (name) {
asyncRouteStore.keepAliveComponents = asyncRouteStore.keepAliveComponents.filter(
(item) => item != name,
);
}
}
};
// 标签页列表
const tabsList: any = computed(() => {
return tabsViewStore.tabsList.map((item) => {
return {
...item,
title: item.meta?.title,
key: item.fullPath,
closable: !item.meta?.affix,
};
});
});
const whiteList: string[] = [
PageEnum.BASE_LOGIN_NAME,
PageEnum.REDIRECT_NAME,
PageEnum.ERROR_PAGE_NAME,
];
watch(
() => route.fullPath,
(to) => {
// 如果您用的路由模式是 hash 请去掉,|| route.hash 判断条件
if (whiteList.includes(route.name as string) || route.hash || route.meta.tagView === false)
return;
activeKey.value = to;
currentTabRoute.value = null;
currentRoute.value = route;
refreshCurrent.value = false;
tabsViewStore.addTabs(getSimpleRoute(route));
},
{ immediate: true },
);
//内容页全屏
function fullScreen() {
emit('pageFullScreen');
}
// 在页面关闭或刷新之前,保存数据
window.addEventListener('beforeunload', () => {
storage.set(TABS_ROUTES, JSON.stringify(tabsList.value));
});
//删除tab
function closeTabItem(fullPath) {
const routeInfo = ref(tabsList.value.find((item) => item.fullPath == fullPath));
removeTab(routeInfo);
}
//删除当前 tab
function closeCurrentTabItem() {
removeTab(currentRoute);
}
//tab 编辑
const onEdit = (targetKey: string | MouseEvent) => {
closeTabItem(targetKey);
};
function goPage(fullPath) {
if (fullPath === route.fullPath) return;
activeKey.value = fullPath;
go(fullPath, true);
}
// 刷新页面
async function reloadPage() {
delKeepAliveCompName();
const redo = useRedo(router);
await redo();
}
// 关闭当前页面
function removeTab(route) {
tabsViewStore.closeCurrentTab(route);
// 如果关闭的是当前页
if (activeKey.value === route.value.fullPath) {
const current = tabsList.value[Math.max(0, tabsList.value.length - 1)];
activeKey.value = current.fullPath;
router.push(current);
}
}
// 关闭左侧
function closeLeft() {
tabsViewStore.closeLeftTabs(getCurrentTabRoute, activeKey.value);
router.replace(route.fullPath);
}
// 关闭右侧
function closeRight() {
tabsViewStore.closeRightTabs(getCurrentTabRoute, activeKey.value);
router.replace(route.fullPath);
}
// 关闭其他
function closeOther() {
tabsViewStore.closeOtherTabs(getCurrentTabRoute, activeKey.value);
router.replace(route.fullPath);
}
// 关闭全部
function closeAll() {
tabsViewStore.closeAllTabs();
router.replace(storage.get(FIRST_ROUTE));
// router.replace(PageEnum.BASE_HOME_REDIRECT);
}
</script>
<style lang="less" scoped>
.tags-view {
:deep(
.ant-tabs.ant-tabs-card .ant-tabs-nav .ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-tab
) {
height: 32px;
line-height: 32px;
border-radius: 3px;
margin-right: 6px;
cursor: pointer;
position: relative;
border: none;
}
:deep(.ant-tabs .ant-tabs-nav .ant-tabs-nav-more) {
padding: 0 16px;
}
:deep(.ant-tabs .ant-tabs-nav .ant-tabs-tab-remove) {
margin-left: 0;
}
:deep(.ant-tabs-bar) {
margin-bottom: 0px;
}
.tabs-close {
min-width: 32px;
width: 32px;
height: 32px;
line-height: 32px;
text-align: center;
border-radius: 2px;
cursor: pointer;
//margin-right: 10px;
&-btn {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.dark-tags-view {
:deep(
.ant-tabs.ant-tabs-card .ant-tabs-nav .ant-tabs-nav-wrap .ant-tabs-nav-list .ant-tabs-tab
) {
background: #151515;
}
:deep(.ant-tabs-top > .ant-tabs-nav::before) {
border: none;
}
.tabs-close {
background: #151515;
}
}
</style>