• 【前端】Vue+Element UI案例:通用后台管理系统-代码总结



    参考视频: VUE项目,VUE项目实战,vue后台管理系统,前端面试,前端面试项目

    案例链接
    【前端】Vue+Element UI案例:通用后台管理系统-导航栏(视频p1-16)https://blog.csdn.net/karshey/article/details/127640658
    【前端】Vue+Element UI案例:通用后台管理系统-Header+导航栏折叠(p17-19)https://blog.csdn.net/karshey/article/details/127652862
    【前端】Vue+Element UI案例:通用后台管理系统-Home组件:卡片、表格(p20-22)https://blog.csdn.net/karshey/article/details/127674643
    【前端】Vue+Element UI案例:通用后台管理系统-Echarts图表准备:axios封装、mock数据模拟实战(p23-25)https://blog.csdn.net/karshey/article/details/127735159
    【前端】Vue+Element UI案例:通用后台管理系统-Echarts图表:折线图、柱状图、饼状图(p27-30)https://blog.csdn.net/karshey/article/details/127737979
    【前端】Vue+Element UI案例:通用后台管理系统-面包屑、tag栏(p31-35)https://blog.csdn.net/karshey/article/details/127756733
    【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Form表单填写、Dialog对话框弹出(p36-38)https://blog.csdn.net/karshey/article/details/127787418
    【前端】Vue+Element UI案例:通用后台管理系统-用户管理:Table表格增删查改、Pagination分页、搜索框(p39-42)https://blog.csdn.net/karshey/article/details/127777962
    【前端】Vue+Element UI案例:通用后台管理系统-登陆页面Login(p44)https://blog.csdn.net/karshey/article/details/127795302
    【前端】Vue+Element UI案例:通用后台管理系统-登陆页面功能:登录权限跳转、路由守卫、退出(p45-46)https://blog.csdn.net/karshey/article/details/127849502
    【前端】Vue+Element UI案例:通用后台管理系统-登陆不同用户显示不同菜单、动态添加路由(p47-48)https://blog.csdn.net/karshey/article/details/127865621

    前言

    本来不打算用博客的方式记录代码的,想用git把它上传到代码仓库。但是由于对git的使用不太熟悉,把写得完善的项目代码初始化掉了!!非常崩溃…后来废了很大力气才把代码找回来。

    为了以后把代码搞丢后还能找回来,还是要写个博客来记录一下代码。

    项目链接:https://pan.baidu.com/s/1fTh4m_OkqV2PIuWdCgE-QQ
    提取码:35sv

    项目文件目录

    在这里插入图片描述

    api

    在这里插入图片描述

    mockServe

    home.js
    // mock数据模拟
    import Mock from 'mockjs'
    // 导入数据
    import videoData from '../../data/mockData/videoData'
    import userData from '../../data/mockData/userData'
    import tableData from '../../data/mockData/tableData'
    
    // 图表数据
    let List =[]
    // 直接导出
    export default {
        getStatisticalData: () => {
            //Mock.Random.float 产生随机数100到8000之间 保留小数 最小0位 最大0位
            for (let i = 0; i < 7; i++) {
                List.push(
                    Mock.mock({
                        苹果: Mock.Random.float(100, 8000, 0, 0),
                        vivo: Mock.Random.float(100, 8000, 0, 0),
                        oppo: Mock.Random.float(100, 8000, 0, 0),
                        魅族: Mock.Random.float(100, 8000, 0, 0),
                        三星: Mock.Random.float(100, 8000, 0, 0),
                        小米: Mock.Random.float(100, 8000, 0, 0)
                    })
                )
            }
            // 返回给浏览器的数据
            return {
                code: 20000,
                data: {
                    // 饼图
                    videoData,
                    // 柱状图
                    userData,
                    // 折线图
                    orderData: {
                        date: ['20191001', '20191002', '20191003', '20191004', '20191005', '20191006', '20191007'],
                        data: List
                    },
                    tableData
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    permission.js
    import Mock from 'mockjs'
    export default {
        getMenu: config => {
            const { username, password } = JSON.parse(config.body)
            // 先判断用户是否存在
            // 判断账号和密码是否对应
            if (username === 'admin' && password === 'admin') {
                return {
                    code: 20000,
                    data: {
                        menu: [
                            {
                                path: '/home',
                                name: 'home',
                                label: '首页',
                                icon: 's-home',
                                url: 'Home.vue'
                            },
                            {
                                path: '/mall',
                                name: 'mall',
                                label: '商品管理',
                                icon: 'video-play',
                                url: 'Mall.vue'
                            },
                            {
                                path: '/user',
                                name: 'user',
                                label: '用户管理',
                                icon: 'user',
                                url: 'User.vue'
                            },
                            {
                                label: '其他',
                                icon: 'location',
                                children: [
                                    {
                                        path: '/page1',
                                        name: 'page1',
                                        label: '页面1',
                                        icon: 'setting',
                                        url: 'PageOne.vue'
                                    },
                                    {
                                        path: '/page2',
                                        name: 'page2',
                                        label: '页面2',
                                        icon: 'setting',
                                        url: 'PageTwo.vue'
                                    }
                                ]
                            }
                        ],
                        token: Mock.Random.guid(),
                        message: '获取成功'
                    }
                }
            } else if (username === 'xiaoxiao' && password === 'xiaoxiao') {
                return {
                    code: 20000,
                    data: {
                        menu: [
                            {
                                path: '/home',
                                name: 'home',
                                label: '首页',
                                icon: 's-home',
                                url: 'Home.vue'
                            },
                            {
                                path: '/video',
                                name: 'video',
                                label: '商品管理',
                                icon: 'video-play',
                                url: 'Mall.vue'
                            }
                        ],
                        token: Mock.Random.guid(),
                        message: '获取成功'
                    }
                }
            } else {
                return {
                    code: -999,
                    data: {
                        message: '密码错误'
                    }
                }
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    index.js

    import http from '../utils/request'
    
    // 请求首页数据,直接把这个对象导出
    export const getData = () => {
        // 返回一个promise
        return http.get('/home/getData')
    }
    
    // 下面四个:用户管理-后端-网络请求接口
    export const getUser = (params) => {
        return http.get('/user/get/', params)
    }
    
    export const createUser = (data) => {
        return http.post('/user/create', data)
    }
    
    export const deleteUser = (data) => {
        return http.post('/user/del', data)
    }
    
    export const updateUser = (data) => {
        return http.post('/user/update', data)
    }
    
    // 登录权限
    export const getMenu = (data) => {
        return http.post('/permission/getMenu',data)
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    mock.js

    import Mock from 'mockjs'
    import homeMock from '../api/mockServe/home'
    import user from './user'
    import permission from './mockServe/permission'
    
    // 定义mock拦截
    Mock.mock('/api/home/getData',homeMock)
    
    // 用户管理:增删查改
    Mock.mock(/\/api\/user\/get/,user.getUserList)
    Mock.mock('/api/user/create','post',user.createUser)
    Mock.mock('/api/user/update','post',user.updateUser)
    Mock.mock('/api/user/del','post',user.deleteUser)
    
    // 登录权限
    Mock.mock(/api\/permission\/getMenu/,'post',permission.getMenu)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    user.js

    import Mock from 'mockjs'
    
    // get请求从config.url获取参数,post从config.body中获取参数
    function param2Obj (url) {
      const search = url.split('?')[1]
      if (!search) {
        return {}
      }
      return JSON.parse(
        '{"' +
        decodeURIComponent(search)
          .replace(/"/g, '\\"')
          .replace(/&/g, '","')
          .replace(/=/g, '":"') +
        '"}'
      )
    }
    
    let List = []
    const count = 200
    
    for (let i = 0; i < count; i++) {
      List.push(
        Mock.mock({
          id: Mock.Random.guid(),
          name: Mock.Random.cname(),
          addr: Mock.mock('@county(true)'),
          'age|18-60': 1,
          birth: Mock.Random.date(),
          sex: Mock.Random.integer(0, 1)
        })
      )
    }
    
    export default {
      /**
       * 获取列表
       * 要带参数 name, page, limt; name可以不填, page,limit有默认值。
       * @param name, page, limit
       * @return {{code: number, count: number, data: *[]}}
       */
      getUserList: config => {
        const { name, page = 1, limit = 20 } = param2Obj(config.url)
        // console.log('name:' + name, 'page:' + page, '分页大小limit:' + limit)
        const mockList = List.filter(user => {
          if (name && user.name.indexOf(name) === -1 && user.addr.indexOf(name) === -1) return false
          return true
        })
        const pageList = mockList.filter((item, index) => index < limit * page && index >= limit * (page - 1))
        return {
          code: 20000,
          count: mockList.length,
          list: pageList
        }
      },
      /**
       * 增加用户
       * @param name, addr, age, birth, sex
       * @return {{code: number, data: {message: string}}}
       */
      createUser: config => {
        const { name, addr, age, birth, sex } = JSON.parse(config.body)
        console.log(JSON.parse(config.body))
        List.unshift({
          id: Mock.Random.guid(),
          name: name,
          addr: addr,
          age: age,
          birth: birth,
          sex: sex
        })
        return {
          code: 20000,
          data: {
            message: '添加成功'
          }
        }
      },
      /**
       * 删除用户
       * @param id
       * @return {*}
       */
      deleteUser: config => {
        const { id } = JSON.parse(config.body)
        if (!id) {
          return {
            code: -999,
            message: '参数不正确'
          }
        } else {
          List = List.filter(u => u.id !== id)
          return {
            code: 20000,
            message: '删除成功'
          }
        }
      },
      /**
       * 批量删除
       * @param config
       * @return {{code: number, data: {message: string}}}
       */
      batchremove: config => {
        let { ids } = param2Obj(config.url)
        ids = ids.split(',')
        List = List.filter(u => !ids.includes(u.id))
        return {
          code: 20000,
          data: {
            message: '批量删除成功'
          }
        }
      },
      /**
       * 修改用户
       * @param id, name, addr, age, birth, sex
       * @return {{code: number, data: {message: string}}}
       */
      updateUser: config => {
        const { id, name, addr, age, birth, sex } = JSON.parse(config.body)
        const sex_num = parseInt(sex)
        List.some(u => {
          if (u.id === id) {
            u.name = name
            u.addr = addr
            u.age = age
            u.birth = birth
            u.sex = sex_num
            return true
          }
        })
        return {
          code: 20000,
          data: {
            message: '编辑成功'
          }
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140

    assert

    这些图片在链接里:

    在这里插入图片描述

    components

    在这里插入图片描述

    CommonAside.vue

    <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="clickItem(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 v-for="item in hasChildren" :key="item.label" :index="item.label">
                <template slot="title">
                    <i :class="`el-icon-${item.icon}`">i>
                    <span slot="title">{{ item.label }}span>
                template>
                <el-menu-item-group v-for="subItem in item.children" :key="subItem.name">
                    <el-menu-item @click="clickItem(subItem)" :index="subItem.name">{{ 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;
        // Aside和Header之间没有边框缝隙
        border-right: none;
    
        h3 {
            text-align: center;
            line-height: 48px;
            color: #fff;
            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);
            },
            clickItem(item) {
                // 防止自己跳自己的报错
                if (this.$route.path !== item.path && !(this.$route.path === '/home' && (item.path === '/'))) {
                    this.$router.push(item.path)
                }
                // 面包屑
                this.$store.commit('SelectMenu', item)
            }
        },
        computed: {
            noChildren() {
                // 如果没有children则返回true,会被过滤器留下
                return this.MenuData.filter(item => !item.children)
            },
            hasChildren() {
                return this.MenuData.filter(item => item.children)
            },
            // 要放到计算属性,自动计算
            isCollapse() {
                return this.$store.state.tab.isCollapse
            },
            // 获取菜单
            MenuData() {
                return JSON.parse(cookie.get('menu')) || this.$store.state.tab.menu
            }
        }
    }
    script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88

    CommonHeader.vue

    <template>
        <div class="header-container">
            <div class="l-content">
                <el-button @click="handleMenu" icon="el-icon-menu" size="mini">el-button>
                
                <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 class="user" src="../assets/images/user.png" alt="">
                    span>
                    <el-dropdown-menu slot="dropdown">
                        <el-dropdown-item>个人信息el-dropdown-item>
                        <el-dropdown-item command="logout">退出el-dropdown-item>
                    el-dropdown-menu>
                el-dropdown>
            div>
        div>
    template>
    
    <script>
    import { mapState } from 'vuex'
    import Cookie from 'js-cookie'
    export default {
        methods: {
            handleMenu() {
                // 相当于调用这个方法
                this.$store.commit('CollapseMenu')
            },
            handleClick(command) {
                if (command === 'logout') {
                    Cookie.remove('token')
                    this.$router.push('/login')
                }
            }
        },
        computed: {
            ...mapState({
                tags: state => state.tab.tabList
            })
        }
    }
    script>
    
    <style lang="less" scoped>
    .header-container {
        background-color: #333;
        height: 60px;
    
        // 让按钮和头像居中
        display: flex;
        justify-content: space-between;
        align-items: center;
        // 不要紧贴边框
        padding: 0 20px;
    
        .el-dropdown-link {
            cursor: pointer;
            color: #409EFF;
    
            .user {
                width: 40px;
                height: 40px;
                // 50%变圆形
                border-radius: 50%;
            }
        }
    }
    
    .l-content {
        display: flex;
        // 上下居中
        align-items: center;
    
        .el-breadcrumb {
            margin-left: 15px;
    
            // deep 强制生效
            /deep/.el-breadcrumb__item {
                .el-breadcrumb__inner {
                    &.is-link {
                        color: #666;
                    }
                }
    
                &:last-child {
                    .el-breadcrumb__inner {
                        color: #fff;
                    }
                }
            }
        }
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    CommonTags.vue

    <template>
        <div class="tabs">
            
            
            <el-tag v-for="(item, index) in tags" :key="item.path" :closable="item.name !== 'home'"
                :effect="item.name === $route.name ? 'dark' : 'plain'" @click="changeMenu(item)"
                @close="handleClose(item, index)">
                {{ item.label }}
            el-tag>
        div>
    template>
    
    <script>
    import { mapState } from 'vuex'
    
    export default {
        methods: {
            changeMenu(item) {
                this.$router.push({ name: item.name })
            },
            handleClose(item, index) {
                // 删除面包屑数据
                this.$store.commit('closeTag', item)
                // 如果删除的刚好是自己
                if (item.name === this.$route.name) {
                    const length = this.tags.length
                    // 如果删除的是最后一个:跳到前一个
                    if (length === index) {
                        this.$router.push({ name: this.tags[index - 1].name })
                    }
                    // 不是最后一个:往后一个
                    else {
                        this.$router.push({ name: this.tags[index].name })
                    }
                }
            }
        },
        computed: {
            ...mapState({
                tags: state => state.tab.tabList
            })
        }
    }
    script>
    
    <style lang="less" scoped>
    .tabs{
        padding: 20px 20px 0 20px;
    
        .el-tag{
            margin-right: 15px;
            // 鼠标悬停:小手
            cursor: pointer;
        }
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    data

    在这里插入图片描述

    echartsData

    order.js
    const order = {
        legend: {
            // 图例文字颜色
            textStyle: {
                color: "#333",
            },
        },
        grid: {
            left: "20%",
        },
        // 提示框
        tooltip: {
            trigger: "axis",
        },
        xAxis: {
            type: "category", // 类目轴
            data: [],
            axisLine: {
                lineStyle: {
                    color: "#17b3a3",
                },
            },
            axisLabel: {
                interval: 0,
                color: "#333",
            },
        },
        yAxis: [
            {
                type: "value",
                axisLine: {
                    lineStyle: {
                        color: "#17b3a3",
                    },
                },
            },
        ],
        color: ["#2ec7c9", "#b6a2de", "#5ab1ef", "#ffb980", "#d87a80", "#8d98b3"],
        series: [],
    }
    
    export default order
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    user.js
    const user = {
        legend: {
            // 图例文字颜色
            textStyle: {
                color: "#333",
            },
        },
        grid: {
            left: "20%",
        },
        // 提示框
        tooltip: {
            trigger: "axis",
        },
        xAxis: {
            type: "category", // 类目轴
            data: [],
            axisLine: {
                lineStyle: {
                    color: "#17b3a3",
                },
            },
            axisLabel: {
                interval: 0,
                color: "#333",
            },
        },
        yAxis: [
            {
                type: "value",
                axisLine: {
                    lineStyle: {
                        color: "#17b3a3",
                    },
                },
            },
        ],
        color: ["#2ec7c9", "#b6a2de"],
        series: [],
    }
    
    export default user
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    video.js
    const video = {
        tooltip: {
            trigger: "item",
        },
        color: [
            "#0f78f4",
            "#dd536b",
            "#9462e5",
            "#a6a6a6",
            "#e1bb22",
            "#39c362",
            "#3ed1cf",
        ],
        series: [],
    }
    
    export default video
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    mockData

    tableData.js
    const tableData = [
        {
            name: 'oppo',
            todayBuy: 500,
            monthBuy: 3500,
            totalBuy: 22000
        },
        {
            name: 'vivo',
            todayBuy: 300,
            monthBuy: 2200,
            totalBuy: 24000
        },
        {
            name: '苹果',
            todayBuy: 800,
            monthBuy: 4500,
            totalBuy: 65000
        },
        {
            name: '小米',
            todayBuy: 1200,
            monthBuy: 6500,
            totalBuy: 45000
        },
        {
            name: '三星',
            todayBuy: 300,
            monthBuy: 2000,
            totalBuy: 34000
        },
        {
            name: '魅族',
            todayBuy: 350,
            monthBuy: 3000,
            totalBuy: 22000
        }
    ]
    
    export default tableData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    userData.js
    // 柱状图
    const userData = [
        {
            date: '周一',
            new: 5,
            active: 200
        },
        {
            date: '周二',
            new: 10,
            active: 500
        },
        {
            date: '周三',
            new: 12,
            active: 550
        },
        {
            date: '周四',
            new: 60,
            active: 800
        },
        {
            date: '周五',
            new: 65,
            active: 550
        },
        {
            date: '周六',
            new: 53,
            active: 770
        },
        {
            date: '周日',
            new: 33,
            active: 170
        }
    ]
    
    export default userData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    videoData.js
    // 饼图
    const videoData = [
        {
            name: '小米',
            value: 2999
        },
        {
            name: '苹果',
            value: 5999
        },
        {
            name: 'vivo',
            value: 1500
        },
        {
            name: 'oppo',
            value: 1999
        },
        {
            name: '魅族',
            value: 2200
        },
        {
            name: '三星',
            value: 4500
        }
    ]
    
    export default videoData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    CountData.js

    const CountData = [
        {
            name: "今日支付订单",
            value: 1234,
            icon: "success",
            color: "#2ec7c9",
        },
        {
            name: "今日收藏订单",
            value: 210,
            icon: "star-on",
            color: "#ffb980",
        },
        {
            name: "今日未支付订单",
            value: 1234,
            icon: "s-goods",
            color: "#5ab1ef",
        },
        {
            name: "本月支付订单",
            value: 1234,
            icon: "success",
            color: "#2ec7c9",
        },
        {
            name: "本月收藏订单",
            value: 210,
            icon: "star-on",
            color: "#ffb980",
        },
        {
            name: "本月未支付订单",
            value: 1234,
            icon: "s-goods",
            color: "#5ab1ef",
        },
    ]
    export default CountData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    MenuData.js

    const MenuData= [
        {
          path: '/',
          name: 'home',
          label: '首页',
          icon: 's-home',
          url: 'Home/Home'
        },
        {
          path: '/mall',
          name: 'mall',
          label: '商品管理',
          icon: 'video-play',
          url: 'MallManage/MallManage'
        },
        {
          path: '/user',
          name: 'user',
          label: '用户管理',
          icon: 'user',
          url: 'UserManage/UserManage'
        },
        {
          label: '其他',
          icon: 'location',
          children: [
            {
              path: '/page1',
              name: 'page1',
              label: '页面1',
              icon: 'setting',
              url: 'Other/PageOne'
            },
            {
              path: '/page2',
              name: 'page2',
              label: '页面2',
              icon: 'setting',
              url: 'Other/PageTwo'
            }
          ]
        }
    ]
    
    export default MenuData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    TableData.js

    const TableData = [
        {
            name: 'oppo',
            todayBuy: 100,
            monthBuy: 300,
            totalBuy: 800
        },
        {
            name: 'vivo',
            todayBuy: 100,
            monthBuy: 300,
            totalBuy: 800
        },
        {
            name: '苹果',
            todayBuy: 100,
            monthBuy: 300,
            totalBuy: 800
        },
        {
            name: '小米',
            todayBuy: 100,
            monthBuy: 300,
            totalBuy: 800
        },
        {
            name: '三星',
            todayBuy: 100,
            monthBuy: 300,
            totalBuy: 800
        },
        {
            name: '魅族',
            todayBuy: 100,
            monthBuy: 300,
            totalBuy: 800
        }
    ]
    
    export default TableData
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    TableLabel.js

    const TableLabel={
        name:'课程',
        todayBuy:'今日购买',
        monthBuy:'本月购买',
        totalBuy:'总购买'
    }
    
    export default TableLabel
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    router

    在这里插入图片描述

    index.js

    import Vue from "vue";
    import VueRouter from "vue-router";
    import Main from '../Views/Main'
    // import Home from '../Views/Home.vue'
    // import Mall from '../Views/Mall.vue'
    // import User from '../Views/User.vue'
    // import PageOne from '../Views/PageOne.vue'
    // import PageTwo from '../Views/PageTwo.vue'
    import Login from '../Views/Login.vue'
    import Cookie from 'js-cookie'
    
    Vue.use(VueRouter)
    
    const routes = [
        // 主路由
        {
            path: '/',
            name:'Main',
            component: Main,
            redirect: '/home', // 重定向
            children: [
                // 子路由
                // { path: '/home', name: 'home', component: Home }, // 首页
                // { path: '/user', name: 'user', component: User }, // 用户管理
                // { path: '/mall', name: 'mall', component: Mall }, // 商品管理
                // { path: '/page1', name: 'page1', component: PageOne }, // 页面1
                // { path: '/page2', name: 'page2', component: PageTwo }, // 页面2
            ]
        },
        {
            path: '/login',
            name: 'login',
            component: Login
        }
    ]
    
    const router = new VueRouter({
        routes
    })
    
    // 路由守卫:全局前置导航守卫
    router.beforeEach((to, from, next) => {
        // 获取token
        const token = Cookie.get('token')
    
        if (!token && to.name !== 'login') {
            next({ name: 'login' })
        } else if (token && to.name === 'login') {
            next({ name: 'home' })
        } else {
            next()
        }
    })
    
    
    export default router
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    store

    在这里插入图片描述

    index.js

    import Vue from "vue";
    import Vuex from 'vuex';
    import tab from './tab';
    
    Vue.use(Vuex)
    
    // 创建Vuex实例并导出
    export default new Vuex.Store({
        modules:{
            tab
        }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    tab.js

    import Cookie from "js-cookie"
    
    export default {
        state: {
            isCollapse: false,//导航栏是否折叠
            tabList: [
                {
                    path: '/',
                    name: 'home',
                    label: '首页',
                    icon: 's-home',
                    url: 'Home/Home'
                }
            ],//面包屑的数据:点了哪个路由,首页是一定有的
            menu: [],//不同用户的菜单
        },
        mutations: {
            // 修改导航栏展开和收起的方法
            CollapseMenu(state) {
                state.isCollapse = !state.isCollapse
            },
            // 更新面包屑的数据
            SelectMenu(state, item) {
                // 如果点击的不在面包屑数据中,则添加
                const index = state.tabList.findIndex(val => val.name === item.name)
                if (index === -1) {
                    state.tabList.push(item)
                }
            },
            // 删除tag:删除tabList中对应的item
            closeTag(state, item) {
                // 要删除的是state.tabList中的item
                const index = state.tabList.findIndex(val => val.name === item.name)
                state.tabList.splice(index, 1)
            },
            // 设置不同用户的菜单
            setMenu(state, val) {
                state.menu = val
                Cookie.set('menu', JSON.stringify(val))
            },
            // 动态添加路由
            addMenu(state, router) {
                // 判断Cookie
                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(itemm => {
                            itemm.component = () => import(`../Views/${itemm.url}`)
                            return itemm
                        })
                        menuArray.push(...item.children)
                    } else {
                        item.component = () => import(`../Views/${item.url}`)
                        menuArray.push(item)
                    }
                });
    
                console.log(menuArray, 'menuArray');
    
                menuArray.forEach(item => {
                    router.addRoute('Main', item)
                })
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72

    utils

    在这里插入图片描述

    request.js

    import axios from "axios";
    
    // 封装一个axios实例
    const http = axios.create({
        // 通用请求的地址前缀
        baseURL: '/api',
        // 超时时间
        timeout: 100000
    })
    
    // 请求拦截器
    http.interceptors.request.use(function (config) {
        // 在发送请求之前做什么
        return config;
    }, function (error) {
        // 对请求错误做什么
        return Promise.reject(error);
    })
    
    // 添加响应拦截器
    http.interceptors.response.use(function (response) {
        // 对响应数据做什么
        return response;
    }, function (error) {
        // 对响应错误做什么
        return Promise.reject(error);
    })
    
    export default http
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    Views

    在这里插入图片描述

    Home.vue

    <template>
        <el-row>
            <el-col :span="8">
                
                <el-card>
                    <div class="user">
                        <img src="../assets/images/user.png" alt="">
                        <div class="userInfo">
                            <p div class="name">Adminp>
                            <p div class="access">超级管理员p>
                        div>
                    div>
                    <div class="loginInfo">
                        <p>上次登录时间:<span>2021-7-19span>p>
                        <p>上次登陆地点:<span>武汉span>p>
                    div>
                el-card>
                
                <el-card style="margin-top: 20px;">
                    <el-table :data="TableData" style="width: 100%">
                        
                        <el-table-column v-for="(value, key) in TableLabel" :prop="key" :label="value">
                        el-table-column>
                    el-table>
                el-card>
            el-col>
            <el-col :span="16">
                <div class="num">
                    <el-card v-for="item in CountData" :key="item.name" :body-style="{ display: 'flex', padding: 0 }">
                        <i class="icon" :class="`el-icon-${item.icon}`" :style="{ backgroundColor: item.color }">i>
                        <div class="details">
                            <p class="price">{{ priceFormate(item.value) }}p>
                            <p class="desc">{{ item.name }}p>
                        div>
                    el-card>
                div>
                
                <div style="margin-left:20px">
                    
                    <el-card style="height:280px">
                        <div ref="echarts1" style="height:280px">div>
                    el-card>
                    <div class="graph">
                        
                        <el-card style="height:280px">
                            <div ref="echarts2" style="height:280px">div>
                        el-card>
                        
                        <el-card style="height:320px">
                            <div ref="echarts3" style="height:320px">div>
                        el-card>
                    div>
                div>
            el-col>
        el-row>
    template>
    
    <script>
    import TableLabel from '../data/TableLabel'
    import CountData from '../data/CountData'
    import { getData } from '../api/index'
    import * as echarts from 'echarts'
    
    // echarts的配置数据
    import order from '../data/echartsData/order'
    import user from '../data/echartsData/user'
    import video from '../data/echartsData/video'
    
    export default {
        data() {
            return {
                TableData: [],
                TableLabel,
                CountData
            }
        },
        methods: {
            priceFormate(price) {
                return "¥" + price
            }
        },
        mounted() {
            getData().then((data) => {
                // console.log(data);
                this.TableData = data.data.getStatisticalData.data.tableData
    
                // echarts图表
    
                // 折线图
    
                // 基于准备好的dom,初始化echarts实例
                const echarts1 = echarts.init(this.$refs.echarts1)
                var echarts1Option = order
                // ES6解构语法
                var { orderData, userData, videoData } = data.data.getStatisticalData.data
    
                // 获取x轴:要求是一个对象
                const xAxis = Object.keys(orderData.data[0])
                const xAxisData = {
                    data: xAxis
                }
    
                // 配置
                echarts1Option.legend = xAxisData
                echarts1Option.xAxis = xAxisData
                echarts1Option.yAxis = {}
                echarts1Option.series = []
    
                // 配置series
                xAxis.forEach(key => {
                    echarts1Option.series.push({
                        name: key,
                        type: 'line',
                        // key对应的orderData的所有值
                        data: orderData.data.map(item => item[key])
                    })
                })
    
                // 使用刚指定的配置项和数据显示图表。
                echarts1.setOption(echarts1Option);
    
                // 柱状图
                const echarts2 = echarts.init(this.$refs.echarts2)
                var echarts2Option = user
    
                // 配置
                echarts2Option.xAxis.data = userData.map(item => item.date)
                echarts2Option.series = [
                    {
                        name: '新增用户',
                        data: userData.map(item => item.new),
                        // 类型:bar是柱状图 
                        type: 'bar'
                    }
                    ,
                    {
                        name: '活跃用户',
                        data: userData.map(item => item.active),
                        type: 'bar'
                    }
                ]
    
                echarts2.setOption(echarts2Option);
    
                // 饼状图
                const echarts3 = echarts.init(this.$refs.echarts3)
                var echarts3Option = video
                echarts3Option.series = {
                    data: videoData,
                    type: 'pie'
                }
                echarts3.setOption(echarts3Option);
            })
        }
    }
    script>
    
    <style lang="less" scoped>
    .user {
        // 垂直居中
        display: flex;
        align-items: center;
    
        // 外边距:分割线距离loginInfo的距离
        margin-bottom: 20px;
        // 内边距:分割线距离User的距离
        padding-bottom: 20px;
        border-bottom: 1px solid #ccc;
    
        img {
            width: 150px;
            height: 150px;
            border-radius: 50%;
            margin-right: 40px;
        }
    
        .userInfo {
            .name {
                font-size: 32px;
                margin-bottom: 10px;
            }
    
            .access {
                color: #999999;
            }
        }
    }
    
    .loginInfo {
        p {
            line-height: 28px;
            font-size: 14px;
            color: #999999;
    
            span {
                color: #666666;
                margin-left: 60px;
            }
        }
    }
    
    .num {
        display: flex;
        // 要换行
        flex-wrap: wrap;
        // 从头到尾均匀排列
        justify-content: space-between;
        margin-left: 20px;
    
        .el-card {
            width: 32%;
            margin-bottom: 20px;
    
            .icon {
                width: 80px;
                height: 80px;
                line-height: 80px;
                text-align: center;
                font-size: 30px;
                color: #fff;
            }
    
            .details {
                // 竖着排且居中
                display: flex;
                flex-direction: column;
                justify-content: center;
    
                margin-left: 15px;
    
                .price {
                    font-size: 30px;
                    margin-bottom: 10px;
                    line-height: 30px;
                    height: 30px;
                }
    
                .desc {
                    font-size: 14px;
                    color: #999;
                    text-align: center;
                }
            }
        }
    }
    
    .graph {
        display: flex;
        // 两个靠边
        justify-content: space-between;
        margin-top: 20px;
    
        .el-card {
            width: 49%;
        }
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257

    Login.vue

    <template>
        <el-form ref="form" class="login_container" :model="login" status-icon :rules="rules" label-width="70px">
            
            <h3 class="login_title">用户登录h3>
            
            <el-form-item label="用户名" prop="username">
                <el-input v-model="login.username" autocomplete="off">el-input>
            el-form-item>
    
            <el-form-item label="密码" prop="password">
                <el-input type="password" v-model="login.password" autocomplete="off">el-input>
            el-form-item>
    
            <el-form-item>
                <el-button @click="submit" type="primary" style="margin-left:30px;margin-top:10px">提交el-button>
            el-form-item>
        el-form>
    template>
    
    <script>
    import Cookie from 'js-cookie'
    import { getMenu } from '../api/index'
    export default {
        data() {
            return {
                // 登陆数据
                login: {
                    username: '',
                    password: ''
                },
                // 校验规则
                rules: {
                    username: [{ required: 'true', message: '请输入用户名', trigger: 'blur' }],
                    password: [{ required: 'true', message: '请输入用户名', trigger: 'blur' }]
                }
            }
        },
        methods: {
            submit() {
                // 表单的校验
                this.$refs.form.validate((valid) => {
                    if (valid) {
                        // 传入表单数据
                        getMenu(this.login).then((data) => {
                            // console.log(data);
                            if(data.data.code===20000){
                                // 记录cookie
                                Cookie.set('token',data.data.data.token)
                                // 设置菜单
                                this.$store.commit('setMenu',data.data.data.menu)
                                // 动态添加路由
                                this.$store.commit('addMenu',this.$router)
                                // 跳转到首页
                                this.$router.push('/home')
                            }else{
                                // 验证失败的弹窗
                                this.$message.error(data.data.data.message);
                            }
                        })
                    }
                })
            }
        }
    }
    script>
    
    <style lang="less" scoped>
    .login_container {
        width: 350px;
        border: 1px solid #eaeaea;
    
        // 居中
        margin: 180px auto;
    
        padding: 35px 35px 15px 35px;
    
        // 让padding在width里面
        box-sizing: border-box;
    
        border-radius: 15px;
        background-color: #fff;
        box-shadow: 0 0 25px #cac6c6;
    
        .login_title {
            color: #505458;
            // 左右居中
            text-align: center;
            margin-bottom: 40px;
        }
    
        .el-input {
            width: 198px;
        }
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    Main.vue

    <template>
        <el-container>
            
            <el-aside width="auto">
                <common-aside/>
            el-aside>
            <el-container>
                <el-header>
                    <common-header/>
                el-header>
                <common-tags/>
                <el-main>
                    <router-view>router-view>
                el-main>
            el-container>
        el-container>
    template>
    
    <script>
    import CommonAside from '../components/CommonAside.vue'
    import CommonHeader from '../components/CommonHeader.vue'
    import CommonTags from '../components/CommonTags.vue'
    export default {
        data(){
            return{}
        },
        components:{
            CommonAside,
            CommonHeader,
            CommonTags
        }
    }
    script>
    
    <style lang="less" scoped>
    .el-header{
        padding:0;
    }
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    Mall.vue

    <template>
      <h1>Mallh1>
    template>
    
    <script>
    export default {
    
    }
    script>
    
    <style>
    
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    PageOne.vue

    <template>
        <h1>Page1h1>
      template>
      
      <script>
      export default {
      
      }
      script>
      
      <style>
      
      style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    PageTwo.vue

    <template>
        <h1>Page2h1>
      template>
      
      <script>
      export default {
      
      }
      script>
      
      <style>
      
      style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    User.vue

    <template>
      <div class="manage">
        <div class="manage-header">
          
          <el-button type="primary" @click="handlecreate">+ 新增el-button>
    
          
          
          <el-dialog :title="modalType == 0 ? '新建' : '编辑'" :visible.sync="dialogVisible" width="50%"
            :before-close="closeDialog">
            
            
            <el-form :inline="true" :model="form" :rules="rules" ref="form" label-width="80px">
              
              <el-form-item label="姓名" prop="name">
                <el-input placeholder="请输入姓名" v-model="form.name">el-input>
              el-form-item>
    
              <el-form-item label="年龄" prop="age">
                <el-input placeholder="请输入年龄" v-model="form.age">el-input>
              el-form-item>
    
              <el-form-item label="性别" prop="sex">
                <el-select v-model="form.sex" placeholder="请输入性别">
                  <el-option label="" :value="1">el-option>
                  <el-option label="" :value="0">el-option>
                el-select>
              el-form-item>
    
              <el-form-item label="出生日期">
                <el-form-item prop="birth">
                  <el-date-picker type="date" placeholder="请选择日期" v-model="form.birth" value-format="yyyy-MM-DD">
                  el-date-picker>
                el-form-item>
              el-form-item>
    
              <el-form-item label="地址" prop="addr">
                <el-input placeholder="请输入地址" v-model="form.addr">el-input>
              el-form-item>
            el-form>
            <div slot="footer" class="dialog-footer">
              <el-button @click="closeDialog">取 消el-button>
              <el-button type="primary" @click="submit">确 定el-button>
            div>
          el-dialog>
    
          
          <el-form :inline="true">
            <el-form-item>
              <el-input v-model="searchForm.name" placeholder="请输入名称">el-input>
            el-form-item>
            <el-form-item>
              <el-button type="primary" @click="search">查询el-button>
            el-form-item>
          el-form>
        div>
        <div class="common-table">
          
          <el-table :data="tableData" stripe style="width: 100%" height="90%">
            <el-table-column prop="name" label="姓名">
            el-table-column>
            <el-table-column prop="age" label="年龄">
            el-table-column>
            <el-table-column prop="sex" label="性别">
              <template slot-scope="scope">
                <span>{{ scope.row.sex == 1 ? '男' : '女' }}span>
              template>
            el-table-column>
            <el-table-column prop="birth" label="出生日期">
            el-table-column>
            <el-table-column prop="addr" label="地址">
            el-table-column>
            
            <el-table-column label="操作">
              <template slot-scope="scope">
                <el-button @click="handleEdit(scope.row)">编辑el-button>
                <el-button type="danger" @click="handleDelete(scope.row)">删除el-button>
              template>
            el-table-column>
          el-table>
          
          <div class="pager">
            <el-pagination layout="prev, pager, next" :total="total" @current-change="currentChange">
            el-pagination>
          div>
        div>
      div>
    template>
      
    <script>
    import { getUser, createUser, deleteUser, updateUser } from '../api/index'
    export default {
      data() {
        return {
          // 表单绑定的数据
          form: {
            name: '',
            age: '',
            sex: '',
            birth: '',
            addr: ''
          },
          // 表单验证规则
          rules: {
            name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
            age: [{ required: true, message: '请输入年龄', trigger: 'blur' }],
            sex: [{ required: true, message: '请输入性别', trigger: 'blur' }],
            birth: [{ required: true, message: '请输入日期', trigger: 'blur' }],
            addr: [{ required: true, message: '请输入地址', trigger: 'blur' }],
          },
          // 表单是否打开
          dialogVisible: false,
          // 列表数据
          tableData: [],
          // 打开表单:新建0,编辑1
          modalType: 0,
          // 分页的对象
          pageData: {
            page: 1,
            limit: 20
          },
          // 分页页数
          total: 0,
          // 搜索框表单
          searchForm: {
            name: ''
          }
        }
      },
      methods: {
        // 获取列表数据
        getList() {
          // 由接口文档知传入一个对象:要返回的是当前页面数据和搜索到的数据的交集
          getUser({ params: { ...this.pageData, ...this.searchForm } }).then((data) => {
            this.tableData = data.data.list
            this.total = data.data.count || 0
          })
        },
        // 表单提交
        submit() {
          // 要用箭头函数,若用function会报错,不知道为什么
          this.$refs.form.validate((valid) => {
            // 符合校验
            if (valid) {
              // 提交数据
              if (this.modalType === 0) {
                // 新增
                createUser(this.form).then(() => {
                  this.getList()
                })
              } else {
                // 编辑
                updateUser(this.form).then(() => {
                  this.getList()
                })
              }
              // 清空,关闭
              this.closeDialog()
            }
          })
        },
        // 关闭对话框
        closeDialog() {
          // 先重置
          this.$refs.form.resetFields()
          // 后关闭
          this.dialogVisible = false
        },
        // 编辑按钮
        handleEdit(index) {
          this.modalType = 1
          this.openForm()
          // 深拷贝
          this.form = JSON.parse(JSON.stringify(index))
        },
        // 删除按钮
        handleDelete(index) {
          this.$confirm('此操作将永久删除该用户, 是否继续?', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            // 删除操作:根据后端接口,参数是对象,id是唯一标识符
            deleteUser({ id: index.id }).then(() => {
              this.$message({
                type: 'success',
                message: '删除成功!'
              })
              this.getList()
            });
          }).catch(() => {
            // 点击取消:不删除了
            this.$message({
              type: 'info',
              message: '已取消删除'
            });
          });
        },
        // 新建按钮
        handlecreate() {
          this.modalType = 0
          this.openForm()
        },
        // 打开表单
        openForm() {
          this.dialogVisible = true
        },
        // 改变页码
        currentChange(val) {
          this.pageData.page = val
          this.getList()
        },
        // 搜索
        search() {
          this.getList()
        }
      },
      mounted() {
        this.getList()
      }
    }
    script>
      
    <style lang="less" scoped>
    .manage {
      height: 100%;
    
      .manage-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
    
      .common-table {
        height: 90%;
        position: relative;
    
        .pager {
          position: absolute;
          right:20px;
          bottom: 0;
        }
      }
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245

    App.vue

    <template>
      <div id="app">
        <router-view>router-view>
      div>
    template>
    
    <script>
    export default {
    }
    script>
    
    <style>
    html,
    body,
    h3,
    p {
      margin: 0;
      padding: 0
    }
    style>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    main.js

    import Vue from 'vue'
    import App from './App.vue'
    import ElementUI from 'element-ui'
    import 'element-ui/lib/theme-chalk/index.css';
    import router from './router/index'
    import store from './store/index'
    import './api/mock'
    
    Vue.config.productionTip = false
    Vue.use(ElementUI)
    
    new Vue({
      router,
      store,
      render: h => h(App),
      created() {
        store.commit('addMenu', router)
      }
    }).$mount('#app')
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    要安装的依赖

    "dependencies": {
        "axios": "^1.1.3",
        "core-js": "^3.8.3",
        "echarts": "^5.1.2",
        "element-ui": "^2.15.10",
        "js-cookie": "^3.0.1",
        "less": "^4.1.3",
        "less-loader": "^11.1.0",
        "mockjs": "^1.1.0",
        "vue": "^2.6.14",
        "vue-router": "^3.6.5",
        "vuex": "^3.6.2"
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    已上传到Gitee

    代码已经上传到Gitee:https://gitee.com/karshey/general-background

  • 相关阅读:
    MassTransit类库Saga文档翻译
    java计算机毕业设计vue架构云餐厅美食订餐系统MyBatis+系统+LW文档+源码+调试部署
    《数据结构》(六)八大排序(下)
    【Leetcode每日一题 1726】「组合|哈希表」同积元组
    11 - YOLO算法二 (目标检测)
    创建一个pod,但pod的status持续:ContainerCreating
    TCP的连接套接口哈希表初始化
    【华为OD机试真题 python】高效的任务规划【2022 Q4 | 200分】
    直流无刷电机(BLDC)转速闭环调速系统及Matlab/Simulink仿真分析
    制售《原神》外挂非法获利200万,外挂的危害有多大?
  • 原文地址:https://blog.csdn.net/karshey/article/details/127891703