- 菜单的权限:
- 超级管理员账号:admin atguigu123 拥有全部的菜单、按钮的权限
- 飞行员账号 硅谷333 111111 不包含权限管理模块、按钮的权限并非全部按钮
- 同一个项目:不同人(职位是不一样的,他能访问到的菜单、按钮的权限是不一样的)
-
- 一、目前整个项目一共多少个路由!!!
- login(登录页面)、
- 404(404一级路由)、
- 任意路由、
- 首页(/home)、
- 数据大屏、
- 权限管理(三个子路由)
- 商品管理模块(四个子路由)
-
- 1.1开发菜单权限
- ---第一步:拆分路由
- 静态(常量)路由:大家都可以拥有的路由
- login、首页、数据大屏、404
-
- 异步路由:不同的身份有的有这个路由、有的没有
- 权限管理(三个子路由)
- 商品管理模块(四个子路由)
-
- 任意路由:任意路由
-
- 1.2菜单权限开发思路
- 目前咱们的项目:任意用户访问大家能看见的、能操作的菜单与按钮都是一样的(大家注册的路由都是一样的)
- //对外暴露配置路由(常量路由)
- export const constantRoute = [
- {
- //登录路由
- path: '/login',
- component: () => import('@/views/login/index.vue'),
- name: 'login', //命名路由
- meta: {
- title: '登录', //菜单标题
- hidden: true, //路由的标题在菜单中是否隐藏
- },
- },
- {
- //登录成功以后展示数据的路由
- path: '/',
- component: () => import('@/layout/index.vue'),
- name: 'layout',
- meta: {
- hidden: false,
- },
- redirect: '/home',
- children: [
- {
- path: '/home',
- component: () => import('@/views/home/index.vue'),
- meta: {
- title: '首页',
- hidden: false,
- icon: 'HomeFilled',
- },
- },
- ],
- },
- {
- path: '/404',
- component: () => import('@/views/404/index.vue'),
- name: '404',
- meta: {
- title: '404',
- hidden: true,
- },
- },
- {
- path: '/screen',
- component: () => import('@/views/screen/index.vue'),
- name: 'Screen',
- meta: {
- hidden: false,
- title: '数据大屏',
- icon: 'Platform',
- },
- },
- ]
-
- //异步路由
- export const asnycRoute = [
- {
- path: '/acl',
- component: () => import('@/layout/index.vue'),
- name: 'Acl',
- meta: {
- hidden: false,
- title: '权限管理',
- icon: 'Lock',
- },
- redirect: '/acl/user',
- children: [
- {
- path: '/acl/user',
- component: () => import('@/views/acl/user/index.vue'),
- name: 'User',
- meta: {
- hidden: false,
- title: '用户管理',
- icon: 'User',
- },
- },
- {
- path: '/acl/role',
- component: () => import('@/views/acl/role/index.vue'),
- name: 'Role',
- meta: {
- hidden: false,
- title: '角色管理',
- icon: 'UserFilled',
- },
- },
- {
- path: '/acl/permission',
- component: () => import('@/views/acl/permission/index.vue'),
- name: 'Permission',
- meta: {
- hidden: false,
- title: '菜单管理',
- icon: 'Monitor',
- },
- },
- ],
- },
- {
- path: '/product',
- component: () => import('@/layout/index.vue'),
- name: 'Product',
- meta: {
- hidden: false,
- title: '商品管理',
- icon: 'Goods',
- },
- redirect: '/product/trademark',
- children: [
- {
- path: '/product/trademark',
- component: () => import('@/views/product/trademark/index.vue'),
- name: 'Trademark',
- meta: {
- hidden: false,
- title: '品牌管理',
- icon: 'ShoppingCartFull',
- },
- },
- {
- path: '/product/attr',
- component: () => import('@/views/product/attr/index.vue'),
- name: 'Attr',
- meta: {
- hidden: false,
- title: '属性管理',
- icon: 'CollectionTag',
- },
- },
- {
- path: '/product/spu',
- component: () => import('@/views/product/spu/index.vue'),
- name: 'Spu',
- meta: {
- hidden: false,
- title: 'SPU管理',
- icon: 'Calendar',
- },
- },
- {
- path: '/product/sku',
- component: () => import('@/views/product/sku/index.vue'),
- name: 'Sku',
- meta: {
- hidden: false,
- title: 'SKU管理',
- icon: 'Orange',
- },
- },
- ],
- },
- ]
-
- //任意路由
- //任意路由
- export const anyRoute = {
- //任意路由
- path: '/:pathMatch(.*)*',
- redirect: '/404',
- name: 'Any',
- meta: {
- title: '任意路由',
- hidden: true,
- icon: 'DataLine',
- },
- }
注意:这里使用了递归。其次,这里是浅拷贝,会改变原有的路由。因此还需要改进。
- //硅谷333: routes['Product','Trademark','Sku']
- let guigu333 = ['Product', 'Trademark', 'Sku'];
- function filterAsyncRoute(asnycRoute, routes) {
- return asnycRoute.filter(item => {
- if (routes.includes(item.name)) {
- if (item.children && item.children.length > 0) {
- item.children = filterAsyncRoute(item.children, routes)
- }
- return true
- }
- })
- }
- //硅谷333需要展示的异步路由
- let guigu333Result = filterAsyncRoute(asnycRoute, guigu333);
- console.log([...constRoute, ...guigu333Result, anyRoute], '硅谷333');
- 。。。。。。
-
- import router from '@/router'
- //引入路由(常量路由)
- import { constantRoute, asnycRoute, anyRoute } from '@/router/routes'
- //用于过滤当前用户需要展示的异步路由
- function filterAsyncRoute(asnycRoute: any, routes: any) {
- return asnycRoute.filter((item: any) => {
- if (routes.includes(item.name)) {
- if (item.children && item.children.length > 0) {
- //硅谷333账号:product\trademark\attr\sku
- item.children = filterAsyncRoute(item.children, routes)
- }
- return true
- }
- })
- }
- //创建用户小仓库
- const useUserStore = defineStore('User', {
- //小仓库存储数据地方
- state: (): UserState => {
- return {
- 。。。。。。。
- menuRoutes: constantRoute, //仓库存储生成菜单需要数组(路由)
- us。。。。。。
- }
- },
- //处理异步|逻辑地方
- actions: {
- 。。。。。。。
- //获取用户信息方法
- async userInfo() {
- //获取用户信息进行存储
- const result: userInfoResponseData = await reqUserInfo()
- if (result.code == 200) {
- this.username = result.data.name
- this.avatar = result.data.avatar
- //计算当前用户需要展示的异步路由
- const userAsyncRoute = filterAsyncRoute(asnycRoute, result.data.routes)
- //菜单需要的数据整理完毕
- this.menuRoutes = [...constantRoute, ...userAsyncRoute, anyRoute]
- //目前路由器管理的只有常量路由:用户计算完毕异步路由、任意路由动态追加
- ;[...userAsyncRoute, anyRoute].forEach((route: any) => {
- router.addRoute(route)
- })
- return 'ok'
- } else {
- return Promise.reject(new Error(result.message))
- }
- },
- 。。。。。。
- })
- //对外暴露小仓库
- export default useUserStore
之前获取需要的路由方法中使用的是浅拷贝,会改变原有的路由。因此我们这里引入深拷贝的方法
- //引入深拷贝方法
- //@ts-expect-error
- import cloneDeep from 'lodash/cloneDeep'
- 。。。。。。
- //获取用户信息方法
- async userInfo() {
- //获取用户信息进行存储
- const result: userInfoResponseData = await reqUserInfo()
- if (result.code == 200) {
- this.username = result.data.name
- this.avatar = result.data.avatar
- //计算当前用户需要展示的异步路由
- const userAsyncRoute = filterAsyncRoute(
- cloneDeep(asnycRoute),
- result.data.routes,
- )
- //菜单需要的数据整理完毕
- this.menuRoutes = [...constantRoute, ...userAsyncRoute, anyRoute]
- //目前路由器管理的只有常量路由:用户计算完毕异步路由、任意路由动态追加
- ;[...userAsyncRoute, anyRoute].forEach((route: any) => {
- router.addRoute(route)
- })
- return 'ok'
- } else {
- return Promise.reject(new Error(result.message))
- }
- },
这样配置路由后,如果你访问的是异步路由,会在刷新的时候出现空白页面。原因是异步路由是异步获取的,加载的时候还没有。因此我们可以在路由守卫文件中改写。这个的意思就是一直加载。

- //用户登录判断
- if (token) {
- //登陆成功,访问login。指向首页
- if (to.path == '/login') {
- next('/')
- } else {
- //登陆成功访问其余的,放行
- //有用户信息
- if (username) {
- //放行
- next()
- } else {
- //如果没有用户信息,在收尾这里发请求获取到了用户信息再放行
- try {
- //获取用户信息
- await userStore.userInfo()
- //万一刷新的时候是异步路由,有可能获取到用户信息但是异步路由没有加载完毕,出现空白效果
- next({ ...to })
- } catch (error) {
- //token过期|用户手动处理token
- //退出登陆->用户相关的数据清空
-
- await userStore.userLogout()
- next({ path: '/login', query: { redirect: to.path } })
- }
- }
- }
- } else {
- //用户未登录
- if (to.path == '/login') {
- next()
- } else {
- next({ path: '/login', query: { redirect: to.path } })
- }
- }