Blame view

src/store/modules/tab.ts 9.12 KB
vben authored
1
import { toRaw } from 'vue';
陈文彬 authored
2
3
4
5
6
7
8
9
10
11

import { unref } from 'vue';
import { Action, Module, Mutation, VuexModule, getModule } from 'vuex-module-decorators';
import { hotModuleUnregisterModule } from '/@/utils/helper/vuexHelper';

import { PageEnum } from '/@/enums/pageEnum';

import store from '/@/store';
import router from '/@/router';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/constant';
vben authored
12
13
14
import { RouteLocationNormalized, RouteLocationRaw } from 'vue-router';
import { getRoute } from '/@/router/helper/routeHelper';
import { useGo, useRedo } from '/@/hooks/web/usePage';
vben authored
15
import { cloneDeep } from 'lodash-es';
陈文彬 authored
16
17
const NAME = 'app-tab';
18
陈文彬 authored
19
20
hotModuleUnregisterModule(NAME);
vben authored
21
22
23
24
25
26
export const PAGE_LAYOUT_KEY = '__PAGE_LAYOUT__';

function isGotoPage() {
  const go = useGo();
  go(unref(router.currentRoute).path, true);
}
陈文彬 authored
27
28
29

@Module({ namespaced: true, name: NAME, dynamic: true, store })
class Tab extends VuexModule {
vben authored
30
  cachedMapState = new Map<string, string[]>();
陈文彬 authored
31
vben authored
32
33
  // tab list
  tabsState: RouteLocationNormalized[] = [];
陈文彬 authored
34
vben authored
35
  lastDragEndIndexState = 0;
36
陈文彬 authored
37
38
39
40
  get getTabsState() {
    return this.tabsState;
  }
vben authored
41
42
43
  get getCurrentTab(): RouteLocationNormalized {
    const route = unref(router.currentRoute);
    return this.tabsState.find((item) => item.path === route.path)!;
陈文彬 authored
44
45
  }
vben authored
46
47
  get getCachedMapState(): Map<string, string[]> {
    return this.cachedMapState;
陈文彬 authored
48
49
  }
vben authored
50
51
  get getLastDragEndIndexState(): number {
    return this.lastDragEndIndexState;
陈文彬 authored
52
53
54
55
  }

  @Mutation
  commitClearCache(): void {
vben authored
56
    this.cachedMapState = new Map();
陈文彬 authored
57
58
59
  }

  @Mutation
vben authored
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  goToPage() {
    const go = useGo();
    const len = this.tabsState.length;
    const { path } = unref(router.currentRoute);

    let toPath: PageEnum | string = PageEnum.BASE_HOME;

    if (len > 0) {
      const page = this.tabsState[len - 1];
      const p = page.fullPath || page.path;
      if (p) {
        toPath = p;
      }
    }
    // Jump to the current page and report an error
    path !== toPath && go(toPath as PageEnum, true);
陈文彬 authored
76
77
78
  }

  @Mutation
vben authored
79
80
81
82
83
84
  commitCachedMapState(): void {
    const cacheMap = new Map<string, string[]>();

    const pageCacheSet = new Set<string>();
    this.tabsState.forEach((tab) => {
      const item = getRoute(tab);
vben authored
85
      const needCache = !item.meta?.ignoreKeepAlive;
vben authored
86
87
      if (!needCache) return;
vben authored
88
      if (item.meta?.affix) {
vben authored
89
90
        const name = item.name as string;
        pageCacheSet.add(name);
91
92
93
      } else if (item?.matched && needCache) {
        const matched = item?.matched;
        if (!matched) return;
vben authored
94
95
96
97
98
99
100
101
102
103
104
105
        const len = matched.length;

        if (len < 2) return;

        for (let i = 0; i < matched.length; i++) {
          const key = matched[i].name as string;

          if (i < 2) {
            pageCacheSet.add(key);
          }
          if (i < len - 1) {
            const { meta, name } = matched[i + 1];
vben authored
106
            if (meta && (meta.affix || needCache)) {
vben authored
107
108
109
110
111
112
113
114
115
116
117
118
119
              const mapList = cacheMap.get(key) || [];
              if (!mapList.includes(name as string)) {
                mapList.push(name as string);
              }
              cacheMap.set(key, mapList);
            }
          }
        }
      }
    });

    cacheMap.set(PAGE_LAYOUT_KEY, Array.from(pageCacheSet));
    this.cachedMapState = cacheMap;
陈文彬 authored
120
121
122
  }

  @Mutation
vben authored
123
124
  commitTabRoutesState(route: RouteLocationNormalized) {
    const { path, fullPath, params, query } = route;
vben authored
125
126
    let updateIndex = -1;
Vben authored
127
    // Existing pages, do not add tabs repeatedly
128
129
130
    const hasTab = this.tabsState.some((tab, index) => {
      updateIndex = index;
      return (tab.fullPath || tab.path) === (fullPath || path);
陈文彬 authored
131
    });
132
133
134
135
136
137
138
139
140
    if (hasTab) {
      const curTab = toRaw(this.tabsState)[updateIndex];
      if (!curTab) return;
      curTab.params = params || curTab.params;
      curTab.query = query || curTab.query;
      curTab.fullPath = fullPath || curTab.fullPath;
      this.tabsState.splice(updateIndex, 1, curTab);
      return;
    }
vben authored
141
    this.tabsState = cloneDeep([...this.tabsState, route]);
陈文彬 authored
142
143
144
145
146
147
  }

  /**
   * @description: close tab
   */
  @Mutation
vben authored
148
149
150
151
152
  commitCloseTab(route: RouteLocationNormalized): void {
    const { fullPath, meta: { affix } = {} } = route;
    if (affix) return;
    const index = this.tabsState.findIndex((item) => item.fullPath === fullPath);
    index !== -1 && this.tabsState.splice(index, 1);
陈文彬 authored
153
154
155
156
157
158
159
160
161
162
163
164
  }

  @Mutation
  commitCloseAllTab(): void {
    this.tabsState = this.tabsState.filter((item) => {
      return item.meta && item.meta.affix;
    });
  }

  @Mutation
  commitResetState(): void {
    this.tabsState = [];
vben authored
165
    this.cachedMapState = new Map();
陈文彬 authored
166
167
168
  }

  @Mutation
169
170
171
172
173
  commitSortTabs({ oldIndex, newIndex }: { oldIndex: number; newIndex: number }): void {
    const currentTab = this.tabsState[oldIndex];

    this.tabsState.splice(oldIndex, 1);
    this.tabsState.splice(newIndex, 0, currentTab);
vben authored
174
    this.lastDragEndIndexState = this.lastDragEndIndexState + 1;
175
176
177
  }

  @Mutation
vben authored
178
  closeMultipleTab({ pathList }: { pathList: string[] }): void {
vben authored
179
    this.tabsState = toRaw(this.tabsState).filter((item) => !pathList.includes(item.fullPath));
vben authored
180
181
182
183
184
  }

  @Action
  addTabAction(route: RouteLocationNormalized) {
    const { path, name } = route;
185
    // 404  The page does not need to add a tab
vben authored
186
187
188
189
190
191
192
193
194
195
196
197
198
    if (
      path === PageEnum.ERROR_PAGE ||
      !name ||
      [REDIRECT_ROUTE.name, PAGE_NOT_FOUND_ROUTE.name].includes(name as string)
    ) {
      return;
    }
    this.commitTabRoutesState(getRoute(route));

    this.commitCachedMapState();
  }

  @Mutation
vben authored
199
  async commitRedoPage() {
vben authored
200
201
202
203
204
205
206
207
208
209
210
211
212
213
    const route = router.currentRoute.value;
    for (const [key, value] of this.cachedMapState) {
      const index = value.findIndex((item) => item === (route.name as string));
      if (index === -1) {
        continue;
      }
      if (value.length === 1) {
        this.cachedMapState.delete(key);
        continue;
      }
      value.splice(index, 1);
      this.cachedMapState.set(key, value);
    }
    const redo = useRedo();
vben authored
214
    await redo();
vben authored
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
  }

  @Action
  closeAllTabAction() {
    this.commitCloseAllTab();
    this.commitClearCache();
    this.goToPage();
  }

  @Action
  closeTabAction(tab: RouteLocationNormalized) {
    function getObj(tabItem: RouteLocationNormalized) {
      const { params, path, query } = tabItem;
      return {
        params: params || {},
        path,
        query: query || {},
      };
    }
    const { currentRoute, replace } = router;

    const { path } = unref(currentRoute);
    if (path !== tab.path) {
      // Closed is not the activation tab
      this.commitCloseTab(tab);
      return;
    }

    // Closed is activated atb
    let toObj: RouteLocationRaw = {};

    const index = this.getTabsState.findIndex((item) => item.path === path);

    // If the current is the leftmost tab
    if (index === 0) {
      // There is only one tab, then jump to the homepage, otherwise jump to the right tab
      if (this.getTabsState.length === 1) {
        toObj = PageEnum.BASE_HOME;
      } else {
        //  Jump to the right tab
        const page = this.getTabsState[index + 1];
        toObj = getObj(page);
      }
    } else {
      // Close the current tab
      const page = this.getTabsState[index - 1];
      toObj = getObj(page);
陈文彬 authored
262
    }
vben authored
263
264
    this.commitCloseTab(currentRoute.value);
    replace(toObj);
陈文彬 authored
265
266
267
  }

  @Action
vben authored
268
269
270
271
272
273
274
  closeTabByKeyAction(key: string) {
    const index = this.tabsState.findIndex((item) => (item.fullPath || item.path) === key);
    index !== -1 && this.closeTabAction(this.tabsState[index]);
  }

  @Action
  closeLeftTabAction(route: RouteLocationNormalized): void {
陈文彬 authored
275
276
277
278
279
280
281
282
    const index = this.tabsState.findIndex((item) => item.path === route.path);

    if (index > 0) {
      const leftTabs = this.tabsState.slice(0, index);
      const pathList: string[] = [];
      for (const item of leftTabs) {
        const affix = item.meta ? item.meta.affix : false;
        if (!affix) {
vben authored
283
          pathList.push(item.fullPath);
陈文彬 authored
284
285
        }
      }
vben authored
286
      this.closeMultipleTab({ pathList });
vben authored
287
    }
vben authored
288
289
    this.commitCachedMapState();
    isGotoPage();
290
291
292
  }

  @Action
vben authored
293
  closeRightTabAction(route: RouteLocationNormalized): void {
vben authored
294
    const index = this.tabsState.findIndex((item) => item.fullPath === route.fullPath);
陈文彬 authored
295
296
297
298
299
300
301
302

    if (index >= 0 && index < this.tabsState.length - 1) {
      const rightTabs = this.tabsState.slice(index + 1, this.tabsState.length);

      const pathList: string[] = [];
      for (const item of rightTabs) {
        const affix = item.meta ? item.meta.affix : false;
        if (!affix) {
vben authored
303
          pathList.push(item.fullPath);
陈文彬 authored
304
305
        }
      }
vben authored
306
      this.closeMultipleTab({ pathList });
陈文彬 authored
307
    }
vben authored
308
309
    this.commitCachedMapState();
    isGotoPage();
陈文彬 authored
310
311
312
  }

  @Action
vben authored
313
  closeOtherTabAction(route: RouteLocationNormalized): void {
vben authored
314
    const closePathList = this.tabsState.map((item) => item.fullPath);
陈文彬 authored
315
316
    const pathList: string[] = [];
    closePathList.forEach((path) => {
vben authored
317
      if (path !== route.fullPath) {
陈文彬 authored
318
319
320
321
        const closeItem = this.tabsState.find((item) => item.path === path);
        if (!closeItem) return;
        const affix = closeItem.meta ? closeItem.meta.affix : false;
        if (!affix) {
vben authored
322
          pathList.push(closeItem.fullPath);
陈文彬 authored
323
324
325
        }
      }
    });
vben authored
326
327
328
    this.closeMultipleTab({ pathList });
    this.commitCachedMapState();
    isGotoPage();
陈文彬 authored
329
330
331
  }
}
export const tabStore = getModule<Tab>(Tab);