质量看板开发实践(三):bug柱状图
前面2章讲了如何从jira获取数据,知道怎样获取数据,就可以绘图了
本篇记录一下bug柱状图的实现过程
对于这个bug柱状图我大致想实现以下功能:
- 能够按照日期查询,同时可以切换不同日期维度:按年查询、按月查询、按周查询、自定义日期范围;
- 能够切换项目;
- 刷新当前页面,自动触发查询请求;
- 切换日期维度,自动触发查询请求;
- 切换项目,自动触发查询请求;
- 显示查询结果总数;
- 最好可以把柱状图和折线图结合起来;
最终的实现效果如下
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个视图函数,分别完成:按日查询、按周查询、按月查询、按年查询
按日查询
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; width: 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,这样就画好柱状图了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
2018-04-08 python爬虫学习(三):使用re库爬取"淘宝商品",并把结果写进txt文件