当前位置: 首页 > news >正文

实现基于Vue的后台管理系统权限控制与动态路由

 在开发后台管理系统时,权限控制是不可或缺的一部分。本文将详细介绍如何使用Vue实现根据不同角色动态生成路由,从而控制用户访问权限。

步骤一:基础路由配置

  • 首先,我们需要配置基础路由,这些路由是所有用户共有的,例如登录页和404页。
const allRoutes = [
  // 基础路由
  {
    path: '/',
    name: 'login',
    component: () => import("@/views/LoginView.vue")
  },
  {
    path: '/404',
    name: '404',
    component: () => import('@/views/Error/404View.vue')
  },
  // 动态路由容器(登录后内容)
  {
    path: '/layout',
    name: 'layout',
    component: () => import('@/Layout/MainLayout.vue'),
    children: []
  },
]

步骤二:完整路由数据 

  • 接下来,创建一个包含所有可能路由的数组。这个数组将用于与后端返回的权限数据对比,以筛选出当前用户有权访问的路由。
// 所有路由
const totalRoute = [
  {
    path: '/',
    name: 'login',
    component: () => import("@/views/LoginView.vue")
  },
  {
    path: '/404',
    name: '404',
    component: () => import('@/views/Error/404View.vue')
  },
  {
    path: '/layout',
    name: 'layout',
    component: () => import('@/Layout/MainLayout.vue'),
  },
  {
    path: '/home',
    name: '首页',
    id: 1,
    pid: 0,
  },
  {
    id: 2,
    pid: 0,
    redirect: null,
    path: '/comp',
    name: '门诊',
    children: [{
      id: 3,
      pid: 2,
      redirect: null,
      component: () => import('@/views/payView.vue'),
      path: "/pay",
      name: "门诊缴费记录",
    },{
      id: 4,
      pid: 2,
      redirect: null,
      component: () => import('@/views/reservationView.vue'),
      path: "/reservation",
      name: "预约记录",
    }]
  },
  { 
    id: 8,
    pid: 0,
    path: '/hospital',
    name: '住院',
    children: [{
      id: 9,
      pid: 8,
      redirect: null,
      component: () => import('@/views/hospitalView.vue'),
      path: "/hospitalpay",
      name: "住院缴费记录",
    },{
      id: 10,
      pid: 8,
      redirect: null,
      component: () => import('@/views/roomView.vue'),
      path: "/room",
      name: "房间管理",
    },{
      id: 11,
      pid: 8,
      redirect: null,
      component: () => import('@/views/inpatientView.vue'),
      path: "/inpatient",
      name: "住院人",
    }]
  }
];

步骤三:模拟后端权限数据 

为了演示,我们使用模拟数据来代表后端返回的权限信息。

  • 然后是后端接口返回的数据,我就先用假数据进行代替了。配置的基础路由和假数据要一致就行。假数据就是动态路由(会发生改变的)
// 动态访问
const dynamicRouteConfigs = [
  // 动态路由容器(登录后内容)
  {
    path: '/home',
    name: '首页',
    id: 1,
    pid: 0,
  },
  {
    id: 2,
    pid: 0,
    redirect: null,
    path: '/comp',
    name: '门诊',
    children: [{
      id: 3,
      pid: 2,
      redirect: null,
      path: "/pay",
      name: "门诊缴费记录",
    },{
      id: 4,
      pid: 2,
      redirect: null,
      path: "/reservation",
      name: "预约记录",
    }]
  },
  { 
    id: 8,
    pid: 0,
    path: '/hospital',
    name: '住院',
    children: [{
      id: 9,
      pid: 8,
      redirect: null,
      path: "/hospitalpay",
      name: "住院缴费记录",
    },{
      id: 10,
      pid: 8,
      redirect: null,
      path: "/room",
      name: "房间管理",
    },{
      id: 11,
      pid: 8,
      redirect: null,
      path: "/inpatient",
      name: "住院人",
    }]
  },
  {
    id: 12,
    pid: 0,
    redirect: null,
    path: '/userinfor',
    name: '用户管理',
    children: [{
      id: 13,
      pid: 12,
      redirect: null,
      path: "/user",
      name: "用户管理",
    },{
      id: 14,
      pid: 12,
      redirect: null,
      path: "/role",
      name: "角色管理",
    },{
      id: 15,
      pid: 12,
      redirect: null,
      path: "/admin",
      name: "管理员管理",
    },{
      id: 27,
      pid: 12,
      redirect: null,
      path: "/visit",
      name: "就诊卡",
    }]
  },
  {
    id: 16,
    pid: 0,
    path: '/department',
    name: '科室管理',
    children: [{
      id: 24,
      pid: 16,
      redirect: null,
      path: "/departments",
      name: "科室管理",
    }]
  },
  {
    id: 17,
    pid: 0,
    path: '/hospitals',
    name: '医院信息',
    redirect: null,
    children: [{
      id: 18,
      pid: 17,
      redirect: null,
      path: "/hospitalList",
      name: "医院信息",
    },{
      id: 19,
      pid: 17,
      redirect: null,
      path: "/doctor",
      name: "医生管理",
    },{
      id: 20,
      pid: 17,
      redirect: null,
      path: "/scheduling",
      name: "医生排班管理",
    },{
      id: 21,
      pid: 17,
      redirect: null,
      path: "/label",
      name: "标签管理",
    },{
      id: 22,
      pid: 17,
      redirect: null,
      path: "/drug",
      name: "药品管理",
    },
    {
      id: 23,
      pid: 17,
      redirect: null,
      path: "/physical",
      name: "体检管理",
    },{
      id: 26,
      pid: 17,
      redirect: null,
      path: "/trends",
      name: "医院动态",
    }]
  }
];

步骤四:创建路由实例

使用Vue Router创建路由实例,并初始化注册基础路由。

// 创建路由实例
const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: allRoutes
})

步骤五:筛选匹配路由

编写一个函数来筛选出匹配的路由。这个函数将遍历后端返回的权限数据和完整路由数据,找出匹配的路由并添加组件。

  • 然后就进行改变判断,通过遍历两个数组,判断两者的name或者path相同的时候将其放入一个新数组中。 
  • 然后再声明一个变量等于component,就是添加基础路由的component组件
const filterRoutes = (dynamicRouteConfigs, totalRoute) => {
  // 打印动态路由配置
  console.log('动态路由', dynamicRouteConfigs);
  // 打印总路由
  console.log('基础路由', totalRoute);
  // 定义一个递归函数findMatchedRoute,用于在路由数组中查找匹配的目标路由
  const findMatchedRoute = (routes, target) => {
    // 遍历路由数组
    for (const route of routes) {
      // 如果路由名称在排除列表中,则跳过
      if (['404', 'home'].includes(route.name)) continue;
      // 如果路由名称或路径与目标匹配,则返回该路由
      if (route.name === target.name || route.path === target.path) {
        return route;
      }
      // 如果当前路由有子路由,则递归查找匹配的子路由
      if (route.children) {
        const matchedChild = findMatchedRoute(route.children, target);
        // 如果找到匹配的子路由,则返回
        if (matchedChild) return matchedChild;
      }
    }
    // 如果没有找到匹配的路由,则返回null
    return null;
  };
  // 定义一个函数mergeRoutes,用于合并源路由和匹配的路由
  const mergeRoutes = (source, target) => {
    // 返回一个新的路由对象,包含源路由的所有属性,以及匹配路由的component属性
    return {
      ...source,
      component: target.component,
      // 如果源路由有子路由,则递归合并子路由
      children: source.children ? source.children.map(child => mergeRoutes(child, findMatchedRoute([target], child) || {})) : undefined,
      // 可以在这里合并其他可能需要的内容,例如meta属性
    };
  };
  // 映射动态路由配置,对每个路由进行匹配和合并操作
  const result = dynamicRouteConfigs
    .map(route => {
      // 查找匹配的路由
      const matchedRoute = findMatchedRoute(totalRoute, route);
      // 打印匹配的路由
      console.log(matchedRoute);
      // 如果找到匹配的路由,则合并路由,否则返回null
      return matchedRoute 
        ? mergeRoutes(route, matchedRoute)
        : null;
    })
    // 过滤掉结果中的null值
    .filter(route => route !== null);
  // 打印过滤后的路由数组
  console.log('过滤后的路由数组:', result);
  // 返回过滤后的路由数组
  return result;
};

步骤六:动态添加路由

编写一个函数来动态添加筛选后的路由到基础路由的layout容器中。

然后后台控制路由就完成了。主要和起那段控制是一样的,都是需要一个基础的路由数组,然后我们将数组对比过滤过之后,需要把过滤好的数组添加注册到路由中。逻辑都是一样的,疏通逻辑就可以了。

只不过前后端控制路由的接口返回不一样而已。

// 动态添加路由到layout
const addDynamicRoutes = (roles) => {
  // 清空已有动态路由
  const layout = router.getRoutes().find(r => r.name === 'layout')
  layout.children.forEach(child => {
    router.removeRoute(child.name)
  })
  // 过滤并添加新路由
  const allowedRoutes = filterRoutes(dynamicRouteConfigs, allRoutes); 
  allowedRoutes.forEach(route => { router.addRoute('layout', route); });
  console.log(allowedRoutes);
  sessionStorage.setItem('menuPath',JSON.stringify(allowedRoutes));//存储的筛选过的动态路由
  // 确保404最后处理
  router.addRoute({ 
    path: '/:pathMatch(.*)*',
    redirect: '/404'
  })
}

步骤七:存储和渲染菜单

将筛选后的路由存储在会话存储中,并在菜单页面进行渲染。

通过以上步骤,我们完成了基于Vue的后台管理系统权限控制与动态路由的设置。不同角色的用户将看到不同的菜单和页面,实现了权限的精细化管理。

最后路由导航守卫加上去就ok了。

// 路由守卫修改部分(router/index.ts)
router.beforeEach(async (to, from, next) => {
  const store = loginStore()
  const isLogin = !!store.id
  // 未登录状态处理
  if (!isLogin) {
    return to.path === '/' ? next() : next('/')
  }
  // 已登录但访问登录页时重定向
  if (to.path === '/') {
    return next('/home')
  }
  // 动态路由加载逻辑
  if (!store.routesLoaded) {
    try {
      // 直接从store获取已保存的角色信息
      const userRoles = store.roles;
      // 如果角色信息不存在则抛出错误
      if (!userRoles || userRoles.length === 0) {
        throw new Error('用户角色信息未获取')
      }
      // 添加动态路由
      addDynamicRoutes(dynamicRouteConfigs)
      // 在添加路由后打印
      console.log('当前所有路由:', router.getRoutes().map(r => r.path))
      // 更新加载状态
      store.setRoutesLoaded(true)
      // 使用replace方式跳转避免重复记录历史
      return next({ ...to, replace: true })
    } catch (error) {
      console.error('路由加载失败:', error)
      // 清除用户状态并跳转登录页
      store.$reset()
      return next('/')
    }
  }
  next();
})

总结:

本文介绍了如何使用Vue和Vue Router实现后台管理系统的权限控制。通过动态生成路由,我们可以根据用户的角色灵活控制页面访问权限,提高系统的安全性和用户体验。

相关文章:

  • 【避坑指南】RAGFlow + Ollama + Deepseek 构建本地知识库
  • 逻辑损失以及梯度下降的实现
  • Docker学习--容器操作相关命令--docker logs 命令
  • 利用 SSRF 和 Redis 未授权访问进行内网渗透
  • Java 中数组转集合的方法
  • 分布式环境下的主从数据同步
  • SpringBoot事务管理(四)
  • Faster-Whisper —— 为语音识别加速的利器
  • 283. 移动零
  • 【QT】Qt4 QtWebKit使用教程
  • 数据结构与算法-双指针法
  • Java 大视界 -- 基于 Java 的大数据可视化在城市规划决策支持中的交互设计与应用案例(164)
  • 30-超市进销存管理系统
  • RAG 高效检索利器 打造企业 “规章制度智能体”(ollama + deepseek + langchain + MinerU)
  • 力扣经典算法篇-5-多数元素(哈希统计,排序,摩尔投票法)
  • CES Asia 2025:行业话语权的逐鹿高地
  • 如何利用系统的数据分析能力提高利润额?
  • websocket获取客服端真实ip
  • Linux | I.MX6ULL 终结者底板原理图讲解(5)
  • 最新万能场馆预约系统源码 基于ThinkPHP+UniApp 含图文搭建部署教程
  • 网站开发培训机构/关键词优化排名软件
  • 山东咕果做网站怎么样/山东最新消息今天
  • 电商网站如何做/简述网站建设的基本流程
  • 网站建设分组任务/员工培训课程
  • 淘宝客个人网站建设/网络推广费用大概价格
  • 网站中怎么做搜索框/湖人队最新消息