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 来实现: