![[1280X1280 (46).PNG]]
![[1280X1280 (48).PNG]]
![[1280X1280 (50).PNG]]
权限管理总结
![[download_image.jpeg]]
模拟路由信息数据
adminRouter.json
[ { "path": "/dashboard", "component": "/layout/index.vue", "title": "Dashboard", "home": "/dashboard/console", "redirect": "/dashboard/console", "icon": "Edit", "name": "dashboard", "children": [ { "path": "console", "component": "/dashboard/console.vue", "title": "主控台", "icon": "Location" }, { "path": "monitor", "component": "/dashboard/monitor.vue", "title": "监控页", "icon": "Location" }, { "path": "workplace", "component": "/dashboard/workplace.vue", "title": "工作台", "icon": "Location" } ] }, { "path": "/student", "component": "/layout/index.vue", "title": "学生管理", "home": "/student/stuAdmin", "icon": "Edit", "name": "student", "children": [ { "path": "stuAdmin", "component": "/student/index.vue", "title": "学生管理", "icon": "Location", "name":"stuAdmin" }, { "path": "addStu", "component": "/student/addStu.vue", "title": "添加学生", "icon": "Location", "name":"addStu" }, { "path": "classAdmin", "component": "/student/classAdmin.vue", "title": "班级管理", "icon": "Location", "name":"classAdmin" } ] }, { "path": "/upload", "component": "/layout/index.vue", "title": "图片上传", "icon": "Edit", "name": "upload", "children": [ { "path": "index", "component": "/upload/index.vue", "title": "图片上传", "icon": "Location", "name":"uploadimg" } ] } ]teacherRoutes.json
[ { "path": "/dashboard", "component": "/layout/index.vue", "title": "Dashboard", "home": "/dashboard/console", "redirect": "/dashboard/console", "icon": "Edit", "name": "dashboard", "children": [ { "path": "console", "component": "/dashboard/console.vue", "title": "主控台", "icon": "Location" }, { "path": "monitor", "component": "/dashboard/monitor.vue", "title": "监控页", "icon": "Location" }, { "path": "workplace", "component": "/dashboard/workplace.vue", "title": "工作台", "icon": "Location" } ] }, { "path": "/student", "component": "/layout/index.vue", "title": "学生管理", "home": "/student/stuAdmin", "icon": "Edit", "name": "student", "children": [ { "path": "stuAdmin", "component": "/student/index.vue", "title": "学生管理", "icon": "Location", "name":"stuAdmin" }, { "path": "addStu", "component": "/student/addStu.vue", "title": "添加学生", "icon": "Location", "name":"addStu" }, { "path": "classAdmin", "component": "/student/classAdmin.vue", "title": "班级管理", "icon": "Location", "name":"classAdmin" } ] } ]从后端接口返回不同权限的路由数据 - user.js
let adminRoutes = require("../util/adminRoutes.json"); let teacherRoutes = require("../util/teacherRoutes.json"); let routes = { admin:adminRoutes, teacher:teacherRoutes } router.post('/login',async (req, res)=>{ // 1. 接收用户名和密码 let {account,pw} = req.body; // 2. 连接数据库,查看用户名 和 密码是否存在 let sql = `select * from user where account = '${account}' and pw = '${pw}'`; let data =await query(sql); let token = await setToken(account); let sendMsg = {}; if(data.data.length > 0){ let role = data.data[0].role; sendMsg = { msg:"登录成功", status:200, token, routesData:routes[role] } }else{ sendMsg = { msg:"用户名或者密码错误", status:102 } } console.log(sendMsg); res.send(sendMsg); });前端接受路由信息
并渲染数据【接收一个路由信息】,在login页面接受数据 - index.vue
<script setup> import { ref, reactive } from "vue"; import { useRouter } from 'vue-router'; import { _login } from "@/api/request" // vite工具 // 针对解析的数据,进行组件懒加载 const Modules = import.meta.glob("@/pages/**/*.vue"); // console.log(Modules); const router = useRouter(); let formData = reactive({ account: "", pw: "" }) let login = async () => { let { data } = await _login(formData); // 接收路由信息中的值(只接受第一组路由信息,用于测试) let { children, component, home, icon, name, path, redirect, title } = data.routesData[0]; // 一级路由渲染 router.addRoute({ name, path, // 注意:引入的路径中,pages后面没有 / component: Modules[`/src/pages${component}`], meta: { title, icon, home }, redirect }) console.log(children[0]); // 二级路由渲染 router.addRoute("dashboard", { path: children[0].path, component: Modules[`/src/pages${children[0].component}`], meta: { title: children[0].title, icon: children[0].icon } }) // 打印路由信息 console.log(router.getRoutes()); if (data.status == 200) { sessionStorage.setItem('token', data.token); console.log(data); router.push('/'); } } </script>遍历二级路由,使dashboard下面的二级路由都可以使用
// 二级路由 children.forEach(item => { let { path, component, title, icon } = item; router.addRoute("dashboard", { path, component: Modules[`/src/pages${component}`], meta: { title, icon } }) })生成动态侧边栏
思路:登陆成功之后,将路由数据存储到vuex中,方便侧边栏NavMenu.vue调用数据
- 创建vuex文件
src/store/index.js
import { createStore } from 'vuex' // 创建一个新的 store 实例 const store = createStore({ state () { return { routesData: [] } }, mutations:{ addRoutersData:(state,payload)=>{ state.routesData = payload } } }) export default store- 在全局注册vuex
import store from "./store" .... app.use(store);- 登陆成功之后,数据存储到vuex中
import {useStore} from "vuex" let store = useStore(); let login = async () => { let { data } = await _login(formData); // 存入store中 store.commit("addRoutersData", data.routesData); ..... ..... }- 在NavMenu.vue侧边栏中调用数据
import { useStore } from "vuex"; import { computed } from "vue"; const store = useStore(); const props = defineProps({ collapse: Boolean }) // 获取数据 console.log("111", store.state.routesData); let routesData = computed(() => { return store.state.routesData; }); // 渲染数据 <el-menu active-text-color="#ffd04b" background-color="#545c64" class="el-menu-vertical-demo" :default-active="$route.path" text-color="#fff" :default-openeds="['/dashboard']" :router="true" :collapse="props.collapse"> <h5 class="title">后台管理系统</h5> <!--template 标签只用来渲染数据,并不会在页面中显示--> <template v-for="(item,index) in routesData" :key="index"> <el-menu-item :index="item.path" v-if="item.children.length == 1"> <el-icon> <component :is="item.icon"></component> </el-icon> <span>{{item.title}}</span> </el-menu-item> <el-sub-menu index="/dashboard" v-else> <template #title> <el-icon> <component :is="item.icon"></component> </el-icon> <span>{{item.title}}</span> </template> <el-menu-item :index="second.path" v-for="(second,i) in item.children" :key="i"> <el-icon> <component :is="second.icon"></component> </el-icon> {{second.title}} </el-menu-item> </el-sub-menu> </template> </el-menu>封装动态生成路由部分
- 创建文件 src/utils/generatorRoutes.js
// import { useRouter } from 'vue-router'; // const router = useRouter(); // 等价于下面的引入 // 引入router import router from "@/router/index.js"; // vite工具 // 针对解析的数据,进行组件懒加载 const Modules = import.meta.glob("@/pages/**/*.vue"); export const generatorRoutes = (routesData)=>{ let { children, component, home, icon, name, path, redirect, title } = routesData[0]; // 一级路由 router.addRoute({ name, path, component: Modules[`/src/pages${component}`], meta: { title, icon, home }, redirect }) // console.log(children[0]); // 二级路由 children.forEach(item => { let { path, component, title, icon } = item; router.addRoute("dashboard", { path, component: Modules[`/src/pages${component}`], meta: { title, icon } }) }) }- 登陆页面中进行引入
import { generatorRoutes } from '@/utils/generatorRoutes.js'; let login = async () => { let { data } = await _login(formData); // 存入store中 store.commit("addRoutersData", data.routesData); // console.log(router.getRoutes()); if (data.status == 200) { sessionStorage.setItem('token', data.token); // -----------动态生成路由 start----------- generatorRoutes(data.routesData); // -----------动态生成路由 end----------- // console.log(data); router.push('/'); } }- 遍历所有的路由信息
// import { useRouter } from 'vue-router'; // const router = useRouter(); // 等价于下面的引入 // 引入router import router from "@/router/index.js"; // vite工具 // 针对解析的数据,进行组件懒加载 const Modules = import.meta.glob("@/pages/**/*.vue"); export const generatorRoutes = (routesData)=>{ // 循环遍历 routesData.forEach((bigItem)=>{ let { children, component, home, icon, name, path, redirect, title } = bigItem; // 一级路由 router.addRoute({ name, path, component: Modules[`/src/pages${component}`], meta: { title, icon, home }, redirect }) // 二级路由 children.forEach(item => { let { path, component, title, icon } = item; router.addRoute(bigItem.name, { path, component: Modules[`/src/pages${component}`], meta: { title, icon } }) }) }) }刷新页面内容消失的解决方案
方案:刷新的时候,判断是否存在token,如果存在,重新从vuex中读取路由数据
router/index.js
//路由拦截 router.beforeEach((to,from)=>{ let token = localStorage.getItem('token'); // 如果token不存在,并且要跳转的不是login页,则重定向到login if(!token && to.fullPath !== '/login'){ return { path:'/login' } } // 解决问题的代码 if(token){ // token存在有两种情况 // 一种是没刷新时,此时动态路由已经创建,可以正常使用 // 一种是刷新后,此时动态路由已经销毁,不能进行路由跳转,需要重新加载 let routesData = store.state.routesData; if (routesData.length === 0) { console.log('刷新'); routesData = JSON.parse(localStorage.getItem("routesData")); // 使用commit调用mutations下面的方法 store.commit("addRoutersData",routesData); generatorRoutes(routesData); // 重定向将要进入的路由 // 如果不加下面的代码,会在路由没有准备好就跳转,出现404 // 如果加,相当于延迟跳转,此时路由已经准备好 return { path:to.fullPath }; } } }) export default router注意:当从本地存储中获取到路由数据之后,一定把把数据给vuex保存一份,否则即便有了数据,还是会一直进行 if routesData.length === 0 这一层判断 store.commit(‘addRoutersData’, routesData);