12.18 中后台项目-权限管理

![[1280X1280 (46).PNG]]

![[1280X1280 (48).PNG]]

![[1280X1280 (50).PNG]]

权限管理总结

![[download_image.jpeg]]

模拟路由信息数据

adminRouter.json

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

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

JavaScript 复制代码
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

HTML 复制代码
<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下面的二级路由都可以使用

JavaScript 复制代码
// 二级路由
children.forEach(item => {
    let { path, component, title, icon } = item;
    router.addRoute("dashboard", {
        path,
        component: Modules[`/src/pages${component}`],
        meta: {
            title,
            icon
        }
    })
})

生成动态侧边栏

思路:登陆成功之后,将路由数据存储到vuex中,方便侧边栏NavMenu.vue调用数据

  1. 创建vuex文件

src/store/index.js

JavaScript 复制代码
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
    state () {
        return {
            routesData: []
        }
    },
    mutations:{
        addRoutersData:(state,payload)=>{
            state.routesData = payload
        }
    }
})
export default store
  1. 在全局注册vuex
JavaScript 复制代码
import store from "./store"
....
app.use(store);
  1. 登陆成功之后,数据存储到vuex中
JavaScript 复制代码
import {useStore} from "vuex"
let store = useStore();
let login = async () => {
        let { data } = await _login(formData);
        // 存入store中
        store.commit("addRoutersData", data.routesData);
        .....
        .....
 }
  1. 在NavMenu.vue侧边栏中调用数据
JavaScript 复制代码
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>

封装动态生成路由部分

  1. 创建文件 src/utils/generatorRoutes.js
JavaScript 复制代码
// 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
            }
        })
    })
}
  1. 登陆页面中进行引入
JavaScript 复制代码
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('/');
    }
}
  1. 遍历所有的路由信息
JavaScript 复制代码
// 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

JavaScript 复制代码
//路由拦截
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);

相关推荐
Y‍waiX‍‍‮‪‎⁠‌‫‎‌‫‬2 小时前
NRM-NPM的镜像源管理工具使用方法
前端·npm·node.js
hssfscv2 小时前
JAVAweb学习笔记——JS
javascript·笔记·学习
茶憶3 小时前
UniApp 安卓端实现文件的生成,写入,获取文件大小以及压缩功能
android·javascript·vue.js·uni-app
云和恩墨4 小时前
OceanBase企业版会话级SQL跟踪实操:DBMS_MONITOR(类Oracle 10046事件)
数据库·sql·oracle·oceanbase
为什么不问问神奇的海螺呢丶4 小时前
oracle 数据库巡检 sql
数据库·sql·oracle
麦麦鸡腿堡4 小时前
MySQL数据库操作指令
数据库·mysql
未来之窗软件服务7 小时前
一体化系统(九)智慧社区综合报表——东方仙盟练气期
大数据·前端·仙盟创梦ide·东方仙盟·东方仙盟一体化
陈天伟教授10 小时前
人工智能训练师认证教程(2)Python os入门教程
前端·数据库·python
Elastic 中国社区官方博客11 小时前
Elasticsearch:在分析过程中对数字进行标准化
大数据·数据库·elasticsearch·搜索引擎·全文检索