From 480580f1046d4a4065ce3dd40b35e4757d3ad78a Mon Sep 17 00:00:00 2001 From: vben Date: Sat, 20 Jul 2024 11:14:32 +0800 Subject: [PATCH] feat: add 'maxNumOfOpenTab' to limit the maximum number of tabs with the same name --- apps/web-antd/src/locales/langs/en-US.json | 3 +- apps/web-antd/src/locales/langs/zh-CN.json | 3 +- .../src/router/routes/modules/demos.ts | 12 ++++++++ .../src/views/demos/features/tabs/index.vue | 19 ++++++++++++ .../views/demos/features/tabs/tab-detail.vue | 29 +++++++++++++++++++ .../eslint-config/src/custom-config.ts | 1 + .../forward/stores/src/modules/tabbar.ts | 17 +++++++++++ .../@core/shared/typings/src/vue-router.d.ts | 5 ++++ .../layouts/src/basic/tabbar/use-tabbar.ts | 2 +- turbo.json | 4 +++ 10 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 apps/web-antd/src/views/demos/features/tabs/tab-detail.vue diff --git a/apps/web-antd/src/locales/langs/en-US.json b/apps/web-antd/src/locales/langs/en-US.json index dec360db..014aabaa 100644 --- a/apps/web-antd/src/locales/langs/en-US.json +++ b/apps/web-antd/src/locales/langs/en-US.json @@ -38,7 +38,8 @@ "title": "Features", "hideChildrenInMenu": "Hide Menu Children", "loginExpired": "Login Expired", - "tabs": "Tabs" + "tabs": "Tabs", + "tabDetail": "Tab Detail Page" }, "breadcrumb": { "navigation": "Breadcrumb Navigation", diff --git a/apps/web-antd/src/locales/langs/zh-CN.json b/apps/web-antd/src/locales/langs/zh-CN.json index 515e45bb..08b3fa1f 100644 --- a/apps/web-antd/src/locales/langs/zh-CN.json +++ b/apps/web-antd/src/locales/langs/zh-CN.json @@ -40,7 +40,8 @@ "title": "功能", "hideChildrenInMenu": "隐藏子菜单", "loginExpired": "登录过期", - "tabs": "标签页" + "tabs": "标签页", + "tabDetail": "标签详情页" }, "breadcrumb": { "navigation": "面包屑导航", diff --git a/apps/web-antd/src/router/routes/modules/demos.ts b/apps/web-antd/src/router/routes/modules/demos.ts index d9cc9afe..c0e369a4 100644 --- a/apps/web-antd/src/router/routes/modules/demos.ts +++ b/apps/web-antd/src/router/routes/modules/demos.ts @@ -107,6 +107,18 @@ const routes: RouteRecordRaw[] = [ title: $t('page.demos.features.tabs'), }, }, + { + name: 'FeatureTabDetailDemo', + path: 'tabs/detail/:id', + component: () => + import('#/views/demos/features/tabs/tab-detail.vue'), + meta: { + activePath: '/demos/features/tabs', + hideInMenu: true, + maxNumOfOpenTab: 3, + title: $t('page.demos.features.tabDetail'), + }, + }, { name: 'HideChildrenInMenuParent', path: 'hide-menu-children', diff --git a/apps/web-antd/src/views/demos/features/tabs/index.vue b/apps/web-antd/src/views/demos/features/tabs/index.vue index df98a4b8..48d52ce3 100644 --- a/apps/web-antd/src/views/demos/features/tabs/index.vue +++ b/apps/web-antd/src/views/demos/features/tabs/index.vue @@ -28,6 +28,11 @@ function openTab() { router.push({ name: 'VbenAbout' }); } +function openTabWithParams(id: number) { + // 这里就是路由跳转,也可以用path + router.push({ name: 'FeatureTabDetailDemo', params: { id } }); +} + function reset() { newTabTitle.value = ''; resetTabTitle(); @@ -92,5 +97,19 @@ function reset() { + +
+
最大打开数量
+
+ 限制带参数的tab打开的最大数量,由 `route.meta.maxNumOfOpenTab` 控制 +
+
+ +
+
diff --git a/apps/web-antd/src/views/demos/features/tabs/tab-detail.vue b/apps/web-antd/src/views/demos/features/tabs/tab-detail.vue new file mode 100644 index 00000000..809cf910 --- /dev/null +++ b/apps/web-antd/src/views/demos/features/tabs/tab-detail.vue @@ -0,0 +1,29 @@ + + + diff --git a/internal/lint-configs/eslint-config/src/custom-config.ts b/internal/lint-configs/eslint-config/src/custom-config.ts index 0ebff774..d871d8bc 100644 --- a/internal/lint-configs/eslint-config/src/custom-config.ts +++ b/internal/lint-configs/eslint-config/src/custom-config.ts @@ -121,6 +121,7 @@ const customConfig: Linter.FlatConfig[] = [ files: ['apps/backend-mock/**/**'], rules: { '@typescript-eslint/no-extraneous-class': 'off', + 'n/no-extraneous-import': 'off', 'n/prefer-global/buffer': 'off', 'no-console': 'off', 'unicorn/prefer-module': 'off', diff --git a/packages/@core/forward/stores/src/modules/tabbar.ts b/packages/@core/forward/stores/src/modules/tabbar.ts index 53dcbdae..770b47b6 100644 --- a/packages/@core/forward/stores/src/modules/tabbar.ts +++ b/packages/@core/forward/stores/src/modules/tabbar.ts @@ -100,6 +100,23 @@ const useCoreTabbarStore = defineStore('core-tabbar', { }); if (tabIndex === -1) { + // 获取动态路由打开数,超过 0 即代表需要控制打开数 + const maxNumOfOpenTab = (routeTab?.meta?.maxNumOfOpenTab ?? + -1) as number; + // 如果动态路由层级大于 0 了,那么就要限制该路由的打开数限制了 + // 获取到已经打开的动态路由数, 判断是否大于某一个值 + if ( + maxNumOfOpenTab > 0 && + this.tabs.filter((tab) => tab.name === routeTab.name).length >= + maxNumOfOpenTab + ) { + // 关闭第一个 + const index = this.tabs.findIndex( + (item) => item.name === routeTab.name, + ); + index !== -1 && this.tabs.splice(index, 1); + } + this.tabs.push(tab); } else { // 页面已经存在,不重复添加选项卡,只更新选项卡参数 diff --git a/packages/@core/shared/typings/src/vue-router.d.ts b/packages/@core/shared/typings/src/vue-router.d.ts index 60d19bb6..e905c2cb 100644 --- a/packages/@core/shared/typings/src/vue-router.d.ts +++ b/packages/@core/shared/typings/src/vue-router.d.ts @@ -85,6 +85,11 @@ interface RouteMeta { * 路由是否已经加载过 */ loaded?: boolean; + /** + * 标签页最大打开数量 + * @default false + */ + maxNumOfOpenTab?: number; /** * 菜单可以看到,但是访问会被重定向到403 */ diff --git a/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts b/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts index 6aaca73b..65533938 100644 --- a/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts +++ b/packages/effects/layouts/src/basic/tabbar/use-tabbar.ts @@ -50,7 +50,7 @@ export function useTabbar() { toggleTabPin, } = useTabs(); const currentActive = computed(() => { - return route.path; + return route.fullPath; }); const { locale } = useI18n(); diff --git a/turbo.json b/turbo.json index dca7fc29..e2881e13 100644 --- a/turbo.json +++ b/turbo.json @@ -18,6 +18,10 @@ "dependsOn": ["^build"], "outputs": ["dist/**"] }, + "@vben/backend-mock#build": { + "dependsOn": ["^build"], + "outputs": [".nitro/**", ".output/**"] + }, "stub": {}, "dev": { "dependsOn": [],