use-tabs.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import type { IContextMenuItem } from '@vben-core/tabs-ui';
  2. import type { TabDefinition } from '@vben-core/typings';
  3. import type {
  4. RouteLocationNormalized,
  5. RouteLocationNormalizedGeneric,
  6. } from 'vue-router';
  7. import { computed, ref, watch } from 'vue';
  8. import { useRoute, useRouter } from 'vue-router';
  9. import {
  10. IcRoundClose,
  11. IcRoundFitScreen,
  12. IcRoundMultipleStop,
  13. IcRoundRefresh,
  14. IcRoundTableView,
  15. IcTwotoneFitScreen,
  16. MdiArrowExpandHorizontal,
  17. MdiFormatHorizontalAlignLeft,
  18. MdiFormatHorizontalAlignRight,
  19. MdiPin,
  20. MdiPinOff,
  21. } from '@vben-core/iconify';
  22. import { $t, useI18n } from '@vben-core/locales';
  23. import { updatePreferences, usePreferences } from '@vben-core/preferences';
  24. import {
  25. storeToRefs,
  26. useCoreAccessStore,
  27. useCoreTabbarStore,
  28. } from '@vben-core/stores';
  29. import { filterTree, openWindow } from '@vben-core/toolkit';
  30. function updateContentScreen(screen: boolean) {
  31. updatePreferences({
  32. header: {
  33. hidden: !!screen,
  34. },
  35. sidebar: {
  36. hidden: !!screen,
  37. },
  38. });
  39. }
  40. function useTabs() {
  41. const router = useRouter();
  42. const route = useRoute();
  43. const accessStore = useCoreAccessStore();
  44. const { contentIsMaximize } = usePreferences();
  45. const coreTabbarStore = useCoreTabbarStore();
  46. const { accessMenus } = storeToRefs(accessStore);
  47. const currentActive = computed(() => {
  48. return route.path;
  49. });
  50. const { locale } = useI18n();
  51. const currentTabs = ref<RouteLocationNormalizedGeneric[]>();
  52. watch([() => coreTabbarStore.getTabs, () => locale.value], ([tabs, _]) => {
  53. currentTabs.value = tabs.map((item) => wrapperTabLocale(item));
  54. });
  55. /**
  56. * 初始化固定标签页
  57. */
  58. const initAffixTabs = () => {
  59. const affixTabs = filterTree(router.getRoutes(), (route) => {
  60. return !!route.meta?.affixTab;
  61. });
  62. coreTabbarStore.setAffixTabs(affixTabs);
  63. };
  64. // 点击tab,跳转路由
  65. const handleClick = (key: string) => {
  66. router.push(key);
  67. };
  68. // 关闭tab
  69. const handleClose = async (key: string) => {
  70. await coreTabbarStore.closeTabByKey(key, router);
  71. };
  72. function wrapperTabLocale(tab: RouteLocationNormalizedGeneric) {
  73. return {
  74. ...tab,
  75. meta: {
  76. ...tab?.meta,
  77. title: $t(tab?.meta?.title as string),
  78. },
  79. };
  80. }
  81. watch(
  82. () => accessMenus.value,
  83. () => {
  84. initAffixTabs();
  85. },
  86. { immediate: true },
  87. );
  88. watch(
  89. () => route.path,
  90. () => {
  91. coreTabbarStore.addTab(route as RouteLocationNormalized);
  92. },
  93. { immediate: true },
  94. );
  95. const createContextMenus = (tab: TabDefinition) => {
  96. const tabs = coreTabbarStore.getTabs;
  97. const affixTabs = coreTabbarStore.affixTabs;
  98. const index = tabs.findIndex((item) => item.path === tab.path);
  99. const disabled = tabs.length <= 1;
  100. const { meta } = tab;
  101. const affixTab = meta?.affixTab ?? false;
  102. const isCurrentTab = route.path === tab.path;
  103. // 当前处于最左侧或者减去固定标签页的数量等于0
  104. const closeLeftDisabled =
  105. index === 0 || index - affixTabs.length <= 0 || !isCurrentTab;
  106. const closeRightDisabled = !isCurrentTab || index === tabs.length - 1;
  107. const closeOtherDisabled =
  108. disabled || !isCurrentTab || tabs.length - affixTabs.length <= 1;
  109. const menus: IContextMenuItem[] = [
  110. {
  111. disabled: !!affixTab || disabled,
  112. handler: async () => {
  113. await coreTabbarStore.closeTab(tab, router);
  114. },
  115. icon: IcRoundClose,
  116. key: 'close',
  117. text: $t('preferences.tabbar.contextMenu.close'),
  118. },
  119. {
  120. handler: async () => {
  121. await (affixTab
  122. ? coreTabbarStore.unpinTab(tab)
  123. : coreTabbarStore.pinTab(tab));
  124. },
  125. icon: affixTab ? MdiPinOff : MdiPin,
  126. key: 'affix',
  127. text: affixTab
  128. ? $t('preferences.tabbar.contextMenu.unpin')
  129. : $t('preferences.tabbar.contextMenu.pin'),
  130. },
  131. {
  132. handler: async () => {
  133. if (!contentIsMaximize.value) {
  134. await router.push(tab.fullPath);
  135. }
  136. updateContentScreen(!contentIsMaximize.value);
  137. },
  138. icon: contentIsMaximize.value ? IcRoundFitScreen : IcTwotoneFitScreen,
  139. key: contentIsMaximize.value ? 'restore-maximize' : 'maximize',
  140. text: contentIsMaximize.value
  141. ? $t('preferences.tabbar.contextMenu.restoreMaximize')
  142. : $t('preferences.tabbar.contextMenu.maximize'),
  143. },
  144. {
  145. disabled: !isCurrentTab,
  146. handler: async () => {
  147. await coreTabbarStore.refresh(router);
  148. },
  149. icon: IcRoundRefresh,
  150. key: 'reload',
  151. text: $t('preferences.tabbar.contextMenu.reload'),
  152. },
  153. {
  154. handler: async () => {
  155. const { hash, origin } = location;
  156. const path = tab.fullPath;
  157. const fullPath = path.startsWith('/') ? path : `/${path}`;
  158. const url = `${origin}${hash ? '/#' : ''}${fullPath}`;
  159. openWindow(url, { target: '_blank' });
  160. },
  161. icon: IcRoundTableView,
  162. key: 'open-in-new-window',
  163. separator: true,
  164. text: $t('preferences.tabbar.contextMenu.openInNewWindow'),
  165. },
  166. {
  167. disabled: closeLeftDisabled,
  168. handler: async () => {
  169. await coreTabbarStore.closeLeftTabs(tab);
  170. },
  171. icon: MdiFormatHorizontalAlignLeft,
  172. key: 'close-left',
  173. text: $t('preferences.tabbar.contextMenu.closeLeft'),
  174. },
  175. {
  176. disabled: closeRightDisabled,
  177. handler: async () => {
  178. await coreTabbarStore.closeRightTabs(tab);
  179. },
  180. icon: MdiFormatHorizontalAlignRight,
  181. key: 'close-right',
  182. separator: true,
  183. text: $t('preferences.tabbar.contextMenu.closeRight'),
  184. },
  185. {
  186. disabled: closeOtherDisabled,
  187. handler: async () => {
  188. await coreTabbarStore.closeOtherTabs(tab);
  189. },
  190. icon: MdiArrowExpandHorizontal,
  191. key: 'close-other',
  192. text: $t('preferences.tabbar.contextMenu.closeOther'),
  193. },
  194. {
  195. disabled,
  196. handler: async () => {
  197. await coreTabbarStore.closeAllTabs(router);
  198. },
  199. icon: IcRoundMultipleStop,
  200. key: 'close-all',
  201. text: $t('preferences.tabbar.contextMenu.closeAll'),
  202. },
  203. ];
  204. return menus;
  205. };
  206. /**
  207. * 取消固定标签页
  208. */
  209. const handleUnpinTab = async (tab: TabDefinition) => {
  210. await coreTabbarStore.unpinTab(tab);
  211. };
  212. return {
  213. createContextMenus,
  214. currentActive,
  215. currentTabs,
  216. handleClick,
  217. handleClose,
  218. handleUnpinTab,
  219. };
  220. }
  221. export { updateContentScreen, useTabs };