前面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个视图函数,分别完成:按日查询、按周查询、按月查询、按年查询
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; 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,这样就画好柱状图了