• 硅谷15菜单权限


    菜单权限

    15.1 路由的拆分

    15.1.1 路由分析
    1. 菜单的权限:
    2. 超级管理员账号:admin atguigu123 拥有全部的菜单、按钮的权限
    3. 飞行员账号 硅谷333 111111 不包含权限管理模块、按钮的权限并非全部按钮
    4. 同一个项目:不同人(职位是不一样的,他能访问到的菜单、按钮的权限是不一样的)
    5. 一、目前整个项目一共多少个路由!!!
    6. login(登录页面)、
    7. 404(404一级路由)、
    8. 任意路由、
    9. 首页(/home)、
    10. 数据大屏、
    11. 权限管理(三个子路由)
    12. 商品管理模块(四个子路由)
    13. 1.1开发菜单权限
    14. ---第一步:拆分路由
    15. 静态(常量)路由:大家都可以拥有的路由
    16. login、首页、数据大屏、404
    17. 异步路由:不同的身份有的有这个路由、有的没有
    18. 权限管理(三个子路由)
    19. 商品管理模块(四个子路由)
    20. 任意路由:任意路由
    21. 1.2菜单权限开发思路
    22. 目前咱们的项目:任意用户访问大家能看见的、能操作的菜单与按钮都是一样的(大家注册的路由都是一样的)
    15.1.2 路由的拆分
    1. //对外暴露配置路由(常量路由)
    2. export const constantRoute = [
    3. {
    4. //登录路由
    5. path: '/login',
    6. component: () => import('@/views/login/index.vue'),
    7. name: 'login', //命名路由
    8. meta: {
    9. title: '登录', //菜单标题
    10. hidden: true, //路由的标题在菜单中是否隐藏
    11. },
    12. },
    13. {
    14. //登录成功以后展示数据的路由
    15. path: '/',
    16. component: () => import('@/layout/index.vue'),
    17. name: 'layout',
    18. meta: {
    19. hidden: false,
    20. },
    21. redirect: '/home',
    22. children: [
    23. {
    24. path: '/home',
    25. component: () => import('@/views/home/index.vue'),
    26. meta: {
    27. title: '首页',
    28. hidden: false,
    29. icon: 'HomeFilled',
    30. },
    31. },
    32. ],
    33. },
    34. {
    35. path: '/404',
    36. component: () => import('@/views/404/index.vue'),
    37. name: '404',
    38. meta: {
    39. title: '404',
    40. hidden: true,
    41. },
    42. },
    43. {
    44. path: '/screen',
    45. component: () => import('@/views/screen/index.vue'),
    46. name: 'Screen',
    47. meta: {
    48. hidden: false,
    49. title: '数据大屏',
    50. icon: 'Platform',
    51. },
    52. },
    53. ]
    54. //异步路由
    55. export const asnycRoute = [
    56. {
    57. path: '/acl',
    58. component: () => import('@/layout/index.vue'),
    59. name: 'Acl',
    60. meta: {
    61. hidden: false,
    62. title: '权限管理',
    63. icon: 'Lock',
    64. },
    65. redirect: '/acl/user',
    66. children: [
    67. {
    68. path: '/acl/user',
    69. component: () => import('@/views/acl/user/index.vue'),
    70. name: 'User',
    71. meta: {
    72. hidden: false,
    73. title: '用户管理',
    74. icon: 'User',
    75. },
    76. },
    77. {
    78. path: '/acl/role',
    79. component: () => import('@/views/acl/role/index.vue'),
    80. name: 'Role',
    81. meta: {
    82. hidden: false,
    83. title: '角色管理',
    84. icon: 'UserFilled',
    85. },
    86. },
    87. {
    88. path: '/acl/permission',
    89. component: () => import('@/views/acl/permission/index.vue'),
    90. name: 'Permission',
    91. meta: {
    92. hidden: false,
    93. title: '菜单管理',
    94. icon: 'Monitor',
    95. },
    96. },
    97. ],
    98. },
    99. {
    100. path: '/product',
    101. component: () => import('@/layout/index.vue'),
    102. name: 'Product',
    103. meta: {
    104. hidden: false,
    105. title: '商品管理',
    106. icon: 'Goods',
    107. },
    108. redirect: '/product/trademark',
    109. children: [
    110. {
    111. path: '/product/trademark',
    112. component: () => import('@/views/product/trademark/index.vue'),
    113. name: 'Trademark',
    114. meta: {
    115. hidden: false,
    116. title: '品牌管理',
    117. icon: 'ShoppingCartFull',
    118. },
    119. },
    120. {
    121. path: '/product/attr',
    122. component: () => import('@/views/product/attr/index.vue'),
    123. name: 'Attr',
    124. meta: {
    125. hidden: false,
    126. title: '属性管理',
    127. icon: 'CollectionTag',
    128. },
    129. },
    130. {
    131. path: '/product/spu',
    132. component: () => import('@/views/product/spu/index.vue'),
    133. name: 'Spu',
    134. meta: {
    135. hidden: false,
    136. title: 'SPU管理',
    137. icon: 'Calendar',
    138. },
    139. },
    140. {
    141. path: '/product/sku',
    142. component: () => import('@/views/product/sku/index.vue'),
    143. name: 'Sku',
    144. meta: {
    145. hidden: false,
    146. title: 'SKU管理',
    147. icon: 'Orange',
    148. },
    149. },
    150. ],
    151. },
    152. ]
    153. //任意路由
    154. //任意路由
    155. export const anyRoute = {
    156. //任意路由
    157. path: '/:pathMatch(.*)*',
    158. redirect: '/404',
    159. name: 'Any',
    160. meta: {
    161. title: '任意路由',
    162. hidden: true,
    163. icon: 'DataLine',
    164. },
    165. }

    15.2 菜单权限的实现

    15.2.1 获取正确路由的方法

    注意:这里使用了递归。其次,这里是浅拷贝,会改变原有的路由。因此还需要改进。

    1. //硅谷333: routes['Product','Trademark','Sku']
    2. let guigu333 = ['Product', 'Trademark', 'Sku'];
    3. function filterAsyncRoute(asnycRoute, routes) {
    4. return asnycRoute.filter(item => {
    5. if (routes.includes(item.name)) {
    6. if (item.children && item.children.length > 0) {
    7. item.children = filterAsyncRoute(item.children, routes)
    8. }
    9. return true
    10. }
    11. })
    12. }
    13. //硅谷333需要展示的异步路由
    14. let guigu333Result = filterAsyncRoute(asnycRoute, guigu333);
    15. console.log([...constRoute, ...guigu333Result, anyRoute], '硅谷333');
    15.2.2 获取路由
    1. 。。。。。。
    2. import router from '@/router'
    3. //引入路由(常量路由)
    4. import { constantRoute, asnycRoute, anyRoute } from '@/router/routes'
    5. //用于过滤当前用户需要展示的异步路由
    6. function filterAsyncRoute(asnycRoute: any, routes: any) {
    7. return asnycRoute.filter((item: any) => {
    8. if (routes.includes(item.name)) {
    9. if (item.children && item.children.length > 0) {
    10. //硅谷333账号:product\trademark\attr\sku
    11. item.children = filterAsyncRoute(item.children, routes)
    12. }
    13. return true
    14. }
    15. })
    16. }
    17. //创建用户小仓库
    18. const useUserStore = defineStore('User', {
    19. //小仓库存储数据地方
    20. state: (): UserState => {
    21. return {
    22. 。。。。。。。
    23. menuRoutes: constantRoute, //仓库存储生成菜单需要数组(路由)
    24. us。。。。。。
    25. }
    26. },
    27. //处理异步|逻辑地方
    28. actions: {
    29. 。。。。。。。
    30. //获取用户信息方法
    31. async userInfo() {
    32. //获取用户信息进行存储
    33. const result: userInfoResponseData = await reqUserInfo()
    34. if (result.code == 200) {
    35. this.username = result.data.name
    36. this.avatar = result.data.avatar
    37. //计算当前用户需要展示的异步路由
    38. const userAsyncRoute = filterAsyncRoute(asnycRoute, result.data.routes)
    39. //菜单需要的数据整理完毕
    40. this.menuRoutes = [...constantRoute, ...userAsyncRoute, anyRoute]
    41. //目前路由器管理的只有常量路由:用户计算完毕异步路由、任意路由动态追加
    42. ;[...userAsyncRoute, anyRoute].forEach((route: any) => {
    43. router.addRoute(route)
    44. })
    45. return 'ok'
    46. } else {
    47. return Promise.reject(new Error(result.message))
    48. }
    49. },
    50. 。。。。。。
    51. })
    52. //对外暴露小仓库
    53. export default useUserStore

    15.3 菜单权限的2个小问题

    15.3.1 深拷贝

    之前获取需要的路由方法中使用的是浅拷贝,会改变原有的路由。因此我们这里引入深拷贝的方法

    1. //引入深拷贝方法
    2. //@ts-expect-error
    3. import cloneDeep from 'lodash/cloneDeep'
    4. 。。。。。。
    5. //获取用户信息方法
    6. async userInfo() {
    7. //获取用户信息进行存储
    8. const result: userInfoResponseData = await reqUserInfo()
    9. if (result.code == 200) {
    10. this.username = result.data.name
    11. this.avatar = result.data.avatar
    12. //计算当前用户需要展示的异步路由
    13. const userAsyncRoute = filterAsyncRoute(
    14. cloneDeep(asnycRoute),
    15. result.data.routes,
    16. )
    17. //菜单需要的数据整理完毕
    18. this.menuRoutes = [...constantRoute, ...userAsyncRoute, anyRoute]
    19. //目前路由器管理的只有常量路由:用户计算完毕异步路由、任意路由动态追加
    20. ;[...userAsyncRoute, anyRoute].forEach((route: any) => {
    21. router.addRoute(route)
    22. })
    23. return 'ok'
    24. } else {
    25. return Promise.reject(new Error(result.message))
    26. }
    27. },
    15.3.2 路由加载问题

    这样配置路由后,如果你访问的是异步路由,会在刷新的时候出现空白页面。原因是异步路由是异步获取的,加载的时候还没有。因此我们可以在路由守卫文件中改写。这个的意思就是一直加载。

    1. //用户登录判断
    2. if (token) {
    3. //登陆成功,访问login。指向首页
    4. if (to.path == '/login') {
    5. next('/')
    6. } else {
    7. //登陆成功访问其余的,放行
    8. //有用户信息
    9. if (username) {
    10. //放行
    11. next()
    12. } else {
    13. //如果没有用户信息,在收尾这里发请求获取到了用户信息再放行
    14. try {
    15. //获取用户信息
    16. await userStore.userInfo()
    17. //万一刷新的时候是异步路由,有可能获取到用户信息但是异步路由没有加载完毕,出现空白效果
    18. next({ ...to })
    19. } catch (error) {
    20. //token过期|用户手动处理token
    21. //退出登陆->用户相关的数据清空
    22. await userStore.userLogout()
    23. next({ path: '/login', query: { redirect: to.path } })
    24. }
    25. }
    26. }
    27. } else {
    28. //用户未登录
    29. if (to.path == '/login') {
    30. next()
    31. } else {
    32. next({ path: '/login', query: { redirect: to.path } })
    33. }
    34. }

  • 相关阅读:
    数字化转型导师坚鹏:基于湖北产业的科技金融创新模式与案例研究
    为什么Video Speed Manager 和 Video Speed Controller 的chrome插件对有些B站视频不能调速
    2.在命令行下使用 Linux 帮助信息
    工程项目管理系统的Java实现:高效协同与信息共享
    2022杭电多校联赛第七场 题解
    HTML核心(1)- 第一个网页
    VUE3 + Django 接口请求每次都产生新的session_id,应该如何解决?
    这款“三无产品“ 值得曝光...
    深度学习之tf.keras.preprocessing.image_dataset_from_directory()函数
    CatBoost高级教程:分布式训练与大规模数据处理
  • 原文地址:https://blog.csdn.net/weixin_74428381/article/details/143406396