Commit 1fc91c860fdac093d738e91128b19fe4f9599f84
1 parent
4f57a60c
Exists in
master
and in
2 other branches
criando a página de relatórios para goals
Showing
5 changed files
with
805 additions
and
2 deletions
Show diff stats
| ... | ... | @@ -0,0 +1,492 @@ |
| 1 | +{% extends "subjects/view.html" %} | |
| 2 | + | |
| 3 | +{% load static i18n pagination permissions_tags subject_counter %} | |
| 4 | +{% load django_bootstrap_breadcrumbs %} | |
| 5 | + | |
| 6 | +{% block javascript%} | |
| 7 | + {{ block.super }} | |
| 8 | + <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> | |
| 9 | + <script type="text/javascript"> | |
| 10 | + var tabela_atual = true; | |
| 11 | + | |
| 12 | + var array_history = []; | |
| 13 | + {%for data_json in json_history.data %} | |
| 14 | + array_history.push(["{{data_json.0}}","{{data_json.1}}","{% if data_json.2 == 'view' %} {{view}} {% elif data_json.2 == 'submit' %} {{submit}} {% endif %}",{% if data_json.3 is not None %}new Date('{{data_json.3.isoformat}}'){% else%}null{% endif %}]); | |
| 15 | + {% endfor%} | |
| 16 | + var json_history = {"data":array_history}; | |
| 17 | + var column_history = [{"string":'{% trans "User" %}'},{"string":'{% trans "Group" %}'},{"string":'{% trans "Action" %}'},{"date":'{% trans "Date of Action" %}'}]; | |
| 18 | + | |
| 19 | + var search = []; | |
| 20 | + for (var i in json_history["data"]){ | |
| 21 | + search.push([json_history["data"][i][0],json_history["data"][i][1], | |
| 22 | + json_history["data"][i][2],json_history["data"][i][3]]); | |
| 23 | + } | |
| 24 | + | |
| 25 | + var array_n_did = []; | |
| 26 | + var checkbox = {}; | |
| 27 | + {%for data_json in json_n_did.data%} | |
| 28 | + var input = '<div class="checkbox">\ | |
| 29 | + <label for="{{data_json.0}}_google_table">\ | |
| 30 | + <input id="{{data_json.0}}_google_table" name="{{data_json.0}}_google_table" type="checkbox"><span class="checkbox-material"><span class="check"></span></span>\ | |
| 31 | + </label>\ | |
| 32 | + </div>' | |
| 33 | + checkbox["{{data_json.0}}_google_table"] = "{{data_json.4}}"; | |
| 34 | + array_n_did.push([input,"{{data_json.1}}","{{data_json.2}}","{{data_json.3}}"]); | |
| 35 | + {% endfor%} | |
| 36 | + var json_n_did = {"data":array_n_did}; | |
| 37 | + var column_n_did = [{"string":'<a href="javascript:void(0);" onclick="return openmodal();"> {% trans "Send message" %}</a>'},{"string":'{% trans "User" %}'},{"string":'{% trans "Group" %}'},{"string":"{% trans "Action don't realized" %}"}]; | |
| 38 | + </script> | |
| 39 | + | |
| 40 | + | |
| 41 | + <script type="text/javascript"> | |
| 42 | + google.charts.load('current', {'packages':['corechart',"table"]}); | |
| 43 | + google.charts.setOnLoadCallback(drawChart); | |
| 44 | + google.charts.setOnLoadCallback(drawTable); | |
| 45 | + | |
| 46 | + function drawChart() { | |
| 47 | + var data = google.visualization.arrayToDataTable({{db_data|safe}}); | |
| 48 | + var options = { | |
| 49 | + title: '{{title_chart}}', | |
| 50 | + // legend: {position: 'right', maxLines: 1}, | |
| 51 | + bar: { groupWidth: '50%' }, | |
| 52 | + chartArea:{width:"50%"}, | |
| 53 | + titlePosition: 'out', | |
| 54 | + vAxis: { | |
| 55 | + title: '{{title_vAxis}}', | |
| 56 | + ticks: [0, .20, .40, .60, .80, 1], | |
| 57 | + viewWindow: { | |
| 58 | + min: 0, | |
| 59 | + max: 1 | |
| 60 | + } | |
| 61 | + }, | |
| 62 | + isStacked: "percent", | |
| 63 | + }; | |
| 64 | + | |
| 65 | + function selectHandler() { | |
| 66 | + var selectedItem = chart.getSelection()[0]; | |
| 67 | + var col = data.getColumnLabel(selectedItem.column); | |
| 68 | + if (selectedItem) { | |
| 69 | + if (selectedItem.row == 0 && selectedItem.column == 1){ | |
| 70 | + tabela_atual = true; | |
| 71 | + search = []; | |
| 72 | + var text = "{{view}}"; | |
| 73 | + for (var i in json_history["data"]){ | |
| 74 | + if (json_history["data"][i][2].toLowerCase().includes(text.toLowerCase())){ | |
| 75 | + search.push([json_history["data"][i][0],json_history["data"][i][1], | |
| 76 | + json_history["data"][i][2],json_history["data"][i][3]]); | |
| 77 | + } | |
| 78 | + } | |
| 79 | + drawTable(column_history,pagination(search,1),true,3); | |
| 80 | + alterTitleTable(search.length); | |
| 81 | + putpagination(search,tabela_atual); | |
| 82 | + } else if(selectedItem.row == 0 && selectedItem.column == 2){ | |
| 83 | + tabela_atual = false; | |
| 84 | + search = []; | |
| 85 | + var text = "{{view}}"; | |
| 86 | + for (var i in json_n_did["data"]){ | |
| 87 | + if (json_n_did["data"][i][3].toLowerCase().includes(text.toLowerCase())){ | |
| 88 | + search.push([json_n_did["data"][i][0],json_n_did["data"][i][1], | |
| 89 | + json_n_did["data"][i][2],json_n_did["data"][i][3]]); | |
| 90 | + } | |
| 91 | + } | |
| 92 | + drawTable(column_n_did,pagination(search,1),false); | |
| 93 | + alterTitleTable(search.length); | |
| 94 | + putpagination(search,tabela_atual); | |
| 95 | + } else if (selectedItem.row == 1 && selectedItem.column == 1){ | |
| 96 | + tabela_atual = true; | |
| 97 | + search = []; | |
| 98 | + var text = "{{submit}}"; | |
| 99 | + for (var i in json_history["data"]){ | |
| 100 | + if (json_history["data"][i][2].toLowerCase().includes(text.toLowerCase())){ | |
| 101 | + search.push([json_history["data"][i][0],json_history["data"][i][1], | |
| 102 | + json_history["data"][i][2],json_history["data"][i][3]]); | |
| 103 | + } | |
| 104 | + } | |
| 105 | + drawTable(column_history,pagination(search,1),true,3); | |
| 106 | + alterTitleTable(search.length); | |
| 107 | + putpagination(search,tabela_atual); | |
| 108 | + } else if(selectedItem.row == 1 && selectedItem.column == 2){ | |
| 109 | + tabela_atual = false; | |
| 110 | + search = []; | |
| 111 | + var text = "{{submit}}"; | |
| 112 | + for (var i in json_n_did["data"]){ | |
| 113 | + if (json_n_did["data"][i][3].toLowerCase().includes(text.toLowerCase())){ | |
| 114 | + search.push([json_n_did["data"][i][0],json_n_did["data"][i][1], | |
| 115 | + json_n_did["data"][i][2],json_n_did["data"][i][3]]); | |
| 116 | + } | |
| 117 | + } | |
| 118 | + drawTable(column_n_did,pagination(search,1),false); | |
| 119 | + alterTitleTable(search.length); | |
| 120 | + putpagination(search,tabela_atual); | |
| 121 | + } else if (col == "{{n_did_table}}"){ | |
| 122 | + tabela_atual = false; | |
| 123 | + search = []; | |
| 124 | + for (var i in json_n_did["data"]){ | |
| 125 | + search.push([json_n_did["data"][i][0],json_n_did["data"][i][1], | |
| 126 | + json_n_did["data"][i][2],json_n_did["data"][i][3]]); | |
| 127 | + } | |
| 128 | + searcher(col, tabela_atual,true); | |
| 129 | + | |
| 130 | + } else if (col == "{{did_table}}"){ | |
| 131 | + tabela_atual = true; | |
| 132 | + search = []; | |
| 133 | + for (var i in json_history["data"]){ | |
| 134 | + search.push([json_history["data"][i][0],json_history["data"][i][1], | |
| 135 | + json_history["data"][i][2],json_history["data"][i][3]]); | |
| 136 | + } | |
| 137 | + searcher(col, tabela_atual,true); | |
| 138 | + } | |
| 139 | + scroll("#title-table"); | |
| 140 | + } | |
| 141 | + chart.setSelection([]) | |
| 142 | + } | |
| 143 | + | |
| 144 | + var chart = new google.visualization.ColumnChart(document.getElementById('chart_div')); | |
| 145 | + google.visualization.events.addListener(chart, 'select', selectHandler); | |
| 146 | + chart.draw(data, options); | |
| 147 | + | |
| 148 | + } | |
| 149 | + | |
| 150 | + var sortAscending = {0:false,1:false,2:false,3:false}; | |
| 151 | + function drawTable(columns = column_history,rows = pagination(json_history["data"],1),isdate = true,columndate = 3) { | |
| 152 | + var data_table = new google.visualization.DataTable(); | |
| 153 | + for (var i in columns){ | |
| 154 | + for (var item in columns[i]){ | |
| 155 | + data_table.addColumn(item,columns[i][item]); | |
| 156 | + } | |
| 157 | + } | |
| 158 | + | |
| 159 | + data_table.addRows(rows); | |
| 160 | + var formate_date = new google.visualization.DateFormat({pattern: 'dd/MM/yyyy HH:mm'}); | |
| 161 | + if (isdate) formate_date.format(data_table, columndate); | |
| 162 | + | |
| 163 | + // var methods = []; | |
| 164 | + // for (var m in data_table) { | |
| 165 | + // if (typeof data_table[m] == "function") { | |
| 166 | + // methods.push(m); | |
| 167 | + // } | |
| 168 | + // } | |
| 169 | + // console.log(methods.join(",")); | |
| 170 | + var options = { | |
| 171 | + sort: "event", | |
| 172 | + allowHtml: true, | |
| 173 | + cssClassNames : { | |
| 174 | + tableRow: 'text-center', | |
| 175 | + tableCell: 'text-center', | |
| 176 | + headerCell: 'text-center' | |
| 177 | + }, | |
| 178 | + showRowNumber: true, | |
| 179 | + width: '100%', | |
| 180 | + height: '100%', | |
| 181 | + } | |
| 182 | + function ordenar(properties){ | |
| 183 | + var columnIndex = properties['column']; | |
| 184 | + if (columnIndex > 0) { | |
| 185 | + options["sortColumn"] = columnIndex; | |
| 186 | + options["sortAscending"] = sortAscending[columnIndex]; | |
| 187 | + data_table.sort({column:columnIndex,desc:sortAscending[columnIndex]}); | |
| 188 | + sortAscending = {0:false,1:false,2:false,3:false}; | |
| 189 | + sortAscending[columnIndex] = !sortAscending[columnIndex]; | |
| 190 | + // console.log(sortAscending); | |
| 191 | + table.draw(data_table, options); | |
| 192 | + } | |
| 193 | + } | |
| 194 | + | |
| 195 | + var table = new google.visualization.Table(document.getElementById('table_div')); | |
| 196 | + google.visualization.events.addListener(table, 'sort', function(e) {ordenar(e)}); | |
| 197 | + table.draw(data_table, options); | |
| 198 | + } | |
| 199 | + </script> | |
| 200 | +{% endblock%} | |
| 201 | + | |
| 202 | +{% block breadcrumbs %} | |
| 203 | + {{ block.super }} | |
| 204 | + {% breadcrumb topic 'subjects:topic_view' subject.slug topic.slug %} | |
| 205 | + {% breadcrumb goal 'goals:submit' goal.slug %} | |
| 206 | + {% trans 'Reports' as bread %} | |
| 207 | + {% breadcrumb bread goal %} | |
| 208 | +{% endblock %} | |
| 209 | + | |
| 210 | +{% block content %} | |
| 211 | + <div id="message-top"> | |
| 212 | + {% if messages %} | |
| 213 | + {% for message in messages %} | |
| 214 | + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert"> | |
| 215 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
| 216 | + <span aria-hidden="true">×</span> | |
| 217 | + </button> | |
| 218 | + <p>{{ message }}</p> | |
| 219 | + </div> | |
| 220 | + {% endfor %} | |
| 221 | + {% endif %} | |
| 222 | + </div> | |
| 223 | + <div class="panel panel-info topic-panel"> | |
| 224 | + <div class="panel-heading"> | |
| 225 | + <div class="row"> | |
| 226 | + <div class="col-md-12 category-header"> | |
| 227 | + <h4 class="panel-title" style="margin-top: 10px; margin-bottom: 8px"> | |
| 228 | + <span>{{goal}} / {% trans "Reports" %}</span> | |
| 229 | + </h4> | |
| 230 | + </div> | |
| 231 | + </div> | |
| 232 | + </div> | |
| 233 | + <div class="row"> | |
| 234 | + <div class="col-md-12 text-center"> | |
| 235 | + <h4 style="margin-top: 15px; margin-bottom: 10px" ><strong>{% trans "Report of the resource " %}{{goal}}</strong></h4> | |
| 236 | + </div> | |
| 237 | + </div> | |
| 238 | + <div class="row"> | |
| 239 | + <div class="col-md-12"> | |
| 240 | + | |
| 241 | + <ul class="list-inline nav-justified"> | |
| 242 | + <div id="general-parameters-div"> | |
| 243 | + <div class="general-parameters-field"> | |
| 244 | + <li class="text-right"><h4>{% trans "Select the period: " %}</h4></li> | |
| 245 | + </div> | |
| 246 | + <form id="period-form" action="" method="get"> | |
| 247 | + <div class="general-parameters-field"> | |
| 248 | + <li> <input class="form-control datetime-picker" name="init_date" type="text" required="" value="{% if LANGUAGE_CODE == 'pt-br' %}{{init_date|date:'d/m/Y H:i'}} {% else %} {{init_date|date:'m/d/Y H:i P'}} {% endif %}"></li> | |
| 249 | + </div> | |
| 250 | + <div class="general-parameters-field"> | |
| 251 | + <li><input id="inputdate" class="form-control datetime-picker" name="end_date" type="text" required="" value="{% if LANGUAGE_CODE == 'pt-br' %}{{end_date|date:'d/m/Y H:i'}} {% else %} {{end_date|date:'m/d/Y H:i P'}} {% endif %}"></li> | |
| 252 | + </div> | |
| 253 | + <li><input type="submit" value="{% trans 'Search' %}" style="margin-left: 15px;" class="btn btn-success btn-raised"></li> | |
| 254 | + </form> | |
| 255 | + </div> | |
| 256 | + <ul> | |
| 257 | + </div> | |
| 258 | + </div> | |
| 259 | + | |
| 260 | + <div class="row"> | |
| 261 | + <div class="col-md-10 col-md-offset-1"> | |
| 262 | + <div id="chart_div" style="height: 500px; margin-top: -50px;"></div> | |
| 263 | + </div> | |
| 264 | + </div> | |
| 265 | + | |
| 266 | + <div class="row"> | |
| 267 | + <div class="col-md-10 col-md-offset-1"> | |
| 268 | + <div class="text-center"> | |
| 269 | + <ul class="list-inline nav-justified"> | |
| 270 | + <li> | |
| 271 | + <ul id="view-table" class="list-inline text-right"> | |
| 272 | + <li><h3 id="title-table"></h3></li> | |
| 273 | + </ul> | |
| 274 | + </li> | |
| 275 | + <li> | |
| 276 | + <ul class="list-inline text-right"> | |
| 277 | + <li><p>{% trans "Filter: " %}</p></li> | |
| 278 | + <li><input id="search-input" class="form-control" type="text" name="search" value=""></li> | |
| 279 | + </ul> | |
| 280 | + </li> | |
| 281 | + </ul> | |
| 282 | + </div> | |
| 283 | + <form id="google-chart-checkbox" action="" method="get"> | |
| 284 | + <div id="table_div"></div> | |
| 285 | + </form> | |
| 286 | + <div class="col-md-12 col-lg-12 col-sm-12 col-xs-12 text-center"> | |
| 287 | + <ul class="pagination"> | |
| 288 | + | |
| 289 | + </ul> | |
| 290 | + </div> | |
| 291 | + </div> | |
| 292 | + </div> | |
| 293 | + <div id="modal-message"></div> | |
| 294 | + <div class="row"> | |
| 295 | + <br><br> | |
| 296 | + </div> | |
| 297 | + </div> | |
| 298 | + | |
| 299 | + <script type="text/javascript"> | |
| 300 | + | |
| 301 | + $("#title-table").text(search.length + " {% trans 'record(s)' %}"); | |
| 302 | + function putpagination(data = json_history["data"], load_histoty = true){ | |
| 303 | + var len = Math.ceil(data.length / 20); | |
| 304 | + $(".pagination").empty(); | |
| 305 | + $(".pagination").append('<li class="disabled"><span>«</span></li>'); | |
| 306 | + $(".pagination").append('<li id="1" class="active">\ | |
| 307 | + <a href="javascript:void(0);" onclick="return clickPagination(1, '+ load_histoty +');">1</a>\ | |
| 308 | + </li>'); | |
| 309 | + for (var i = 2; i <= len;i++){ | |
| 310 | + $(".pagination").append('<li id="' + i + '">\ | |
| 311 | + <a href="javascript:void(0);" onclick="return clickPagination(' + i +', ' + load_histoty + ');">' + i + '</a>\ | |
| 312 | + </li>'); | |
| 313 | + } | |
| 314 | + if (len > 1) $(".pagination").append('<li><a href="javascript:void(0);" onclick="return clickPagination(2, '+ load_histoty +');"><span>»</span></a></li>'); | |
| 315 | + else $(".pagination").append('<li class="disabled"><span>»</span></li>'); | |
| 316 | + }; | |
| 317 | + putpagination(); | |
| 318 | + | |
| 319 | + $('#period-form').submit(function(event) { | |
| 320 | + $('<input />').attr('type', 'hidden') | |
| 321 | + .attr('name', "language") | |
| 322 | + .attr('value', '{{ LANGUAGE_CODE }}') | |
| 323 | + .appendTo('#period-form'); | |
| 324 | + }); | |
| 325 | + function add(element,local, first = false){ | |
| 326 | + if (first) $(local).prepend(element); | |
| 327 | + else $(local).append(element); | |
| 328 | + } | |
| 329 | + function text(element){ | |
| 330 | + return $(element).text(); | |
| 331 | + } | |
| 332 | + function length(element) { | |
| 333 | + return $(element).length; | |
| 334 | + } | |
| 335 | + | |
| 336 | + $("#search-input").on("keyup",function(){ | |
| 337 | + search = []; | |
| 338 | + var text = $("#search-input").val(); | |
| 339 | + searcher(text,tabela_atual); | |
| 340 | + }); | |
| 341 | + | |
| 342 | + function searcher(text, load_histoty = false,apaga=false){ | |
| 343 | + if(apaga){ | |
| 344 | + $("#search-input").val(""); | |
| 345 | + } | |
| 346 | + var data = []; | |
| 347 | + if (!load_histoty){ | |
| 348 | + data = $.map(json_n_did["data"], function (obj) { | |
| 349 | + return $.extend(true, {}, obj); | |
| 350 | + }); | |
| 351 | + } else { | |
| 352 | + data = $.map(json_history["data"], function (obj) { | |
| 353 | + return $.extend(true, {}, obj); | |
| 354 | + }); | |
| 355 | + } | |
| 356 | + if (load_histoty){ | |
| 357 | + for (var i in data){ | |
| 358 | + data[i][3] = moment(data[i][3]).format("DD/MM/YYYY HH:mm"); | |
| 359 | + } | |
| 360 | + } | |
| 361 | + if (load_histoty){ | |
| 362 | + for (var i in data){ | |
| 363 | + if (data[i][0].toLowerCase().includes(text.toLowerCase()) | |
| 364 | + || data[i][1].toLowerCase().includes(text.toLowerCase()) | |
| 365 | + || data[i][2].toLowerCase().includes(text.toLowerCase()) | |
| 366 | + || data[i][3].toLowerCase().includes(text.toLowerCase())){ | |
| 367 | + search.push(json_history["data"][i]); | |
| 368 | + } | |
| 369 | + } | |
| 370 | + } | |
| 371 | + else { | |
| 372 | + for (var i in data){ | |
| 373 | + if (data[i][1].toLowerCase().includes(text.toLowerCase()) | |
| 374 | + || data[i][2].toLowerCase().includes(text.toLowerCase()) | |
| 375 | + || data[i][3].toLowerCase().includes(text.toLowerCase())){ | |
| 376 | + search.push(json_n_did["data"][i]); | |
| 377 | + } | |
| 378 | + } | |
| 379 | + } | |
| 380 | + console.log(search); | |
| 381 | + if (!load_histoty){ | |
| 382 | + drawTable(column_n_did,pagination(search,1),false); | |
| 383 | + } else { | |
| 384 | + drawTable(column_history,pagination(search,1),true,3); | |
| 385 | + } | |
| 386 | + $("#title-table").text(search.length + " {% trans 'record(s)' %}"); | |
| 387 | + putpagination(search,load_histoty); | |
| 388 | + } | |
| 389 | + | |
| 390 | + function pagination(data,pag){ | |
| 391 | + var len = data.length; | |
| 392 | + var first = (pag * 20 - 20 < len) ? pag * 20 - 20:len; | |
| 393 | + var end = (pag * 20 < len) ? pag * 20:len; | |
| 394 | + var search = data.slice(first,end); | |
| 395 | + return search; | |
| 396 | + } | |
| 397 | + | |
| 398 | + function clickPagination(pag, load_histoty = false){ | |
| 399 | + $(".pagination > li").last().remove(); | |
| 400 | + $(".pagination > li").first().remove(); | |
| 401 | + | |
| 402 | + if (!load_histoty){ | |
| 403 | + drawTable(column_n_did,pagination(search,pag),false); | |
| 404 | + } else { | |
| 405 | + drawTable(column_history,pagination(search,pag),true,3); | |
| 406 | + } | |
| 407 | + | |
| 408 | + if (pag < Math.ceil(search.length / 20)) | |
| 409 | + $(".pagination").append('<li><a href="javascript:void(0);" onclick="return clickPagination(' + (pag + 1) + ', '+ load_histoty +');"><span>»</span></a></li>'); | |
| 410 | + else $(".pagination").append('<li class="disabled"><span>»</span></li>'); | |
| 411 | + if (pag > 1) | |
| 412 | + $(".pagination").prepend('<li><a href="javascript:void(0);" onclick="return clickPagination(' + (pag - 1) + ', '+ load_histoty +');"><span>«</span></a></li>'); | |
| 413 | + else $(".pagination").prepend('<li class="disabled"><span>«</span></li>'); | |
| 414 | + $(".active").removeClass("active"); | |
| 415 | + $("#" + pag).addClass("active"); | |
| 416 | + } | |
| 417 | + | |
| 418 | + function openmodal(){ | |
| 419 | + $( "#modal-message" ).empty(); | |
| 420 | + $.get( "{% url 'goals:send_message' goal.slug %}", function( data ) { | |
| 421 | + $( "#modal-message" ).append( data ); | |
| 422 | + $("#send-message-modal").modal("show"); | |
| 423 | + }); | |
| 424 | + } | |
| 425 | + | |
| 426 | + function sendMessage(){ | |
| 427 | + $("#send-message-modal").modal("hide"); | |
| 428 | + var checked = $("#google-chart-checkbox").serializeArray(); | |
| 429 | + var email = []; | |
| 430 | + for (var i in checked){ | |
| 431 | + email.push(checkbox[checked[i]["name"]]); | |
| 432 | + } | |
| 433 | + $('<input />').attr('type', 'hidden') | |
| 434 | + .attr('name', "users[]") | |
| 435 | + .attr('value', email) | |
| 436 | + .appendTo('#text_chat_form'); | |
| 437 | + | |
| 438 | + var formData = new FormData($('#text_chat_form').get(0)); | |
| 439 | + $.ajax({ | |
| 440 | + url: "{% url 'goals:send_message' goal.slug %}", | |
| 441 | + type: "POST", | |
| 442 | + data: formData, | |
| 443 | + cache: false, | |
| 444 | + processData: false, | |
| 445 | + contentType: false, | |
| 446 | + success: function(data) { | |
| 447 | + if (data["message"]){ | |
| 448 | + console.log("success"); | |
| 449 | + $("body").removeClass("modal-open"); | |
| 450 | + $( "#modal-message" ).empty(); | |
| 451 | + $(".modal-backdrop.fade.in").remove(); | |
| 452 | + $("#message-top").empty(); | |
| 453 | + $("#message-top").append('\ | |
| 454 | + <div class="alert alert-success alert-dismissible" role="alert">\ | |
| 455 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close">\ | |
| 456 | + <span aria-hidden="true">×</span>\ | |
| 457 | + </button>\ | |
| 458 | + <p>' + data["message"] + '</p>\ | |
| 459 | + </div>\ | |
| 460 | + '); | |
| 461 | + $("html, body").animate({ scrollTop: 0 }, "slow"); | |
| 462 | + $('#google-chart-checkbox')[0].reset(); | |
| 463 | + } else { | |
| 464 | + $( "#modal-message" ).empty(); | |
| 465 | + $(".modal-backdrop.fade.in").remove(); | |
| 466 | + $( "#modal-message" ).append( data ); | |
| 467 | + $("#send-message-modal").modal("show"); | |
| 468 | + $("html, body").animate({ scrollTop: 0 }, "slow"); | |
| 469 | + } | |
| 470 | + }, | |
| 471 | + error: function(data){ | |
| 472 | + $("#message-top").empty(); | |
| 473 | + $("#message-top").append('\ | |
| 474 | + <div class="alert alert-danger alert-dismissible" role="alert">\ | |
| 475 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close">\ | |
| 476 | + <span aria-hidden="true">×</span>\ | |
| 477 | + </button>\ | |
| 478 | + <p>' + data.responseText + '</p>\ | |
| 479 | + </div>\ | |
| 480 | + '); | |
| 481 | + $("html, body").animate({ scrollTop: 0 }, "slow"); | |
| 482 | + } | |
| 483 | + }); | |
| 484 | + } | |
| 485 | + function scroll(to){ | |
| 486 | + $("html, body").animate({ scrollTop: $(to).offset().top }, "slow"); | |
| 487 | + } | |
| 488 | + function alterTitleTable (quant){ | |
| 489 | + $("#title-table").text(quant + " {% trans 'record(s)' %}"); | |
| 490 | + } | |
| 491 | + </script> | |
| 492 | +{% endblock %} | ... | ... |
| ... | ... | @@ -0,0 +1,112 @@ |
| 1 | + | |
| 2 | + {% load widget_tweaks i18n %} | |
| 3 | + <!-- Modal (remember to change the ids!!!) --> | |
| 4 | +<div class="modal fade" id="send-message-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> | |
| 5 | + <div class="modal-dialog" role="document"> | |
| 6 | + <div class="modal-content"> | |
| 7 | + <!-- Modal Body --> | |
| 8 | + <div class="modal-body"> | |
| 9 | + <form id="text_chat_form" action="" method="POST" enctype="multipart/form-data"> | |
| 10 | + {% csrf_token %} | |
| 11 | + {% comment %}Area para o Texto{% endcomment %} | |
| 12 | + <div class="form-group{% if form.has_error %} has-error {% endif %}"> | |
| 13 | + <label for="{{ form.comment.auto_id }}">{{ form.comment.label }}: <span>*</span></label> | |
| 14 | + {% render_field form.comment class='form-control text_simple_wysiwyg' %} | |
| 15 | + | |
| 16 | + <span id="helpBlock" class="help-block">{{ form.comment.help_text }}</span> | |
| 17 | + | |
| 18 | + {% if form.comment.errors %} | |
| 19 | + <div class="alert alert-danger alert-dismissible" role="alert"> | |
| 20 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
| 21 | + <span aria-hidden="true">×</span> | |
| 22 | + </button> | |
| 23 | + <ul> | |
| 24 | + {% for error in form.comment.errors %} | |
| 25 | + <li>{{ error }}</li> | |
| 26 | + {% endfor %} | |
| 27 | + </ul> | |
| 28 | + </div> | |
| 29 | + {% endif %} | |
| 30 | + </div> | |
| 31 | + {% comment %}Area para anexar a imagem {% endcomment %} | |
| 32 | + <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput"> | |
| 33 | + {% render_field form.image %} | |
| 34 | + | |
| 35 | + <div class="filedrag"> | |
| 36 | + {% trans 'Click or drop the picture here' %}<br /> | |
| 37 | + | |
| 38 | + <small>{% trans 'The picture could not exceed 5MB.' %}</small> | |
| 39 | + </div> | |
| 40 | + | |
| 41 | + {% if form.image.errors %} | |
| 42 | + <div class="alert alert-danger alert-dismissible" role="alert"> | |
| 43 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
| 44 | + <span aria-hidden="true">×</span> | |
| 45 | + </button> | |
| 46 | + <ul> | |
| 47 | + {% for error in form.image.errors %} | |
| 48 | + <li>{{ error }}</li> | |
| 49 | + {% endfor %} | |
| 50 | + </ul> | |
| 51 | + </div> | |
| 52 | + {% endif %} | |
| 53 | + | |
| 54 | + </div> | |
| 55 | + </form> | |
| 56 | + </div> | |
| 57 | + <!-- Modal Footer --> | |
| 58 | + <div id="delete-category-footer"class="modal-footer"> | |
| 59 | + <!-- Don't remove that!!! --> | |
| 60 | + <button type="button" class="btn btn-default btn-raised" data-dismiss="modal">{% trans "Close" %}</button> | |
| 61 | + <a href="javascript:void(0)" onclick="return sendMessage()" form="text_chat_form" class="btn btn-success btn-raised erase-button">{% trans "Send" %}</a> | |
| 62 | + </div> | |
| 63 | + </div> | |
| 64 | + </div> | |
| 65 | +</div> | |
| 66 | + | |
| 67 | +<script type="text/javascript"> | |
| 68 | + | |
| 69 | + $('.text_simple_wysiwyg').summernote({ | |
| 70 | + dialogsInBody: true, | |
| 71 | + disableDragAndDrop: true, | |
| 72 | + height: 150, | |
| 73 | + toolbar: [ | |
| 74 | + // [groupName, [list of button]] | |
| 75 | + ['style', ['bold', 'italic']], | |
| 76 | + ['insert', ['link']] | |
| 77 | + ] | |
| 78 | + }); | |
| 79 | + | |
| 80 | + if (window.File && window.FileList && window.FileReader) { | |
| 81 | + Init(); | |
| 82 | + } | |
| 83 | + | |
| 84 | + function Init() { | |
| 85 | + var small = $("#id_image"), | |
| 86 | + filedrag = $(".filedrag"), | |
| 87 | + common = $(".common-file-input"); | |
| 88 | + | |
| 89 | + // file select | |
| 90 | + small.on("change", FileSelectHandler); | |
| 91 | + | |
| 92 | + // is XHR2 available? | |
| 93 | + var xhr = new XMLHttpRequest(); | |
| 94 | + if (xhr.upload) { | |
| 95 | + // file drop | |
| 96 | + filedrag.on("drop", FileSelectHandler); | |
| 97 | + filedrag.attr('style', 'display:block'); | |
| 98 | + common.attr('style', 'display:none'); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + // file selection | |
| 103 | + function FileSelectHandler(e) { | |
| 104 | + var files = e.target.files || e.dataTransfer.files, | |
| 105 | + parent = $(e.target.offsetParent); | |
| 106 | + | |
| 107 | + // process all File objects | |
| 108 | + for (var i = 0, f; f = files[i]; i++) { | |
| 109 | + parent.find('.filedrag').html(f.name); | |
| 110 | + } | |
| 111 | + } | |
| 112 | +</script> | |
| 0 | 113 | \ No newline at end of file | ... | ... |
goals/urls.py
| ... | ... | @@ -16,4 +16,6 @@ urlpatterns = [ |
| 16 | 16 | url(r'^unanswered_report/(?P<slug>[\w_-]+)/$', views.UnansweredReport.as_view(), name = 'unanswered_report'), |
| 17 | 17 | url(r'^history_report/(?P<slug>[\w_-]+)/$', views.HistoryReport.as_view(), name = 'history_report'), |
| 18 | 18 | url(r'^view_log/(?P<goal>[\w_-]+)/(?P<report>[\w_-]+)/$', views.reports_log, name = 'reports_log'), |
| 19 | + url(r'^chart/(?P<slug>[\w_-]+)/$', views.StatisticsView.as_view(), name = 'get_chart'), | |
| 20 | + url(r'^send-message/(?P<slug>[\w_-]+)/$', views.SendMessage.as_view(), name = 'send_message'), | |
| 19 | 21 | ] | ... | ... |
goals/views.py
| ... | ... | @@ -20,6 +20,22 @@ from users.models import User |
| 20 | 20 | from .forms import GoalsForm, MyGoalsForm, InlinePendenciesFormset, InlineGoalItemFormset |
| 21 | 21 | from .models import Goals, MyGoals |
| 22 | 22 | |
| 23 | +import datetime | |
| 24 | +from log.models import Log | |
| 25 | +from chat.models import Conversation, TalkMessages, ChatVisualizations | |
| 26 | +from users.models import User | |
| 27 | +from subjects.models import Subject | |
| 28 | + | |
| 29 | +from webpage.forms import FormModalMessage | |
| 30 | + | |
| 31 | +from django.db.models import Q | |
| 32 | +from django.template.loader import render_to_string | |
| 33 | +from django.utils import formats | |
| 34 | +import textwrap | |
| 35 | +from django.utils.html import strip_tags | |
| 36 | +import json | |
| 37 | +from channels import Group | |
| 38 | + | |
| 23 | 39 | class Reports(LoginRequiredMixin, generic.ListView): |
| 24 | 40 | login_url = reverse_lazy("users:login") |
| 25 | 41 | redirect_field_name = 'next' |
| ... | ... | @@ -966,4 +982,185 @@ def reports_log(request, goal, report): |
| 966 | 982 | |
| 967 | 983 | return JsonResponse({'message': 'ok', 'log_id': log_id}) |
| 968 | 984 | |
| 969 | - return JsonResponse({'message': 'ok'}) | |
| 970 | 985 | \ No newline at end of file |
| 986 | + return JsonResponse({'message': 'ok'}) | |
| 987 | + | |
| 988 | +class StatisticsView(LoginRequiredMixin, LogMixin, generic.DetailView): | |
| 989 | + log_component = 'resources' | |
| 990 | + log_action = 'view_statistics' | |
| 991 | + log_resource = 'goals' | |
| 992 | + log_context = {} | |
| 993 | + | |
| 994 | + login_url = reverse_lazy("users:login") | |
| 995 | + redirect_field_name = 'next' | |
| 996 | + model = Goals | |
| 997 | + template_name = 'goals/relatorios.html' | |
| 998 | + | |
| 999 | + def dispatch(self, request, *args, **kwargs): | |
| 1000 | + slug = self.kwargs.get('slug', '') | |
| 1001 | + goal = get_object_or_404(Goals, slug = slug) | |
| 1002 | + | |
| 1003 | + if not has_subject_permissions(request.user, goal.topic.subject): | |
| 1004 | + return redirect(reverse_lazy('subjects:home')) | |
| 1005 | + | |
| 1006 | + return super(StatisticsView, self).dispatch(request, *args, **kwargs) | |
| 1007 | + | |
| 1008 | + def get_context_data(self, **kwargs): | |
| 1009 | + context = super(StatisticsView, self).get_context_data(**kwargs) | |
| 1010 | + | |
| 1011 | + self.log_context['category_id'] = self.object.topic.subject.category.id | |
| 1012 | + self.log_context['category_name'] = self.object.topic.subject.category.name | |
| 1013 | + self.log_context['category_slug'] = self.object.topic.subject.category.slug | |
| 1014 | + self.log_context['subject_id'] = self.object.topic.subject.id | |
| 1015 | + self.log_context['subject_name'] = self.object.topic.subject.name | |
| 1016 | + self.log_context['subject_slug'] = self.object.topic.subject.slug | |
| 1017 | + self.log_context['topic_id'] = self.object.topic.id | |
| 1018 | + self.log_context['topic_name'] = self.object.topic.name | |
| 1019 | + self.log_context['topic_slug'] = self.object.topic.slug | |
| 1020 | + self.log_context['goals_id'] = self.object.id | |
| 1021 | + self.log_context['goals_name'] = self.object.name | |
| 1022 | + self.log_context['goals_slug'] = self.object.slug | |
| 1023 | + | |
| 1024 | + super(StatisticsView, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context) | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + context['title'] = _('Goals Reports') | |
| 1028 | + | |
| 1029 | + slug = self.kwargs.get('slug') | |
| 1030 | + goal = get_object_or_404(Goals, slug = slug) | |
| 1031 | + | |
| 1032 | + date_format = "%d/%m/%Y %H:%M" if self.request.GET.get('language','') == 'pt-br' else "%m/%d/%Y %I:%M %p" | |
| 1033 | + if self.request.GET.get('language','') == "": | |
| 1034 | + start_date = datetime.datetime.now() - datetime.timedelta(30) | |
| 1035 | + end_date = datetime.datetime.now() | |
| 1036 | + else : | |
| 1037 | + start_date = datetime.datetime.strptime(self.request.GET.get('init_date',''),date_format) | |
| 1038 | + end_date = datetime.datetime.strptime(self.request.GET.get('end_date',''),date_format) | |
| 1039 | + context["init_date"] = start_date | |
| 1040 | + context["end_date"] = end_date | |
| 1041 | + alunos = goal.students.all() | |
| 1042 | + if goal.all_students : | |
| 1043 | + alunos = goal.topic.subject.students.all() | |
| 1044 | + | |
| 1045 | + vis_ou = Log.objects.filter(context__contains={'goals_id':goal.id},resource="goals",user_email__in=(aluno.email for aluno in alunos), datetime__range=(start_date,end_date + datetime.timedelta(minutes = 1))).filter(Q(action="view") | Q(action="submit")) | |
| 1046 | + did,n_did,history = str(_("Realized")),str(_("Unrealized")),str(_("Historic")) | |
| 1047 | + re = [] | |
| 1048 | + data_n_did,data_history = [],[] | |
| 1049 | + json_n_did, json_history = {},{} | |
| 1050 | + | |
| 1051 | + for log_al in vis_ou.order_by("datetime"): | |
| 1052 | + data_history.append([str(alunos.get(email=log_al.user_email)), | |
| 1053 | + ", ".join([str(x) for x in goal.topic.subject.group_subject.filter(participants__email=log_al.user_email)]), | |
| 1054 | + log_al.action,log_al.datetime]) | |
| 1055 | + | |
| 1056 | + json_history["data"] = data_history | |
| 1057 | + | |
| 1058 | + column_view,column_submit = str(_('View')),str(_('Submitted')) | |
| 1059 | + | |
| 1060 | + not_view = alunos.exclude(email__in=[log.user_email for log in vis_ou.filter(action="view").distinct("user_email")]) | |
| 1061 | + index = 0 | |
| 1062 | + for alun in not_view: | |
| 1063 | + data_n_did.append([index,str(alun),", ".join([str(x) for x in goal.topic.subject.group_subject.filter(participants__email=alun.email)]),column_view, str(alun.email)]) | |
| 1064 | + index += 1 | |
| 1065 | + | |
| 1066 | + not_watch = alunos.exclude(email__in=[log.user_email for log in vis_ou.filter(action="submit").distinct("user_email")]) | |
| 1067 | + for alun in not_watch: | |
| 1068 | + data_n_did.append([index,str(alun),", ".join([str(x) for x in goal.topic.subject.group_subject.filter(participants__email=alun.email)]),column_submit, str(alun.email)]) | |
| 1069 | + index += 1 | |
| 1070 | + | |
| 1071 | + json_n_did["data"] = data_n_did | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + context["json_n_did"] = json_n_did | |
| 1075 | + context["json_history"] = json_history | |
| 1076 | + c_visualizou = vis_ou.filter(action="view").distinct("user_email").count() | |
| 1077 | + c_submit = vis_ou.filter(action="submit").distinct("user_email").count() | |
| 1078 | + re.append([str(_('Goals')),did,n_did]) | |
| 1079 | + | |
| 1080 | + re.append([column_view,c_visualizou, alunos.count() - c_visualizou]) | |
| 1081 | + re.append([column_submit,c_submit, alunos.count() - c_submit]) | |
| 1082 | + | |
| 1083 | + context['view'] = column_view | |
| 1084 | + context['submit'] = column_submit | |
| 1085 | + context['topic'] = goal.topic | |
| 1086 | + context['subject'] = goal.topic.subject | |
| 1087 | + context['goal'] = goal | |
| 1088 | + context['db_data'] = re | |
| 1089 | + context['title_chart'] = _('Actions about resource') | |
| 1090 | + context['title_vAxis'] = _('Quantity') | |
| 1091 | + | |
| 1092 | + context["n_did_table"] = n_did | |
| 1093 | + context["did_table"] = did | |
| 1094 | + context["history_table"] = history | |
| 1095 | + return context | |
| 1096 | + | |
| 1097 | +from django.http import HttpResponse #used to send HTTP 404 error to ajax | |
| 1098 | + | |
| 1099 | +class SendMessage(LoginRequiredMixin, LogMixin, generic.edit.FormView): | |
| 1100 | + log_component = 'resources' | |
| 1101 | + log_action = 'send' | |
| 1102 | + log_resource = 'goals' | |
| 1103 | + log_context = {} | |
| 1104 | + | |
| 1105 | + login_url = reverse_lazy("users:login") | |
| 1106 | + redirect_field_name = 'next' | |
| 1107 | + | |
| 1108 | + template_name = 'goals/send_message.html' | |
| 1109 | + form_class = FormModalMessage | |
| 1110 | + | |
| 1111 | + def dispatch(self, request, *args, **kwargs): | |
| 1112 | + slug = self.kwargs.get('slug', '') | |
| 1113 | + goal = get_object_or_404(Goals, slug = slug) | |
| 1114 | + self.goal = goal | |
| 1115 | + | |
| 1116 | + if not has_subject_permissions(request.user, goal.topic.subject): | |
| 1117 | + return redirect(reverse_lazy('subjects:home')) | |
| 1118 | + | |
| 1119 | + return super(SendMessage, self).dispatch(request, *args, **kwargs) | |
| 1120 | + | |
| 1121 | + def form_valid(self, form): | |
| 1122 | + message = form.cleaned_data.get('comment') | |
| 1123 | + image = form.cleaned_data.get("image",'') | |
| 1124 | + users = (self.request.POST.get('users[]','')).split(",") | |
| 1125 | + user = self.request.user | |
| 1126 | + subject = self.goal.topic.subject | |
| 1127 | + | |
| 1128 | + if (users[0] is not ''): | |
| 1129 | + for u in users: | |
| 1130 | + to_user = User.objects.get(email=u) | |
| 1131 | + talk, create = Conversation.objects.get_or_create(user_one=user,user_two=to_user) | |
| 1132 | + created = TalkMessages.objects.create(text=message,talk=talk,user=user,subject=subject,image=image) | |
| 1133 | + | |
| 1134 | + simple_notify = textwrap.shorten(strip_tags(message), width = 30, placeholder = "...") | |
| 1135 | + | |
| 1136 | + if image is not '': | |
| 1137 | + simple_notify += " ".join(_("[Photo]")) | |
| 1138 | + | |
| 1139 | + notification = { | |
| 1140 | + "type": "chat", | |
| 1141 | + "subtype": "subject", | |
| 1142 | + "space": subject.slug, | |
| 1143 | + "user_icon": created.user.image_url, | |
| 1144 | + "notify_title": str(created.user), | |
| 1145 | + "simple_notify": simple_notify, | |
| 1146 | + "view_url": reverse("chat:view_message", args = (created.id, ), kwargs = {}), | |
| 1147 | + "complete": render_to_string("chat/_message.html", {"talk_msg": created}, self.request), | |
| 1148 | + "container": "chat-" + str(created.user.id), | |
| 1149 | + "last_date": _("Last message in %s")%(formats.date_format(created.create_date, "SHORT_DATETIME_FORMAT")) | |
| 1150 | + } | |
| 1151 | + | |
| 1152 | + notification = json.dumps(notification) | |
| 1153 | + | |
| 1154 | + Group("user-%s" % to_user.id).send({'text': notification}) | |
| 1155 | + | |
| 1156 | + ChatVisualizations.objects.create(viewed = False, message = created, user = to_user) | |
| 1157 | + success = str(_('The message was successfull sent!')) | |
| 1158 | + return JsonResponse({"message":success}) | |
| 1159 | + erro = HttpResponse(str(_("No user selected!"))) | |
| 1160 | + erro.status_code = 404 | |
| 1161 | + return erro | |
| 1162 | + | |
| 1163 | + def get_context_data(self, **kwargs): | |
| 1164 | + context = super(SendMessage,self).get_context_data() | |
| 1165 | + context["goal"] = get_object_or_404(Goals, slug=self.kwargs.get('slug', '')) | |
| 1166 | + return context | |
| 1167 | + | ... | ... |