代码编织梦想

文件路径:src\store\modules\permission.ts

权限/菜单/路由信息Store主要定义存储权限代码列表是否已动态建立路由菜单最后更新时间、后端角色权限菜单列表、前端角色权限菜单列表,并注册到项目中,通过getters属性中的方法向外暴露存储的属性,通过提供actions属性中的方法,包括构建动态路buildRoutesAction由便于外部调用。同时导出usePermissionStoreWithOut用于没有使用 setup 组件时使用 。 更多信息,请见代码注释

import type { AppRouteRecordRaw, Menu } from '/@/router/types';

import { defineStore } from 'pinia';
import { store } from '/@/store';
import { useI18n } from '/@/hooks/web/useI18n';
import { useUserStore } from './user';
import { useAppStoreWithOut } from './app';
import { toRaw } from 'vue';
import { transformObjToRoute, flatMultiLevelRoutes } from '/@/router/helper/routeHelper';
import { transformRouteToMenu } from '/@/router/helper/menuHelper';

import projectSetting from '/@/settings/projectSetting';

import { PermissionModeEnum } from '/@/enums/appEnum';

import { asyncRoutes } from '/@/router/routes';
import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic';

import { filter } from '/@/utils/helper/treeHelper';

import { getMenuList } from '/@/api/sys/menu';
import { getPermCode } from '/@/api/sys/user';

import { useMessage } from '/@/hooks/web/useMessage';
import { PageEnum } from '/@/enums/pageEnum';

interface PermissionState {
  // 权限代码列表
  permCodeList: string[] | number[];
  // 动态建立路由后设置为true
  isDynamicAddedRoute: boolean;
  // 菜单最后更新时间
  lastBuildMenuTime: number;
  // 后端角色权限菜单列表
  backMenuList: Menu[];
  // 前端角色权限菜单列表
  frontMenuList: Menu[];
}
export const usePermissionStore = defineStore({
  id: 'app-permission',
  state: (): PermissionState => ({
    permCodeList: [], // 权限代码列表
    isDynamicAddedRoute: false, // 动态建立路由后设置为true
    lastBuildMenuTime: 0, // 菜单最后更新时间
    // Backstage menu list
    backMenuList: [], // 后端角色权限菜单列表
    // menu List
    frontMenuList: [], // 前端角色权限菜单列表
  }),
  getters: {
    // 获取权限代码列表
    getPermCodeList(): string[] | number[] {
      return this.permCodeList;
    },
    // 后端菜单
    getBackMenuList(): Menu[] {
      return this.backMenuList;
    },

    // 前端菜单
    getFrontMenuList(): Menu[] {
      return this.frontMenuList;
    },

    // 菜单最后更新时间
    getLastBuildMenuTime(): number {
      return this.lastBuildMenuTime;
    },

    //是否已经动态建立路由
    getIsDynamicAddedRoute(): boolean {
      return this.isDynamicAddedRoute;
    },
  },
  actions: {
    // 设置权限代码列表
    setPermCodeList(codeList: string[]) {
      this.permCodeList = codeList;
    },

    // 设置后端菜单
    setBackMenuList(list: Menu[]) {
      this.backMenuList = list;
      //更新菜单最后更新时间
      list?.length > 0 && this.setLastBuildMenuTime();
    },

    // 设置前端菜单
    setFrontMenuList(list: Menu[]) {
      this.frontMenuList = list;
    },

    // 设置菜单最后更新时间
    setLastBuildMenuTime() {
      this.lastBuildMenuTime = new Date().getTime(); // 一个代表时间毫秒数的数值
    },
    // 设置是否已经动态建立路由
    setDynamicAddedRoute(added: boolean) {
      this.isDynamicAddedRoute = added;
    },

    // 重置状态属性
    resetState(): void {
      this.isDynamicAddedRoute = false;
      this.permCodeList = [];
      this.backMenuList = [];
      this.lastBuildMenuTime = 0;
    },

    // 改变权限代码列表
    async changePermissionCode() {
      // 获取权限代码列表
      const codeList = await getPermCode();
      // 设置权限代码列表
      this.setPermCodeList(codeList);
    },

    //构建动态路由根据用户权限过滤
    async buildRoutesAction(): Promise<AppRouteRecordRaw[]> {
      const { t } = useI18n(); // 国际化
      const userStore = useUserStore(); // 用户信息存储
      const appStore = useAppStoreWithOut(); // 项目配置信息存储
      let routes: AppRouteRecordRaw[] = [];
      // 用户角色列表
      const roleList = toRaw(userStore.getRoleList) || [];
      // 获取权限模式
      const { permissionMode = projectSetting.permissionMode } = appStore.getProjectConfig;
      // 基于角色过滤方法
      const routeFilter = (route: AppRouteRecordRaw) => {
        const { meta } = route;
        const { roles } = meta || {};
        if (!roles) return true; //true表示允许显示,路由中不设置角色表示允许显示
        return roleList.some((role) => roles.includes(role)); //判断路由设置的角色是否包含用户角色
      };
      // 基于 ignoreRoute 属性过滤
      const routeRemoveIgnoreFilter = (route: AppRouteRecordRaw) => {
        const { meta } = route;
        const { ignoreRoute } = meta || {};
        return !ignoreRoute; // 忽略路由。用于在ROUTE_MAPPING以及BACK权限模式下,生成对应的菜单而忽略路由。2.5.3以上版本有效
      };

      /**
       * @description 根据设置的首页path,修正routes中的affix标记(固定首页)//affix为true,表示不允许关闭tab
       * */
      const patchHomeAffix = (routes: AppRouteRecordRaw[]) => {
        if (!routes || routes.length === 0) return;
        let homePath: string = userStore.getUserInfo.homePath || PageEnum.BASE_HOME; //首页path
        function patcher(routes: AppRouteRecordRaw[], parentPath = '') {
          // 父路径添加'/'
          if (parentPath) parentPath = parentPath + '/';
          routes.forEach((route: AppRouteRecordRaw) => {
            const { path, children, redirect } = route;
            //没有以/开头的路由会加上父路由路径
            const currentPath = path.startsWith('/') ? path : parentPath + path;
            if (currentPath === homePath) {
              // 当前路由是homePath
              if (redirect) {
                homePath = route.redirect! as string;
              } else {
                //非重定向的homePath添加affix为true
                route.meta = Object.assign({}, route.meta, { affix: true });
                throw new Error('end');
              }
            }
            // 递归调用,遍历每一个子项
            children && children.length > 0 && patcher(children, currentPath);
          });
        }
        try {
          patcher(routes);
        } catch (e) {
          // 已处理完毕跳出循环
        }
        return;
      };
      debugger;
      // 不同权限模式处理逻辑
      switch (permissionMode) {
        case PermissionModeEnum.ROLE: // 前端方式控制(菜单和路由分开配置)
          // 这里遍历路由及它的子级,根据角色控制是否允许显示,当子路由需要显示时,不管父路由是否有角色权限都会显示
          routes = filter(asyncRoutes, routeFilter);
          //这里第二次过滤,当父路由没有角色权限,则不论子路由是否有权限,都会过滤掉,不显示
          routes = routes.filter(routeFilter);
          // 将多级路由转换为二级路由
          routes = flatMultiLevelRoutes(routes);
          break;

        case PermissionModeEnum.ROUTE_MAPPING: // 前端方式控制(菜单由路由配置自动生成)
          // 这里遍历路由及它的子级,根据角色控制是否允许显示,当子路由需要显示时,不管父路由是否有角色权限都会显示
          routes = filter(asyncRoutes, routeFilter);
          // 这里第二次过滤,当父路由没有角色权限,则不论子路由是否有权限,都会过滤掉,不显示
          routes = routes.filter(routeFilter);
          // 通过转换路由生成菜单
          const menuList = transformRouteToMenu(routes, true);
          // 移除属性 meta.ignoreRoute 路由
          routes = filter(routes, routeRemoveIgnoreFilter);
          routes = routes.filter(routeRemoveIgnoreFilter);
          // 菜单排序
          menuList.sort((a, b) => {
            return (a.meta?.orderNo || 0) - (b.meta?.orderNo || 0);
          });
          // 设置菜单
          this.setFrontMenuList(menuList);
          // 将多级路由转换为二级路由
          routes = flatMultiLevelRoutes(routes);
          break;

        //  If you are sure that you do not need to do background dynamic permissions, please comment the entire judgment below
        case PermissionModeEnum.BACK: // 后台方式控制
          // 页面提升菜单加载中
          const { createMessage } = useMessage();
          createMessage.loading({
            content: t('sys.app.menuLoading'),
            duration: 1,
          });

          // 模拟从后台获取权限码,
          // 这个函数可能只需要执行一次,实际项目本身就可以放在合适的时间
          let routeList: AppRouteRecordRaw[] = [];
          try {
            //改变权限代码列表
            this.changePermissionCode();
            // 获取菜单路由
            routeList = (await getMenuList()) as AppRouteRecordRaw[];
          } catch (error) {
            console.error(error);
          }

          // 动态引入组件
          routeList = transformObjToRoute(routeList);

          // 后台路由转菜单结构
          const backMenuList = transformRouteToMenu(routeList);
          // 数组后台菜单
          this.setBackMenuList(backMenuList);

          // 删除ignoreRoute项
          routeList = filter(routeList, routeRemoveIgnoreFilter);
          routeList = routeList.filter(routeRemoveIgnoreFilter);
          // 将多级路由转换为二级路由
          routeList = flatMultiLevelRoutes(routeList);
          // 添加404页
          routes = [PAGE_NOT_FOUND_ROUTE, ...routeList];
          break;
      }

      routes.push(ERROR_LOG_ROUTE); // 添加`错误日志列表`页面路由
      //根据设置的首页path,修正routes中的affix标记(固定首页)//affix为true,表示不允许关闭tab
      patchHomeAffix(routes);
      return routes;
    },
  },
});

// Need to be used outside the setup
export function usePermissionStoreWithOut() {
  return usePermissionStore(store);
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/new______object/article/details/128859319

vben-admin 路由配置项-爱代码爱编程

 接触vben-admin已经一段时间了,一直记不住vben-adimn的路由配置项,记录一下: import type { AppRouteModule } from '/@/router/types'; import { LAYOUT } from '/@/router/constant'; const dashboard: AppRouteMo

vben-admin路由配置项-爱代码爱编程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 vben-admin路由配置项?总结 vben-admin路由配置项? import type { AppRouteModule } from '/@/router/types'; import { LAYOUT } from '/@/router/c

vue-vben-admin(初始化项目遇到的问题)_蔡大美美的博客-爱代码爱编程

这个开源项目应该已经有超级超级超级多的人做过了,我属于那种干啥都能遇到莫名其妙bug的人,先浅浅记录一下打开这个开源项目遇到的问题吧。 先附一下这个开源项目的链接:vue-vben-admin/README.zh-CN.md at main · vbenjs/vue-vben-admin · GitHub 根据官网的路径:  第一步git操作的时

【vben-admin-学习-网络请求代码配置】_好抖啊!的博客-爱代码爱编程

最近在学vben-admin框架。 axios网络请求配置 proxy 解决代理问题 根目录找到 .env.development.ts 开发配置文件 注释的地方 添加 # Whether to open mock V

web前端面试题附答案033-b端管理系统,我输入了一个没有权限的路由,坏了_xingyu_qie的博客-爱代码爱编程

        B端管理系统现在很多都是一个单页面应用,用1个HTML,写很多路由,首页,这个管理,那个管理,一直到系统管理,里面有权限管理,用户管理,角色管理,最基本的3块。然后通过admin添加用户,再做一个权限树,用来添加系统内的一些模块权限,然后就是给用户赋权限。这样用户登录系统的时候,身上自带权限,所以自然菜单模块就可以匹配出这个用户应该看

vben admin 源码学习笔记(二)- 状态管理模块-爱代码爱编程

配置存储代码分析 在main.ts中执行“setupStore(app)”,将调用src\store\index.ts文件中声明的setupStore方法。 src\store\index.ts 文件代码: impor

vben admin 源码学习笔记(三)- 错误日志记录store-爱代码爱编程

错误日志记录Store src\store\modules\errorLog.ts 文件代码: import type { ErrorLogInfo } from '/#/store'; import { define

vben admin 源码学习笔记(四)- 国际化/多语言信息store-爱代码爱编程

国际化/多语言信息Store 1、在types/config.d.ts文件中定义了LocaleSetting 接口 export interface LocaleSetting { showPicker: boole

vben admin 源码学习笔记(五)- 锁屏信息store-爱代码爱编程

锁屏信息Store 1、在types/store.d.ts文件中定义了LockInfo接口 export interface LockInfo { // 锁屏密码 pwd?: string | undefined

vben admin 源码学习笔记(六)-项目配置信息store-爱代码爱编程

app.ts 项目配置信息Store 项目配置信息Store主要定义存储主题模式、页面加载状态、项目配置、窗口缩小时的菜单状态的配置信息,并注册到项目中,通过getters属性中的方法向外暴露存储的属性,通过提供actio

vben admin 源码学习笔记(七)- 多标签页store-爱代码爱编程

文件路径:src\store\modules\multipleTab.ts MultipleTabState接口定义了Store需要存储的信息,包括标签页路由列表、缓存标签页名称以及最后一次拖动标签的索引 export

vben-爱代码爱编程

vben-admin 学习记录 前言一、vben admin 新增路由测试二、vben admin 当中使用 mock 模拟数据以及对响应数据进行处理三、表格的基本使用1.基本使用 1.02. vben adm

vben admin(ant-爱代码爱编程

vben admin(ant-design-vue2 + vue3)表格实现列拉伸 基于vben admin实现table表格列拖拽拉伸的功能 背景 公司项目中使用了vben admin作为后台管理系统的框架,但是an