Blame view

泰额版/Food Labeling Management Code/Yi.Vben5.Vue3/apps/web-antd/src/router/guard.ts 6.2 KB
383e20a3   杨鑫   拉取
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  import type { Router } from 'vue-router';
  
  import { nextTick } from 'vue';
  
  import { LOGIN_PATH } from '@vben/constants';
  import { preferences } from '@vben/preferences';
  import { useAccessStore, useTabbarStore, useUserStore } from '@vben/stores';
  import { startProgress, stopProgress } from '@vben/utils';
  
  import { accessRoutes, coreRouteNames } from '#/router/routes';
  import { useAuthStore } from '#/store';
  
  import { generateAccess } from './access';
  
f64eecbf   杨鑫   前端更新
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
  function findFirstAccessiblePath(routes: any[]): string {
    for (const route of routes) {
      if (route?.meta?.hideInMenu) {
        continue;
      }
      if (
        typeof route?.redirect === 'string' &&
        route.redirect &&
        route.redirect !== 'noRedirect'
      ) {
        return route.redirect;
      }
      if (Array.isArray(route?.children) && route.children.length > 0) {
        const childPath = findFirstAccessiblePath(route.children);
        if (childPath) {
          return childPath;
        }
      }
      if (typeof route?.path === 'string' && route.path) {
        return route.path;
      }
    }
    return '';
  }
  
383e20a3   杨鑫   拉取
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
134
135
136
  /**
   * 通用守卫配置
   * @param router
   */
  function setupCommonGuard(router: Router) {
    // 记录已经加载的页面
    const loadedPaths = new Set<string>();
  
    router.beforeEach((to) => {
      to.meta.loaded = loadedPaths.has(to.path);
  
      // 页面加载进度条
      if (!to.meta.loaded && preferences.transition.progress) {
        startProgress();
      }
      return true;
    });
  
    router.afterEach((to) => {
      // 记录页面是否加载,如果已经加载,后续的页面切换动画等效果不在重复执行
  
      loadedPaths.add(to.path);
  
      // 关闭页面加载进度条
      if (preferences.transition.progress) {
        stopProgress();
      }
    });
  }
  
  /**
   * 权限访问守卫配置
   * @param router
   */
  function setupAccessGuard(router: Router) {
    router.beforeEach(async (to, from) => {
      const accessStore = useAccessStore();
      const userStore = useUserStore();
      const authStore = useAuthStore();
  
      // 基本路由,这些路由不需要进入权限拦截
      if (coreRouteNames.includes(to.name as string)) {
        if (to.path === LOGIN_PATH && accessStore.accessToken) {
          return decodeURIComponent(
            (to.query?.redirect as string) ||
              userStore.userInfo?.homePath ||
              preferences.app.defaultHomePath,
          );
        }
        return true;
      }
  
      // accessToken 检查
      if (!accessStore.accessToken) {
        // 明确声明忽略权限访问权限,则可以访问
        if (to.meta.ignoreAccess) {
          return true;
        }
  
        // 没有访问权限,跳转登录页面
        if (to.fullPath !== LOGIN_PATH) {
          return {
            path: LOGIN_PATH,
            // 如不需要,直接删除 query
            query:
              to.fullPath === preferences.app.defaultHomePath
                ? {}
                : { redirect: encodeURIComponent(to.fullPath) },
            // 携带当前跳转的页面,登录后重新跳转该页面
            replace: true,
          };
        }
        return to;
      }
  
      // 是否已经生成过动态路由
      if (accessStore.isAccessChecked) {
        return true;
      }
  
      // 生成路由表
      // 当前登录用户拥有的角色标识列表
      const userInfo = userStore.userInfo || (await authStore.fetchUserInfo());
      const userRoles = userInfo.roles ?? [];
  
      // 生成菜单和路由
      const { accessibleMenus, accessibleRoutes } = await generateAccess({
        roles: userRoles,
        router,
        // 则会在菜单中显示,但是访问会被重定向到403
        routes: accessRoutes,
      });
  
      // 保存菜单信息和路由信息
      accessStore.setAccessMenus(accessibleMenus);
      accessStore.setAccessRoutes(accessibleRoutes);
      accessStore.setIsAccessChecked(true);
f64eecbf   杨鑫   前端更新
137
      let redirectPath = (from.query.redirect ??
383e20a3   杨鑫   拉取
138
139
140
        (to.path === preferences.app.defaultHomePath
          ? userInfo.homePath || preferences.app.defaultHomePath
          : to.fullPath)) as string;
f64eecbf   杨鑫   前端更新
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
      const decodedRedirectPath = decodeURIComponent(redirectPath);
      const firstAccessiblePath = findFirstAccessiblePath(accessibleMenus as any[]);
      if (firstAccessiblePath && userInfo.homePath !== firstAccessiblePath) {
        userStore.setUserInfo({
          ...userInfo,
          homePath: firstAccessiblePath,
        });
      }
      if (
        decodedRedirectPath === preferences.app.defaultHomePath &&
        firstAccessiblePath &&
        firstAccessiblePath !== preferences.app.defaultHomePath
      ) {
        redirectPath = firstAccessiblePath;
      }
383e20a3   杨鑫   拉取
156
157
158
159
160
161
162
163
164
165
166
167
168
  
      return {
        ...router.resolve(decodeURIComponent(redirectPath)),
        replace: true,
      };
    });
  }
  
  /**
   * 任意路由切换前先卸载 RouterView,避免报表/Vxe/ECharts 卸载时报 parentNode 为 null,
   * 导致 router.push 后 URL 已变但主区域仍显示上一页。
   */
  function setupRouteViewRemountGuard(router: Router) {
f64eecbf   杨鑫   前端更新
169
170
171
172
173
174
175
    function restoreRouteView() {
      const tabbarStore = useTabbarStore();
      if (tabbarStore.renderRouteView === false) {
        tabbarStore.renderRouteView = true;
      }
    }
  
383e20a3   杨鑫   拉取
176
177
178
179
    router.beforeEach(async (to, from) => {
      if (from.matched.length > 0 && to.path !== from.path) {
        const tabbarStore = useTabbarStore();
        tabbarStore.renderRouteView = false;
f64eecbf   杨鑫   前端更新
180
        window.setTimeout(restoreRouteView, 1200);
383e20a3   杨鑫   拉取
181
182
183
184
185
186
187
188
189
        await nextTick();
        await new Promise<void>((resolve) => {
          requestAnimationFrame(() => resolve());
        });
        await nextTick();
      }
      return true;
    });
  
f64eecbf   杨鑫   前端更新
190
191
192
193
    router.onError(() => {
      restoreRouteView();
    });
  
383e20a3   杨鑫   拉取
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
    router.afterEach(async (to) => {
      const tabbarStore = useTabbarStore();
      if (tabbarStore.renderRouteView === false) {
        await nextTick();
        await new Promise<void>((resolve) => {
          requestAnimationFrame(() => resolve());
        });
        await nextTick();
        tabbarStore.renderRouteView = true;
      }
      // 导航完成后再次等待一帧,避免报表 RangePicker 卸载异常时新页未挂上
      if (to.matched.length > 0) {
        await nextTick();
      }
    });
  }
  
  /**
   * 项目守卫配置
   * @param router
   */
  function createRouterGuard(router: Router) {
    /** 通用 */
    setupCommonGuard(router);
    /** 权限访问 */
    setupAccessGuard(router);
    /** 路由切换前强制卸载主内容区 */
    setupRouteViewRemountGuard(router);
  }
  
  export { createRouterGuard };