[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航

文章目录

    • 项目目录:
    • 项目地址
    • 1、项目准备
      • 1、使用vue-cli 脚手架创建项目
      • 2、项目是vue-cli +element-ui+axios+less 搭建的项目
      • 3、安装项目element-ui
      • 4、在main.js中引入字体图标
      • 5、mock生成模拟数据
      • 6、安装js-cookie 函数,
      • 7、封装axios请求
      • 8、配置项目路由 router
      • 9、定义后端接口
      • 10、后端登录接口
      • 11. 前端定义所有接口请求 http.js
    • 2、登录页 Login.vue
    • 3、使用vuex 存储路由和角色
    • 4、 设置全局前置导航守卫
    • 5、首页
      • 1、Layout.vue 首页整体布局
      • 2、header.vue头部组件
      • 3、Aside.vue侧边栏
      • 4、Bread.vue面包屑导航
      • 5、首页右侧主体
        • 1、home页
          • 效果展示
          • 1、定义首页数据接口(后端),mock/index.js
          • 2、mock/homeMock.js
          • 3、http/http.js 定义首页的数据请求
          • 4、home/home.vue
          • 5、components/BarEchart.vue 柱形图组件
          • 6、components/PieEchart.vue 饼形图组件
        • 2、user页
          • 效果展示
          • 1、定义首页数据接口 mock/index.js
          • 2、mock/userMock.js
          • 3、http/http.js 定义user 页的数据请求
          • 4、views /user.vue 首页右侧主体部分对应的首页页面。

项目目录:

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第1张图片

项目地址

https://gitee.com/sansan533/bk2115_pc

1、项目准备

1、使用vue-cli 脚手架创建项目

2、项目是vue-cli +element-ui+axios+less 搭建的项目

3、安装项目element-ui

npm i element-ui -S
//在main.js中 引入element-ui
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);

4、在main.js中引入字体图标

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第2张图片

//在main.js中 iconfont注册
import './assets/iconfont/iconfont.css'

5、mock生成模拟数据

安装mock 用来生成模拟数据,用来模拟后台接口
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第3张图片

npm install mockjs --save -dev
//在main.js 中引入mock
import './mock'

6、安装js-cookie 函数,

该插件封装了cookie 对应的操作方法

npm install js-cookie

7、封装axios请求

在src 目录下的utils文件中,定义request.js 文件,用来封装axios请求。
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第4张图片

src\utils\request.js

import {
      getCookie } from './cookie.js';
import Vue from 'vue'
import axios from 'axios';

//2。创建server
const instance = axios.create({
     
    baseURL: '',//  index/index  http://kumanxuan1.f3322.net:8001
    timeout: 10000  //超时链接
})

//3.请求拦截    登陆放token的地方
instance.interceptors.request.use(config => {
     
    config.headers['My_ToKen'] = getCookie('token')
    return config
})

//4.响应拦截   解码加密  公共逻辑判断   项目中所有的错误  都可以在这个位置进行处理
instance.interceptors.response.use(res => {
     
    console.log(res)
    //全局错误提示
    if (res.status === 200 || res.data.code == 200) {
     
        return res.data
    } else {
     
        Vue.prototype.$message({
     
            message: '网络不通',
            type: 'error'
        });
    }
})
export default instance

8、配置项目路由 router

在src目录下,新建router目录,在该目录下新建index.js 文件。路由配置如下:
在这里插入图片描述

src\router\index.js

//公共权限
const routes = [
    {
     
        path: '/',
        redirect: '/layout'
    },
    {
     
        path: '/layout',
        name: 'Layout',
        component: Layout,
        children: [
            {
     
                path: '',
                component: Home, 
                name: 'Home',
                meta: {
     
                    title: '首页',
                    icon: 'el-icon-attract'
                }
            }, {
     
                path: 'user',
                name: 'User',
                component: () => import('@/views/user/User.vue'),
                meta: {
     
                    title: '用户管理',
                    icon: 'el-icon-coordinate'
                }
            }, {
     
                path: 'msg',   // 信息管理功能
                name: 'Msg',
                component: () => import('@/views/msg/Msg.vue'),
                meta: {
     
                    title: '信息管理功能',
                    icon: 'el-icon-wallet'
                },
                children: [
                    {
     
                        path: 'mymsg',   //个人信息
                        name: 'Mymsg',
                        component: () => import('@/views/msg/Mymsg.vue'),
                        meta: {
     
                            title: '个人信息',
                            icon: 'el-icon-set-up'
                        },
                    }
                ]
            }
        ]
    },
    {
     
        path: '/login',
        name: 'Login',
        component: Login
    }
]
const router = new VueRouter({
     
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})

9、定义后端接口

在src 目录下新建mock 目录,在mock目录下,创建index.js 文件,该文件中定义所有的接口请求如下:
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第5张图片
src\mock\index.js

import Mock from 'mockjs'
import loginMock from './loginMock.js'
Mock.setup({
     
    timeout: 400 //表示 400 毫秒 后才会返回响应内容
})

//mock语法:
//Mock.mock( rurl, rtype, function( options ) )
//记录用于生成响应数据的函数。当拦截到匹配 rurl 和 rtype 的 Ajax 请求时,函数 function(options) 
//将被执行,并把执行结果作为响应数据返回。


// 定义所有接口
//1. 登陆接口
Mock.mock('/login', 'post', loginMock.login)
//2.角色获取权限列表
Mock.mock('/getPress', 'post', loginMock.getPress)

10、后端登录接口

在src目录的mock文件中,新建loginMock.js文件,定义用于生成响应数据的函数

后端根据不同的role角色,返回不同的导航菜单

  • admin—管理员–导航菜单[审批管理,请假审批,我要请假]
  • user—普通用户—导航菜单[我要请假]

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第6张图片

src\mock\loginMock.js

//Mock.mock( rurl, rtype, function( options ) )
//记录用于生成响应数据的函数。当拦截到匹配 rurl 和 rtype 的 Ajax 请求时,函数 function(options) 
//将被执行,并把执行结果作为响应数据返回。

export default {
     
    login: config => {
     
        console.log(110, config)// config 含有 url、type 和 body 三个属性,body为参数
        let {
      name, pwd } = JSON.parse(config.body) // 获取参数
        let token = ''   //token是就是用户账号和密码按规则转化而来
        let role = ''
        // 自定义如下2个账号
        if (name === 'admin' && pwd == '123456') {
       //管理员账号
            token = 'admin---token--XXXXX'
            role = '管理员'
        } else if (name === 'user' && pwd == '123456') {
      //大壮的账号   
            token = 'user---token--XXXXX'
            role = '普通用户'
        } else {
     
            return {
     
                code: 101,
                msg: '账号密码不存在',
                data: null
            }
        }

        // 如果是admin或user 账户,则返回如下
        return {
     
            code: 200,
            msg: '登陆成功',
            data: {
     
                token: token,
                role: role
            }
        }
    },
    // 后端根据不同的role角色,返回不同的导航菜单
    getPress: config => {
     
        //admin---管理员--导航菜单[审批管理,请假审批,我要请假] 
        //user---普通用户---导航菜单[我要请假]
        let {
      role } = JSON.parse(config.body) //管理员  普通用户
        if (role == '管理员') {
     
            return {
     
                code: 200,
                msg: '成功',
                data: [
                    {
     
                        path: 'shenpi', //审批管理
                        meta: {
     
                            title: '审批管理',
                            icon: 'el-icon-bangzhu'
                        },
                        name: 'Shenpi'  //componet
                    },
                    {
     
                        path: 'qingjia', //请假审批
                        meta: {
     
                            title: '请假审批',
                            icon: 'el-icon-bangzhu'
                        },
                        name: 'Qingjia'  //componet
                    }, {
     
                        path: 'woqingjia', //我要请假
                        meta: {
     
                            title: '我要请假',
                            icon: 'el-icon-bangzhu'
                        },
                        name: 'Woqingjia'  //componet
                    }
                ]
            }
        } else if (role == '普通用户') {
     
            return {
     
                code: 200,
                msg: '成功',
                data: [{
     
                    path: 'woqingjia', //我要请假
                    meta: {
     
                        title: '我要请假',
                        icon: 'el-icon-bangzhu'
                    },
                    name: 'Woqingjia'  //componet
                }
                ]
            }
        }
    }

}

11. 前端定义所有接口请求 http.js

在这里插入图片描述
src\http\http.js

// 存放所有的接口请求
import instance from "../utils/request";

// 登录接口
export function loginApi(params) {
     
    return instance({
     
        url: '/login',
        method: 'post',
        data: params   //axios是就是promise封装的ajax  工具类
    })
}

//根据角色获取权限菜单列表接口
export function getPressApi(params) {
     
    return instance({
     
        url: '/getPress',
        method: 'post',
        data: params
    })
}

2、登录页 Login.vue

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第7张图片
登陆成功,在cookie中存放token,在localstorage中存储role(管理员或者普通用户)

在src文件下的views目录中创建Login.vue 文件,代码如下:
src\views\Login.vue
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第8张图片

element表单form
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第9张图片

模仿下面这个写的
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第10张图片

src\views\Login.vue

<!-- 登录页面 -->
<template>
  <div class="container">
    <div class="form">
      <div class="title">
        <span>千锋科技后台管理</span>
      </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="pwd">
          <el-input v-model="ruleForm.pwd"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submitForm('ruleForm')"
            >提交</el-button
          >
          <el-button @click="resetForm('ruleForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
import {
      loginApi } from "@/http/http";
import {
      setCookie } from "../utils/cookie.js";
export default {
     
  data() {
     
    return {
     
      ruleForm: {
     
        // 表单数据
        name: "",
        pwd: "",
      },
      rules: {
     
        // 验证规则
        name: [{
      required: true, message: "用户名不能为空", trigger: "blur" }],
        pwd: [{
      required: true, message: "密码不能为空", trigger: "blur" }],
      },
    };
  },
  methods: {
     
    submitForm(formName) {
     
      this.$refs[formName].validate((valid) => {
     
        if (valid) {
     
          //   alert("submit!");
          //验证通过
          loginApi(this.ruleForm).then((res) => {
     
            if (res.code === 200) {
     
              //1.将token 存到cookie中
              setCookie("token", res.data.token);
              //2.将角色role保存到localStorage
              localStorage.setItem("role", res.data.role);
              //3. 跳转到首页
              this.$router.push("/");
            } else {
     
              this.$message.error("账号不存在");
            }
          });
        } else {
     
          this.$message.error("账号密码错误");
          return false;
        }
      });
    },
    resetForm(formName) {
     
      this.$refs[formName].resetFields();
    },
  },
};
</script>
<style scoped lang='less'>
/* @import url(); 引入css类 */
.container {
     
  width: 100%;
  height: 100%;
  background: url("../assets/bg9.jpg") no-repeat center;
  background-size: cover;
  .form {
     
    width: 370px;
    height: 298px;
    padding: 5px 10px;
    background-color: #fff;
    border-radius: 10px;
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    .title {
     
      width: 100%;
      line-height: 50px;
      text-align: center;
      font-size: 18px;
      font-weight: bold;
    }
    /deep/.ivu-form {
     
      width: 300px;
    }
    /deep/.ivu-btn {
     
      width: 300px;
      height: 30px;
    }
  }
}
</style>

3、使用vuex 存储路由和角色

1、在用户登录成功到跳转到首页之前,需要根据用户的角色role 请求角色菜单接口getPress,将请求返回的路由菜单添加到路由路由对象中,然后将更新后的路由数组存到vuex,在首页中从vuex 中获取路由数组,这样实现数据的全局获取和操作。可以将role 和 route数组 存到vuex全局变量中

  • 安装vuex
npm install vuex --save
  • 在src目录下新建store 目录,该目录下新建index.js 文件 代码如下:
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
     
  state: {
     
    routes: [], //打算存routes这个数组
    role: localStorage.getItem('role')//保存角色信息
  },
  getters: {
     
    getRoutes(state) {
     
      return state.routes
    }
  },
  mutations: {
     
    setRoutes(state, routes) {
     
      state.routes = routes
    },
    clearRoute(state) {
     
      state.routes = []
    },
    setRole(state, role) {
     
      state.role = role
    }
  },
  actions: {
     
    setRoleAction({
       commit }, role) {
     
      commit('setRoutes', role)
    }
  },
  modules: {
     
  }
})

4、 设置全局前置导航守卫

在router目录下的index.js 文件中,设置全局前置导航守卫,在登录成功后,页面跳转到首页前,对首页的左侧菜单栏根据角色接口返回的数据,动态修改左侧菜单栏,代码如下:
在这里插入图片描述
后端根据不同的role角色,返回不同的导航菜单

  • admin—管理员–导航菜单[审批管理,请假审批,我要请假]
  • user—普通用户—导航菜单[我要请假]
    [vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第11张图片


    [vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第12张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第13张图片
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第14张图片
至于为什么要把添加后的路由添加到vuex的store的state中,这是在router/index.js文件中生成了路由,存到store中

在下面的MyAside.vue中,需要遍历动态生成的路由,渲染页面

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第15张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第16张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第17张图片


[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第18张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第19张图片
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第20张图片

src\router\index.js


import Vue from 'vue';
import VueRouter from 'vue-router';
Vue.use(VueRouter)
import {
     
    getCookie
} from '@/utils/cookie'
import {
     
    getPressApi
} from '@/http/http'
// 导入store 
import store from '@/store'

//解决vue-router在3.0版本以上重复点菜单报错的问题
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
     
    return originalPush.call(this, location).catch(err => err)
}


//公共权限
const routes = [{
     
        path: '/',
        redirect: '/layout'
    },
    {
     
        path: '/layout',
        name: 'Layout',
        component: () => import('@/views/layout/Layout.vue'),
        children: [{
     
            path: '',
            component: () => import('@/views/home/Home.vue'),
            name: 'Home',
            meta: {
     
                title: '首页',
                icon: 'el-icon-attract'
            }
        }, {
     
            path: 'user',
            name: 'User',
            component: () => import('@/views/user/User.vue'),
            meta: {
     
                title: '用户管理',
                icon: 'el-icon-coordinate'
            }
        }, {
     
            path: 'msg', // 信息管理功能
            name: 'Msg',
            component: () => import('@/views/msg/Msg.vue'),
            meta: {
     
                title: '信息管理功能',
                icon: 'el-icon-wallet'
            },
            children: [{
     
                path: 'mymsg', //个人信息
                name: 'Mymsg',
                component: () => import('@/views/msg/Mymsg.vue'),
                meta: {
     
                    title: '个人信息',
                    icon: 'el-icon-set-up'
                },
            }]
        }]
    },
    {
     
        path: '/login',
        name: 'Login',
        component: () => import('@/views/Login.vue')
    }
]
const router = new VueRouter({
     
    mode: 'history',
    base: process.env.BASE_URL,
    routes
})





router.beforeEach((to, from, next) => {
     
    let token = getCookie('token')
    // console.log('333', token);

    // 已经登录了
    if (token) {
     
        // 登录了,访问的是登录页
        if (to.path === '/login') {
     
            // 直接跳转到首页
            next('/')
        }
        // 登录了,访问的不是登录页 动态添加路由
        else {
     
            console.log('查看', store.state.routes);  //切换用户  没有清空
            
            // 第一次,store.state.routes里没有值
            if (store.state.routes.length === 0) {
     
                 //用户不同-角色不同--权限不同(菜单)  
                //admin---管理员--导航菜单[审批管理,请假审批,我要请假] 
                //user---普通用户---导航菜单[我要请假]
                let role = localStorage.getItem('role')  //获取角色

                // 发送请求,获取不同角色,所对应的导航菜单
                getPressApi({
     role: role}).then((res) => {
     
                    if (res.code == 200) {
     
                        res.data.forEach(item=>{
     
                            console.log('添加前的routes',routes);

                            routes[1].children.push({
     
                                path: item.path,
                                name: item.name,
                                meta: {
     
                                    title: item.meta.title,
                                    icon: item.meta.icon
                                },
                                component: () => import('@/views/' + item.name)
                            })
                            
                        })
                        console.log('添加后的route',routes);

                        store.dispatch('setRoleAction', routes).then(() => {
     
                            console.log('动态生成的路由', routes);
                            //在addRoutes()之后第一次访问被添加的路由会白屏,这是因为刚刚addRoutes()就立刻访问被添加的路由,然而此时addRoutes()没有执行结束,因而找不到刚刚被添加的路由导致白屏。因此需要从新访问一次路由才行。
                            router.addRoutes(routes) //动态添加路由
                            next({
      ...to, replace: true }) //解决动态添加路由白屏问题  bug
                        })
                    }
                })
            }else{
     
                next()  //放行
                console.log('store.state.routes.',store.state.routes);
            }
        }
    }
    // 没登录,
    else {
     
        //  没登录,访问的不是登录页,直接去登录页
        if (to.path != '/login') {
     
            next('/login')
        }
        //   没登录,跳转的是登录页,直接放行
        else {
     
            next()
        }
    }
})

export default router

5、首页

1、Layout.vue 首页整体布局

在views目录下,新建layout 目录,layout目录下新建layout.vue 文件,该页面是首页整体布局。代码如下

一级路由想要显示得在APP.vue那留个坑
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第21张图片

二级路由想要显示得在一级路由那留个坑
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第22张图片
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第23张图片
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第24张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第25张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第26张图片

src\views\layout\Layout.vue

<!--首页-->
<template>
  <el-container>
    <!-- 头部组件 -->
    <el-header>
      <Header></Header>
    </el-header>
    <!-- 下方主体部分 -->
    <el-container>
      <!-- 左侧边栏 -->
      <el-aside style="width: 200px">
        <Aside></Aside>
      </el-aside>
      <!-- 右侧主体 -->
      <el-container>
        <!-- 面包屑导航 -->
        <Bread></Bread>
        <el-main>
          <!-- 二级路由坑 -->
          <router-view></router-view>
        </el-main>
        <el-footer>Footer</el-footer>
      </el-container>
    </el-container>
  </el-container>
</template>

<script>
// 引入头部
import Header from "./Header";
//引入左侧导航栏
import Aside from "./Aside.vue";
//引入面包屑导航
import Bread from "./Bread.vue";
export default {
     
  data() {
     
    return {
     };
  },
  components: {
     
    Header,
    Aside,
    Bread,
  },
};
</script>
<style scoped lang='less'>
/* @import url(); 引入css类 */
@mainColor: #eaebec; //正确的
.el-container {
     
  width: 100%;
  height: 100%;
}
.el-main {
     
  background: @mainColor;
}
.el-footer {
     
  background: lightblue;
}
</style>

2、header.vue头部组件

在layout目录下,同时再新建header.vue头部组件,代码如下:
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第27张图片

<template>
    <div class="head-box">
        <div class="logo">
            <img src="../../assets/logo.png" alt="" />
            <h3>千锋后台管理</h3>
        </div>
        <div class="right">
            <el-dropdown @command="handleCommand">
                <span class="el-dropdown-link">
                    你好,{
     {
      role }}
                    <img :src="avatar2" alt="" />
                    <i class="el-icon-arrow-down el-icon--right"></i>
                </span>
                <el-dropdown-menu slot="dropdown">
                    <el-dropdown-item command="info">个人信息</el-dropdown-item>
                    <el-dropdown-item command="change">修改</el-dropdown-item>
                    <el-dropdown-item command="logout">退出</el-dropdown-item>
                </el-dropdown-menu>
            </el-dropdown>
        </div>
    </div>
</template>

<script>
import {
      removeCookie } from '@/utils/cookie'
import avatar2 from "@/assets/avatar-2.jpg"; //推荐使用

export default {
     
    name: 'myheader',
    data() {
     
        return {
     
            role: '',
            avatar2:avatar2
        }
    },
    created() {
     
        console.log('8888',);
        this.role = localStorage.getItem('role')

    },
    methods: {
     
        handleCommand(command) {
     
            if (command === 'logout') {
     
                // 删除cookie
                removeCookie('token')
                // 刷新页面
                this.$router.go(0)
            }

        }
    }
}
</script>

<style lang="less" scoped>
.head-box {
     
    height: 60px;
    .logo {
     
        float: left;
        width: 180px;
        height: 100%;;
        display: flex;
        align-items: center;
        img {
     
            width: 36px;
            height: 36px;
        }
        h3 {
     
        }
    }
    .right {
     
        float: right;
        line-height: 60px;
        img{
     
            width: 24px;
            height: 24px;
            vertical-align: middle;
        }
    }
}
</style>

3、Aside.vue侧边栏

在layout目录下,新建Aside.vue侧边栏组件,由于显示首页左侧菜单导航,代码如下:

src\views\layout\MyAside.vue
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第28张图片

<!-- 侧边栏导航 -->
<template>
  <div>
    <el-menu
      default-active="2"
      class="el-menu-vertical-demo"
      @open="handleOpen"
      @close="handleClose"
    >
      <template v-for="(item, index) in menu">
        <!-- 一级导航 -->
        <router-link :to="'/layout/' + item.path" :key="item.path">
          <el-menu-item
            :index="item.path + index"
            :key="item.path"
            v-if="!item.children"
          >
            <i :class="item.meta.icon"></i>
            <span slot="title">{
     {
      item.meta.title }}</span>
          </el-menu-item>
        </router-link>

        <!-- 二级导航 -->
        <el-submenu
          :index="item.path + index"
          :key="item.path + index"
          v-if="item.children"
        >
          <template slot="title">
            <i :class="item.meta.icon"></i>
            <span slot="title">{
     {
      item.meta.title }}</span>
          </template>
          <template v-for="(child, cindex) in item.children">
            <router-link
              :to="'/layout/' + item.path + '/' + child.path"
              :key="child.path + cindex"
            >
              <el-menu-item :index="child.path + cindex">
                <i :class="child.meta.icon"></i>
                <span>{
     {
      child.meta.title }}</span>
              </el-menu-item>
            </router-link>
          </template>
        </el-submenu>
      </template>
    </el-menu>
  </div>
</template>

<script>
export default {
     
  data() {
     
    return {
     };
  },
  computed: {
     
    menu() {
     
      console.log("所有菜单", this.$store.getters.getRoutes);
      return this.$store.getters.getRoutes[1].children;
    },
  },
  methods: {
     
    handleOpen() {
     },
    handleClose() {
     },
  },
};
</script>
<style scoped>
/* @import url(); 引入css类 */
</style>

4、Bread.vue面包屑导航

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第29张图片

在layout目录下,新建Bread.vue面包屑导航组件,引入到layout文件中

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第30张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第31张图片
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第32张图片
[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第33张图片

matched 顾名思义 就是 匹配,假如我们目前的路由是/a/aa-01,那么此时 this.$route.matched匹配到的会是一个数组,包含'/','/a','/a/aa-01',这三个path的路由信息。然后我们可以直接利用路由信息渲染我们的面包屑导航。

src\views\layout\Bread.vue

<!-- 面包屑导航 -->
<template>
  <div class="container">
    <i class="el-icon-s-fold"></i>
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item v-for="(item, index) in breadArr" :key="index">
        {
     {
      item.name }}
      </el-breadcrumb-item>
    </el-breadcrumb>
  </div>
</template>

<script>
export default {
     
  data() {
     
    return {
     
      breadArr: [], // 面包屑数组
    };
  },
  watch: {
     
    // $route(to, from) {
     
    //   // console.log(to)
    //   // 当前路由赋值
    //   this.currentPath = to.path;
    //   console.log(1, this.$route);
    //   this.breadcrumbArr = this.$route.matched; // 获取当前的路由记录
    // },
    $route: {
     
      handler(val) {
     
        // console.log(11, val); // val 即为监听的$route对象
        // 先清空 breadArr,要不然越push 越多
        this.breadArr = [];
        val.matched.forEach((item, index) => {
     
          if (index > 0) {
     
            this.breadArr.push({
     
              path: item.path,
              name: item.meta.title,
            });
          }
        });
        //console.log(22, this.breadArr);
      },
      immediate: true, // 第一次页面加载就监听 而不是该对象发生变化才去监听
      deep: true,
    },
  },
};
</script>
<style scoped lang='less'>
/* @import url(); 引入css类 */
@mainColor: #eaebec; //正确的
.container {
     
  height: 30px;
  width: 100%;
  display: flex;
  align-items: center;
  background: @mainColor; // @mainColor;
  i {
     
    line-height: 30px;
    font-size: 20px;
    cursor: pointer;
    padding-right: 20px;
  }
}
</style>

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第34张图片

5、首页右侧主体

1、home页

效果展示

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第35张图片

1、定义首页数据接口(后端),mock/index.js

在mock文件夹下的index.js文件中,定义接口如下:

//6.柱形图接口
Mock.mock('/getBarData', 'get', home.barData)
//7.饼形图接口
Mock.mock('/getPieData', 'get', home.pieData)
2、mock/homeMock.js

在mock文件夹下,创建homeMock.js文件,用来定义接口的数据返回:代码如下:

export default {
     
    barData: () => {
     
        // 返回柱形图数据
        return {
     
            code: 200,
            msg: "柱形图数据",
            data: {
     
                name: "出勤率",
                xAxisData: ["Mon", "Tue", "wed", "Thu", "Fri", "Sat"],
                seriesData: [90, 85, 50, 100, 95, 92]
            }
        }
    },
    pieData: () => {
     
        // 返回饼形图数据
        return {
     
            code: 200,
            msg: "饼形图数据",
            data: {
     
                name: "",
                seriesData: [{
     
                    // 数据项的名称
                    name: "HTML5",
                    // 数据项值8
                    value: 500,
                },
                {
     
                    // 数据项的名称
                    name: "JAVA",
                    // 数据项值8
                    value: 200,
                },
                {
     
                    // 数据项的名称
                    name: "大数据",
                    // 数据项值8
                    value: 100,
                },
                {
     
                    // 数据项的名称
                    name: "unity",
                    // 数据项值8
                    value: 50,
                },
                {
     
                    // 数据项的名称
                    name: "UI",
                    // 数据项值8
                    value: 50,
                }]
            }
        }
    }
}
3、http/http.js 定义首页的数据请求

在http目录下的http.js文件中,定义首页的数据请求,代码如下:

// 获取首页柱形图接口数据
export function getBarData(params) {
     
    return instance({
     
        url: '/getBarData',
        method: 'get',
        params: params
    })
}
// 获取首页饼形图接口数据
export function getPieData(params) {
     
    return instance({
     
        url: '/getPieData',
        method: 'get',
        params: params
    })
}
4、home/home.vue

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第36张图片

在home目录下的home.vue中,引入接口请求,然后渲染页面,代码如下:

<!-- 首页 -->
<template>
  <div class="home">
    <el-row>
      <el-col :span="12">
        <BarEchart></BarEchart>
      </el-col>
      <el-col :span="12">
        <PieEchart></PieEchart>
      </el-col>
    </el-row>
  </div>
</template>
<script>
// 引入柱形图组件
import BarEchart from "@/components/BarEchart";
// 引入饼形图
import PieEchart from "@/components/PieEchart";
export default {
     
  data() {
     
    return {
     };
  },
  mounted() {
     },
  components: {
     
    BarEchart,
    PieEchart,
  },
};
</script>
<style scoped lang='less'>
/* @import url(); 引入css类 */
.home {
     
  width: 100%;
  height: 500px;
}
</style>
5、components/BarEchart.vue 柱形图组件

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第37张图片

在components目录下,将饼形图和柱状图分别定义成单独的组件。BarEchart.vue和PieEchart.vue如下:

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第38张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第39张图片

BarEchart.vue 代码如下:

<!-- BarEchart.vue 柱形图组件  -->
<template>
  <div id="Barbox">
    <div id="barwrap"></div>
  </div>
</template>

<script>
// 引入echarts
import * as echarts from "echarts";
// 引入请求接口
import {
      getBarData } from "@/http/http";
export default {
     
  data() {
     
    return {
     
      myChart: "",
    };
  },
  mounted() {
     
    // 基于准备好的dom,初始化echarts实例
    this.myChart = echarts.init(document.getElementById("barwrap"));
    // 绘制图表
    getBarData().then((res) => {
     
      if (res.code == 200) {
     
        this.myChart.setOption(this.options(res.data));
      }
    });
  },
  methods: {
     
    options(val) {
     
      let option = {
     
        title: {
     
          text: "2115班每天出勤统计",
        },
        tooltip: {
     
          formatter: "{b0}: {c0}%",
        },
        xAxis: {
     
          data: val.xAxisData,
        },
        grid: {
     },
        yAxis: {
     
          name: "出勤率",
          axisLine: {
     
            show: true, // 显示y轴轴线
            lineStyle: {
     
              type: "solid",
            },
          },
        },
        series: [
          {
     
            name: "出勤率",
            type: "bar",
            data: val.seriesData,
          },
        ],
      };

      return option;
    },
  },
};
</script>
<style scoped lang='less'>
/* @import url(); 引入css类 */

#barwrap {
     
  width: 100%;
  height: 500px;
}
</style>
6、components/PieEchart.vue 饼形图组件

echart饼图示例: https://echarts.apache.org/examples/zh/editor.html?c=pie-simple

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第40张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第41张图片

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第42张图片

<!-- 饼形图组件 -->
<template>
  <div class="pie_box">
    <div id="pie_wrap"></div>
  </div>
</template>

<script>
// 引入 echarts
import * as echarts from "echarts";
// 引入 接口请求
import {
      getPieData } from "@/http/http";
export default {
     
  data() {
     
    return {
     
      myechart: "",
    };
  },
  mounted() {
     
    this.myechart = echarts.init(document.getElementById("pie_wrap"));
    getPieData().then((res) => {
     
      if (res.code == 200) {
     
        //给图表传参
        this.myechart.setOption(this.options(res.data.seriesData));
      }
    });
  },
  methods: {
     
    options(val) {
     
      let option = {
     
        title: {
     
          text: "千锋各学科人数占比",
        },
        legend: {
     
          right: 0,
          top: "30px",
          data: val.map((item) => {
     
            return item.name;
          }),
        },
        tooltip: {
     },
        series: [
          {
     
            type: "pie",
            radius: [0, "50%"],
            data: val,
          },
        ],
      };
      return option;
    },
  },
};
</script>
<style scoped>
/* @import url(); 引入css类 */
#pie_wrap {
     
  width: 100%;
  height: 500px;
}
</style>

2、user页

效果展示

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第43张图片

1、定义首页数据接口 mock/index.js

在mock下的index.js 文件中,定义首页后台数据接口

// 3.定义首页学生数据列表接口
// RegExp('/userList.*')
// 发现 Mockjs 本身对 GET 请求的支持并不是很友好。举个例子,使用 Mock.mock("/user/getUserInfo", "get", mockData) 的时候,它只会拦截url等于 /user/getUserInfo 的请求,而对于带参数的请求,如/user/getUserInfo?id=12,因为不等于 /user/getUserInfo 就拦截不到,报404错误。
// 使用正则进行匹配,Mock.mock(new RegExp(url + ".*"), "get", mockData) 
// 其中表达式正则 .* 表示任意长度的任意字符; 

Mock.mock(new RegExp('/getStudentList.*'), 'get', user.getTable)
2、mock/userMock.js

在mock 目录下,新建userMock.js文件,定义该接口数据返回。

import Mock from 'mockjs'
let List = []  //全局list 保存所有的数据
let id = 1;
for (var i = 0; i < 100; i++) {
     
    List.push(Mock.mock({
     
        id: id++,
        name: Mock.Random.cname(),
        age: Mock.Random.integer(18, 30),
        major: 'html5',
        address: Mock.Random.county(true),
        pay: Mock.Random.integer(0, 1),
        graduateTime: Mock.Random.date('yyyy-MM-dd')

    }))
}

// console.log(44, List)
export default {
     
    getTable: (config) => {
     
        // console.log(JSON.parse(config.body))
        //搜索逻辑
        const {
      searchVal, page, pageSize } = JSON.parse(config.body)
        //分页逻辑 mock    56
        // page=1 pageSize=10
        // page=2  pageSiz=10
        // page=3  pageSiz=10
        //公式:     (page-1)*pageSize  <= index< page* pageSize   0----9
        let newList1 = List.filter(item => {
     
            return item.name.indexOf(searchVal) != -1
        })
        let newList2 = newList1.filter((item, index) => {
     
            return (page - 1) * pageSize <= index && index < page * pageSize
        })                                       //10 ----- 19
        // 20 ---- 29
        return {
     
            code: 200,
            msg: '',
            data: newList2,  //10条数
            total: List.length
        }
    },
    editData: (config) => {
     
        console.log(config)
        let {
      id, name, age, pay, major, address, graduateTime } = JSON.parse(config.body)
        List.forEach(item => {
     
            if (item.id == id) {
     
                item.name = name;
                item.age = age;
                item.pay = pay;
                item.major = major;
                item.address = address;
                item.graduateTime = graduateTime
            }
        })
        return {
     
            code: 200,
            msg: '修改成功',
            data: null
        }
    },
    deleteData: (config) => {
     
        //console.log(config);
        let id = config.url.split('?')[1].split('=')[1]
        let newList = List.filter((item) => {
     
            return item.id != id
        })
        List = newList
        return {
     
            code: 200,
            msg: "删除成功",
            data: null
        }
    }
}
3、http/http.js 定义user 页的数据请求
//获取用户管理页列表数据
export function getStudentList(params) {
     
    return instance({
     
        url: '/getStudentList',
        method: 'get',
        data: params
    })
}
// 编辑用户接口
export function editUser(params) {
     
    return instance({
     
        url: '/editUser',
        method: 'post',
        data: params
    })
}
// 删除用户接口
export function deleteUser(params) {
     
    return instance({
     
        url: '/deleteUser',
        method: 'get',
        params: params
    })
}

4、views /user.vue 首页右侧主体部分对应的首页页面。

在views 目录下,新建user.vue组件,用于展示首页右侧主体部分对应的首页页面。

[vue项目] pc后台管理系统 (vue-cli +element-ui+axios+less) --- element-ui axios请求 权限管理面包屑导航_第44张图片







你可能感兴趣的:(#,前端小项目,#,vue,vue.js)