tab.ts 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 list
  31. tabsState: TabItem[] = [];
  32. // tab cache list
  33. keepAliveTabsState: CacheName[] = [];
  34. currentContextMenuIndexState = -1;
  35. currentContextMenuState: TabItem | null = null;
  36. get getTabsState() {
  37. return this.tabsState;
  38. }
  39. get getCurrentContextMenuIndexState() {
  40. return this.currentContextMenuIndexState;
  41. }
  42. get getCurrentContextMenuState() {
  43. return this.currentContextMenuState;
  44. }
  45. get getKeepAliveTabsState() {
  46. return this.keepAliveTabsState;
  47. }
  48. get getCurrentTab(): TabItem {
  49. const route = unref(router.currentRoute);
  50. return this.tabsState.find((item) => item.path === route.path)!;
  51. }
  52. @Mutation
  53. commitClearCache(): void {
  54. this.keepAliveTabsState = [];
  55. }
  56. @Mutation
  57. commitCurrentContextMenuIndexState(index: number): void {
  58. this.currentContextMenuIndexState = index;
  59. }
  60. @Mutation
  61. commitCurrentContextMenuState(item: TabItem): void {
  62. this.currentContextMenuState = item;
  63. }
  64. /**
  65. * @description: add tab
  66. */
  67. @Mutation
  68. commitAddTab(route: AppRouteRecordRaw | TabItem): void {
  69. const { path, name, meta, fullPath, params, query } = route as TabItem;
  70. // 404 页面不需要添加tab
  71. if (path === PageEnum.ERROR_PAGE) {
  72. return;
  73. } else if ([REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)) {
  74. return;
  75. }
  76. let updateIndex = -1;
  77. // 已经存在的页面,不重复添加tab
  78. const hasTab = this.tabsState.some((tab, index) => {
  79. updateIndex = index;
  80. return (tab.fullPath || tab.path) === (fullPath || path);
  81. });
  82. if (hasTab) {
  83. const curTab = toRaw(this.tabsState)[updateIndex];
  84. if (!curTab) return;
  85. curTab.params = params || curTab.params;
  86. curTab.query = query || curTab.query;
  87. curTab.fullPath = fullPath || curTab.fullPath;
  88. this.tabsState.splice(updateIndex, 1, curTab);
  89. return;
  90. }
  91. this.tabsState.push({ path, fullPath, name, meta, params, query });
  92. if (unref(getOpenKeepAliveRef) && name) {
  93. const noKeepAlive = meta && meta.ignoreKeepAlive;
  94. const hasName = this.keepAliveTabsState.includes(name);
  95. !noKeepAlive && !hasName && this.keepAliveTabsState.push(name);
  96. }
  97. }
  98. /**
  99. * @description: close tab
  100. */
  101. @Mutation
  102. commitCloseTab(route: AppRouteRecordRaw | TabItem): void {
  103. try {
  104. const { fullPath, name, meta: { affix } = {} } = route;
  105. if (affix) return;
  106. const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
  107. index !== -1 && this.tabsState.splice(index, 1);
  108. if (unref(getOpenKeepAliveRef) && name) {
  109. const i = this.keepAliveTabsState.findIndex((item) => item === name);
  110. i !== -1 && this.keepAliveTabsState.splice(i, 1);
  111. }
  112. } catch (error) {}
  113. }
  114. @Mutation
  115. commitCloseTabKeepAlive(route: AppRouteRecordRaw | TabItem): void {
  116. const { name } = route;
  117. if (unref(getOpenKeepAliveRef) && name) {
  118. const i = this.keepAliveTabsState.findIndex((item) => item === name);
  119. i !== -1 && toRaw(this.keepAliveTabsState).splice(i, 1);
  120. }
  121. }
  122. @Mutation
  123. commitCloseAllTab(): void {
  124. this.tabsState = this.tabsState.filter((item) => {
  125. return item.meta && item.meta.affix;
  126. });
  127. const names = this.tabsState.map((item) => item.name);
  128. this.keepAliveTabsState = names as string[];
  129. }
  130. @Mutation
  131. commitResetState(): void {
  132. this.tabsState = [];
  133. this.currentContextMenuState = null;
  134. this.currentContextMenuIndexState = -1;
  135. this.keepAliveTabsState = [];
  136. }
  137. @Mutation
  138. closeMultipleTab({ pathList, nameList }: { pathList: string[]; nameList: string[] }): void {
  139. this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
  140. if (unref(getOpenKeepAliveRef) && nameList) {
  141. this.keepAliveTabsState = toRaw(this.keepAliveTabsState).filter(
  142. (item) => !nameList.includes(item as string)
  143. );
  144. }
  145. }
  146. @Action
  147. closeLeftTabAction(route: AppRouteRecordRaw | TabItem): void {
  148. const index = this.tabsState.findIndex((item) => item.path === route.path);
  149. if (index > 0) {
  150. const leftTabs = this.tabsState.slice(0, index);
  151. const pathList: string[] = [];
  152. const nameList: string[] = [];
  153. for (const item of leftTabs) {
  154. const affix = item.meta ? item.meta.affix : false;
  155. if (!affix) {
  156. pathList.push(item.fullPath);
  157. nameList.push(item.name as string);
  158. }
  159. }
  160. this.closeMultipleTab({ pathList, nameList });
  161. }
  162. }
  163. @Action
  164. addTabByPathAction(): void {
  165. const toRoute = getCurrentTo();
  166. if (!toRoute) return;
  167. const { meta } = toRoute;
  168. if (meta && meta.affix) {
  169. return;
  170. }
  171. this.commitAddTab((toRoute as unknown) as AppRouteRecordRaw);
  172. }
  173. @Action
  174. closeRightTabAction(route: AppRouteRecordRaw | TabItem): void {
  175. const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
  176. if (index >= 0 && index < this.tabsState.length - 1) {
  177. const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);
  178. const pathList: string[] = [];
  179. const nameList: string[] = [];
  180. for (const item of rightTabs) {
  181. const affix = item.meta ? item.meta.affix : false;
  182. if (!affix) {
  183. pathList.push(item.fullPath);
  184. nameList.push(item.name as string);
  185. }
  186. }
  187. this.closeMultipleTab({ pathList, nameList });
  188. }
  189. }
  190. @Action
  191. closeOtherTabAction(route: AppRouteRecordRaw | TabItem): void {
  192. const closePathList = this.tabsState.map((item) => item.fullPath);
  193. const pathList: string[] = [];
  194. const nameList: string[] = [];
  195. closePathList.forEach((path) => {
  196. if (path !== route.fullPath) {
  197. const closeItem = this.tabsState.find((item) => item.path === path);
  198. if (!closeItem) return;
  199. const affix = closeItem.meta ? closeItem.meta.affix : false;
  200. if (!affix) {
  201. pathList.push(closeItem.fullPath);
  202. nameList.push(closeItem.name as string);
  203. }
  204. }
  205. });
  206. this.closeMultipleTab({ pathList, nameList });
  207. }
  208. }
  209. export { Tab };
  210. export const tabStore = getModule<Tab>(Tab);