雪忆
2024-07-29 ecfe66a0199606241c73a52519bbe800c9aa31f8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import type { Router, RouteRecordRaw } from 'vue-router';
 
import { usePermissionStoreWithOut } from '@/store/modules/permission';
 
import { PageEnum } from '@/enums/pageEnum';
import { useUserStoreWithOut } from '@/store/modules/user';
 
import { PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic';
 
import { RootRoute } from '@/router/routes';
 
const LOGIN_PATH = PageEnum.BASE_LOGIN;
 
const ROOT_PATH = RootRoute.path;
 
const whitePathList: PageEnum[] = [LOGIN_PATH];
 
export function createPermissionGuard(router: Router) {
  const userStore = useUserStoreWithOut();
  const permissionStore = usePermissionStoreWithOut();
  router.beforeEach(async (to, from, next) => {
    if (
      from.path === ROOT_PATH &&
      to.path === PageEnum.BASE_HOME &&
      userStore.getUserInfo.homePath &&
      userStore.getUserInfo.homePath !== PageEnum.BASE_HOME
    ) {
      next(userStore.getUserInfo.homePath);
      return;
    }
 
    const token = userStore.getToken;
 
    // Whitelist can be directly entered
    if (whitePathList.includes(to.path as PageEnum)) {
      if (to.path === LOGIN_PATH && token) {
        const isSessionTimeout = userStore.getSessionTimeout;
        try {
          await userStore.afterLoginAction();
          if (!isSessionTimeout) {
            next(decodeURIComponent((to.query?.redirect as string) || '/'));
            return;
          }
        } catch {
          //
        }
      }
      next();
      return;
    }
    // token or user does not exist
    if (!token) {
      // You can access without permission. You need to set the routing meta.ignoreAuth to true
      if (to.meta.ignoreAuth) {
        next();
        return;
      }
 
      // redirect login page
      const redirectData: { path: string; replace: boolean; query?: Recordable<string> } = {
        path: LOGIN_PATH,
        replace: true,
      };
      if (to.fullPath) {
        redirectData.query = {
          ...redirectData.query,
          redirect: to.fullPath,
        };
      }
      next(redirectData);
      return;
    }
 
    // get userinfo while last fetch time is empty
    if (userStore.getLastUpdateTime === 0) {
      try {
        await userStore.getUserInfoAction();
      } catch (err) {
        next();
        return;
      }
    }
 
    // 动态路由加载(首次)
    if (!permissionStore.getIsDynamicAddedRoute) {
      const routes = await permissionStore.buildRoutesAction();
      [...routes, PAGE_NOT_FOUND_ROUTE].forEach((route) => {
        router.addRoute(route as unknown as RouteRecordRaw);
      });
      // 记录动态路由加载完成
      permissionStore.setDynamicAddedRoute(true);
 
      // 现在的to动态路由加载之前的,可能为PAGE_NOT_FOUND_ROUTE(例如,登陆后,刷新的时候)
      // 此处应当重定向到fullPath,否则会加载404页面内容
      next({ path: to.fullPath, replace: true, query: to.query });
      return;
    }
 
    if (to.name === PAGE_NOT_FOUND_ROUTE.name) {
      // 遇到不存在页面,后续逻辑不再处理redirect(阻止下面else逻辑)
      from.query.redirect = '';
 
      if (
        from.path === LOGIN_PATH &&
        to.fullPath !== (userStore.getUserInfo.homePath || PageEnum.BASE_HOME)
      ) {
        // 登陆重定向不存在路由,转去“首页”
        next({ path: userStore.getUserInfo.homePath || PageEnum.BASE_HOME, replace: true });
      } else {
        // 正常前往“404”页面
        next();
      }
    } else if (from.query.redirect) {
      // 存在redirect
      const redirect = decodeURIComponent((from.query.redirect as string) || '');
 
      // 只处理一次 from.query.redirect
      // 也避免某场景(指向路由定义了 redirect)下的死循环
      from.query.redirect = '';
 
      if (redirect === to.fullPath) {
        // 已经被redirect
        next();
      } else {
        // 指向redirect
        next({ path: redirect, replace: true });
      }
    } else {
      // 正常访问
      next();
    }
  });
}