使用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(和settings.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="width: 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="width: 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報表,包含前后端處理邏輯


下一篇講一下如何給折線圖添加一個按照時間篩選的功能:篩選不同的周,顯示對應的圖

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM