获取token信息

Src/network/request.js

import axios from 'axios'

export let request = (config) => {
    //创建axios实例
    let instance = axios.create({})
    return instance(config)
}

src/api/login.js

import {request} from '../network/request'

function loginByUsername(username, password) {
    let data = {
        username,
        password
    }
    return request({
        url: "https://elm.cangdu.org/v2/login",
        method: "post",
        data//这就是向服务器发送了用户填写的数据
    })
    //axios是promise对象,返回的是服务器返回的东西
}
export { loginByUsername }

src/store/index.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
import {loginByUsername} from '../api/login'

let store = new Vuex.Store({
    state:{
        token:""
    },
    mutations:{
        Set_Token(state,token){
            state.token=token
        }
    },
    actions:{
        LoginByUsername({commit},userInfo){
            //userInfo,就是用户传来的用户名+密码信息
            let username=userInfo.username.trim()
            return new Promise((resolve,reject)=>{
                loginByUsername(username,userInfo.password).then(response=>{
                    //response 是服务器发回来的数据
                    //我们使用的是里面的data数据
                    let data=response.data
                    commit('Set_Token',data.token)
                    //我感觉用cookie或者storage都可以啊 做一个本地储存很重要
                    window.localStorage.setItem('token',data.token)
                    resolve()
                }).catch(err=>{
                    reject(err)
                })
            })
        }
    }
})

export default store

Login.vue

<template>
  <div>
    <el-form
      :model="ruleForm"
      :rules="rules"
      ref="ruleForm"
      label-width="100px"
      class="demo-ruleForm"
    >
      <el-form-item label="用户名" prop="name">
        <el-input v-model="ruleForm.name"></el-input>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input v-model="ruleForm.password"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="submitForm('ruleForm')">登录</el-button>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>

export default {
  name: "Login",
  data() {
    return {
      loading:false,
      ruleForm: {
        username: "",
        password: ""
      },
      rules: {
        name: [
          { required: true, message: "请输入用户名", trigger: "blur" },
        ],
        password:[
          { required: true, message: "请输入密码", trigger: "blur" },
        ]
      }
    }
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate(valid => {
        if (valid) {
            //把用户填写的用户名+密码发送过去
            this.$store.dispatch('LoginByUsername',this.ruleForm).then(()=>{
                this.$router.push('/home')
            }).catch(()=>{
                this.loading=false
                console.log(123);
                
            })
           
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    }
  }
};
</script>
<style scoped>
</style>

获取role信息

每个用户可以访问的路由是不一样的,有路由权限
当我们获取服务器发过来的token值后,我们再利用这个token值向服务器发送请求,获取该用户的role信息,再根据role信息,知道该用户可以访问哪些路由

使用全局守卫,在进入下一个路由之前,如果还没有获取用户的role信息,就先获取role信息

router/index.js

router.beforeEach((to, from, next) => {
  //用户已经登录,获取了token信息,但是用户还没有获取路由信息的话
  //利用token发送请求,获取可以访问的路由信息
  if (store.state.token) {
    if (store.state.roles.length === 0) {
      store.dispatch('getInfo', store.state.token).then(() => {
        next()
      })
    }
  }else{
    next()
  }
})

Store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import loadByUsername from '../api/login'
import {request} from '../network/request'
Vue.use(Vuex)

let store = new Vuex.Store({
    state:{
        token:"",
        //用户获取用户的可以访问的路由信息
        roles: []
    },
    
    mutations:{
        setToken(state,token){
            state.token=token
        },
        setRoles(state,roles){
            state.roles=roles
        }
    },
    actions:{
        LoadByUsername({commit},userInfo){
           return new Promise((resolve,reject)=>{
               let username=userInfo.username.trim()
               loadByUsername(username,userInfo.password).then(data=>{
                   let dataFromEnd=data.data
                   //服务器返回一个token
                   commit('setToken',dataFromEnd.message)
                   window.localStorage.setItem('token',dataFromEnd.message)
                   resolve()
               }).catch(err=>reject(err))
           })
        },
        getInfo({commit},token){
            return new Promise((resolve,reject)=>{
                request({
                    url: "https://elm.cangdu.org/v2/login",
                    method:"post",
                    token
                }).then(response=>{
                    commit('setRoles',response.data.roles)
                    resolve()
                }).catch(err=>reject(err))
            })
        }
    }
})
export default store

做项目

结合登录权限,username+password → token → role →routes

导航栏中遍历routes

https://juejin.im/post/591aa14f570c35006961acac

使用了mock

自己写得:
Router/index.js

import Vue from 'vue'
import Router from 'vue-router'

import store from '../store'

let Login = () => import('@/components/Login')
let Home = () => import('@/components/Home')

let SystemHome = () => import('@/components/SystemHome')
let BasicTable = () => import('@/components/BasicTable')
let Tab = () => import('@/components/Tab')
let RelevantInput = () => import('@/components/RelevantInput')
let BasicInput = () => import('@/components/BasicInput')
let ThirdMenu = () => import('@/components/ThirdMenu')
let Editor = () => import('../components/Editor/Editor.vue')
let MarkDown = () => import('@/components/MarkDown')
let Echart = () => import('@/components/Echart')
let Drag = () => import('@/components/Drag')
let DragTable = () => import('@/components/DragTable')
let DragBox = () => import('@/components/DragBox')
let Language = () => import('@/components/Language')
let ChangeColor = () => import('@/components/ChangeColor')

let Lint = () => import('@/components/Lint')
let Icon = () => import('@/components/Icon')


Vue.use(Router)

let constantRouterMap = [
    {
        path: "",
        redirect: "/login"
    },

    {
        path: "/login",
        name: "Login",
        component: Login
    },
]

let router = new Router({
    mode: "history",
    routes: constantRouterMap
})

let asyncRouterMap = [
    {
        path: "/home",
        name: "Home",
        component: Home,
        meta: {
            role: ['admin', 'editor'],
            icon: "el-icon-delete",
            title:"后台管理系统"
        },
        children: [


            {
                path: "/home",
                name: "SystemHome",
                component: SystemHome,
                meta: {
                    role: ['admin', 'editor'],
                    icon: "el-icon-s-home",
                    title: "系统首页"
                }
            },
            {
                path: "/icon",
                name: "Icon",
                component: Icon,
                meta: {
                    role: ['admin', 'editor'],
                    icon: "el-icon-view",
                    title: "Icon图标"
                }
            },
            {
                path: "/tab",
                name: "Tab",
                component: Tab,
                meta: {
                    role: ['admin', 'editor'], icon: "el-icon-s-order",
                    title: "Tab选项卡"
                },
            },
           
            {
                //大家都可以进入用户界面,只是admin和edtior的导航会不一样
                path: "/input",
                name: "RelevantInput",
                component: RelevantInput,
                meta: {
                    role: ['admin', 'editor'], icon: "el-icon-tickets",
                    title: "表单相关"
                },
                children: [
                    {
                        path: "/basicinput",
                        name: "BasicInput",
                        component: BasicInput,
                        meta: {
                            role: ['admin', 'editor'],
                            title: "基本表单"
                        },
                    },
                    {
                        path: "/thirdmenu",
                        name: 'ThirdMenu',
                        component: ThirdMenu,
                        meta: {
                            role: ['admin', 'editor'],
                            title: "三级菜单"
                        },
                        children: [
                            {
                                path: "/editor",
                                name: "Editor",
                                component: Editor,
                                meta: {
                                    role: ['admin', 'editor'], icon: "",
                                    title: "富文本编辑器"
                                },
                            },
                            {
                                path: "/markdown",
                                name: "MarkDown",
                                component: MarkDown,
                                meta: {
                                    role: ['admin', 'editor'], icon: "",
                                    title: "Mark Down编辑器"

                                },
                            }
                        ]
                    }
                ]

            },
            {
                path: "/echart",
                name: "Echart",
                component: Echart,
                meta: {
                    role: ['admin'], icon: "el-icon-pie-chart",
                    title: "Echart图表"

                },
            },
            {
                path: "/drag",
                name: "Drag",
                component: Drag,
                meta: {
                    role: ['admin', 'editor'], icon: "el-icon-s-data",
                    title: "表格展示"

                },
                children: [
                    {
                        path: "/basictable",
                        name: "BasicTable",
                        component: BasicTable,
                        meta: {
                            role: ['admin', 'editor'],
                            icon: "el-icon-menu",
                            title: "基本表格"
                        }
                    },
                    {
                        path: "/DragTable",
                        name: "DragTable",
                        component: DragTable,
                        meta: {
                            role: ['admin', 'editor'], icon: "",
                            title: "拖拽表格"

                        },
                    },
                    {
                        path: "/dragbox",
                        name: "DragBox",
                        component: DragBox,
                        meta: {
                            role: ['admin', 'editor'], icon: "",
                            title: "动态表格"

                        },
                    },
                ]
            },
            {
                path: "/language",
                name: "Language",
                component: Language,
                meta: {
                    role: ['admin', 'editor'], icon: "el-icon-coordinate",
                    title: "国际化功能"
                },
            },
            {
                path: "/changecolor",
                name: "ChangeColor",
                component: ChangeColor,
                meta: {
                    role: ['admin', 'editor'], icon: "el-icon-orange",
                    title: "个性换肤"
                },
            },
            {
                path: "/lint",
                name: "Lint",
                component: Lint,
                meta: {
                    role: ['admin'], icon: "el-icon-s-custom",
                title: "权限测试"

                },

            }
        ]
    },
];


router.beforeEach((to, from, next) => {
    //结合本地 储存账户信息
    if(window.sessionStorage.getItem('token')){
    store.commit('setToken',window.sessionStorage.getItem('token'))
}
    if (store.state.token) { // 判断是否有token
        if (to.path === '/login') {
            next({ path: '/home' });
        } else {
          if(store.state.roles.length===0){
               store.dispatch('getRole', store.state.token).then(res => { // 拉取info
                    const role = res;//admin/editor
                    store.dispatch('GenerateRoutes', role).then(() => { // 生成可访问的路由表
                        router.addRoutes(store.state.addRouters) // 动态添加可访问路由表
                        next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
                    })
                }).catch(err => {
                    console.log(err);
                });
        
          }else{
              next()
          }
               



        }
    } else {
        //最后这么写
        if (to.path === '/login') {
            next()
        } else {
            next('/login'); // 否则全部重定向到登录页
        }
    }
});

export { router, asyncRouterMap, constantRouterMap }

Store/index.js

import Vue from 'vue'
import Vuex from 'vuex'
import axios from '../network'

import { router, asyncRouterMap, constantRouterMap } from '../router'
Vue.use(Vuex)

function hasPermission(roles, route) {
    if (route.meta && route.meta.role) {
        return roles.some(role => route.meta.role.indexOf(role) >= 0)
    } else {
        return true
    }
}


let store = new Vuex.Store({
    state: {
        bgcolor:"rgba(119, 152, 187, 0.66)",
        token: "",
        roles: [],
        routers: constantRouterMap,
        addRouters: [],
        messageBadge:true
    },
    getters:{
        changeSrc(state) {
            if (state.roles[0] === "admin") {
                return "https://tvax4.sinaimg.cn/crop.0.0.996.996.180/0074HXD9ly8gaoj4s7bm8j30ro0roac8.jpg?KID=imgbed,tva&Expires=1578838255&ssig=HU9QjO0%2BIJ";
            }
            if (state.roles[0] === "editor") {
                return "https://wx2.sinaimg.cn/mw1024/0074HXD9gy1gadxbg0q2zj30460463yd.jpg";
            }
        }
    },
    mutations: {
        changeBgcolor(state,color){
            state.bgcolor=color
        },
        changeMessageBadge(state,boo){
            state.messageBadge=boo
        },
        setToken(state, token) {
            state.token = token
        },
        setRole(state, role) {
            state.roles.pop()
            state.roles.push(role)
        },
        backRole(state, role) {
            state.roles=[]
        },
        backRouters(state) {
            state.routers=constantRouterMap
        },
        changeRole(state, role) {
            state.roles.pop()
            state.roles.push(role)
        },

        SET_ROUTERS: (state, routers) => {
            state.addRouters = routers;
            state.routers = constantRouterMap.concat(routers);
        }
    },
    actions: {
        LoadByUsername({ commit }, userForm) {
            return new Promise((resolve, reject) => {
                let username = userForm.username.trim()
                let password = userForm.password
                let data = {
                    username, password
                }
                axios({
                    //因为接口不能判断用户名,所以我创建了两个接口
                    url: '/news/gettoken',
                    method: "post",
                    data
                }).then(response => {
                    let res = response.data.data
                    commit('setToken', res.token)
                    window.sessionStorage.setItem('token', res.token)
                    router.push('/home')
                    resolve()
                }).catch(err => reject(err))
            })
        },
        getRole(context,tok) {
            //把独一无二的token信息打出去
            return new Promise((resolve, reject) => {
               
                if(tok==='adminToken'){
                    axios({
                        //尽管这里是发送了token信息,可是不知道为什么在mock中,token值为null,不能进行判断,所以我直接在这里进行判断
                        //Yinwei返回的都是false
                        url:"/news/adminrole",
                        method: "get",

                    }).then(response => {
                        let role = response.data.data.role
                        context.commit('setRole', role)
                        resolve(role)
                        // console.log(role)

                    }).catch(err => reject(err))
                } else if (tok === 'editorToken'){
                    axios({
                        //尽管这里是发送了token信息,可是不知道为什么在mock中,token值为null,不能进行判断,所以我直接在这里进行判断
                        //Yinwei返回的都是false
                        url:"/news/editorrole",
                        method: "get",

                    }).then(response => {
                        let role = response.data.data.role
                        context.commit('setRole', role)
                        resolve(role)
                        // console.log(role)

                    }).catch(err => reject(err))
                }


            })

        },

        GenerateRoutes({ commit }, data) {
            commit('setRole', data)
            return new Promise(resolve => {
                const roles = []
                roles.push(data)//roles=['admin']/['editor']
                const accessedRouters = asyncRouterMap.filter(v => {
                    if (roles.indexOf('admin') >= 0) return true;
                    if (hasPermission(roles, v)) {
                        if (v.children && v.children.length > 0) {
                            v.children = v.children.filter(child => {
                                if (hasPermission(roles, child)) {
                                    return child
                                }
                                return false;
                            });
                            return v
                        } else {
                            return v
                        }
                        
                    }
                    return false;
                });
                commit('SET_ROUTERS', accessedRouters);
                resolve();
            })
        }
    },
})

export default store

假如退出当前账户:

  this.$store.commit("setToken", null);
      window.sessionStorage.clear()
      this.$store.commit("backRole");
      this.$store.commit("backRouters");
      this.$router.push("/login");

mock和axios自然连接,要在axios中引入mock
感觉只要写好mock就可以了啊
Mock/index.js

import Mock from 'mockjs'

Mock.mock('/news/gettoken', "post", function (options) {
    let obj = JSON.parse(options.body)//from
    if (obj.username === 'admin') {
        return {
            data: {
                token: "adminToken"
            }
        }
    } else {
        return {
            data: {
                token: "editorToken"
            }
        }
    }
})
Mock.mock('/news/adminrole', 'post', function (options) {
        return {
            data: {
                role: "admin"
            }
        }
})
Mock.mock('/news/editorrole', 'post', function (options) {
    return {
        data: {
            role: "editor"
        }
    }
})

export default Mock

Axios/index.js

import axios from 'axios'
import Mock from '../mock'

// axios.defaults.baseURL ='http://localhost:8080'

export default axios


导航栏,使用了三级菜单
<template>
  <div>
    <el-container style="border:1px solid black">
      <el-aside width="200px">
          <el-menu   :collapse="collapse" background-color="#eeefef" text-color="#666" active-text-color="#20a0ff" unique-opened router @select="addTab">

        <!-- 一级菜单 -->
        <template v-for="item in showRouters" >
          <el-submenu v-if="item.children&&item.children.length" :index="item.path" :key="item.path">
            <template slot="title"><span>{{item.name}}</span></template>

            <!-- 二级菜单 -->
            <template v-for="itemChild in item.children">
              <el-submenu v-if="itemChild.children&&itemChild.children.length" :index="itemChild.path" :key="itemChild.path" >
                <template slot="title"><span>{{itemChild.name}}</span></template>

                <!-- 三级菜单 -->
                <el-menu-item v-for="itemChild_Child in itemChild.children" :index="itemChild_Child.path" :key="itemChild_Child.path">
                <span slot="title">{{itemChild_Child.name}}</span>
                </el-menu-item>
              </el-submenu>

              <el-menu-item v-else :index="itemChild.path" :key="itemChild.path"><span slot="title">{{itemChild.name}}</span></el-menu-item>
            </template>
          </el-submenu>

          <el-menu-item v-else :index="item.path" :key="item.path"><span slot="title">{{item.name}}</span></el-menu-item>
        </template>

    </el-menu>

      </el-aside>
      <el-main>
        <router-link to="/cart">购物车</router-link>

        <router-view />
      </el-main>
    </el-container>
  </div>
</template>
<script>
export default {
  name: "Home",
  methods: {
    moreBtn() {
      this.$router.push("/more");
    }
  },
  computed: {
    showRouters() {
      let homeRoutes = this.$store.state.routers.filter(
        r => r.path === "/home"
      )[0].children;
      console.log(homeRoutes);

      return homeRoutes.filter(route => {
        if (!route.path) {
          return false;
        } else if (route.path === "/login") {
          return false;
        } else {
          return true;
        }
      });
      return homeRoutes;
    }
  },
  mounted() {
    window.vue = this;
  },
  
};
</script>

利用表格做待办事项

点击check,cell可以添加样式
有删除和编辑功能

<el-table
                :data="tableData"
                style="width: 100%"
                @selection-change="handleSelectionChange"
                :cell-style="addTextDecoration" fit
              >
                <el-table-column  type="selection" label='打卡'></el-table-column>
                <el-table-column  prop="project" label='事项名称'>
                  <template slot-scope="scope">
                    <div v-if="show&&scope.$index==i">
                      <el-input v-model="scope.row.project"></el-input>
                    </div>
                    <div v-else>
                      <span>{{scope.row.project}}</span>
                    </div>
                  </template>
                </el-table-column>
                <el-table-column align='right'>
                  <template slot-scope="scope">
                    <el-button size="mini" @click="handleEdit(scope.$index)">
                      <span v-if="show&&scope.$index==i">确定</span>
                      <span v-else>编辑</span>
                    </el-button>
                    <el-button
                      size="mini"
                      type="danger"
                      @click="handleDelete(scope.$index, scope.row)"
                    >删除</el-button>
                  </template>
                </el-table-column>
              </el-table>

  data() {
    return {
      tableData: [
        {
          id: 0,
          project: "背50个单词背50个单词背50个单词"
        },
        {
          id: 1,
          project: "三篇阅读三篇阅读三篇阅读"
        },
        {
          id: 2,
          project: "两张试卷两张试卷两张试卷"
        },
        {
          id: 3,
          project: "vue练习vue练习vue练习"
        },
        {
          id: 4,
          project: "后台管理系统项目后台管理系统项目"
        }
      ],
      i: -1,
      multipleSelection: [],
      show: true
    };
  },
  methods: {
    handleSelectionChange(rere) {
      let arr = [];
      rere.forEach((val, index) => {
        this.tableData.forEach((v, i) => {
          if (val.id == v.id) {
            arr.push(i);
          }
        });
      });
      this.multipleSelection = arr;
    },

    handleDelete(index, row) {
      console.log(row);
      this.tableData.splice(index, 1);
    },
    handleEdit(index) {
      console.log(index);
      this.i = index;
      this.show = !this.show;
    },
    // hehe({row, column, rowIndex, columnIndex}){
    //     if(this.checkedId.indexOf(rowIndex)){return 'text-decoration:line-through'}

    // },
    addTextDecoration({ row, rowIndex }) {
      let arr = this.multipleSelection;
      for (let i = 0; i < arr.length; i++) {
        if (rowIndex === arr[i]) {
          return "text-decoration:line-through";
        }
      }
    },
    addproject() {
      let thisid = this.tableData[this.tableData.length - 1].id;
      let obj = {
        id: thisid + 1,
        project: ""
      };
      this.tableData.push(obj);
    }
  },

container中
左边aside右边main
aside是导航栏

想要左边导航栏固定不会滚动,右边内容会滚动

我们可以设置整个container的高度是window的innerheight,
main设置overflow-y:scroll

借助dialog修改表格的内容

(另外这里通过mock,axios获得数据)

<template>
  <div>
    <el-table :data="tableData" fit>
      <el-table-column prop="ID" label="ID"></el-table-column>
      <el-table-column prop="name" label="姓名"></el-table-column>
      <el-table-column prop="price" label="账户余额"></el-table-column>
      <el-table-column label="头像">
        <template slot-scope="scope">
          <img :src="scope.row.image" style="width:50px;height:50px" @click="imageClick(scope.row)" />
        </template>
      </el-table-column>
      <el-table-column prop="location" label="地址"></el-table-column>
      <el-table-column prop="status" label="状态">
        <template slot-scope="scope">
          <el-button
            size="mini"
            plain
            :type="(scope.row.status==='成功')?'success':'warning'"
          >{{scope.row.status}}</el-button>
        </template>
      </el-table-column>
      <el-table-column prop="date" label="注册日期"></el-table-column>
      <el-table-column label="操作">
        <template slot-scope="scope">
          <div style="display:flex;flex-direction:row">
            <el-button type="primary" @click="editData(scope.row,scope.$index)">编辑</el-button>
            <el-button type="danger" @click="deleteData(scope.$index)">删除</el-button>
          </div>
        </template>
      </el-table-column>
    </el-table>

    <el-dialog :visible.sync="dialogTableVisible" style="padding:0;">
      <img :src="showImage" alt />
    </el-dialog>

    <el-dialog title="编辑信息" :visible.sync="editBox">
      <el-form :model="form">
        <el-form-item label="ID">
          <el-input v-model.lazy="form.ID" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="姓名">
          <el-input v-model="form.name" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="账户余额">
          <el-input v-model="form.price" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="头像">
          <el-input v-model="form.image" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="状态">
          <el-input v-model="form.status" autocomplete="off"></el-input>
        </el-form-item>
        <el-form-item label="注册日期">
          <el-input v-model="form.date" autocomplete="off"></el-input>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="editBox = false">取 消</el-button>
        <el-button type="primary" @click="handleUpdate('form')">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import axios from "../network";
export default {
  name: "BasicTable",
  data() {
    return {
      tableData: [],
      dialogTableVisible: false,
      showImage: "",
      editBox: false,
      form: {
        ID: "3",
        name: "dsd",
        image: "ssaa",
        date: "dssd",
        status: "sas",
        price: "g"
      },
      i:0
    };
  },
  methods: {
    imageClick(row, index) {
      this.dialogTableVisible = true;
      this.showImage = row.image;
    },
    deleteData(index) {
      this.tableData.splice(index, 1);
    },
    editData(row, index) {
      this.editBox = true;
      this.i=index//关键
      //表格展示row的内容,同时在表单改写的内容还是储存到this.form
     this.form=Object.assign({},row)
    },
    handleUpdate(forName) {
        //对tableData进行修改,页面上的内容自然修改
         this.tableData.splice(this.i,1,this.form)
      this.editBox = false;
    }
  },
  created() {
    axios.get("/news/gettable").then(res => {
      this.tableData = res.data.data.tableData;
    });
  }
};
</script>
<style scoped>
</style>

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐