tab.ts 7.5 KB

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