JS组件 + django hightcharts画折线图 饼图,柱状图
一,折线图
1.前端
<script src="{% static "plugin/highcharts/highcharts.js" %}"></script>
<div class="panel panel-default"> <div class="panel-heading"> <i class="fa fa-bar-chart" aria-hidden="true"></i> 新增问题趋势 </div> <div class="panel-body"> <div id="chart" style="width:100%;min-height:200px"></div> </div> </div>
<script> var init_chart_url = "{% url "issues_chart" project_id=request.tracer.project.id %}" $(function () { initChart(); }) Highcharts.setOptions({global:{ useUTC:false }}); function initChart() { var config = { title: { text: null }, subtitle: { text: null }, yAxis: { title: { text: '问题数量' } }, xAxis:{ type:"datetime", tickInterval:60*60*24*1000, labels:{ //轴标签格式化 formatter:function () { return Highcharts.dateFormat("%m-%d",this.value) }, rotation:-30 //旋转角度 } }, tooltip:{ //鼠标悬浮后提示 (数据提示框) headerFormat:"<b>{point.key}</b><br>", pointFormat:"<span style='{series.color}'>\u25CF</span> 数量:{point.y}", xDateFormat:"%Y-%m-%d", }, legend: { enabled:false }, credits: { enabled:false }, plotOptions: { area: { stacking: 'normal', lineColor: '#666666', lineWidth: 1, marker: { lineWidth: 1, lineColor: '#666666' } } }, series: [{ data:[] }], }; $.get( init_chart_url,{}, function (res) { config.series[0].data=res.data; var chart = Highcharts.chart('chart', config); } ); } </script>
2.后端
def issues_chart(request,project_id): """ 在概览页面生成highcharts所需的数据 """ # dict = { # "2020-3-5":[153651351,0], # "2020-3-5":[153651351,0], # } today = datetime.datetime.now().date() data_dict = {} for item in range(0,30): day = today - datetime.timedelta(days=item) data_dict[day.strftime("%Y-%m-%d")] = [time.mktime(day.timetuple()) * 1000,0] # mysql中 "DATE_FORMAT(web_transaction.create_datetime,'%%Y-%%m-%%d')" #sqlite中 ""strftime('%%Y-%%m-%%d',web_issues.create_datetime)"" result = models.Issues.objects.filter(project_id=project_id,create_time__gte=today-datetime.timedelta(days=30)).extra( select={"ctime":"strftime('%%Y-%%m-%%d',web_issues.create_time)"}).values("ctime").annotate(ct=Count("id")) for i in result: data_dict[i["ctime"]][1] = i["ct"] return JsonResponse({"status":True,"data":list(data_dict.values())})
二 饼图+柱状图
1.前端
<link rel="stylesheet" href="{% static 'plugin/daterangepicker/daterangepicker.css' %}"> <script src="{% static 'plugin/daterangepicker/moment.min.js' %}"></script> <script src="{% static 'plugin/daterangepicker/daterangepicker.js' %}"></script> <script src="{% static 'plugin/highcharts/highcharts.js' %}"></script>
<div class="container-fluid" style="margin-top: 20px;"> <div> <div class="input-group" style="width: 300px;"> <span class="input-group-addon">日期范围</span> <input id="rangePicker" type="text" class="form-control"> </div> </div> <div class="row" style="margin-top: 20px;"> <div class="col-md-8"> <div class="panel panel-default"> <div class="panel-heading"> <i class="fa fa-bar-chart" aria-hidden="true"></i> 人员工作进度 </div> <div class="panel-body"> <div id="projectUser" style="height: 300px;"></div> </div> </div> </div> <div class="col-md-4"> <div class="panel panel-default"> <div class="panel-heading"> <i class="fa fa-pie-chart" aria-hidden="true"></i> 优先级统计 </div> <div class="panel-body"> <div id="priority" style="height: 300px;"></div> </div> </div> </div> </div> </div>
<script> priority_api = "{% url "statistics_priority" project_id=request.tracer.project.id %}" projectUser_api = "{% url "statistics_projectUser" project_id=request.tracer.project.id %}" $(function () { initDateRangePicker(); priority(moment().format('YYYY-MM-DD'),moment().add(1,"days").format("YYYY-MM-DD")); projectUser(moment().format('YYYY-MM-DD'),moment().add(1,"days").format("YYYY-MM-DD")); }) function initDateRangePicker(){ var options = { maxDate: moment(), alwaysShowCalendars: true, showWeekNumbers: true, ranges: { '今天': [moment(), moment()], '昨天': [moment().subtract(1, 'days'), moment().subtract(1, 'days')], '最近7天': [moment().subtract(6, 'days'), moment()], '最近30天': [moment().subtract(29, 'days'), moment()], '本月': [moment().startOf('month'), moment().endOf('month')] }, locale: { format: 'YYYY-MM-DD', separator: ' 至 ', applyLabel: '确定', cancelLabel: '取消', fromLabel: '开始', toLabel: '结束', customRangeLabel: '自定义', weekLabel: 'W', daysOfWeek: ['一', '二', '三', '四', '五', '六', '日'], monthNames: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], firstDay: 1 } }; $('#rangePicker').daterangepicker(options, function (start, end, label) { // 选择了时间之后,函数自动被触发。 priority(start.format('YYYY-MM-DD'), end.add(1, 'days').format('YYYY-MM-DD')); projectUser(start.format('YYYY-MM-DD'), end.add(1, 'days').format('YYYY-MM-DD')); }); } function priority(start,end) { var config = { chart: { type: 'pie' }, title: { text: null }, tooltip: { pointFormat: '{series.name}: <b>{point.y}</b>' }, plotOptions: { pie: { allowPointSelect: true, cursor: 'pointer', dataLabels: { //关闭数据 折线标签 enabled: false, }, showInLegend: true //显示下方图例 } }, credits:{ enabled:false }, series: [{ name: '优先级', colorByPoint: true, data: [] }] } var chart = Highcharts.chart("priority",config); $.get(priority_api,{start:start,end:end},function (res) { config.series[0].data = res.data; Highcharts.chart("priority",config); }) } function projectUser(start,end) { var config = { chart: { type: 'column' }, title: { text: null }, credits:{ enabled:false }, xAxis: { categories: ['小张', '132', 'oo'] }, yAxis: { min: 0, title: { text: '问题数量' }, stackLabels: { // 堆叠数据标签 enabled: true, style: { fontWeight: 'bold', color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray' } } }, legend: { align: 'center', verticalAlign: 'top' }, tooltip: { formatter: function () { return '<b>' + this.x + '</b><br/>' + this.series.name + ': ' + this.y + '<br/>' + '总量: ' + this.point.stackTotal; } }, plotOptions: { column: { stacking: 'normal', dataLabels: { enabled:false } } }, series: [ { name: '新建', data: [5, 3, 4] }, {name: '处理中', data: [2, 9, 3,] }, ] }; $.get(projectUser_api,{start:start,end:end},function (res) { config.series = res.data.data; config.xAxis.categories = res.data.categories; Highcharts.chart("projectUser",config); }) } </script>
2.后端
from django.shortcuts import render,HttpResponse,redirect from django.http import JsonResponse from web import models from django.db.models import Count def statistics(request,project_id): return render(request,"statistics.html") def statistics_priority(request,project_id): ''' 优先级数据处理''' ''' 数据类型:第一种:data = [{name: '高', y: 0,}, ] 第二种:data = [ danger:{name:"高",y:0} warning:{name:"中",y:0} ] ''' start = request.GET.get("start") end = request.GET.get("end") data = {} for key,value in models.Issues.priority_choices: data[key] = {"name":value,"y":0} result = models.Issues.objects.filter(project_id=project_id,create_time__gte=start,create_time__lte=end).values("priority").annotate(ct=Count("id")) for item in result: data[item["priority"]]["y"] = item["ct"] return JsonResponse({"status":True,"data":list(data.values()) }) def statistics_projectUser(request,project_id): ''' :param request: :param project_id: :return: 需要返回的数据: 1. categories: ['小张', '132', 'oo'] 2: { name: '新建', data: [5, 3, 4] }, { name: '处理中', data: [2, 9, 3,] }, 构造data字典: 第一步:info = { 1:{ name:"武沛齐", status:{ 1:0, 2:1, 3:0, 4:0, 5:0, 6:0, 7:0, } }, None:{ name:"未指派", status:{ 1:0, 2:0, 3:1, 4:0, 5:0, 6:0, 7:0, } } } 第二部:data_result_dict = { 1:{name:新建,data:[0,0]}, 2:{name:处理中,data:[1,0]}, 3:{name:已解决,data:[0,1]}, 4:{name:已忽略,data:[]}, 5:{name:待反馈,data:[]}, 6:{name:已关闭,data:[]}, 7:{name:重新打开,data:[]}, } ''' start = request.GET.get("start") end = request.GET.get("end") # 1.所有项目成员 及 未指派 all_user_dict = {} # 未指派 all_user_dict[None] = { "name": "未指派", "status": {k: 0 for k, v in models.Issues.status_choices} } # 创建者 all_user_dict[request.tracer.project.creater.id] = { "name":request.tracer.project.creater.username, "status":{ k:0 for k,v in models.Issues.status_choices} } #参与者 project_user_list = models.ProjectUser.objects.filter(project_id=project_id) for item in project_user_list: all_user_dict[item.user.id] = { "name":item.user.username, "status":{k:0 for k,v in models.Issues.status_choices} } # 2、获取所有问题 issues_list = models.Issues.objects.filter(project_id=project_id,create_time__gte=start,create_time__lte=end) for item in issues_list: if item.assign: all_user_dict[item.assign_id]["status"][item.status] += 1 else: all_user_dict[None]["status"][item.status] += 1 # 3.获取所有成员列表 构造categories categories = [item["name"] for item in all_user_dict.values()] # 4 构造dict字典并返回 dict = {} # 4.1 构造一个符合结构的空字典 for k,v in models.Issues.status_choices: dict[k] = { "name":v, "data":[] } #4.2 填入数据 for k,v in models.Issues.status_choices: for item in all_user_dict.values(): dict[k]["data"].append(item["status"][k]) #返回数据 注意字典的values方法要用list()改成列表 content = { "categories":categories, "data":list(dict.values()), } return JsonResponse({"status": True, "data": content})