tab.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { computed, toRaw } from 'vue';
  2. import type { AppRouteRecordRaw, RouteMeta } from '/@/router/types.d';
  3. import { unref } from 'vue';
  4. import { Action, Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators';
  5. import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';
  6. import { PageEnum } from '/@/enums/pageEnum';
  7. import { appStore } from '/@/store/modules/app';
  8. import store from '/@/store';
  9. import router from '/@/router';
  10. import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
  11. import { getCurrentTo } from '/@/utils/helper/routeHelper';
  12. type CacheName = string | symbol | null | undefined;
  13. /**
  14. * @description: vuex Tab模块
  15. */
  16. // declare namespace TabsStore {
  17. export interface TabItem {
  18. fullPath: string;
  19. path?: string;
  20. params?: any;
  21. query?: any;
  22. name?: CacheName;
  23. meta?: RouteMeta;
  24. }
  25. const NAME = 'tab';
  26. hotModuleUnregisterModule(NAME);
  27. const getOpenKeepAliveRef = computed(() => appStore.getProjectConfig.openKeepAlive);
  28. @Module({ namespaced: true, name: NAME, dynamic: true, store })
  29. class Tab extends VuexModule {
  30. // tab列表
  31. tabsState: TabItem[] = [];
  32. // 缓存列表
  33. keepAliveTabsState: CacheName[] = [];
  34. currentContextMenuIndexState = -1;
  35. currentContextMenuState: TabItem | null = null;
  36. /**
  37. * @description: 获取tabs
  38. */
  39. get getTabsState() {
  40. return this.tabsState;
  41. }
  42. get getCurrentContextMenuIndexState() {
  43. return this.currentContextMenuIndexState;
  44. }
  45. get getCurrentContextMenuState() {
  46. return this.currentContextMenuState;
  47. }
  48. /**
  49. * @description: 获取缓存的tab列表
  50. */
  51. get getKeepAliveTabsState() {
  52. return this.keepAliveTabsState;
  53. }
  54. get getCurrentTab(): TabItem {
  55. const route = unref(router.currentRoute);
  56. return this.tabsState.find((item) => item.path === route.path)!;
  57. }
  58. @Mutation
  59. commitClearCache(): void {
  60. this.keepAliveTabsState = [];
  61. }
  62. @Mutation
  63. commitCurrentContextMenuIndexState(index: number): void {
  64. this.currentContextMenuIndexState = index;
  65. }
  66. @Mutation
  67. commitCurrentContextMenuState(item: TabItem): void {
  68. this.currentContextMenuState = item;
  69. }
  70. /**
  71. * @description: add tab
  72. */
  73. @Mutation
  74. commitAddTab(route: AppRouteRecordRaw | TabItem): void {
  75. const { path, name, meta, fullPath, params, query } = route as TabItem;
  76. // 404 页面不需要添加tab
  77. if (path === PageEnum.ERROR_PAGE) {
  78. return;
  79. } else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) {
  80. return;
  81. }
  82. // 已经存在的页面,不重复添加tab
  83. const hasTab = this.tabsState.some((tab) => {
  84. return tab.fullPath === fullPath;
  85. });
  86. if (hasTab) return;
  87. this.tabsState.push({ path, fullPath, name, meta, params, query });
  88. if (unref(getOpenKeepAliveRef) && name) {
  89. const noKeepAlive = meta && meta.ignoreKeepAlive;
  90. const hasName = this.keepAliveTabsState.includes(name);
  91. !noKeepAlive && !hasName && this.keepAliveTabsState.push(name);
  92. }
  93. }
  94. /**
  95. * @description: close tab
  96. */
  97. @Mutation
  98. commitCloseTab(route: AppRouteRecordRaw | TabItem): void {
  99. try {
  100. const { fullPath, name, meta: { affix } = {} } = route;
  101. if (affix) return;
  102. const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
  103. index !== -1 && this.tabsState.splice(index, 1);
  104. if (unref(getOpenKeepAliveRef) && name) {
  105. const i = this.keepAliveTabsState.findIndex((item) => item === name);
  106. i !== -1 && this.keepAliveTabsState.splice(i, 1);
  107. }
  108. } catch (error) {}
  109. }
  110. @Mutation
  111. commitCloseTabKeepAlive(route: AppRouteRecordRaw | TabItem): void {
  112. const { name } = route;
  113. if (unref(getOpenKeepAliveRef) && name) {
  114. const i = this.keepAliveTabsState.findIndex((item) => item === name);
  115. i !== -1 && toRaw(this.keepAliveTabsState).splice(i, 1);
  116. }
  117. }
  118. @Mutation
  119. commitCloseAllTab(): void {
  120. this.tabsState = this.tabsState.filter((item) => {
  121. return item.meta && item.meta.affix;
  122. });
  123. const names = this.tabsState.map((item) => item.name);
  124. this.keepAliveTabsState = names as string[];
  125. }
  126. @Mutation
  127. commitResetState(): void {
  128. this.tabsState = [];
  129. this.currentContextMenuState = null;
  130. this.currentContextMenuIndexState = -1;
  131. this.keepAliveTabsState = [];
  132. }
  133. @Mutation
  134. closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void {
  135. this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
  136. if (unref(getOpenKeepAliveRef) && nameList) {
  137. this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter(
  138. (item) => !nameList.includes(item as string)
  139. );
  140. }
  141. }
  142. @Action
  143. closeLeftTabAction(route: AppRouteRecordRaw | TabItem): void {
  144. const index = this.tabsState.findIndex((item) => item.path === route.path);
  145. if (index > 0) {
  146. const leftTabs = this.tabsState.slice(0, index);
  147. const pathList: string[] = [];
  148. const nameList: string[] = [];
  149. for (const item of leftTabs) {
  150. const affix = item.meta ? item.meta.affix : false;
  151. if (!affix) {
  152. pathList.push(item.fullPath);
  153. nameList.push(item.name as string);
  154. }
  155. }
  156. this.closeMultipleTab({ pathList, nameList });
  157. }
  158. }
  159. @Action
  160. addTabByPathAction(): void {
  161. const toRoute = getCurrentTo();
  162. if (!toRoute) return;
  163. const { meta } = toRoute;
  164. if (meta && meta.affix) {
  165. return;
  166. }
  167. this.commitAddTab((toRoute as unknown) as AppRouteRecordRaw);
  168. }
  169. @Action
  170. closeRightTabAction(route: AppRouteRecordRaw | TabItem): void {
  171. const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
  172. if (index >= 0 && index < this.tabsState.length - 1) {
  173. const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
  174. const pathList: string[] = [];
  175. const nameList: string[] = [];
  176. for (const item of rightTabs) {
  177. const affix = item.meta ? item.meta.affix : false;
  178. if (!affix) {
  179. pathList.push(item.fullPath);
  180. nameList.push(item.name as string);
  181. }
  182. }
  183. this.closeMultipleTab({ pathList, nameList });
  184. }
  185. }
  186. @Action
  187. closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void {
  188. const closePathList = this.tabsState.map((item) => item.fullPath);
  189. const pathList: string[] = [];
  190. const nameList: string[] = [];
  191. closePathList.forEach((path) => {
  192. if (path !== route.fullPath) {
  193. const closeItem = this.tabsState.find((item) => item.path === path);
  194. if (!closeItem) return;
  195. const affix = closeItem.meta ? closeItem.meta.affix : false;
  196. if (!affix) {
  197. pathList.push(closeItem.fullPath);
  198. nameList.push(closeItem.name as string);
  199. }
  200. }
  201. });
  202. this.closeMultipleTab({ pathList, nameList });
  203. }
  204. }
  205. export { Tab };
  206. export const tabStore = getModule<Tab>(Tab);