resuming views for stat
This commit is contained in:
commit
d19daa04b1
56 changed files with 1326 additions and 243 deletions
|
@ -8,7 +8,5 @@ from channels.routing import route, route_class
|
|||
from kfet import consumers
|
||||
|
||||
channel_routing = [
|
||||
route_class(consumers.KPsul, path=r"^/gestion/ws/k-fet/k-psul/$"),
|
||||
#route("websocket.connect", ws_kpsul_history_connect),
|
||||
#route('websocket.receive', ws_message)
|
||||
route_class(consumers.KPsul, path=r"^ws/k-fet/k-psul/$"),
|
||||
]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
{% extends 'kfet/base.html' %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}Informations sur l'article {{ article }}{% endblock %}
|
||||
{% block content-header-title %}Article - {{ article.name }}{% endblock %}
|
||||
|
@ -76,10 +77,69 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /row-->
|
||||
<h2>Statistiques</h2>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-6 nopadding">
|
||||
<div class="panel-md-margin">
|
||||
<h3>Ventes de {{ article.name }}</h3>
|
||||
<canvas id="myChart1" width="200" height="200"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-6 nopadding">
|
||||
<div class="panel-md-margin">
|
||||
<h3>Répartition des câlins</h3>
|
||||
<canvas id="myChart2" width="200" height="200"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /row -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_head %}
|
||||
<script src="{% static 'kfet/js/Chart.bundle.js' %}"></script>
|
||||
<script>
|
||||
jQuery(document).ready(function() {
|
||||
var ctx1 = $("#myChart1");
|
||||
var myChart = new Chart(ctx1, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
|
||||
datasets: [{
|
||||
label: '# of Votes',
|
||||
data: [12, 19, 3, 5, 2, 3],
|
||||
backgroundColor: [
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
'rgba(54, 162, 235, 0.2)',
|
||||
'rgba(255, 206, 86, 0.2)',
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(153, 102, 255, 0.2)',
|
||||
'rgba(255, 159, 64, 0.2)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(255,99,132,1)',
|
||||
'rgba(54, 162, 235, 1)',
|
||||
'rgba(255, 206, 86, 1)',
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(153, 102, 255, 1)',
|
||||
'rgba(255, 159, 64, 1)'
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero:true
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -74,7 +74,7 @@ jQuery(document).ready(function() {
|
|||
options: {
|
||||
responsive: true,
|
||||
tooltips: {
|
||||
mode: 'nearest',
|
||||
mode: 'index',
|
||||
intersect: false,
|
||||
},
|
||||
hover: {
|
64
kfet/templates/kfet/object_stat_resume.html
Normal file
64
kfet/templates/kfet/object_stat_resume.html
Normal file
|
@ -0,0 +1,64 @@
|
|||
<!doctype html>
|
||||
{% load staticfiles %}
|
||||
{% load dictionary_extras %}
|
||||
|
||||
<!-- TODO: SUPPRIMER-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
{# CSS #}
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto:400,700|Oswald:400,700|Roboto+Mono:400,700' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'kfet/css/jquery-confirm.css' %}">
|
||||
<link rel="stylesheet" type="text/css" href="{% static 'kfet/css/index.css' %}">
|
||||
|
||||
{# JS #}
|
||||
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
|
||||
</head>
|
||||
<!-- END TODO -->
|
||||
<body>
|
||||
<div class="btn-group btn-group-justified" role="group" aria-label="select-period">
|
||||
{% for k,stat in stats.items %}
|
||||
<div class="btn-group" role="group">
|
||||
<button id="{{ stat | get_item:'btn' }}" type="button" class="btn btn-primary">{{ stat | get_item:'label' }}</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div><!-- /boutons -->
|
||||
<div id="{{ content_id}}">
|
||||
</div>
|
||||
<script>
|
||||
jQuery(document).ready(function() {
|
||||
// VARIABLES
|
||||
// défaut
|
||||
content_id = $("#{{content_id}}");
|
||||
{% for k,stat in stats.items %}
|
||||
{% if k == default_stat %}
|
||||
default_url_{{id_prefix}} = "{{ stat | get_item:'url' }}";
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
// INIT
|
||||
get_thing(default_url_{{id_prefix}}, content_id, "Ouppss ?");
|
||||
{% for k,stat in stats.items %}
|
||||
$("#{{stat|get_item:'btn'}}").on('click', function() {
|
||||
get_thing("{{stat|get_item:'url'}}", content_id, "Ouuups ?")
|
||||
});
|
||||
{% endfor %}
|
||||
// FONCTIONS
|
||||
// Permet de raffraichir un champ, étant donné :
|
||||
// thing_url : l'url contenant le contenu
|
||||
// thing_div : le div où le mettre
|
||||
// empty_... : le truc à dire si on a un contenu vide
|
||||
function get_thing(thing_url, thing_div, empty_thing_message) {
|
||||
$.get(thing_url, function(data) {
|
||||
if(jQuery.trim(data).length==0) {
|
||||
thing_div.html(empty_thing_message);
|
||||
} else {
|
||||
thing_div.html(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
5
kfet/templatetags/dictionary_extras.py
Normal file
5
kfet/templatetags/dictionary_extras.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.template.defaulttags import register
|
||||
|
||||
@register.filter
|
||||
def get_item(dictionary, key):
|
||||
return dictionary.get(key)
|
15
kfet/urls.py
15
kfet/urls.py
|
@ -122,12 +122,15 @@ urlpatterns = [
|
|||
name = 'kfet.article.update'),
|
||||
|
||||
# Article - Statistics
|
||||
url('^articles/(?P<pk>\d+)/stat/week$',
|
||||
views.ArticleStatWeek.as_view(),
|
||||
name = 'kfet.article.stats.week'),
|
||||
url('^articles/(?P<pk>\d+)/stat/day$',
|
||||
views.ArticleStatDay.as_view(),
|
||||
name = 'kfet.article.stats.day'),
|
||||
url('^articles/(?P<pk>\d+)/stat/last/$',
|
||||
views.ArticleStatLastAll.as_view(),
|
||||
name = 'kfet.article.stat.last'),
|
||||
url('^articles/(?P<pk>\d+)/stat/last/week/$',
|
||||
views.ArticleStatLastWeek.as_view(),
|
||||
name = 'kfet.article.stat.last.week'),
|
||||
url('^articles/(?P<pk>\d+)/stat/last/day/$',
|
||||
views.ArticleStatLastDay.as_view(),
|
||||
name = 'kfet.article.stat.last.day'),
|
||||
|
||||
# -----
|
||||
# K-Psul urls
|
||||
|
|
|
@ -1948,11 +1948,13 @@ class SupplierUpdate(SuccessMessageMixin, UpdateView):
|
|||
return super(SupplierUpdate, self).form_valid(form)
|
||||
|
||||
|
||||
# -----
|
||||
# ==========
|
||||
# Statistics
|
||||
# -----
|
||||
# ==========
|
||||
|
||||
# ---------------
|
||||
# Vues génériques
|
||||
# ---------------
|
||||
# source : docs.djangoproject.com/fr/1.10/topics/class-based-views/mixins/
|
||||
class JSONResponseMixin(object):
|
||||
"""
|
||||
|
@ -1991,12 +1993,72 @@ class HybridDetailView(JSONResponseMixin,
|
|||
return super(HybridDetailView, self).render_to_response(context)
|
||||
|
||||
|
||||
# Article Statistiques
|
||||
# Un résume des toutes les vues de stat d'un objet
|
||||
# NE REND PAS DE JSON
|
||||
class ObjectResumeStat(DetailView):
|
||||
template_name = 'kfet/object_stat_resume.html'
|
||||
context_object_name = 'lul'
|
||||
id_prefix = 'id_a_definir'
|
||||
# nombre de vues à résumer
|
||||
nb_stat = 2
|
||||
# Le combienième est celui par defaut ?
|
||||
# (entre 0 et nb_stat-1)
|
||||
nb_default = 0
|
||||
stat_labels = ['stat_1', 'stat_2']
|
||||
stat_urls = ['url_1', 'url_2']
|
||||
|
||||
|
||||
class ArticleStat(HybridDetailView):
|
||||
def get_context_data(self, **kwargs):
|
||||
# On hérite
|
||||
# Pas besoin, c'est essentiellement inutile
|
||||
# context = super(ObjectResumeStat, self).get_context_data(**kwargs)
|
||||
object_id = self.object.id
|
||||
context = {}
|
||||
stats = {}
|
||||
for i in range(self.nb_stat):
|
||||
stats[i] = {
|
||||
'label': self.stat_labels[i],
|
||||
'btn': "btn_%s_%d_%d" % (self.id_prefix,
|
||||
object_id,
|
||||
i),
|
||||
'url': reverse_lazy(self.stat_urls[i],
|
||||
args=[object_id]),
|
||||
}
|
||||
prefix = "%s_%d" % (self.id_prefix, object_id)
|
||||
context['id_prefix'] = prefix
|
||||
context['content_id'] = "content_%s" % prefix
|
||||
context['stats'] = stats
|
||||
context['default_stat'] = self.nb_default
|
||||
context['object_id'] = object_id
|
||||
return context
|
||||
|
||||
|
||||
# ------------------------
|
||||
# Article Satistiques Last
|
||||
# ------------------------
|
||||
ID_PREFIX_ART_LAST = "last_art"
|
||||
ID_PREFIX_ART_LAST_DAYS = "last_days_art"
|
||||
ID_PREFIX_ART_LAST_WEEKS = "last_weeks_art"
|
||||
|
||||
|
||||
# Un résumé de toutes les vues ArticleStatLast
|
||||
# NE REND PAS DE JSON
|
||||
class ArticleStatLastAll(ObjectResumeStat):
|
||||
model = Article
|
||||
template_name = 'kfet/article_stat.html'
|
||||
context_object_name = 'article'
|
||||
id_prefix = ID_PREFIX_ART_LAST
|
||||
nb_stat = 2
|
||||
nb_default = 1
|
||||
stat_labels = ["Dernières semaines", "Derniers jours"]
|
||||
stat_urls = ['kfet.article.stat.last.week',
|
||||
'kfet.article.stat.last.day']
|
||||
|
||||
|
||||
# Rend un graph des ventes sur une plage de temps à préciser.
|
||||
# Le graphique distingue les ventes sur LIQ et sur les autres trigrammes
|
||||
class ArticleStatLast(HybridDetailView):
|
||||
model = Article
|
||||
template_name = 'kfet/article_stat_last.html'
|
||||
context_object_name = 'article'
|
||||
end_date = timezone.now()
|
||||
id_prefix = "lol"
|
||||
|
@ -2006,7 +2068,7 @@ class ArticleStat(HybridDetailView):
|
|||
if self.request.GET.get('format') == 'json':
|
||||
return self.render_to_json_response(context)
|
||||
else:
|
||||
return super(ArticleStat, self).render_to_response(context)
|
||||
return super(ArticleStatLast, self).render_to_response(context)
|
||||
|
||||
# doit rendre un dictionnaire des dates
|
||||
# la première date correspond au début
|
||||
|
@ -2064,14 +2126,16 @@ class ArticleStat(HybridDetailView):
|
|||
context['nb_accounts'] = nb_accounts
|
||||
context['nb_liq'] = nb_liq
|
||||
# ID unique
|
||||
context['chart_id'] = "%s_%s" % (self.id_prefix,
|
||||
self.object.name)
|
||||
context['chart_id'] = "%s_%d" % (self.id_prefix,
|
||||
self.object.id)
|
||||
return context
|
||||
|
||||
|
||||
class ArticleStatDay(ArticleStat):
|
||||
# Rend les ventes des 7 derniers jours
|
||||
# Aujourd'hui non compris
|
||||
class ArticleStatLastDay(ArticleStatLast):
|
||||
end_date = this_morning()
|
||||
id_prefix = "last_week"
|
||||
id_prefix = ID_PREFIX_ART_LAST_DAYS
|
||||
|
||||
def get_dates(self, **kwargs):
|
||||
return lastdays(7)
|
||||
|
@ -2081,9 +2145,11 @@ class ArticleStatDay(ArticleStat):
|
|||
return daynames(days)
|
||||
|
||||
|
||||
class ArticleStatWeek(ArticleStat):
|
||||
# Rend les ventes de 7 dernières semaines
|
||||
# La semaine en cours n'est pas comprise
|
||||
class ArticleStatLastWeek(ArticleStatLast):
|
||||
end_date = this_monday_morning()
|
||||
id_prefix = "last_weeks"
|
||||
id_prefix = ID_PREFIX_ART_LAST_WEEKS
|
||||
|
||||
def get_dates(self, **kwargs):
|
||||
return lastweeks(7)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue