zoukankan      html  css  js  c++  java
  • 使用echarts做一个可视化报表(一)

    前段时间利用django+vue编写了一个构造测试数据的平台,目前已经把各个系统常用的构造数据请求放到了平台上。

    为了更直观的观察这个平台的使用情况,利用echarts做了一个可视化的报表,最终效果如下

    本篇来介绍下报表从构思到实现的过程

    我的需求:

    1、本次打算做2张表,一个以周为维度,统计每天在平台上构造数据的次数(前者使用折线图、后者使用饼图);

    2、以系统为维度,统计每个系统构造数据的次数;

    根据需求,拆解下我要做的事情:

    1、在数据库里创建一张表,记录创建数据过程;

    2、添加后端逻辑,每构造一条数据(前端每发起一次创建数据的请求),便向表里插入一条记录;

    3、后端新增视图函数,通过查询数据库,把数据返回给前端报表;

    4、前端处理后端返回的数据,传给echarts,把数据展示出来;

    一、Django连接mysql数据库并创建表

    1、把django默认数据库配置,由sqlite3改为mysql

    打开 settings.py,定位到DATABASES配置项

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'OPTIONS': {
                'init_command': "SET sql_mode='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,"
                                "ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'",
            },  # 连接到数据库时要使用的其他参数。可用参数取决于您的数据库后端
            'NAME': 'data_factory',  # 要使用的数据库的名称(先到mysql数据库创建一个库)
            'USER': 'root',
            'PASSWORD': '12345678',
            'HOST': '127.0.0.1',
            'PORT': '3306',
        }
    }

    2、由于后面我是用pymysql来操作数据库的,所以需要配置一下,使django能够通过pymysql操作数据库

    打开django项目根目录下__init__py

    import pymysql
    pymysql.install_as_MySQLdb()

     3、打开models.py,利用django自带的模型来创建一张表(也可以自己在数据库中建好)

    from django.db import models
    
    
    # Create your models here.
    
    class DataFactory(models.Model):
        id = models.AutoField
        class_name = models.CharField(max_length=50)
        class_id = models.CharField(max_length=50)
        start_time = models.DateTimeField(auto_now=False)
        end_time = models.DateTimeField(auto_now=False)

    这张表定义了5个字段

    id表示数据的自增编号;

    class_name表示数据类型名称,用来区分是哪个系统创建的数据;

    class_id表示数据类型id;

    start_time表示数据开始创建的时间;

    end_time表示数据创建完成的时间;

    上述字段是我自己定义的,可以根据需要自己进行修改

    定义好模型后,需要把表映射到数据库中,执行以下命令

    先执行
    python manage.py makemigrations app
    再执行 python manage.py migrate

    这样在数据库中就创建好了一张表

     二、修改django视图文件,向数据库插入数据

    关于如何利用django 模型models向数据插入数据,可以参考下面一篇博客:如何使用Django模型Models对数据库进行增删改查

    因为我打算每创建成功一条数据,就向数据库里插入一条数据,这条数据需要包含:数据类型名称、数据类型id、开始创建时间、创建成功时间

    所以我需要定义上述字段的值,然后插入库里

    
    
    from app.models import DataFactory

    def
    create_draft_bill(contract_code, num, money): """ 创建【草稿】账单 :param money: :param contract_code: :param num: :return: """ start_time = timezone.now() # 数据开始创建的时间 data = contract_bill.create_contract_bill(contract_code, num, money) end_time = timezone.now() # 数据创建结束时间 df = DataFactory(class_name="合同", class_id="1", start_time=start_time, end_time=end_time) # 执行后,向数据库插入一条数据 df.save() return data

    如上是我定义的一个创建账单的方法,每当创建成功一条账单时,要把这条记录插入数据库。

    我把 DataFactory模型导进来,然后分别定义了开始、结束时间、数据名称等,调用模型把数据插入库并保存即可。

    三、新增视图方法供前端调用

    由于我把报表放在了一个单独的页面,期望每当打开这个页面时,就展示图表,所以这里面发生了2件事:

    1、打开报表页面时,向后端发送请求获取数据;

    2、拿到数据后,前端把数据渲染到页面的报表中;

    因为有2个表,所以我打算写2个视图函数分别来提供对应的数据

    折线图

    折线图的横轴为日期:【周一】~【周日】,纵轴为数量

    所以我要查到当前周的数据,并把日期与周几做一个映射,最终 sql 如下

    select case dayofweek(date_format(start_time, '%Y-%m-%d'))
        when 1 then '周日'
        when 2 then '周一'
        when 3 then '周二'
        when 4 then '周三'
        when 5 then '周四'
        when 6 then '周五'
        when 7 then '周六'
        end as week
         , count(*) as count from app_datafactory where yearweek(date_format(start_time, '%Y-%m-%d'))=yearweek(now())
    group by week;  # 按照周纬度统计

    查出来的效果如下

    这里有个问题,当这一天有数据时,则可以查出这条记录;当这一天没数据时,并不是显示类似【周三  0】,而是直接没有这条记录

    这种不能直接返到前端,需要把0的情况处理下

    最终的折线图对应的视图方法如下

    def query_value_statistics(request):
        """折线图数据"""
    
        conn = pymysql.connect(host="localhost", user="root", password="12345678", port=3306, db="data_factory",
                               charset='utf8')  # 链接数据库
        cursor = conn.cursor()  # 不能共用一个线程池,一个方法链接一个mysql
        sql = "select case dayofweek(date_format(start_time, '%Y-%m-%d')) " \
              "when 1 then '周日' " \
              "when 2 then '周一' " \
              "when 3 then '周二' " \
              "when 4 then '周三' " \
              "when 5 then '周四' " \
              "when 6 then '周五' " \
              "when 7 then '周六' " \
              "end as week, " \
              "count(*) as count " \
              "from app_datafactory " \
              "where yearweek(date_format(start_time, '%Y-%m-%d'))=yearweek(now()) group by week;"# yearweek(xx,mode=1),表示周一是一周的第一天;默认周日是第一天
        # print(sql)
        conn.ping(reconnect=True)
        cursor.execute(sql)
        t = cursor.fetchall()
    
        cursor.close()  # 关闭游标
        conn.close()  # 关闭连接
    
        dict_value = {} # 定义一个空字典
        for i in t:
            j = {i[0]: i[1]}
            dict_value.update(j)  # 遍历从数据库查到的数据,把每组数据都追加的字典中,最后dict_value形如{"周二":xx, "周四":xx, "周六":xx}
    
        week = {"周一": 0, "周二": 0, "周三": 0, "周四": 0, "周五": 0, "周六": 0, "周日": 0}  # 定义一个字典,每天的数据为0
    
        week.update(dict_value)  # 把dict_value字典合并到week字典中,这样有数据的日期正常显示数据,无数据的日期显示0
    
        statistics_data = [] # 定义一个空列表
    for t in week.items(): # 把字典中的数据处理为一个个小的字典,形如{"周一": 3},依次追加到列表中 statistics_data.append({ "name": t[0], "value": t[1] }) data = { "code": "200", "data": statistics_data } return JsonResponse(data, json_dumps_params={'ensure_ascii': False})

    最终的 statistics_data 打印效果如下

    [{'name': '周一', 'value': 12}, {'name': '周二', 'value': 4}, {'name': '周三', 'value': 0}, {'name': '周四', 'value': 0}, {'name': '周五', 'value': 0}, {'name': '': 0}, {'name': '周日', 'value': 0}]

    饼图

    饼图是统计每个系统构造数据的数量,sql如下

    select class_name, count(*) from app_datafactory group by class_name;

    视图函数如下

    def pie_statistics(request):
    
        """饼图数据"""
        conn = pymysql.connect(host="localhost", user="root", password="12345678", port=3306, db="data_factory",
                               charset='utf8')  # 链接数据库
        cursor = conn.cursor()
        values = []
        sql1 = "select class_name, count(*) from app_datafactory group by class_name;"    conn.ping(reconnect=True)
    
        cursor.execute(sql1)
        t = cursor.fetchall()
    
        for i in t:
            block = {
                "value": i[1],
                "name": i[0]
            }
            values.append(block)
        cursor.close()  # 关闭游标
        conn.close()  # 关闭连接
    
        data = {
            "code": "200",
            "data": values
        }
    
        return JsonResponse(data, json_dumps_params={'ensure_ascii': False})

    values打印结果如下

    [{'value': 44, 'name': '合同'}, {'value': 2, 'name': '项目运营'}, {'value': 26, 'name': '线索商机'}]

    四、前端引入echarts,渲染数据

    关于如何再vue中使用echarts,这里不做赘述,重点写一下报表前端处理逻辑,新建一个 statistics.vue

    1、折线图

    (1)引入折线图相关的echart代码

    html代码中留出一个div容器,存放折线图

    <div id="main1" style=" 600px;height:400px;"></div>

    在script标签下先引入echarts包

    import * as echarts from 'echarts'

    在methods下新建一个方法,存放折线图echarts相关代码

    echarts_test(data) {
    
          let myChart1 = echarts.init(document.getElementById('main1'));
    
    // 指定图表的配置项和数据
          let val = data.map(x => x.value)
          // console.log(val) 
    
          let option1 = {
            // title: {  //图表的标题
            //   text: '每日创建数据汇总',
            //   left: 'center',
            //   show: false
            // },
            tooltip: {
              trigger: 'axis',
              // axisPointer: {
              //   type: 'cross'
              // }
            },
            grid:{  //折线图在当前容器的位置调整
              x:22, //左侧距离左边的距离
              y:4,  //顶部最高点距离顶部的位置
              x2:50, // 右侧距离右侧的距离
              y2:20,  //距离底部距离
              borderWidth:1
            },
            color: ['#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
            xAxis: {
              type: 'category',
              data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
              // axisPointer: {  //配置show为true,显示此轴的axisPointer
              //   show: true
              // }
            },
            yAxis: {
              type: 'value'
            },
            series: [
              {
                name: "创建数据",
                smooth: false,  // 控制是否为平滑曲线(false为折线)
                data: val,
                type: 'line',
                areaStyle: { //区域填充样式 https://echarts.apache.org/zh/option.html#series-line.areaStyle
                  color:  // 线性渐变填充
                      {
                        type: 'linear',
                        x: 0,
                        y: 1,
                        x2: 0,
                        y2: 0,
                        colorStops: [{
                          offset: 0, color: 'white' // 0% 处的颜色
                        }, {
                          offset: 1, color: 'green' // 100% 处的颜色
                        }],
                        global: false // 缺省为 false
                      }
                }
              }
            ]
          };

    这个方法传了一个data参数,这个就是数据源,即后端返回的数据;

    使用 map 方法提取其中的value ,如 let val = data.map(x => x.value)

    (2)在methods下再新建一个方法,发送请求,获取折线图数据

    query_value_statistics() {
    this.$http.get("http://10.237.x.xx:8000/data_factory/query_value_statistics",
              {
                // timeout: 10000,
                params:{
    
    } }) .then(response
    =>{ let datas= response.data.data; console.log("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>") console.log(datas) // console.log(datas[0]["name"]) // console.log(datas[0].name)

    this.echarts_test(response.data.data) # 调用echarts_test,把请求返回数据中的data传给echarts_test() }).catch((reason)=>{ console.log(reason) this.$message({ message: '接口调用失败,请检查系统是否正常', type: 'warning' }); }) },

    2、饼图

    (1)引入饼图相关的echarts代码

    html代码中留出一个div容器,存放饼图

    <div id="main2" style=" 600px;height:380px; margin-top: 20px;"></div>

    在methods下新建一个方法,存放饼图echarts相关代码

    echarts_pie(datasource) {
          let chartDom = document.getElementById('main2');
          let myChart = echarts.init(chartDom);
          let option;
          
          option = {
            // title: {
            //   text: '各系统调用次数汇总',
            //   left: 'center'
            // },
      
            tooltip: {
              show: true,
              trigger: 'item'
    
            },
            legend: {
              top: '2%',
              left: 'center'
            },
            color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
            series: [
              {
                // name: 'Access From',
                type: 'pie',
                radius: ['40%', '70%'],
                avoidLabelOverlap: false,
                center:['50%', '50%'], //控制左右上下
                itemStyle: {
                  borderRadius: 30,
                  borderColor: '#fff',
                  borderWidth: 2
                },
                label: {
                  show: false,
                  position: 'center'
                },
                emphasis: {
                  label: {
                    show: true,
                    fontSize: '30',
                    fontWeight: 'bold'
                  }
                },
                labelLine: {
                  show: false
                },
                data: datasource
              }
            ]
          };
    
          option && myChart.setOption(option);
        }

    这个方法有一个 datasource参数,它是饼图的数据源

    (2)在methods下新建一个方法,发送请求,获取饼图数据

    pie_statistics() {
          this.$http.get("http://10.237.x.xx:8000/data_factory/pie_statistics",
              {
                // timeout: 10000,
                params:{
    
                }
    
              })
              .then(response =>{
       
                this.echarts_pie(response.data.data) # 调用echarts_pie方法,把请求返回数据传进去
                
              }).catch((reason)=>{
            console.log(reason)
    
            this.$message({
              message: '接口调用失败,请检查系统是否正常',
              type: 'warning'
            });
          })
        },

    为了实现打开页面即可发送请求并渲染报表,需要在mounted()下挂载上述2个发送请求的方法

    mounted() {
        this.query_value_statistics()
        this.pie_statistics()
      }

    综上,我们就完成了2个echarts报表,包含前后端处理逻辑


    下一篇讲一下如何给折线图添加一个按照时间筛选的功能:筛选不同的周,显示对应的图

  • 相关阅读:
    2020/3/12
    练习题1
    2020/3/26
    2020/3/25
    2020/3/24
    2020/3/23
    应用层
    bzoj3326[SCOI2013]数数
    HEOI2017游记
    bzoj4417[SHOI2013]超级跳马
  • 原文地址:https://www.cnblogs.com/hanmk/p/15713879.html
Copyright © 2011-2022 走看看