vite-plugin-pages实现路由权限和组件权限
项目基本架构跟 vite实现element-plus按需配置,自定义主题和读取/修改系统主题色 相同。项目地址。
目标:在vite-plugin-pages 自动读取文件夹配置下,设置前端路由权限和单组件权限。
权限模块后台返回数据假设:返回 与前端文件夹匹配的路径数据,并包含权限信息。
假设,无权限数据为:
{ "code": 200, "data": [ { "menu": [ { "label": "面板1", "key": "index", "meta": { "isAdmin": false, "requiresAuth": false } }, { "label": "统计分析", "key": "index-analysis", "meta": { "isAdmin": true, "requiresAuth": false } }, { "label": "编辑器", "key": "index-editor", "meta": { "isAdmin": false, "requiresAuth": false } }, { "label": "权限管理", "key": "index-permission", "meta": { "isAdmin": false, "requiresAuth": true } }, { "label": "关注", "key": "attention", "meta": { "isAdmin": false, "requiresAuth": false } } ] } ] }
有权限数据为:
...... { "label": "权限管理", "key": "index-permission", "meta": { "isAdmin": true, ..... } }, ......
实现功能:判断当前用户是否为管理员,如果不是,切换为管理员。
<template> <div class="index-permission w-full overflow-hidden bg-slate-100 p-4"> <p v-if="route.meta.isAdmin">当前是admin用户</p> <p v-else>当前不是admin用户</p> <el-button v-if="!route.meta.isAdmin" type="primary" size="default" @click="changeMenu">切换为admin用户</el-button> </div> </template> <script setup lang="ts"> import { handleRouterMeta } from '@/router'; import { useMenuStore } from '@/stores/menu'; let route = useRoute() const { changeMenus, sideMenusFlat } = useMenuStore() const changeMenu = async () => { await changeMenus() handleRouterMeta(sideMenusFlat); location.reload() } </script>
方案:使用router的beforeEach对路由进行修改。
import {IMenuItem} from "@/models/menu";
import {useMenuStore} from "./stores/menu";
import {createWebHistory, createRouter, RouteMeta} from "vue-router";
import routes from "~pages";
import "vue-router";
declare module "vue-router" {
interface RouteMeta {
// 是可选的
isAdmin?: boolean;
// 每个路由都必须声明
requiresAuth: boolean;
}
}
export const router = createRouter({
history: createWebHistory("/"),
routes,
});
export const handleRouterMeta = (sideMenusFlat: IMenuItem[]) => {
let routesFlat = router.getRoutes();
sideMenusFlat.forEach((curRoute) => {
let match = routesFlat.find((i) => i.name == curRoute.key);
if (match) {
match.meta = curRoute.meta as RouteMeta;
}
});
};
let isFresh = true; //刷新页面重新处理路由
router.beforeEach(async (to, _, next) => {
if (to.path === "/login") {
next();
return;
}
const {sideMenus, getMenus, sideMenusFlat} = useMenuStore();
if (isFresh && sideMenus.length) {
isFresh = false;
handleRouterMeta(sideMenusFlat);
next({...to});
return;
}
if (sideMenus.length === 0) {
isFresh = false;
await getMenus();
handleRouterMeta(sideMenusFlat);
next({...to});
} else {
isFresh = false;
handleRouterMeta(sideMenusFlat);
next();
}
});
这里我把路由和导航的处理放在了一起 menu.Store.ts
import {IMenuItem} from "@/models/menu";
import {IMenu} from "@/models/menu";
import {defineStore} from "pinia";
import {useSideMenu1, useSideMenu2} from "@/utils/api";
export const useMenuStore = defineStore(
"menu",
() => {
let sideMenus = ref<IMenu[]>([]);
let sideMenusFlat = ref<IMenuItem[]>([]);
const flatMenu = (menus: IMenu[]) => {
menus.forEach((m: any) => {
m.menu ? flatMenu(m.menu) : sideMenusFlat.value.push(m);
});
};
const getMenus = async () => {
const {code, data} = await useSideMenu1();
if (code === 200) {
sideMenus.value = data;
flatMenu(sideMenus.value);
return;
}
};
const changeMenus = async () => {
sideMenus.value = [];
const {code, data} = await useSideMenu2();
if (code === 200) {
sideMenus.value = data;
flatMenu(sideMenus.value);
return;
}
};
return {
getMenus,
sideMenus,
sideMenusFlat,
changeMenus,
};
},
{
persist: {
paths: ["sideMenus", "sideMenusFlat"],
},
}
);
页面示例:
<template> <div class="index-permission w-full overflow-hidden bg-slate-100 p-4"> <p v-if="route.meta.isAdmin">当前是admin用户</p> <p v-else>当前不是admin用户</p> <el-button v-if="!route.meta.isAdmin" type="primary" size="default" @click="changeMenu">切换为admin用户</el-button> </div> </template> <script setup lang="ts"> import { handleRouterMeta } from '@/router'; import { useMenuStore } from '@/stores/menu'; let route = useRoute() const { changeMenus, sideMenusFlat } = useMenuStore() const changeMenu = async () => { await changeMenus() handleRouterMeta(sideMenusFlat); location.reload() } </script>
单组件权限
app.directive("permission", (el, binding) => { const permission = binding.value; let routeMeta = router.currentRoute.value.meta; if (routeMeta[permission]) { el.style.display = "block"; } else { el.style.display = "none"; } });

浙公网安备 33010602011771号