• 质量看板开发实践(三):bug柱状图


    前面2章讲了如何从jira获取数据,知道怎样获取数据,就可以绘图了

    本篇记录一下bug柱状图的实现过程

    对于这个bug柱状图我大致想实现以下功能:

    1. 能够按照日期查询,同时可以切换不同日期维度:按年查询、按月查询、按周查询、自定义日期范围;
    2. 能够切换项目;
    3. 刷新当前页面,自动触发查询请求;
    4. 切换日期维度,自动触发查询请求;
    5. 切换项目,自动触发查询请求;
    6. 显示查询结果总数;
    7. 最好可以把柱状图和折线图结合起来;

    最终的实现效果如下

    1、前端基本样式搭建

    前端样式基于element-ui,绘图仍然借助echarts

    创建一个文件jira_data.vue

    (1)编写日期组件

    <div style="float: left;">
              <el-select v-model="date_type" @change="switch_date_type" clearable placeholder="请选择日期维度">
                <el-option label="按年查询" value="year"></el-option>
                <el-option label="按月查询" value="month"></el-option>
                <el-option label="按周查询" value="week"></el-option>
                <el-option label="按日查询" value="day"></el-option>
              </el-select>
              <el-date-picker
                  v-if="date_type === 'year'"
                  v-model="year_value"
                  align="right"
                  type="year"
                  value-format="yyyy-MM-dd"
                  @change="get_histogram"
                  placeholder="选择年">
              </el-date-picker>
              <el-date-picker
                  v-else-if="date_type === 'month'"
                  v-model="month_value"
                  align="right"
                  type="month"
                  placeholder="选择月"
                  value-format="yyyy-MM-dd"
                  @change="get_histogram">
              </el-date-picker>
              <el-date-picker
                  v-else-if="date_type === 'week'"
                  v-model="week_value"
                  :clearable="false"
                  align="right"
                  type="week"
                  format="yyyy 第 WW 周"
                  value-format="yyyy-MM-dd"
                  placeholder="选择周"
                  @change="get_histogram">
              <!-- 如果想把clearable设置为false,需要使用 :clearable='false',不能用clearable='false' -->
              </el-date-picker>
              <el-date-picker
                  v-else
                  v-model="day_value"
                  type="daterange"
                  :clearable="false"
                  align="right"
                  range-separator=""
                  start-placeholder="开始日期"
                  end-placeholder="结束日期"
                  value-format="yyyy-MM-dd"
                  @change="get_histogram">
              </el-date-picker>
            </div>

    代码说明:

    el-select组件 包含4个选项:year、month、week、day,

    el-date-picker组件也对应的有4种形式,当切换不同日期维度时,显示对应的日期组件

    为了实现这一功能,在el-date-picker组件中使用v-if进行条件判断

    因为我想实现"切换日期类型、切换日期范围"后能够重新向后端发起请求,所以需要给组件绑定change事件

    这里我事先定义2个方法名,分别在组件中进行绑定,后续再完善2个方法的逻辑

    el-select组件中@change="switch_date_type",切换日期类型时,就触发这个方法;

    每个el-date-picker组件@change="get_histogram",切换日期范围时,就触发这个方法。

    (2)编写选择项目组件

    因为我希望能够按照不同项目进行筛选,所以这里需要加一个下拉选择框,能够选择不同项目

    <div style="float: left; padding-left: 20px">
      <el-select v-model="project_code" @change="switch_project" placeholder="请选择项目">
        <el-option label="项目1" value="xxx"></el-option>
        <el-option label="项目2" value="xxx"></el-option>
        <el-option label="项目3" value="xxx"></el-option>
        <el-option label="项目4" value="xxx"></el-option>
        <el-option label="全部" value="xxx, xxx, xxx, xxx"></el-option>
      </el-select>
    </div>

    代码说明:

    这个字段的值到时候需要传给后端,后端根据项目编码查询jira数据

    同时这里也绑定了一个change事件@change="switch_project"

    当切换项目时,触发switch_project这个方法

    (3)预留一个位置,显示查询到的bug总数

    <div class="top_count">
       查询到总bug数:<span>{{day_range_sum}}</span></div>

    上述组件对应的js代码

    <script>
    export default {
    
      data() {
        return {
          date_type: 'day', //select选择器的值,默认按照日查询
          year_value: "",
          month_value: "",
          week_value: "",
          day_value: "",
          project_code: "xxx",
          day_range_sum: null //查询到的bug总数
        }
      },
      methods: {
        //绑定到选择日期类型组件下的change事件,每次切换日期类型,就触发这个事件,进而触发请求
        switch_date_type(type) {
          
    
        },
    
        //绑定到选择项目组件下的change事件,每次切换项目,就触发这个事件,进而触发请求
        switch_project(project_code) {
          
    
        },
        get_histogram(value) {
    
        },
    
      }
    }
    </script>

    2、添加echarts柱状图代码:

    为了方便管理,我单独创建了一个vue文件来存放echarts相关的代码,创建文件histogram.vue

    从echarts官网中找到一个柱状图&折线图混合的例子,去掉一些不需要的字段,代码如下

    <template>
    
    </template>
    
    <script>
    import * as echarts from 'echarts';
    
    export default {
    
      methods: {
        histogram_statistics(data, x_data) {
          let chartDom = document.getElementById('histogram');
          // console.log(chartDom)
          let myChart = echarts.init(chartDom);
          let option;
    
          option = {
            grid:{  //折线图在当前容器的位置调整
              x:50, //左侧距离左边的距离
              y:50,  //顶部最高点距离顶部的位置
              x2:80, // 右侧距离右侧的距离
              y2:40,  //距离底部距离
              borderWidth:1
            },
            title: {
              text: 'bug汇总',
              // subtext: 'Living Expenses in Shenzhen'
              top: '5%', // 距离顶部位置
              left: 'center',
              textStyle: {
                fontSize: 15,
                fontWeight: 'bold',
                color: '#464646'
    
              }
            },
            tooltip: {
              trigger: 'axis',
              axisPointer: {
                type: 'cross',
                crossStyle: {
                  color: '#999'
                }
              }
            },
            toolbox: {
              feature: {
                // dataView: { show: true, readOnly: false },// 数据视图按钮
                // magicType: { show: true, type: ['line', 'bar'] }, //切换图形按钮
                // restore: { show: true },  //刷新按钮
                // saveAsImage: { show: true } //下载图片按钮
              }
            },
            // legend: {
            //   data: ['Evaporation', 'Precipitation', 'Temperature']
            // },
            xAxis: [
              {
                type: 'category',
                data: x_data, // ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
                axisPointer: {
                  type: 'shadow'
                }
              }
            ],
            yAxis: [
              {
                type: 'value',
                // name: '数量',
                // min: 0,
                // max: 250,
                interval: 10,  //y轴间隔数
                axisLabel: {
                  formatter: '{value} 个'
                }
              }
            ],
            series: [
              {
                // name: 'Evaporation',
                type: 'bar',
                itemStyle:{
                  // color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc']
                  normal:{
                    color:'#5470c6'  // 调整柱子的颜色
                  }
                },
                tooltip: {
                  show: true, //设置是否显示提示信息
                  // valueFormatter: function (value) {
                  //   return value + '';
                  // }
                },
                data: data//[2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6]
              },
    
              {
                // name: 'Temperature',
                type: 'line',
                itemStyle:{
                  color: '#91cc75'  // 调整折线的颜色
                },
                tooltip: {
                  show: false,
                // valueFormatter: function (value) {
                //   return value + ' °C';
                // }
                },
                data: data // [2.0, 4.9, 7.0, 23.2, 25.6, 76.7, 135.6]
              }
            ]
          };
    
          option && myChart.setOption(option);
    
    
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>

    代码说明:

    这里新增了一个方法histogram_statistics(),里面存放柱状图echarts相关代码

    方法有2个参数:data--纵轴数据、x_data--横轴数据,它俩被echarts中对应的字段接收

    数据格式为:[value1, value2, value3, value4, value5, value6]

    到时候传数据时需要转换为这种形式

    有这样一行代码let chartDom = document.getElementById('histogram');

    这个histogram代表div标签的id属性值,到时候图表会渲染到这个div容器中,记得在页面中添加这样一个div标签

    3、后端处理逻辑

    后端主要实现从jira取数并处理的逻辑

    (1)提取jira数据

    新建一个文件jira_data.py

    from jira import JIRA
    from collections import Counter
    
    class JiraData:
        def __init__(self):
            self.jira = JIRA(server='http://jira.xxx.xxx/', basic_auth=('user', 'password'))
    
    
        def get_bug(self, project, start_date, end_date, class_type):
            """
            以时间维度获取项目的bug信息
            :param project:
            :param start_date:
            :param end_date:
            :param class_type:
            :return:
            """
            try:
                jql = "project in ({}) AND issuetype = 缺陷 AND created >= {} AND created <= {}".format(project, start_date,
                                                                                                      end_date)
                print("打印正在执行的jql:", jql)
                issues = self.jira.search_issues(jql, fields="summary, priority, status, creator, created, customfield_11200", maxResults=-1)
    
                result = []
                for i in issues:
                    # print(type(i.fields.status))
                    # result.append(i.fields.status)
                    # print(i.raw["fields"]["priority"]["name"])
                    # print(i.raw["fields"]["status"]["name"])
                    # print(i.raw["fields"]["created"])
    
                    if class_type == "priority":  # 按优先级统计
                        result.append(i.raw["fields"]["priority"]["name"])
    
                    elif class_type == "status":  # 按bug状态统计
                        result.append(i.raw["fields"]["status"]["name"])
    
                    elif class_type == "creator":  # 按创建者统计
                        result.append(i.raw["fields"]["creator"]["name"])
    
                    elif class_type == "created":  # 按创建日期统计
                        result.append(i.raw["fields"]["created"].split("T")[0])  # 截取年月日部分
                # print(result)
                temp = Counter(result)  # 汇总每个级别的数量
                # print(temp)
                # print(temp["中"])
                # print(dict(temp))  # 使用dict方法将结果转为字典
                temp_sum = sum(temp.values())  # 对temp中的value求和
                # print(temp_sum)
                bug_data = dict(temp)
                # print(bug_data)  # 形式 {'中': 164, '低': 74, '建议': 9, '最高': 4, '高': 34}
    
                res = {
                    "bug_data": bug_data,
                    "sum": temp_sum
                }
                return res
    
            except Exception as e:
                raise e

    代码说明:

    ① 定义了一个方法get_bug(),它需要4个参数:project, start_date, end_date, class_type

    其中project, start_date, end_date需要传递到jql中,查询jira相关数据

    class_type这个参数我用来汇总不同维度的数据,例如按照bug优先级汇总、按照bug状态汇总、按照bug创建者汇总、按照bug创建日期汇总等

    本次柱状图是从时间维度统计,所以调用这个方法时,会把class_type设置为"created"

    ②在提取jira数据时,我事先定义了一个空列表result,然后遍历issues,向result中追加数据

                result = []
                for i in issues:
    
                    if class_type == "priority":  # 按优先级统计
                        result.append(i.raw["fields"]["priority"]["name"])
    
                    elif class_type == "status":  # 按bug状态统计
                        result.append(i.raw["fields"]["status"]["name"])
    
                    elif class_type == "creator":  # 按创建者统计
                        result.append(i.raw["fields"]["creator"]["name"])
    
                    elif class_type == "created":  # 按创建日期统计
                        result.append(i.raw["fields"]["created"].split("T")[0])

    class_type =="created"时打印一下result的结果,如下,会把每个bug的创建日期追加到列表中

    ['2022-03-24', '2022-03-23', '2022-03-23', '2022-03-23', '2022-03-23', '2022-03-23', '2022-03-23', '2022-03-23', '2022-03-23', '2022-03-23', '2022-03-23']

    因为我的目的是统计每天有多少个bug,观察上面的列表:一个日期代表一个bug,相同日期就代表这几个bug的创建日期都是这一天,所以我们就可以直接按照日期进行汇总

    python中有一个库可以很方便的统计一个列表中的元素出现的次数:collections.Counter

    temp = Counter(result)  # 汇总每个级别的数量

    打印temp的结果

    Counter({'2022-03-23': 10, '2022-03-24': 1})

    此时不能直接用它,需要进一步转换为字典

    bug_data = dict(temp)

    结果如下

    {'2022-03-24': 1, '2022-03-23': 10}

    如果要统计查询结果总数,可以使用sum函数来求和

    temp_sum = sum(temp.values())  # 对temp中的value求和

    (2)编写接口,给前端返回数据

    新建一个视图文件jira_data_views.py

    在这里面我定义了4个视图函数,分别完成:按日查询、按周查询、按月查询、按年查询

    from django.http import JsonResponse
    from app.api.jira_data import JiraData
    from dateutil.relativedelta import relativedelta
    import pandas as pd
    
    class JiraSprintData:
        def __init__(self):
            self.jira = JiraData()

    按日查询

    def bug_day_data(request):
        """
        柱状图,按照日期范围查询
        :param request:
        :return:
        """
        sd = JiraSprintData()
    
        project = request.GET.get("project")
        start_date = request.GET.get("start_date")
        end_date = request.GET.get("end_date")
    
        # 从jira查到的日期-bug列表
        bug = sd.jira.get_bug(project=project, start_date=start_date, end_date=end_date, class_type="created")
    
        start_date_to_datetime = datetime.datetime.strptime(start_date, "%Y-%m-%d")  # 把从前端获取的起始月份转为datetime对象
        end_date_to_datetime = datetime.datetime.strptime(end_date, "%Y-%m-%d")
        # print(start_date_to_datetime)
        date_poor = (end_date_to_datetime - start_date_to_datetime).days  # 计算收尾日期差
        # print(date_poor)
        
        dates = []  # 定义一个日期范围列表
        for i in range(date_poor + 1):
            temp = start_date_to_datetime + datetime.timedelta(days=i)  # 从起始日期开始,依次把日期追加到列表中
            dates.append(temp.strftime("%Y-%m-%d"))
        # print(dates)
    
        result = []  # 定义一个最终结果列表
        for j in dates:  # 遍历日期范围列表
            if j in bug["bug_data"]:
                # 如果一个日期在bug列表中,说明这个日期有值,取bug字典中该日期的值赋给bug_num,同时date取当前日期,组合为一个字典
                result.append({"date": j, "bug_num": bug["bug_data"][j]})
            else:
                # 否则这个日期对应的bug_num=0
                result.append({"date": j, "bug_num": 0})
        # print(result)
    
        res = {
            "code": "200",
            "bug_data": result,
            "sum": bug["sum"]
        }
    
        return JsonResponse(res, json_dumps_params={'ensure_ascii': False})

    代码说明:

    start_date_to_datetime是从前端读取的开始日期

    end_date_to_datetime是从前端读取的结束日期

    dates是一个日期范围列表,它记录了从开始日期到结束日期这个范围内的每一天的日期

    result是最终返回的结果,它由一个个小的字典构成,即每个日期对应的bug数,具体可以看下注释

    同理可以写出按周查询、按月查询、按年查询的视图函数

    按周查询

    def bug_week_data(request):
        """
        柱状图,按照周查询
        :param request:
        :return:
        """
        sd = JiraSprintData()
    
        project = request.GET.get("project")
        start_date = request.GET.get("date")
    
        start_date_to_datetime = datetime.datetime.strptime(start_date, "%Y-%m-%d")  # 把从前端获取的起始月份转为datetime对象
        end_date = None
        dates = []  # 定义一个日期范围列表
        for i in range(7):
            temp = start_date_to_datetime + datetime.timedelta(days=i)  # 从起始日期开始,依次把日期追加到列表中
            dates.append(temp.strftime("%Y-%m-%d"))
            if i == 6:
                end_date = temp.strftime("%Y-%m-%d")  # 结束日期,即开始日期往后推6天
        # print(dates)
    
        bug = sd.jira.get_bug(project=project, start_date=start_date, end_date=end_date, class_type="created")
    
        result = []  # 定义一个最终结果列表
        for j in dates:  # 遍历日期范围列表
            if j in bug["bug_data"]:
                # 如果一个日期在bug列表中,说明这个日期有值,取bug字典中该日期的值赋给bug_num,同时date取当前日期,组合为一个字典
                result.append({"date": j, "bug_num": bug["bug_data"][j]})
            else:
                # 否则这个日期对应的bug_num=0
                result.append({"date": j, "bug_num": 0})
        # print(result)
    
        res = {
            "code": "200",
            "bug_data": result,
            "sum": bug["sum"]
        }
    
        return JsonResponse(res, json_dumps_params={'ensure_ascii': False})

    按月查询

    def bug_month_data(request):
        """
        柱状图,按照月查询
        :return:
        """
    
        sd = JiraSprintData()
    
        project = request.GET.get("project")
        start_date = request.GET.get("date")  # 获取前端传来的起始日期(每个月的1号)
        start_date_to_datetime = datetime.datetime.strptime(start_date, "%Y-%m-%d")  # 把从前端获取的起始月份转为datetime对象
    
        # 先通过开始日期得到下个月1号,再往前倒1天,得到本月最后一天
        end_date_to_datetime = start_date_to_datetime + relativedelta(months=1) + datetime.timedelta(days=-1)
    
        end_date = end_date_to_datetime.strftime("%Y-%m-%d")  # 把结束日期转为字符串
    
        # print(end_date_to_datetime)
        date_poor = (end_date_to_datetime - start_date_to_datetime).days  # 计算收尾日期差
    
        # 从jira查到的日期-bug列表
        bug = sd.jira.get_bug(project=project, start_date=start_date, end_date=end_date, class_type="created")
    
        dates = []  # 定义一个日期范围列表
    
        for i in range(date_poor + 1):
            temp = start_date_to_datetime + datetime.timedelta(days=i)  # 从起始日期开始,依次把日期追加到列表中
            dates.append(temp.strftime("%Y-%m-%d"))
        # print(dates)
    
        result = []  # 定义一个最终结果列表
        for j in dates:  # 遍历日期范围列表
            if j in bug["bug_data"]:
                # 如果一个日期在bug列表中,说明这个日期有值,取bug字典中该日期的值赋给bug_num,同时date取当前日期,组合为一个字典
                result.append({"date": j, "bug_num": bug["bug_data"][j]})
            else:
                # 否则这个日期对应的bug_num=0
                result.append({"date": j, "bug_num": 0})
        # print(result)
    
        res = {
            "code": "200",
            "bug_data": result,
            "sum": bug["sum"]
        }
    
        return JsonResponse(res, json_dumps_params={'ensure_ascii': False})

    按年查询

    def bug_year_data(request):
        """
        柱状图,按照年查询
        :return:
        """
    
        sd = JiraSprintData()
    
        project = request.GET.get("project")
        start_date = request.GET.get("date")  # 获取前端传来的起始日期(每年的1月1号)
    
        start_date_to_datetime = datetime.datetime.strptime(start_date, "%Y-%m-%d")  # 把从前端获取的起始月份转为datetime对象
    
        end_date_to_datetime = datetime.datetime(start_date_to_datetime.year, 12, 31)  # 传入年份的最后一天
    
        # print(end_date_to_datetime)
        end_date = end_date_to_datetime.strftime("%Y-%m-%d")  # 把结束日期转为字符串
    
        # 从jira查到的日期-bug数据
        bug = sd.jira.get_bug(project=project, start_date=start_date, end_date=end_date, class_type="created")
    
        # print(bug.get("bug_data"))
    
        temp_date_list = list(bug.get("bug_data").keys())  # 取字典的所有key,并转成一个列表
        date_list = [i[0:7] for i in temp_date_list]  # 只取key的前6位,如2022-01
        # print(date_list)
    
        value_list = list(bug.get("bug_data").values())  # 取字典所有的value,并转成一个列表
        # print(value_list)
    
        df = pd.DataFrame(data={'date': date_list, 'value': value_list})  # 利用pandas处理日期列表和value列表
        # print(df)
        # 利用groupby分,以日期为维度进行分组聚合;,groupby()之后,使用sum对相同元素求和 <class 'pandas.core.frame.DataFrame'>
        temp = df.groupby('date', as_index=True).sum()
        # print(temp)
    
        bugs = temp.to_dict()["value"]
        # 也可以使用 json.loads(temp.to_json())["value"]
        # temp.to_json()的值 {"value":{"2021-08":131,"2021-09":54,"2021-10":8,"2021-11":10,"2021-12":15}}
        # print(type(temp.to_json()))  # <class 'str'>
        # 因为temp.to_json()为json格式字符串,需要转为python字典对象才能使用键访问值,使用json.loads转换
        # print(bugs)
    
        dates = []  # 定一个空的日期列表,存放每年的1~12月,形式:[2022-01,2022-02, ...]
        for i in range(12):
            next_month = start_date_to_datetime + relativedelta(months=i)  # 从起始日期开始,计算下一个月
            dates.append(next_month.strftime("%Y-%m"))
        # print(dates)
    
        result = []  # 定义一个最终结果列表
        for j in dates:  # 遍历日期范围列表
            if j in bugs:
                # 如果一个日期在bug列表中,说明这个日期有值,取bug字典中该日期的值赋给bug_num,同时date取当前日期,组合为一个字典
                result.append({"date": j, "bug_num": bugs[j]})
            else:
                # 否则这个日期对应的bug_num=0
                result.append({"date": j, "bug_num": 0})
        # print(result)
    
        res = {
            "code": "200",
            "bug_data": result,
            "sum": bug["sum"]
        }
    
        return JsonResponse(res, json_dumps_params={'ensure_ascii': False})

    代码说明:

    按周查询和按月查询这两个的处理方式和按日查询类似,因为它们的横轴都具体到某一天

    只要拿到开始日期,就能计算得到结束日期,具体过程可以看注释,注释写的很详细

    按年查询有一点区别,我希望按年查询时,横轴是一年的12个月份

    由于从jira查询到的bug数据是具体到某一天的,所以得到1年365天的bug数据后,需要对它们进行聚合,以月份进行分组求和

    这就很麻烦了,想了很久才找到解决方法,步骤如下

    从jira提取bug数据后,把日期和bug数分别存到一个列表中,对日期列表进行切割,只保留到月份

    temp_date_list = list(bug.get("bug_data").keys())  # 取字典的所有key,并转成一个列表
    date_list = [i[0:7] for i in temp_date_list]  # 只取key的前6位,如2022-01
    
    value_list = list(bug.get("bug_data").values())  # 取字典所有的value,并转成一个列表

    这样就得到了2组数据,一组日期列表,日期只到月份;一组bug数量列表

    利用pandas对上面2个列表数据进行聚合

    df = pd.DataFrame(data={'date': date_list, 'value': value_list})  # 利用pandas处理日期列表和value列表
    # print(df)
    # 利用groupby分,以日期为维度进行分组聚合;,groupby()之后,使用sum对相同元素求和 <class 'pandas.core.frame.DataFrame'>
    temp = df.groupby('date', as_index=True).sum()
    # print(temp)
    
    bugs = temp.to_dict()["value"]

    最终bugs结果如下

    {'2021-08': 131, '2021-09': 54, '2021-10': 8, '2021-11': 10, '2021-12': 15}

    接口定义好后,需要配置路由,这里就不赘述了

    4、前端发送请求,渲染数据

    后端定义好接口后,前端需要调用接口,接收数据并渲染到前端,打开jira_data.vue

    首先完善get_histogram方法

    get_histogram(value) {
          let url = this.COMMON.uat_url
          // console.log(value)  //打印value的值,这里value是指日期组件的值
          // console.log(value.length)
          // console.log(this.date_type)  //打印此时的date_type
          if (this.date_type === "day") {
    
            if (value != null) {
              console.log("起始日期:", value[0])
              console.log("结束日期:", value[1])
              // console.log(this.day_value)  // 因为这个函数用change事件绑定了,所以这个函数传的值val=day_value的值
    
              this.$http.get(
                  url+"/data_factory/bug_day_data",
                  {
                    timeout: 10000,
                    params:{
                      start_date: value[0],
                      end_date: value[1],
                      project: this.project_code,
                    }
                  }).then(response =>{
                // this.data = JSON.stringify(response.data, null, 2);  //格式化显示响应内容
                if(response.data.code === "200"){
                  // console.log(response.data.bug_data)
                  this.day_range_sum = response.data.sum
    
                  let data = response.data.bug_data  //提取返回结果中的bug_data数据
                  let x_data = data.map(x => x.date)  //利用map方法提取列表中每个字典的date值
                  let y_data = data.map(x => x.bug_num)  //利用map方法提取列表中每个字典的bug_num值
    
                  this.$refs.histogram_pic.histogram_statistics(y_data, x_data)  //调用histogram_pic方法,传入y轴数据和x轴数据(须使用$refs.histogram_pic形势调用)
    
                  this.$message({
                    message: "请求成功",
                    type: 'success'
                  });
                }
                else{
                  this.$message({
                    message: "请求失败",
                    type: ' warning'
                  });
                  console.log(response.data)
                }
              }).catch((reason)=>{
                console.log(reason)
                this.$message({
                  message: '接口调用失败,请检查系统是否正常',
                  type: 'warning'
                });
              })
            }
    
          }
          else if(this.date_type === "week") {
            this.$http.get(
                url+"/data_factory/bug_week_data",
                {
                  timeout: 10000,
                  params:{
                    date: value,
                    project: this.project_code,
                  }
                }).then(response =>{
              // this.data = JSON.stringify(response.data, null, 2);  //格式化显示响应内容
              if(response.data.code === "200"){
                // console.log(response.data.bug_data)
                this.day_range_sum = response.data.sum
    
                let data = response.data.bug_data  //提取返回结果中的bug_data数据
                let x_data = data.map(x => x.date)  //利用map方法提取列表中每个字典的date值
                let y_data = data.map(x => x.bug_num)  //利用map方法提取列表中每个字典的bug_num值
    
                this.$refs.histogram_pic.histogram_statistics(y_data, x_data)  //调用histogram_pic方法,传入y轴数据和x轴数据(须使用$refs.histogram_pic形势调用)
    
                this.$message({
                  message: "请求成功",
                  type: 'success'
                });
              }
              else{
                this.$message({
                  message: "请求失败",
                  type: 'warning'
                });
                console.log(response.data)
              }
            }).catch((reason)=>{
              console.log(reason)
              this.$message({
                message: '接口调用失败,请检查系统是否正常',
                type: 'warning'
              });
            })
    
          }
          else if(this.date_type === "month") {
            this.$http.get(
                url+"/data_factory/bug_month_data",
                {
                  timeout: 10000,
                  params:{
                    date: value,
                    project: this.project_code,
                  }
                }).then(response =>{
              // this.data = JSON.stringify(response.data, null, 2);  //格式化显示响应内容
              if(response.data.code === "200"){
                // console.log(response.data.bug_data)
                this.day_range_sum = response.data.sum
    
                let data = response.data.bug_data  //提取返回结果中的bug_data数据
                let x_data = data.map(x => x.date)  //利用map方法提取列表中每个字典的date值
                let y_data = data.map(x => x.bug_num)  //利用map方法提取列表中每个字典的bug_num值
    
                this.$refs.histogram_pic.histogram_statistics(y_data, x_data)  //调用histogram_pic方法,传入y轴数据和x轴数据(须使用$refs.histogram_pic形势调用)
    
                // console.log(x_data)
                // console.log(y_data)
    
                this.$message({
                  message: "请求成功",
                  type: 'success'
                });
              }
              else{
                this.$message({
                  message: "请求失败",
                  type: 'warning'
                });
                console.log(response.data)
              }
            }).catch((reason)=>{
              console.log(reason)
              this.$message({
                message: '接口调用失败,请检查系统是否正常',
                type: 'warning'
              });
            })
    
          }
          else if(this.date_type === "year") {
            this.$http.get(
                url+"/data_factory/bug_year_data",
                {
                  timeout: 10000,
                  params:{
                    date: value,
                    project: this.project_code,
                  }
                }).then(response =>{
              // this.data = JSON.stringify(response.data, null, 2);  //格式化显示响应内容
              if(response.data.code === "200"){
                // console.log(response.data.bug_data)
                this.day_range_sum = response.data.sum
    
                let data = response.data.bug_data  //提取返回结果中的bug_data数据
                let x_data = data.map(x => x.date)  //利用map方法提取列表中每个字典的date值
                let y_data = data.map(x => x.bug_num)  //利用map方法提取列表中每个字典的bug_num值
                //
                this.$refs.histogram_pic.histogram_statistics(y_data, x_data)  //调用histogram_pic方法,传入y轴数据和x轴数据(须使用$refs.histogram_pic形势调用)
    
                this.$message({
                  message: "接口调用成功",
                  type: 'success'
                });
              }
              else{
                this.$message({
                  message: "接口调用失败",
                  type: 'warning'
                });
                console.log(response.data)
              }
            }).catch((reason)=>{
              console.log(reason)
              this.$message({
                message: '接口调用失败,请检查系统是否正常',
                type: 'warning'
              });
            })
    
          }
        },

    代码说明:

    在这个方法中需要做2件事情:

    • 调用后台接口请求数据;
    • 拿到数据后,调用柱状图方法 histogram_statistics(),把数据传进来

    首先需要把histogram.vue这个组件导进来

    import Histogram from './histogram.vue'
    
    // console.log(Histogram)
    
    export default {
      components: {
        Histogram
      },

    然后声明这个组件

    这里我定义了一个div,id属性位histogram(所以这个柱状图最终会渲染到这个容器中)

    <div id="histogram" style="margin-top: 30px;margin-bottom: 20px;  100%;height:500px;display:flex;justify-content:center">
      <Histogram ref="histogram_pic"></Histogram>  <!--使用ref定义一个变量接收组件-->
    </div>

    如果想引用histogram.vue中的方法,在这里需要用ref属性接收,ref的值可以自己定义

    最后调用histogram.vue中的方法时,按照如下方式

    this.$refs.histogram_pic.histogram_statistics(y_data, x_data)  //调用histogram_pic方法,传入y轴数据和x轴数据(须使用$refs.histogram_pic形式调用)

    完善switch_date_type方法

    这里我加了一点逻辑,每次切换日期为度时,给对应日期组件加一个默认日期

    //绑定到选择日期类型组件下的change事件,每次切换日期类型,就触发这个事件,进而触发请求
        switch_date_type(type) {
          if (type === "week"){
            // console.log(type)
            let now = new Date()  //当前时间 Tue Mar 29 2022 18:42:01 GMT+0800 (中国标准时间)
            // now.setDate(now.getDate()+5)  // 把当前时间往后延期5天
            // console.log("打印now", now)
            let nowTime = now.getTime()  //当前时间时间戳
            // console.log("打印nowTime", nowTime)
            let day = now.getDay() || 7;  //获取当前星期几,例如星期二,则结果为2,星期天为 0, 星期一为 1;
            // 只要“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值。只要“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值
            // 所以当周日时,now.getDay()=0,为false,所以取后面的值7
            // 一定要这样处理,不然下面的MondayTime会取到下周一,而不是本周一。
            // console.log("打印day", day)
            let oneDayTime = 24*60*60*1000
            let MondayTime = nowTime - (day-1)*oneDayTime ;  //计算得到本周周一(当前时间减去距离周一的日期差)
            // console.log(MondayTime)  //此时还是时间戳格式
            // console.log(new Date(MondayTime))  //转为日期格式
            let Monday_date = new Date(MondayTime)
            // console.log("打印字符串格式的Monday", Monday)
            this.week_value = Monday_date.getFullYear()+'-'+(Monday_date.getMonth()+1)+'-'+Monday_date.getDate()  //给week_value赋值本周周一的字符串
            this.get_histogram(this.week_value)  // 调用get_histogram方法(这样的话切换到按周查询时,会触发请求)
          }
          else if (type === "day") {
            this.get_histogram(this.day_value)
          }
          else if (type === "month") {
            let now = new Date(), y = now.getFullYear(), m = now.getMonth()
            let first_day = new Date(y, m, 1);  //当前月第一天
            // let last_day = new Date(y, m+1, 0)  // 当前月最后1天,注意需要把m+1,不然获取到的是上个月最后1天
            // console.log(y)
            // console.log(m)  // 0代表1月,11代表12月
            // console.log(now.getDate())
            console.log("本月第一天", first_day)
            // console.log(last_day)
            this.month_value = first_day.getFullYear()+'-'+(first_day.getMonth()+1)+'-'+first_day.getDate()
            this.get_histogram(this.month_value)
          }
    
          else if (type === "year") {
            let now = new Date(); //当前日期
            let currentYear=now.getFullYear();//获得当前年份4位年
            let currentYearFirstDate=new Date(currentYear,0,1); //本年第一天
            // console.log(currentYearFirstDate)
            // this.year_value = currentYearFirstDate.getFullYear()+'-'+(currentYearFirstDate.getMonth()+1)+'-'+currentYearFirstDate.getDate()
            this.year_value = currentYear + '-' + '01' + '-' + '01'  //也可以用这种方式获取本年第一天的字符串形式
            console.log(this.year_value)
            this.get_histogram(this.year_value)
          }
    
        },

    完善 switch_project方法

    //绑定到选择项目组件下的change事件,每次切换项目,就触发这个事件,进而触发请求
        switch_project(project_code) {
          // console.log("打印当前change事件的传参:", project_code)
          // console.log("打印this.project_code:", this.project_code)
          if (this.date_type === "week") {
            this.get_histogram(this.week_value)
          }
          else if (this.date_type === "day") {
            this.get_histogram(this.day_value)
          }
          else if (this.date_type === "month") {
            this.get_histogram(this.month_value)
          }
          else if (this.date_type === "year") {
            this.get_histogram(this.year_value)
          }
    
        },

    最后还有一个功能:刷新页面后触发请求

    定义一个方法refresh_page()

    因为日期类型那里,我给定的默认值为"day"

    所以在这个方法中,给日期范围赋一个初始值,这样每次刷新页面,日期组件就能得到初始范围

        // 定义一个方法,实现给定日期范围默认值,触发请求
        refresh_page() {
          if (this.date_type === "day") {
            let end = new Date();
            let start = new Date();
            start.setTime(start.getTime() - 60* 60 * 24 * 6 * 1000);  // 当前日期往前倒7天
            start = start.getFullYear()+'-'+(start.getMonth()+1)+'-'+start.getDate() // 转换为"年-月-日"
            end = end.getFullYear()+'-'+(end.getMonth()+1)+'-'+end.getDate()
            this.day_value = [start, end]  //给day_value赋默认值,默认选中最近7天
            // console.log(this.day_value)
            this.get_histogram(this.day_value)  // 打开菜单或刷新,默认显示最近7天的数据
          }
        }

    添加生命周期函数created(),在里面调用refresh_page()即可

      created() {
        this.refresh_page()  // 在生命周期函数中created中调用refresh_page,实现刷新页面触发请求
      }

    OK,这样就画好柱状图了

  • 相关阅读:
    解决:信息中插入avi格式的视频时,提示“unsupported video format”
    java字节数组和16进制之间的转换
    16进制转换字节数组工具类
    如何在ubuntu 12.04 中安装经典的 GNOME桌面
    Ubuntu安装软件提示”需要安装不能信任的软件包”解决办法
    Ubuntu系统下运行Eclipse出现找不到jre的问题的解决方法
    ubuntu添加共享出错
    从scrapy使用经历说开来
    有趣的问题--12 coins problem
    一个奇怪的MySQL错误返回
  • 原文地址:https://www.cnblogs.com/hanmk/p/16115513.html
Copyright © 2020-2023  润新知