Vue2项目练手——通用后台管理项目第八节

菜单权限功能

  1. 不同的账号登录,会有不同的菜单权限
  2. 通过url输入地址来显示页面
  3. 对于菜单的数据在不同页面之间的数据通信

tab.js

import Cookie from "js-cookie";
export default {
    state:{
        menu:[]
    },
	mutations:{
	//设置menu的数据
        setMenu(state,val){
            state.menu=val
            console.log("val",val)
            Cookie.set('menu',JSON.stringify(val))
        },
        //动态注册路由
        addMenu(state,router){
            //判断缓存中是否有数据
            if(!Cookie.get('menu')) return
            const menu=JSON.parse(Cookie.get('menu'))
            state.menu=menu
            //组装动态路由的数据
            const menuArray=[]
            menu.forEach(item=>{
                if(item.children){
                    item.children= item.children.map(item=>{
                        item.component=()=>import(`../pages/${item.url}`)
                        return item
                    })
                    menuArray.push(...item.children)
                }else{
                    item.component=()=>import(`../pages/${item.url}`)
                    menuArray.push(item)
                }
            })
            console.log("menuArray",menuArray)
            //路由的动态添加
            menuArray.forEach(item=>{
                router.addRoute('main',item)
            })
            console.log("menuArray",menuArray)
        }
    }

全部代码:

import Cookie from "js-cookie";
export default {
    state:{
        isCollapse:false,  //控制菜单的展开还是收起
        tabsList:[
            {
                path:'/',
                name:"home",
                label:"首页",
                icon:"s-home",
                url:'Home/Home'
            },
        ],  //面包屑数据
        menu:[]
    },
    mutations:{
        //   修改菜单展开收起的方法
        collapseMenu(state){
            state.isCollapse=!state.isCollapse
        },
        //更新面包屑
        selectMenu(state,val){
            //判断添加的数据是否为首页
            if(val.name!=='home'){
                // console.log("state",state)
                const index=state.tabsList.findIndex(item=>item.name===val.name)
                //如果不存在
                if(index===-1){
                    state.tabsList.push(val)
                }
            }
        },
        //删除指定的tag
        closeTag(state,item){
            const index=state.tabsList.findIndex(val=>val.name===item.name)
            state.tabsList.splice(index,1)   //splice(删除的位置,删除的个数)
        },
        //设置menu的数据
        setMenu(state,val){
            state.menu=val
            console.log("val",val)
            Cookie.set('menu',JSON.stringify(val))
        },
        //动态注册路由
        addMenu(state,router){
            //判断缓存中是否有数据
            if(!Cookie.get('menu')) return
            const menu=JSON.parse(Cookie.get('menu'))
            state.menu=menu
            //组装动态路由的数据
            const menuArray=[]
            menu.forEach(item=>{
                if(item.children){
                    item.children= item.children.map(item=>{
                        item.component=()=>import(`../pages/${item.url}`)
                        return item
                    })
                    menuArray.push(...item.children)
                }else{
                    item.component=()=>import(`../pages/${item.url}`)
                    menuArray.push(item)
                }
            })
            console.log("menuArray",menuArray)
            //路由的动态添加
            menuArray.forEach(item=>{
                router.addRoute('main',item)
            })
            console.log("menuArray",menuArray)
        }
    }
}

Login.vue

getMenu(this.form).then(({data})=>{
            console.log(data)
            if(data.code===20000){
              Cookie.set('token',data.data.token)
              //获取菜单的数据,存入store中
              this.$store.commit('setMenu',data.data.menu)
              this.$store.commit('addMenu',this.$router)
              //跳转到首页
              this.$router.push('/home')
            }else{
              this.$message.error(data.data.message)
            }
          })

全部代码:

<template>
  <div id="app">
    <div class="main-content">
      <div class="title">系统登录</div>
      <div class="content">
        <el-form label-width="70px" :inline="true" :model="form" status-icon :rules="rules" ref="ruleForm" class="demo-ruleForm">
          <el-form-item label="用户名" prop="username">
            <el-input v-model="form.username" placeholder="请输入账号"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input v-model="form.password" type="password" autocomplete="off" placeholder="请输入密码"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button></el-col>
          </el-form-item>
        </el-form>
      </div>
    </div>

  </div>

</template>

<script>
// import Mock from 'mockjs'
import Cookie from 'js-cookie'
import {getMenu} from "@/api";
export default {
  name: "login",
  data(){
    return{
      form: {
        username: '',
        password:""
      },
      rules: {
        username: [
          {required: true, message: '请输入用户名', trigger: 'blur'},
        ],
        password: [
          {required:true,message:"请输入密码",trigger:"blur"}
        ]
      }
    }
  },
  methods:{
    //登录
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          //token信息
          /*const token=Mock.Random.guid()  //生成随机数
          //token信息存入cookie用于不同页面间的通信
          Cookie.set('token',token)*/
          getMenu(this.form).then(({data})=>{
            console.log(data)
            if(data.code===20000){
              Cookie.set('token',data.data.token)
              //获取菜单的数据,存入store中
              this.$store.commit('setMenu',data.data.menu)
              this.$store.commit('addMenu',this.$router)
              //跳转到首页
              this.$router.push('/home')
            }else{
              this.$message.error(data.data.message)
            }
          })

        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
  }
}
</script>

<style lang="less" scoped>
#app {
  display: flex;
  background-color: #333;
  height: 100vh;
  .main-content{
    height: 300px;
    width: 350px;
    //line-height: 100vh;
    background-color: #fff;
    margin: 200px auto;
    border-radius: 15px;
    padding: 35px 35px 15px 35px;
    box-sizing: border-box;
    box-shadow: 5px  5px 10px rgba(0,0,0,0.5),-5px -5px 10px rgba(0,0,0,0.5);
    .title{
      font-size: 20px;
      text-align: center;
      font-weight: 300;
    }
    .content{
      margin-top: 30px;
    }
    .el-input{
      width: 198px;
    }
    .el-button{
      margin-left: 105px;
    }
  }
}
</style>

CommonAside.vue

data() {
    return {
    };
  },
menuData(){
      //判断当前数据,如果缓存中没有,当前store中获取
      return JSON.parse(Cookie.get('menu'))||this.$store.state.tab.menu
    }

全部代码:

<template>
    <el-menu default-active="1-4-1" class="el-menu-vertical-demo" @open="handleOpen" @close="handleClose"
             :collapse="isCollapse" background-color="#545c64" text-color="#fff"
             active-text-color="#ffd04b">
      <h3>{{isCollapse?'后台':'通用后台管理系统'}}</h3>
      <el-menu-item @click="clickMenu(item)"  v-for="item in noChildren" :key="item.name" :index="item.name">
        <i :class="`el-icon-${item.icon}`"></i>
        <span slot="title">{{item.label}}</span>
      </el-menu-item>
      <el-submenu :index="item.label" v-for="item in hasChildren" :key="item.label">
        <template slot="title">
          <i :class="`el-icon-${item.icon}`"></i>
          <span slot="title">{{item.label}}</span>
        </template>
        <el-menu-item-group>
          <el-menu-item @click="clickMenu(subItem)" :index="subItem.path" :key="subItem.path" v-for="subItem in item.children">
            {{subItem.label}}
          </el-menu-item>
        </el-menu-item-group>
      </el-submenu>
    </el-menu>

</template>



<style lang="less" scoped>
.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
  min-height: 400px;
}
.el-menu{
  height: 100vh;  //占据页面高度100%
  h3{
    color: #fff;
    text-align: center;
    line-height: 48px;
    font-size: 16px;
    font-weight: 400;
  }
}
</style>

<script>
import Cookie  from "js-cookie";
export default {
  data() {
    return {
    };
  },
  methods: {
    handleOpen(key, keyPath) {
      console.log(key, keyPath);
    },
    handleClose(key, keyPath) {
      console.log(key, keyPath);
    },
    clickMenu(item){
      // console.log(item)
      // console.log(this.$route.path)
      // 当页面的路由与跳转的路由不一致才允许跳转
      if(this.$route.path!==item.path && !(this.$route.path==='/home'&&(item.path==='/'))){
        this.$router.push(item.path)
      }
      this.$store.commit('selectMenu',item)
    }
  },
  mounted() {
    // console.log(this.$route.path)
  },
  computed:{
    //没有子菜单的数据
    noChildren(){
      return this.menuData.filter(item=>!item.children)
    },
    //有子菜单数组
    hasChildren(){
      return this.menuData.filter(item=>item.children)
    },
    isCollapse(){
      return this.$store.state.tab.isCollapse
    },
    menuData(){
      //判断当前数据,如果缓存中没有,当前store中获取
      return JSON.parse(Cookie.get('menu'))||this.$store.state.tab.menu
    }

  }
}
</script>

router/index.js

{
            // 子路由
            name:"main",
            path:'/',
            redirect:"/home",  //重定向 当路径为/,则重定向home
            component:Main,
            children:[
                    /*{
                        name:"user",
                        path:"user",
                        component:User,
                        meta:{title:"用户管理"}
                    },
                    {
                        name:"home",
                        path:"home",
                        component:Home,
                        meta:{title:"首页"}
                    },
                    {
                        name:"mall",
                        path:"mall",
                        component:Mall,
                        meta:{title:"商品管理"}
                    },
                    {
                        name:"page1",
                        path:"page1",
                        component:PageOne,
                        meta:{title:"页面1"}
                    },
                    {
                        name:"page2",
                        path:"page2",
                        component:PageTwo,
                        meta:{title:"页面2"}
                    }*/
            ]
        }

全部代码:

import VueRouter from "vue-router";
import Login from "@/pages/Login.vue";
import Main from '@/pages/Main.vue';
import User from "@/pages/User.vue";
import Home from "@/pages/Home.vue";
import Mall from "@/pages/Mall.vue";
import PageOne from "@/pages/PageOne.vue";
import PageTwo from "@/pages/PageTwo.vue";
import Cookie from "js-cookie";

const router= new VueRouter({
    // 浏览器模式设置,设置为history模式
    // mode:'history',
    routes:[
        {
            name:'login',
            path:"/login",
            component:Login,
            meta:{title:"登录"},
        },
        {
            // 子路由
            name:"main",
            path:'/',
            redirect:"/home",  //重定向 当路径为/,则重定向home
            component:Main,
            children:[
                    /*{
                        name:"user",
                        path:"user",
                        component:User,
                        meta:{title:"用户管理"}
                    },
                    {
                        name:"home",
                        path:"home",
                        component:Home,
                        meta:{title:"首页"}
                    },
                    {
                        name:"mall",
                        path:"mall",
                        component:Mall,
                        meta:{title:"商品管理"}
                    },
                    {
                        name:"page1",
                        path:"page1",
                        component:PageOne,
                        meta:{title:"页面1"}
                    },
                    {
                        name:"page2",
                        path:"page2",
                        component:PageTwo,
                        meta:{title:"页面2"}
                    }*/
            ]
        }

    ]
})
//添加全局前置导航守卫
router.beforeEach((to,from,next)=>{
    //判断token存不存在
    const token=Cookie.get('token')
    //token不存在,说明当前用户是未登录,应该跳转至登录页
    if(!token&&to.name!=='login'){
        next({name:'login'})
    }else if(token && to.name=="login"){   //token存在,说明用户登录,此时跳转至首页
        next({name:'home'})
    }else{
        next()
    }
})
// 后置路由守卫
router.afterEach((to,from)=>{
    document.title=to.meta.title||"通用后台管理系统"
})
export default router

请添加图片描述

权限管理问题解决

router/tab.js

clearTabs(state){
            //清除除过首页之外的所有面包屑
            state.tabsList=state.tabsList.splice(0,1)
        }

全部代码:

import Cookie from "js-cookie";
export default {
    state:{
        isCollapse:false,  //控制菜单的展开还是收起
        tabsList:[
            {
                path:'/',
                name:"home",
                label:"首页",
                icon:"s-home",
                url:'Home/Home'
            },
        ],  //面包屑数据
        menu:[]
    },
    mutations:{
        //   修改菜单展开收起的方法
        collapseMenu(state){
            state.isCollapse=!state.isCollapse
        },
        //更新面包屑
        selectMenu(state,val){
            //判断添加的数据是否为首页
            if(val.name!=='home'){
                // console.log("state",state)
                const index=state.tabsList.findIndex(item=>item.name===val.name)
                //如果不存在
                if(index===-1){
                    state.tabsList.push(val)
                }
            }
        },
        //删除指定的tag
        closeTag(state,item){
            const index=state.tabsList.findIndex(val=>val.name===item.name)
            state.tabsList.splice(index,1)   //splice(删除的位置,删除的个数)
        },
        //设置menu的数据
        setMenu(state,val){
            state.menu=val
            console.log("val",val)
            Cookie.set('menu',JSON.stringify(val))
        },
        //动态注册路由
        addMenu(state,router){
            //判断缓存中是否有数据
            if(!Cookie.get('menu')) return
            const menu=JSON.parse(Cookie.get('menu'))
            state.menu=menu
            //组装动态路由的数据
            const menuArray=[]
            menu.forEach(item=>{
                if(item.children){
                    item.children= item.children.map(item=>{
                        item.component=()=>import(`../pages/${item.url}`)
                        return item
                    })
                    menuArray.push(...item.children)
                }else{
                    item.component=()=>import(`../pages/${item.url}`)
                    menuArray.push(item)
                }
            })
            console.log("menuArray",menuArray)
            //路由的动态添加
            menuArray.forEach(item=>{
                router.addRoute('main',item)
            })
            console.log("menuArray",menuArray)
        },
        clearTabs(state){
            //清除除过首页之外的所有面包屑
            state.tabsList=state.tabsList.splice(0,1)
        }
    }
}

CommonHeader.vue

handleClick(command){
      if(command==='cancel'){
        console.log("登出")
        //清除Cookie的token信息
        Cookie.remove('token')
        //清除cookie中的menu
        Cookie.remove('menu')
        this.$store.commit('clearTabs')
        this.$router.push('/login')
      }

    }

全部代码:

<template>
  <div class="header-container">
    <div class="l-content">
      <el-button style="margin-right: 20px" icon="el-icon-menu" size="mini" @click="handleMenu"></el-button>
      <!--      面包屑-->
<!--      <span class="text">首页</span>-->
      <el-breadcrumb separator="/">
        <el-breadcrumb-item v-for="item in tags" :key="item.path" :to="{ path: item.path }">{{ item.label }}</el-breadcrumb-item>
      </el-breadcrumb>
    </div>
    <div class="r-content">
      <el-dropdown @command="handleClick">
          <span class="el-dropdown-link">
            <img src="@/assets/user.webp" alt="">
          </span>
          <el-dropdown-menu slot="dropdown">
            <el-dropdown-item>个人中心</el-dropdown-item>
            <el-dropdown-item command="cancel">退出</el-dropdown-item>
          </el-dropdown-menu>
      </el-dropdown>
    </div>
  </div>

</template>

<script>
import {mapState} from 'vuex'
import Cookie from 'js-cookie'
export default {
  name: "CommonHeader",
  methods:{
    handleMenu(){
      this.$store.commit('collapseMenu')
    },
    handleClick(command){
      if(command==='cancel'){
        console.log("登出")
        //清除Cookie的token信息
        Cookie.remove('token')
        //清除cookie中的menu
        Cookie.remove('menu')
        this.$store.commit('clearTabs')
        this.$router.push('/login')
      }

    }
  },
  computed:{
    ...mapState({
      tags: state=>state.tab.tabsList
    })
  }
}
</script>

<style scoped lang="less">
.header-container {
  height: 60px;
  background-color: #333;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20px;

  .text {
    color: #fff;
    font-size: 14px;
    margin-left: 10px;
  }
  .r-content{
    img{
      width: 40px;
      height: 40px;
      border-radius: 50%;
    }
  }
  .l-content{
    display: flex;
    align-items: center;
    /deep/.el-breadcrumb__item{   /*元素没有绑定data-v-5a90ec03这样的编号时候,样式不起作用,使用deep进行穿刺可解决问题*/
      .el-breadcrumb__inner{
        font-weight: normal;
        &.is-link{
          color: #666;
        }
      }
      &:last-child{
        .el-breadcrumb__inner {
          color: #fff;
        }
      }
    }
  }
}
</style>

main.js

created(){
    store.commit('addMenu',router)
  }

全部代码:

import Vue from 'vue'
import App from './App.vue'
import VueRouter from "vue-router";
import router from "@/router";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css'
import store from '@/store'
//引入mock模拟
import '@/api/mock'

Vue.config.productionTip = false
Vue.use(VueRouter)
Vue.use(ElementUI)
new Vue({
  store,
  router,
  render: h => h(App),
  created(){
    store.commit('addMenu',router)
  }
}).$mount('#app')

请添加图片描述

项目到此Vue2部分也就结束了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值