use-tabs.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. import type { IContextMenuItem } from '@vben-core/tabs-ui';
  2. import type { TabItem } from '@vben-core/typings';
  3. import type {
  4. RouteLocationNormalized,
  5. RouteRecordNormalized,
  6. } from 'vue-router';
  7. import { computed, watch } from 'vue';
  8. import { useRoute, useRouter } from 'vue-router';
  9. import { $t } from '@vben/locales';
  10. import {
  11. IcRoundClose,
  12. IcRoundMultipleStop,
  13. IcRoundRefresh,
  14. MdiArrowExpandHorizontal,
  15. MdiFormatHorizontalAlignLeft,
  16. MdiFormatHorizontalAlignRight,
  17. MdiPin,
  18. MdiPinOff,
  19. } from '@vben-core/iconify';
  20. import { storeToRefs, useAccessStore, useTabbarStore } from '@vben-core/stores';
  21. import { filterTree } from '@vben-core/toolkit';
  22. function useTabs() {
  23. const router = useRouter();
  24. const route = useRoute();
  25. const accessStore = useAccessStore();
  26. const tabsStore = useTabbarStore();
  27. const { accessMenus } = storeToRefs(accessStore);
  28. const currentActive = computed(() => {
  29. return route.path;
  30. });
  31. const currentTabs = computed(() => {
  32. return tabsStore.getTabs;
  33. });
  34. /**
  35. * 初始化固定标签页
  36. */
  37. const initAffixTabs = () => {
  38. const affixTabs = filterTree(router.getRoutes(), (route) => {
  39. return !!route.meta?.affixTab;
  40. });
  41. affixTabs.forEach((tab) => {
  42. Object.assign(tab, wrapperTabLocale(tab));
  43. });
  44. tabsStore.setAffixTabs(affixTabs);
  45. };
  46. // 点击tab,跳转路由
  47. const handleClick = (key: string) => {
  48. router.push(key);
  49. };
  50. // 关闭tab
  51. const handleClose = async (key: string) => {
  52. await tabsStore.closeTabByKey(key, router);
  53. };
  54. function wrapperTabLocale(
  55. tab: RouteLocationNormalized | RouteRecordNormalized,
  56. ) {
  57. return {
  58. ...tab,
  59. meta: {
  60. ...tab.meta,
  61. title: $t(tab.meta.title as string),
  62. },
  63. };
  64. }
  65. watch(
  66. () => accessMenus.value,
  67. () => {
  68. initAffixTabs();
  69. },
  70. { immediate: true },
  71. );
  72. watch(
  73. () => route.path,
  74. () => {
  75. tabsStore.addTab(wrapperTabLocale(route) as RouteLocationNormalized);
  76. },
  77. { immediate: true },
  78. );
  79. const createContextMenus = (tab: TabItem) => {
  80. const tabs = tabsStore.getTabs;
  81. const affixTabs = tabsStore.affixTabs;
  82. const index = tabs.findIndex((item) => item.path === tab.path);
  83. const disabled = tabs.length <= 1;
  84. const { meta } = tab;
  85. const affixTab = meta?.affixTab ?? false;
  86. const isCurrentTab = route.path === tab.path;
  87. // 当前处于最左侧或者减去固定标签页的数量等于0
  88. const closeLeftDisabled =
  89. index === 0 || index - affixTabs.length <= 0 || !isCurrentTab;
  90. const closeRightDisabled = !isCurrentTab || index === tabs.length - 1;
  91. const closeOtherDisabled =
  92. disabled || !isCurrentTab || tabs.length - affixTabs.length <= 1;
  93. const menus: IContextMenuItem[] = [
  94. {
  95. disabled: !isCurrentTab,
  96. handler: async () => {
  97. await tabsStore.refreshTab(router);
  98. },
  99. icon: IcRoundRefresh,
  100. key: 'reload',
  101. text: '重新加载',
  102. },
  103. {
  104. disabled: !!affixTab || disabled,
  105. handler: async () => {
  106. await tabsStore.closeTab(tab, router);
  107. },
  108. icon: IcRoundClose,
  109. key: 'close',
  110. text: '关闭标签页',
  111. },
  112. {
  113. handler: async () => {
  114. await (affixTab
  115. ? tabsStore.unPushPinTab(tab)
  116. : tabsStore.pushPinTab(tab));
  117. },
  118. icon: affixTab ? MdiPinOff : MdiPin,
  119. key: 'affix',
  120. separator: true,
  121. text: affixTab ? '取消固定标签页' : '固定标签页',
  122. },
  123. {
  124. disabled: closeLeftDisabled,
  125. handler: async () => {
  126. await tabsStore.closeLeftTabs(tab);
  127. },
  128. icon: MdiFormatHorizontalAlignLeft,
  129. key: 'close-left',
  130. text: '关闭左侧标签页',
  131. },
  132. {
  133. disabled: closeRightDisabled,
  134. handler: async () => {
  135. await tabsStore.closeRightTabs(tab);
  136. },
  137. icon: MdiFormatHorizontalAlignRight,
  138. key: 'close-right',
  139. separator: true,
  140. text: '关闭右侧标签页',
  141. },
  142. {
  143. disabled: closeOtherDisabled,
  144. handler: async () => {
  145. await tabsStore.closeOtherTabs(tab);
  146. },
  147. icon: MdiArrowExpandHorizontal,
  148. key: 'close-other',
  149. text: '关闭其他标签页',
  150. },
  151. {
  152. disabled,
  153. handler: async () => {
  154. await tabsStore.closeAllTabs(router);
  155. },
  156. icon: IcRoundMultipleStop,
  157. key: 'close-all',
  158. text: '关闭全部标签页',
  159. },
  160. // {
  161. // icon: 'icon-[material-symbols--back-to-tab-sharp]',
  162. // key: 'close-all',
  163. // text: '新窗口打开',
  164. // },
  165. ];
  166. return menus;
  167. };
  168. /**
  169. * 取消固定标签页
  170. */
  171. const handleUnPushPin = async (tab: TabItem) => {
  172. await tabsStore.unPushPinTab(tab);
  173. };
  174. return {
  175. createContextMenus,
  176. currentActive,
  177. currentTabs,
  178. handleClick,
  179. handleClose,
  180. handleUnPushPin,
  181. };
  182. }
  183. export { useTabs };