随着B/S大行其道,Web端急需一个兼容绝大部分浏览器,直观,生动,可交互,可高度个性化定制的数据可视化图开发库。百度公司可能听到了众多程序猿的心声,速速开放、贡献出了echarts。echarts是纯JavaScript的图表库,可绘制折线图、柱状图、散点图、K线图、饼图、雷达图、地图、仪表盘、漏斗图等美丽、大气的图表。
尽管echarts好用,漂亮,但在生成图表时,经常需要做繁琐的数据类型转化、修改复杂的配置项。有家企业实在看不下去了,就对 Vue2.0 和 echarts 进行了封装,形成了 v-charts 图表组件。
使用v-charts只需要统一提供一种对前后端都友好的数据格式设置简单的配置项,便可轻松生成常见的图表。
45.1 v-charts安装
要想获得v-charts的支持,可通过npm进行安装。
npm i v-charts echarts -S
也可以通过cdn进行引入,其中style.min.css是可选项。
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/v-charts/lib/index.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/v-charts/lib/style.min.css">
详细用法,可参考官网https://v-charts.js.org/#/上的教程。为了方便,咱就使用cdn引入的方式。
45.2 数据分析
不用说你也应该知道,在templates/admin下创建的模板名称应该叫sale_sum.html,
如果真的不知道,往上仔细阅读admin.py中,SaleSumAdmin类的代码。如果知道,那就把templates/admin/change_list.html里的代码拷贝出来,粘贴到sale_sum.html中。
进行乾坤大挪移,移形换影后的代码如下。只知道引进了3个js文件并没多大意义,关键是要阅读并理解new Vue(…)里面的代码,因为那才是你想要的"财富"。
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static admin_list %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% static "admin/css/changelists.css" %}?_=20180905"/>
{# <link rel="stylesheet" type="text/css" href="{% static "admin/simpleui/layui/css/layui.css" %}"/>#}
{% if cl.formset %}
<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}"/>
{% endif %}
{% if cl.formset or action_form %}
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/v-charts/lib/index.min.js"></script>
{% endif %}
{{ media.css }}
{% if not actions_on_top and not actions_on_bottom %}
<style>
#changelist table thead th:first-child {
width: inherit
}
</style>
{% endif %}
{% endblock %}
{% block extrahead %}
{{ block.super }}
{{ media.js }}
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} change-list{% endblock %}
{% if not is_popup %}
{% block breadcrumbs %}
<div>
<a href="{% url 'admin:index' %}">{% trans 'Home' %}</a>
› <a
href="{% url 'admin:app_list' app_label=cl.opts.app_label %}">{{ cl.opts.app_config.verbose_name }}</a>
› {{ cl.opts.verbose_name_plural|capfirst }}
</div>
{% endblock %}
{% endif %}
{% block coltype %}flex{% endblock %}
{% block content_title %}
{% endblock %}
{% block content %}
<style>
#content {
position: relative;
}
.object-tools {
position: absolute;
top: 16px;
right: 20px;
height: 50px;
z-index: 2;
}
.object-tools .import_link, .object-tools .export_link {
color: white !important;
}
</style>
{% block object-tools %}
<ul>
{% block object-tools-items %}
{% if has_add_permission %}
{{ block.super }}
{% endif %}
{% endblock %}
</ul>
{% endblock %}
<div id="content-main">
{% if cl.formset.errors %}
<p>
{% if cl.formset.total_error_count == 1 %}{% trans "Please correct the error below." %}{% else %}
{% trans "Please correct the errors below." %}{% endif %}
</p>
{{ cl.formset.non_form_errors }}
{% endif %}
<div class="module{% if cl.has_filters %} filtered{% endif %}" id="changelist">
{% block search %}{% search_form cl %}{% endblock %}
{% block date_hierarchy %}{% date_hierarchy cl %}{% endblock %}
<div id="app" style="margin-top: 10px;margin-left: 5px">
<ve-histogram :data="chartData" :mark-point="markPoint" :extend="chartExtend" :colors="colors">
</ve-histogram>
</div>
</div>
</div>
<script>
new Vue({
el: '#app',
data: function () {
this.chartExtend = {
title: {
text: '{{ bar_title }}售业绩统计报表',
subtext: '{{ subtext }}',
},
}
this.markPoint = {
data : [
{type : 'max', name: '最大值'},
{type : 'min', name: '最小值'}
]
}
return {
colors: ['#c23531','#2f4554'],
chartData: {
columns: ['日期', '销售目标(万元)', '实际销售额(万元)'],
rows: [
{% if task %}
{ '日期': '1月', '销售目标(万元)': {{ task.Jan_task }} ,'实际销售额(万元)': {{ task.Jan_sale }}},
{ '日期': '2月', '销售目标(万元)': {{ task.Feb_task }} ,'实际销售额(万元)': {{ task.Feb_sale }}},
{ '日期': '3月', '销售目标(万元)': {{ task.Mar_task }} ,'实际销售额(万元)': {{ task.Mar_sale }}},
{ '日期': '4月', '销售目标(万元)': {{ task.Apr_task }} ,'实际销售额(万元)': {{ task.Apr_sale }}},
{ '日期': '5月', '销售目标(万元)': {{ task.May_task }} ,'实际销售额(万元)': {{ task.May_sale }}},
{ '日期': '6月', '销售目标(万元)': {{ task.Jun_task }} ,'实际销售额(万元)': {{ task.Jun_sale }}},
{ '日期': '7月', '销售目标(万元)': {{ task.Jul_task }} ,'实际销售额(万元)': {{ task.Jul_sale }}},
{ '日期': '8月', '销售目标(万元)': {{ task.Aug_task }} ,'实际销售额(万元)': {{ task.Aug_sale }}},
{ '日期': '9月', '销售目标(万元)': {{ task.Sep_task }} ,'实际销售额(万元)': {{ task.Sep_sale }}},
{ '日期': '10月', '销售目标(万元)': {{ task.Oct_task }} ,'实际销售额(万元)': {{ task.Oct_sale }}},
{ '日期': '11月', '销售目标(万元)': {{ task.Nov_task }} ,'实际销售额(万元)': {{ task.Nov_sale }}},
{ '日期': '12月', '销售目标(万元)': {{ task.Dec_task }} ,'实际销售额(万元)': {{ task.Dec_sale }}},
{% endif %}
]
},
dataEmpty: true
}
}
})
</script>
<script type="text/javascript">
$(".object-tools").hide().find('li a').each(function () {
_action.exts.push({
name:$(this).text(),
url:$(this).attr('href')
})
})
</script>
{% endblock %}
万万没想到,在ModelAdmin里,竟然可以自定义过滤器,可以覆盖模板,还可以调整查询方法。更让人惊喜的,连模板里的代码都是通过拷贝完成的。
不试不知道,一试吓一跳,本以为不可能实现的功能,原来都是可以做得到的。所以说编程还是要多尝试,多动手。
好了,关于销售管理系统用Django实现的内容,总算开发完成了,下一步就说一下关于系统上线的内容。