赞
踩
将项目路由拆分为:
- 静态路由:login、404、home、screen
- 异步路由:权限管理(包含三个子路由)、商品管理(包含四个子路由)
- 任意路由:任意路由
src/router/routes.ts
- // 对外暴露配置路由(常量路由):全部用户都可以访问到的路由
- export const constantRoute = [
- {
- // 登录
- path: '/login',
- component: () => import('@/views/login/index.vue'),
- name: 'login',
- meta: {
- title: '登录', // 菜单标题
- hidden: true, // 代表路由标题在菜单中是否隐藏 true:隐藏 false:显示
- icon: 'Promotion', // 菜单文字左侧的图标,支持element-plus全部图标
- },
- },
- {
- // 登录成功以后展示数据的路由
- path: '/',
- component: () => import('@/layout/index.vue'),
- name: 'layout',
- meta: {
- title: '',
- hidden: true,
- icon: '',
- },
- redirect: '/home',
- children: [
- {
- path: '/home',
- component: () => import('@/views/home/index.vue'),
- name: 'home',
- meta: {
- title: '首页',
- hidden: false,
- icon: 'HomeFilled',
- },
- },
- ],
- },
- {
- // 404
- path: '/404',
- component: () => import('@/views/404/index.vue'),
- name: '404',
- meta: {
- title: '404',
- hidden: true,
- icon: 'BrushFilled',
- },
- },
- {
- path: '/screen',
- component: () => import('@/views/screen/index.vue'),
- name: 'Screen',
- meta: {
- title: '数据大屏',
- hidden: false,
- icon: 'Platform',
- },
- }
- ]
-
- //异步路由
- export const asnycRoute = [
- {
- path: '/acl',
- component: () => import('@/layout/index.vue'),
- name: 'Acl',
- meta: {
- title: '权限管理',
- icon: 'Lock',
- },
- redirect: '/acl/user',
- children: [
- {
- path: '/acl/user',
- component: () => import('@/views/acl/user/index.vue'),
- name: 'User',
- meta: {
- title: '用户管理',
- icon: 'User',
- },
- },
- {
- path: '/acl/role',
- component: () => import('@/views/acl/role/index.vue'),
- name: 'Role',
- meta: {
- title: '角色管理',
- icon: 'UserFilled',
- },
- },
- {
- path: '/acl/permission',
- component: () => import('@/views/acl/permission/index.vue'),
- name: 'Permission',
- meta: {
- title: '菜单管理',
- icon: 'Monitor',
- },
- },
- ],
- },
- {
- path: '/product',
- component: () => import('@/layout/index.vue'),
- name: 'Product',
- meta: {
- title: '商品管理',
- icon: 'Goods',
- },
- redirect: '/product/trademark',
- children: [
- {
- path: '/product/trademark',
- component: () => import('@/views/product/trademark/index.vue'),
- name: 'Trademark',
- meta: {
- title: '品牌管理',
- icon: 'ShoppingCartFull',
- },
- },
- {
- path: '/product/attr',
- component: () => import('@/views/product/attr/index.vue'),
- name: 'Attr',
- meta: {
- title: '属性管理',
- icon: 'ChromeFilled',
- },
- },
- {
- path: '/product/spu',
- component: () => import('@/views/product/spu/index.vue'),
- name: 'Spu',
- meta: {
- title: 'SPU管理',
- icon: 'Calendar',
- },
- },
- {
- path: '/product/sku',
- component: () => import('@/views/product/sku/index.vue'),
- name: 'Sku',
- meta: {
- title: 'SKU管理',
- icon: 'Orange',
- },
- },
- ],
- },
- ]
-
- //任意路由
- export const anyRoute = {
- // 任意路由
- path: '/:pathMatch(.*)*',
- redirect: '/404',
- name: 'Any',
- meta: {
- title: '任意路由',
- hidden: true,
- icon: 'Wallet',
- },
- }
PS:退出登录记得删除添加的路由,防止切换角色后还能访问另一个角色的权限
src/store/modules/user.ts
- ......
- // 引入路由(常量路由)
- import { constantRoute, asnycRoute, anyRoute } from '@/router/routes'
-
- // 引入深拷贝方法
- //@ts-expect-error
- import cloneDeep from 'lodash/cloneDeep'
- import router from '@/router'
- // 用于过滤当前用户需要展示的异步路由
- function filterAsyncRoute(asnycRoute: any, routes: any) {
- return asnycRoute.filter((item: any) => {
- if (routes.includes(item.name)) {
- if (item.children && item.children.length > 0) {
- item.children = filterAsyncRoute(item.children, routes)
- }
- return true
- }
- })
- }
- ......
-
- const useUserStore = defineStore('User', {
- // 小仓库存储数据的地方
- state: (): UserState => {
- return {
- ......
- menuRoutes: constantRoute, // 仓库存储生成菜单需要数组(路由)
- removeRouteCallbackList: []
- }
- },
- // 异步|逻辑的地方
- actions: {
- ......
-
- // 获取用户信息
- async userInfo() {
- // 获取用户信息进行存储仓库当中(用户头像、名字)
- let result: userInfoResponeData = 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) => {
- let removeRoute = router.addRoute(route)
- this.removeRouteCallbackList.push(removeRoute)
- })
- return 'ok'
- } else {
- return Promise.reject(new Error(result.message))
- }
- },
- // 退出登录
- async userLogout() {
- let result: any = await reqLogout()
- if (result.code === 200) {
- // 目前没有mock接口:退出登录接口(通知服务器本地用户唯一标识失败)
- this.token = ''
- this.username = ''
- this.avatar = ''
- REMOVE_TOKEN()
- // 退出登录时删除登录添加的路由
- this.removeRouteCallbackList.forEach((removeRouteCallback: any) => {
- removeRouteCallback()
- })
- return 'ok'
- } else {
- return Promise.reject(new Error(result.message))
- }
- },
- },
- getters: {},
- })
刷新的时候是异步路由,有可能获取到用户信息,异步路由还没有加载完毕,出现空白的效果!!
解决方法:在全局前置守卫中,获取用户信息后改成next({...to})
- next() :直接放行(这种写法会导致刷新产生空白的效果)
- next({...to}):等待路由加载完毕再放行
src/permission.ts
- ......
-
- try {
- // 获取用户信息
- await useStore.userInfo()
- // 放行
- //等待路由加载完毕再放行
- next({ ...to})
- } catch (error) {
-
- }
-
- .......
src/store/modules/user.ts
- ......
- state: (): UserState => {
- return {
- ......
- //存储当前用户是否包含某一个按钮
- buttons: [],
- }
- ......
- async userInfo() {
- ......
- // 如果获取信息成功,存储下用户信息
- if (result.code === 200) {
- ......
- this.buttons = result.data.buttons
- ......
- }
src/directive/has.ts
- import pinia from "@/store"
- import useUserStore from "@/store/modules/user"
- const userStore = useUserStore(pinia)
- export const isHasButton = (app: any) => {
- // 获取对应的用户仓库
- // 全局自定义指令:实现按钮的权限
- app.directive('has', {
- // 代表使用这个全局指令的DOM|组件挂载完毕的时候会执行一次
- mounted(el: any, options: any) {
- // 自定义指令右侧的数值:如果在用户信息buttons数组中没有
- // 从DOM树上干掉
- if (!userStore.buttons.includes(options.value)) {
- el.parentNode.removeChild(el)
- }
- },
- })
- }
在main.ts文件中引入自定义指令文件
- // 引入自定义指令文件
- import { isHasButton } from '@/directive/has'
- isHasButton(app)
PS:此处以其中一个按钮作为例子,项目中其他按钮的权限都需要配置
<el-button type="primary" size="default" icon="Plus" @click="addTrademark" v-has="'btn.Trademark.add'">
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。