首页 > 其他分享 >Vue2+ECharts+Mock.js实现前端后台通用管理系统页面

Vue2+ECharts+Mock.js实现前端后台通用管理系统页面

时间:2024-10-14 21:53:14浏览次数:3  
标签:name series js item Vue2 new data ECharts Mock

一、前言

    在现代Web开发中,前端框架与数据可视化工具的结合能够显著提升用户体验。本文将介绍如何使用Vue2和ECharts构建一个通用的后台管理系统页面。利用Vue2的组件化特性,可以高效管理应用状态与UI交互,而ECharts则提供多样的图表类型,便于展示数据分析结果。通过整合这两者,开发者能够快速构建出既美观又功能强大的后台管理系统,实现数据的动态展示与实时更新,从而帮助用户做出更明智的决策。

二、技术栈

Vue2+Vuex+Echarts+Element-ui+Axios+Mock.js

  • Vue.js:前端框架,用于构建用户界面。
  • Vue Router:用于页面路由管理。
  • Vuex:状态管理库,用于管理应用的共享状态。
  • ECharts:用于数据可视化展示。
  • Mock.js:用于模拟后端接口数据。

三、页面区域结构

   页面整体分为三个区域,CommandAside区域、CommandHeader区域、HomePage区域,HomePage区域又分为左侧数据和右侧图标区域。图表区域又分为折线图、饼状图、柱状图区域。

1.MainPage代码实现

  • <el-container>: Element UI 提供的布局容器,用于构建页面的整体结构。

  • <el-aside>: 侧边栏区域,这里包含了 CommonAside 组件,通常用于放置导航或菜单。

  • <el-header>: 页头区域,这里包含了 CommonHeader 组件,通常用于显示标题或工具条。

  • <el-main>: 主内容区域,这里包含 <router-view>,这是 Vue Router 的占位符,用于渲染匹配的子路由组件。

<template>
    <el-container>
        <el-aside width="auto">
            <common-aside />
        </el-aside>
        <el-container>
            <!--使用小驼峰命名法  -->
            <el-header>
                <common-header />
            </el-header>
            <el-main>
                <!-- 二级路由出口 -->
                <router-view></router-view>
            </el-main>
        </el-container>
    </el-container>
</template>

<!-- 样式区域 -->
<style lang="less">
.el-header {
    background-color: #333;

}
</style>

<script>
import CommonAside from '@/components/CommonAside.vue'
import CommonHeader from '@/components/CommonHeader.vue'
export default {
    name: 'MainPage',
    data() {
        return {

        }
    },
    components: {
        CommonAside,
        CommonHeader
    }
}
</script>

2.HomePage首页搭建

  1. 整体布局:使用 <el-row> 和 <el-col> 来构建响应式布局。:gutter="20" 指定了列之间的间隔为 20 像素。

  2. 左侧边栏区域 (<el-col :span="8">):

    • 包含两个主要部分:用户信息和一个表格。

    • 用户信息:使用 <el-card> 组件来显示用户头像和基本信息(用户名及角色)。显示上次登录时间和地点。

    • 表格:另一个 <el-card> 组件中嵌入了 <el-table>,通过 v-for 动态生成表格的列。

  3. 右侧区域 (<el-col :span="16">):

    • 包含统计数据和图表。

    • 统计信息:使用 v-for 迭代 countData 数组生成多个 <el-card>,每个卡片展示一个统计项(如图标、价格和描述)。

    • 折线图区域:一个 <el-card> 用于显示折线图,通过 ref="echart" 以便后续在 JavaScript 中引用。

    • 饼状图区域:一个包含两个 <el-card> 的容器,用于显示不同的图表,分别通过 ref 引用。

<template>
    <el-row class="home" :gutter="20">
        <!-- 左侧边栏区域 gutter="20" 表示左右两列之间的间隔为20像素。:offset="8" 表示该列向右偏移8个单位-->
        <el-col :span="8">
            <el-card shadow=" hover">
                <!-- 用户信息头像区域 -->
                <div class="user">
                    <!-- <img :src="getImageUrl('user')" class="user" /> -->
                    <img src="../assets/images/user.png" alt="">
                    <div class="user-info">
                        <p class="name">Admin</p>
                        <p class="access">超级管理员</p>
                    </div>
                </div>
                <!-- 登录信息区域布局 -->
                <div class="login-info">
                    <p>上次登录时间:<span>2022-7-11</span></p>
                    <p>上次登录的地点:<span>北京</span></p>
                </div>
            </el-card>

            <!-- 底部卡片区域  shadow="hover" 应用到一个元素上时,该元素在鼠标悬停时会显示特定的阴影-->
            <el-card style="margin-top: 20px; height: 410px;" shadow="hover" class="table">
                <el-table :data="tableData">
                    <el-table-column v-for="(val, key) in tableLabel" :key="key" :prop="key" :label="val">
                    </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="icons" :class="`el-icon-${item.icon}`" :style="{ background: item.color }"></i>
                    <div class="detail">
                        <p class="price">¥{{ item.value }}</p>
                        <p class="desc">{{ item.name }}</p>
                    </div>
                </el-card>
            </div>
            <!-- 右侧底部折线图片区域 //三个图表的容器-->
            <el-card style="height: 280px;" class="top-echart">
                <!--折线图区域  -->
                <div ref="echart" style="height: 280px;"></div>
            </el-card>
            <!-- 右侧底部饼状图区域 -->
            <div class="graph">
                <el-card style="height: 210px;">
                    <div ref="userEchart" style="height: 240px"></div>
                </el-card>
                <el-card style="height: 210px;">
                    <div ref="videoEchart" style="height: 240px"></div>
                </el-card>
            </div>
        </el-col>
    </el-row>
</template>

3.HomePage首页中在mounted()中进行数据渲染逻辑实现

<script>
import { getHomeData } from "@/api";
//引入echarts
import * as echarts from "echarts";
export default {
    name: 'HomePage',
    data() {
        return {
            tableData: [],
            tableLabel: {
                name: "课程",
                todayBuy: "今日购买",
                monthBuy: "本月购买",
                totalBuy: "总购买",
            },
            countData:
                [
                    {
                        name: "今日支付订单",
                        value: 1234,
                        icon: "success",
                        color: "#2ec7c9",
                    },
                    {
                        name: "今日收藏订单",
                        value: 210,
                        icon: "star-on",
                        color: "#ffb980",
                    },
                    {
                        name: "今日未支付订单",
                        value: 1234,
                        icon: "goods",
                        color: "#5ab1ef",
                    },
                    {
                        name: "本月支付订单",
                        value: 1234,
                        icon: "success",
                        color: "#2ec7c9",
                    },
                    {
                        name: "本月收藏订单",
                        value: 210,
                        icon: "star-on",
                        color: "#ffb980",
                    },
                    {
                        name: "本月未支付订单",
                        value: 1234,
                        icon: "goods",
                        color: "#5ab1ef",
                    },
                ],
            observer: null,
            xOptions: {
                // 图例文字颜色
                textStyle: {
                    color: "#333",
                },
                legend: {},
                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: [],
            },
            pieOptions: {
                tooltip: {
                    trigger: "item",
                },
                legend: {},
                color: [
                    "#0f78f4",
                    "#dd536b",
                    "#9462e5",
                    "#a6a6a6",
                    "#e1bb22",
                    "#39c362",
                    "#3ed1cf",
                ],
                series: []
            },
        }
    },
    methods: {
        getImageUrl(user) {
            return new URL(`../assets/images/${user}.png`, import.meta.url).href;
        }
    },
    mounted() {
        getHomeData().then(async ({ data }) => {
            const { tableData } = data.data;
            console.log(tableData);
            this.tableData = tableData;
            // 在当前位置进行echarsts,初始化echarts实
            // this.getChartData();
            const { orderData, userData, videoData } = data.data;
            console.log(111);
            console.log(orderData, userData, videoData);
            // 对第一个图表的xAxis和series赋值
            this.xOptions.xAxis.data = orderData.date;
            this.xOptions.series = Object.keys(orderData.data[0]).map(val => ({
                name: val,
                data: orderData.data.map(item => item[val]),
                type: "line"
            }));

            // one
            const OneEcharts = echarts.init(this.$refs["echart"]);
            OneEcharts.setOption(this.xOptions);

            // 对第二个图表的xAxis和series赋值
            this.xOptions.xAxis.data = userData.map(item => item.date);
            this.xOptions.series = [
                {
                    name: "新增用户",
                    data: userData.map(item => item.new),
                    type: "bar",
                },
                {
                    name: "活跃用户",
                    data: userData.map(item => item.active),
                    type: "bar",
                }
            ];

            // two
            const TwoEcharts = echarts.init(this.$refs["userEchart"]);
            TwoEcharts.setOption(this.xOptions);

            // 对第三个图表的series赋值
            this.pieOptions.series = [
                {
                    data: videoData,
                    type: "pie",
                },
            ];

            // three
            const ThreeEcharts = echarts.init(this.$refs["videoEchart"]);
            ThreeEcharts.setOption(this.pieOptions);

            // ResizeObserver 如果监视的容器大小变化,如果改变会执行传递的回调
            this.observer = new ResizeObserver(entries => {
                OneEcharts.resize();
                TwoEcharts.resize();
                ThreeEcharts.resize();
            });

            // 如果这个容器存在
            if (this.$refs["echart"]) {
                // 则调用监视器的observe方法,监视这个容器的大小
                this.observer.observe(this.$refs["echart"]);
            }

        })


    }
}
</script>

四、使用mock.js模拟后端接口数据

1.安装mock.js

npm i mockjs

2.创建mockData,新建home.js文件储存HomePage数据

      如何创建 mock 数据文件,并在其中定义 HomePage 所需的数据结构。

// 首页数组
//用户的数组
import Mock from "mockjs";
//图表数据
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: 200,
            data: {
                // 左侧底部card数据
                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,
                    },
                ],
                // 饼图
                videoData: [
                    { name: "小米", value: 2999 },
                    { name: "苹果", value: 5999 },
                    { name: "vivo", value: 1500 },
                    { name: "oppo", value: 1999 },
                    { name: "魅族", value: 2200 },
                    { name: "三星", value: 4500 },
                ],
                // 柱状图
                orderData: {
                    date: [
                        "2019-10-01",
                        "2019-10-02",
                        "2019-10-03",
                        "2019-10-04",
                        "2019-10-05",
                        "2019-10-06",
                        "2019-10-07",
                    ],
                    data: [
                        {
                            苹果: 3839,
                            小米: 1423,
                            华为: 4965,
                            oppo: 3334,
                            vivo: 2820,
                            一加: 4751,
                        },
                        {
                            苹果: 3560,
                            小米: 2099,
                            华为: 3192,
                            oppo: 4210,
                            vivo: 1283,
                            一加: 1613,
                        },
                        {
                            苹果: 1864,
                            小米: 4598,
                            华为: 4202,
                            oppo: 4377,
                            vivo: 4123,
                            一加: 4750,
                        },
                        {
                            苹果: 2634,
                            小米: 1458,
                            华为: 4155,
                            oppo: 2847,
                            vivo: 2551,
                            一加: 1733,
                        },
                        {
                            苹果: 3622,
                            小米: 3990,
                            华为: 2860,
                            oppo: 3870,
                            vivo: 1852,
                            一加: 1712,
                        },
                        {
                            苹果: 2004,
                            小米: 1864,
                            华为: 1395,
                            oppo: 1315,
                            vivo: 4051,
                            一加: 2293,
                        },
                        {
                            苹果: 3797,
                            小米: 3936,
                            华为: 3642,
                            oppo: 4408,
                            vivo: 3374,
                            一加: 3874,
                        },
                    ],
                },
                // 折线图
                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 },
                ]
            },
        }
    }

}

3. 创建Mock.js创建后端请求接口

import Mock from 'mockjs'
//引入数据
import homeApi from './mockServeData/home'
Mock.mock('/api/home/getData', 'get', homeApi.getStatisticalData)

4.页面中引入使用发起异步请求

import { getHomeData } from "@/api";
  mounted() {
        getHomeData().then(async ({ data }) => {
            const { tableData } = data.data;
            console.log(tableData);
            this.tableData = tableData;
            // 在当前位置进行echarsts,初始化echarts实
            // this.getChartData();
            const { orderData, userData, videoData } = data.data;
            console.log(111);
            console.log(orderData, userData, videoData);
            // 对第一个图表的xAxis和series赋值
            this.xOptions.xAxis.data = orderData.date;
            this.xOptions.series = Object.keys(orderData.data[0]).map(val => ({
                name: val,
                data: orderData.data.map(item => item[val]),
                type: "line"
            }));

            // one
            const OneEcharts = echarts.init(this.$refs["echart"]);
            OneEcharts.setOption(this.xOptions);

            // 对第二个图表的xAxis和series赋值
            this.xOptions.xAxis.data = userData.map(item => item.date);
            this.xOptions.series = [
                {
                    name: "新增用户",
                    data: userData.map(item => item.new),
                    type: "bar",
                },
                {
                    name: "活跃用户",
                    data: userData.map(item => item.active),
                    type: "bar",
                }
            ];

            // two
            const TwoEcharts = echarts.init(this.$refs["userEchart"]);
            TwoEcharts.setOption(this.xOptions);

            // 对第三个图表的series赋值
            this.pieOptions.series = [
                {
                    data: videoData,
                    type: "pie",
                },
            ];

            // three
            const ThreeEcharts = echarts.init(this.$refs["videoEchart"]);
            ThreeEcharts.setOption(this.pieOptions);

            // ResizeObserver 如果监视的容器大小变化,如果改变会执行传递的回调
            this.observer = new ResizeObserver(entries => {
                OneEcharts.resize();
                TwoEcharts.resize();
                ThreeEcharts.resize();
            });

            // 如果这个容器存在
            if (this.$refs["echart"]) {
                // 则调用监视器的observe方法,监视这个容器的大小
                this.observer.observe(this.$refs["echart"]);
            }

        })

 五、使用Vuex进行状态管理

1.安装Vuex

npm i vuex

2.main.js中挂载Vuex

// Vue.use(VueRouter)
new Vue({
  render: h => h(App),
  router, // 将 router 注入到根实例
  store
}).$mount('#app')

 3.在index.js创建Vuex实例

import Vue from 'vue'
import Vuex from 'vuex'
import tab from './tab'
Vue.use(Vuex)
//创建vuex的实例
export default new Vuex.Store({
    state: {
    },
    modules: {
        tab
    }
})

4.示例tab.js导出 

      提供 tab.js 的示例代码,展示如何管理选项卡的状态。

export default {
    state: {
        isCollapse: false//控制菜单的展开还是收齐
    },

    mutations: {
        // 定义菜单收齐的方法
        collapseMenu(state) {
            state.isCollapse = !state.isCollapse
        }
    }
}

5.CommandHeader组件中使用,头部菜单栏折叠与显示

    在 CommandHeader 组件中使用 Vuex 管理菜单栏的显示与隐藏。

​
  computed: {
        //没有子菜单
        noChilden() {
            return this.menuData.filter(item => !item.children)
        },
        hasChilden() {
            return this.menuData.filter(item => item.children)
        },
        // 控制菜单栏的收起与折叠
        isCollapse() {
            return this.$store.state.tab.isCollapse
        }

    }

​

六、完整页面实现

 

七、代码仓库地址

https://gitee.com/tanzero/back-office.git 后续还在更新中~

八、参考视频

30-vue通用后台管理(面包屑&tag介绍)_哔哩哔哩_bilibilivue项目实战,vue3项目实战,vue2+element-ui项目,vue3项目实战(已完结)_哔哩哔哩_bilibili30-vue通用后台管理(面包屑&tag介绍)_哔哩哔哩_bilibili

九、总结 

    本项目致力于使用Vue2+Vuex+Echarts+Element-ui+Axios+Mock.js构建一个功能强大的后台管理系统,旨在提升用户体验和开发效率。通过引入 Vue Router,项目能够实现灵活的页面路由管理,使得不同功能模块的切换更加顺畅。同时,使用 Vuex 进行全局状态管理,可以有效地处理应用中的共享数据,确保各个组件之间的数据一致性。为了方便前端开发,利用 Mock.js 模拟后端接口数据,允许开发者在没有真实后端服务的情况下,依然能够进行数据渲染与交互测试。首页设计采用组件化结构,通过 ECharts 实现数据可视化,帮助用户更直观地理解数据趋势。通过本项目,希望大家可以一起了解前端项目开发的流程,一起学习~

    

标签:name,series,js,item,Vue2,new,data,ECharts,Mock
From: https://blog.csdn.net/weixin_74457498/article/details/142928090

相关文章

  • JSP第一次作业
    1、应用eclipse新建一个web项目,新建一个JSP页面。要求在页面的声明块中声明一个方法,方法功能为求2个数的平方和。在程序片中调用此方法求值,用java的表达式输出结果。要求调试程序,粘贴程序代码,并截图显示结果。<%@pagelanguage="java"contentType="text/html;charset=UTF-8......
  • node打包报错:ERROR in xxxx.js Module not found: Error: Can’t resolve xxxx in ‘
    原文链接:node打包报错:ERRORinxxxx.jsModulenotfound:Error:Can’tresolvexxxxin‘xxx’errorCommandfailedwithexitcode1.–每天进步一点点(longkui.site) 0.背景anguar项目。分为主包和子包,子包推送到npm私有仓库中,然后主包在packjson中引入子包的版本......
  • vue(vue.js) —style样式
    原文链接:vue(vue.js)—style样式–每天进步一点点(longkui.site)上一篇文章中简单介绍了vue中style的用法,这篇文章介绍以下vue中style的用法我们可以直接像下面这样写style<divstyle="width:50px;background-color:red"@click="changeCss">我是div</div>像......
  • vue(vue.js) —条件渲染(v-if、v-show)
    原文链接:vue(vue.js)—条件渲染(v-if、v-show)–每天进步一点点(longkui.site)1.v-showv-show是控制元素隐藏与删除的语句,基础用法如下:<divv-show='true'>我是第一个div</div><divv-show='false'>我是第二个div</div>效果如下:可以看出,v-show=’false’在实际渲染中......
  • vue(vue-js)—列表渲染(v-for)
    原文链接:vue(vue-js)—列表渲染(v-for)–每天进步一点点(longkui.site)列表渲染是前端经常用到的代码,在vue中用v-for做列表渲染。1.基础用法首先我们构造一个json数据,[{"name":"张三1","sex":"男","age":12},{"na......
  • vue(vue.js)—列表过滤
    原文链接:vue(vue.js)—列表过滤–每天进步一点点(longkui.site) 列表过滤可以认为是模糊搜索。实现的下面的这种效果:1.监视属性watch实现参考代码如下:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatibl......
  • MacOS安装nvm管理NodeJs
    安装nvm%curl-o-https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.4/install.sh|bash安装完成验证%nvm--version0.40.0安装NodeJs%nvminstall14.21.3%nvminstall20查看安装的NodeJs%nvmls->v14.21.3v20.18.0切换NodeJs版本......
  • 基于nodejs+vue基于springboot的高校资源共享平台[开题+源码+程序+论文]计算机毕业设
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展和教育改革的不断深入,高校资源共享已成为提升教育质量、促进学术交流的重要途径。然而,传统的高校资源管理模式存在资源分散、利用率......
  • 基于nodejs+vue基于springboot的个人博客设计与实现[开题+源码+程序+论文]计算机毕业
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展和信息时代的到来,个人表达与分享的需求日益增长。博客作为一种重要的网络应用形式,为博主提供了展示自我、分享知识与见解的平台。......
  • 基于nodejs+vue基于SpringBoot的个人健康管理系统[开题+源码+程序+论文]计算机毕业设
    本系统(程序+源码+数据库+调试部署+开发环境)带文档lw万字以上,文末可获取源码系统程序文件列表开题报告内容研究背景随着现代生活节奏的加快和工作压力的增大,个人健康问题日益受到社会各界的广泛关注。传统的健康管理方式往往依赖于线下医院或体检中心,不仅耗时费力,还难以满......