From b92a1a24fccc7c403df87780e29a09869bb60348 Mon Sep 17 00:00:00 2001
From: pany <939630029@qq.com>
Date: Tue, 6 Feb 2024 20:22:07 +0800
Subject: [PATCH] =?UTF-8?q?refactor:=20=E7=AE=80=E5=8C=96=E8=B7=AF?=
 =?UTF-8?q?=E7=94=B1=E5=AE=88=E5=8D=AB=E9=80=BB=E8=BE=91?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/router/permission.ts                      | 28 ++++++-------------
 src/store/modules/permission.ts               | 14 ++++++++--
 src/store/modules/user.ts                     | 16 +++--------
 .../permission/components/SwitchRoles.vue     | 12 ++------
 src/views/permission/directive.vue            | 15 +++-------
 5 files changed, 31 insertions(+), 54 deletions(-)

diff --git a/src/router/permission.ts b/src/router/permission.ts
index 880dc0a..fc6205c 100644
--- a/src/router/permission.ts
+++ b/src/router/permission.ts
@@ -22,19 +22,13 @@ router.beforeEach(async (to, _from, next) => {
   // 判断该用户是否已经登录
   if (!token) {
     // 如果在免登录的白名单中,则直接进入
-    if (isWhiteList(to)) {
-      next()
-    } else {
-      // 其他没有访问权限的页面将被重定向到登录页面
-      NProgress.done()
-      next("/login")
-    }
-    return
+    if (isWhiteList(to)) return next()
+    // 其他没有访问权限的页面将被重定向到登录页面
+    return next("/login")
   }
 
   // 如果已经登录,并准备进入 Login 页面,则重定向到主页
   if (to.path === "/login") {
-    NProgress.done()
     return next({ path: "/" })
   }
 
@@ -44,16 +38,11 @@ router.beforeEach(async (to, _from, next) => {
   // 否则要重新获取权限角色
   try {
     await userStore.getInfo()
-    if (routeSettings.async) {
-      // 注意:角色必须是一个数组! 例如: ['admin'] 或 ['developer', 'editor']
-      const roles = userStore.roles
-      // 根据角色生成可访问的 Routes(可访问路由 = 常驻路由 + 有访问权限的动态路由)
-      permissionStore.setRoutes(roles)
-    } else {
-      // 没有开启动态路由功能,则启用默认角色来生成
-      permissionStore.setRoutes(routeSettings.defaultRoles)
-    }
-    // 将'有访问权限的动态路由' 添加到 Router 中
+    // 注意:角色必须是一个数组! 例如: ["admin"] 或 ["developer", "editor"]
+    const roles = userStore.roles
+    // 生成可访问的 Routes
+    routeSettings.async ? permissionStore.setRoutes(roles) : permissionStore.setAllRoutes()
+    // 将 "有访问权限的动态路由" 添加到 Router 中
     permissionStore.dynamicRoutes.forEach((route) => router.addRoute(route))
     // 确保添加路由已完成
     // 设置 replace: true, 因此导航将不会留下历史记录
@@ -62,7 +51,6 @@ router.beforeEach(async (to, _from, next) => {
     // 过程中发生任何错误,都直接重置 Token,并重定向到登录页面
     userStore.resetToken()
     ElMessage.error(err.message || "路由守卫过程发生错误")
-    NProgress.done()
     next("/login")
   }
 })
diff --git a/src/store/modules/permission.ts b/src/store/modules/permission.ts
index a7c364e..4af385a 100644
--- a/src/store/modules/permission.ts
+++ b/src/store/modules/permission.ts
@@ -29,13 +29,23 @@ export const usePermissionStore = defineStore("permission", () => {
   const routes = ref<RouteRecordRaw[]>([])
   const dynamicRoutes = ref<RouteRecordRaw[]>([])
 
+  /** 根据角色生成可访问的 Routes(可访问路由 = 常驻路由 + 有访问权限的动态路由) */
   const setRoutes = (roles: string[]) => {
-    const accessedRoutes = routeSettings.async ? filterAsyncRoutes(asyncRoutes, roles) : asyncRoutes
+    const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
+    _set(accessedRoutes)
+  }
+
+  /** 所有路由 = 所有常驻路由 + 所有动态路由 */
+  const setAllRoutes = () => {
+    _set(asyncRoutes)
+  }
+
+  const _set = (accessedRoutes: RouteRecordRaw[]) => {
     routes.value = constantRoutes.concat(accessedRoutes)
     dynamicRoutes.value = routeSettings.thirdLevelRouteCache ? flatMultiLevelRoutes(accessedRoutes) : accessedRoutes
   }
 
-  return { routes, dynamicRoutes, setRoutes }
+  return { routes, dynamicRoutes, setRoutes, setAllRoutes }
 })
 
 /** 在 setup 外使用 */
diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts
index 231a303..90cfe12 100644
--- a/src/store/modules/user.ts
+++ b/src/store/modules/user.ts
@@ -1,14 +1,12 @@
 import { ref } from "vue"
 import store from "@/store"
 import { defineStore } from "pinia"
-import { usePermissionStore } from "./permission"
 import { useTagsViewStore } from "./tags-view"
 import { useSettingsStore } from "./settings"
 import { getToken, removeToken, setToken } from "@/utils/cache/cookies"
-import router, { resetRouter } from "@/router"
+import { resetRouter } from "@/router"
 import { loginApi, getUserInfoApi } from "@/api/login"
 import { type LoginRequestData } from "@/api/login/types/login"
-import { type RouteRecordRaw } from "vue-router"
 import routeSettings from "@/config/route"
 
 export const useUserStore = defineStore("user", () => {
@@ -16,7 +14,6 @@ export const useUserStore = defineStore("user", () => {
   const roles = ref<string[]>([])
   const username = ref<string>("")
 
-  const permissionStore = usePermissionStore()
   const tagsViewStore = useTagsViewStore()
   const settingsStore = useSettingsStore()
 
@@ -33,18 +30,13 @@ export const useUserStore = defineStore("user", () => {
     // 验证返回的 roles 是否为一个非空数组,否则塞入一个没有任何作用的默认角色,防止路由守卫逻辑进入无限循环
     roles.value = data.roles?.length > 0 ? data.roles : routeSettings.defaultRoles
   }
-  /** 切换角色 */
+  /** 模拟角色变化 */
   const changeRoles = async (role: string) => {
     const newToken = "token-" + role
     token.value = newToken
     setToken(newToken)
-    await getInfo()
-    permissionStore.setRoutes(roles.value)
-    resetRouter()
-    permissionStore.dynamicRoutes.forEach((item: RouteRecordRaw) => {
-      router.addRoute(item)
-    })
-    _resetTagsView()
+    // 用刷新页面代替重新登陆
+    window.location.reload()
   }
   /** 登出 */
   const logout = () => {
diff --git a/src/views/permission/components/SwitchRoles.vue b/src/views/permission/components/SwitchRoles.vue
index ef8ba9d..7f25d00 100644
--- a/src/views/permission/components/SwitchRoles.vue
+++ b/src/views/permission/components/SwitchRoles.vue
@@ -2,16 +2,10 @@
 import { ref, watch } from "vue"
 import { useUserStore } from "@/store/modules/user"
 
-/** Vue 3.3+ defineEmits 语法 */
-const emit = defineEmits<{
-  change: []
-}>()
-
 const userStore = useUserStore()
 const switchRoles = ref(userStore.roles[0])
-watch(switchRoles, async (value) => {
-  await userStore.changeRoles(value)
-  emit("change")
+watch(switchRoles, (value) => {
+  userStore.changeRoles(value)
 })
 </script>
 
@@ -19,7 +13,7 @@ watch(switchRoles, async (value) => {
   <div>
     <div>你的权限:{{ userStore.roles }}</div>
     <div class="switch-roles">
-      <span>切换权限:</span>
+      <span>切换权限(模拟权限变化后重新登陆):</span>
       <el-radio-group v-model="switchRoles">
         <el-radio-button label="editor" />
         <el-radio-button label="admin" />
diff --git a/src/views/permission/directive.vue b/src/views/permission/directive.vue
index 2e4b204..1de6bf8 100644
--- a/src/views/permission/directive.vue
+++ b/src/views/permission/directive.vue
@@ -1,20 +1,13 @@
 <script lang="ts" setup>
-import { ref } from "vue"
-import { checkPermission } from "@/utils/permission" // checkPermission 权限判断函数
+import { checkPermission } from "@/utils/permission"
 import SwitchRoles from "./components/SwitchRoles.vue"
-
-/** key 是为了能每次切换权限的时候重新初始化指令 */
-const key = ref(1)
-const handleRolesChange = () => {
-  key.value++
-}
 </script>
 
 <template>
   <div class="app-container">
-    <SwitchRoles @change="handleRolesChange" />
+    <SwitchRoles />
     <!-- v-permission 示例 -->
-    <div :key="key" class="margin-top-30">
+    <div class="margin-top-30">
       <div>
         <el-tag v-permission="['admin']" type="success" size="large" effect="plain">
           这里采用了 v-permission="['admin']" 所以只有 admin 可以看见这句话
@@ -32,7 +25,7 @@ const handleRolesChange = () => {
       </div>
     </div>
     <!-- checkPermission 示例 -->
-    <div :key="`checkPermission${key}`" class="margin-top-30">
+    <div class="margin-top-30">
       <el-tag type="warning" size="large">
         例如 Element Plus 的 el-tab-pane 或 el-table-column 以及其它动态渲染 Dom 的场景不适合使用
         v-permission,这种情况下你可以通过 v-if 和 checkPermission 来实现: