diff --git a/frontend/src/__apps/painel/main.js b/frontend/src/__apps/painel/main.js index fdf4e5dbd..2328573fa 100644 --- a/frontend/src/__apps/painel/main.js +++ b/frontend/src/__apps/painel/main.js @@ -1 +1,267 @@ import './scss/painel.scss' +import Vue from 'vue' +import axios from 'axios' + +axios.defaults.xsrfCookieName = 'csrftoken' +axios.defaults.xsrfHeaderName = 'X-CSRFToken' + +// Variaveis dos cronometros +var crono = 0 +var time = null +var timeEnd = null +var audioAlertFinish = document.getElementById('audio') +var cronometroStart = [] + +const v = new Vue({ // eslint-disable-line + delimiters: ['[[', ']]'], + el: '#app-painel', + data () { + return { + message: 'Hello VueJUS', // TODO: remove when porting to VueJS is done + polling: null, + painel_aberto: true, + sessao_plenaria: '', + sessao_plenaria_data: '', + sessao_plenaria_hora_inicio: '', + brasao: '', + cronometro_discurso: '', + cronometro_aparte: '', + cronometro_ordem: '', + cronometro_consideracoes: '', + sessao_solene: false, + sessao_solene_tema: '', + presentes: [], + oradores: [], + numero_votos_sim: 0, + numero_votos_nao: 0, + numero_abstencoes: 0, + num_presentes: 0, + total_votos: 0, + sessao_finalizada: true, + materia_legislativa_texto: '', + materia_legislativa_ementa: '', + observacao_materia: '', + mat_em_votacao: '', + resultado_votacao_css: '', + tipo_resultado: '', + tipo_votacao: '', + running: 0 + } + }, + methods: { + msgMateria () { + if (this.tipo_resultado && this.painel_aberto) { + if (this.tipo_votacao !== 'Leitura' && !this.sessao_finalizada && !this.sessao_solene) { + this.resultado_votacao_css = 'color: #45919D' + this.mat_em_votacao = 'Matéria em Votação' + } else { + this.resultado_votacao_css = 'color: #45919D' + this.mat_em_votacao = 'Matéria em Leitura' + } + + this.resultado_votacao = this.tipo_resultado + + var resultado_votacao_upper = this.resultado_votacao.toUpperCase() + + if (resultado_votacao_upper.search('APROV') !== -1) { + this.resultado_votacao_css = 'color: #7CFC00' + this.mat_em_votacao = 'Matéria Votada' + } else if (resultado_votacao_upper.search('REJEIT') !== -1) { + this.resultado_votacao_css = 'color: red' + this.mat_em_votacao = 'Matéria Votada' + } else if (resultado_votacao_upper.search('LIDA') !== -1) { + this.mat_em_votacao = 'Matéria Lida' + } + } else { + this.resultado_votacao = '' + if (this.tipo_votacao !== 'Leitura') { + this.mat_em_votacao = 'Matéria em Votação' + } else { + this.mat_em_votacao = 'Matéria em Leitura' + } + } + }, + atribuiColor (parlamentar) { + var color = 'white' + if (parlamentar.voto === 'Voto Informado' || parlamentar.voto === '') { + color = 'yellow' + } else { + if (parlamentar.voto === 'Sim') { + color = 'green' + } else if (parlamentar.voto === 'Não') { + color = 'red' + } + } + parlamentar.color = color + }, + capObservacao (texto) { + if (texto && texto.length > 151) { + return texto.substr(0, 145).concat('(...)') + } + return texto + }, + converterUrl (url) { + url = url.slice(-(url.length - url.lastIndexOf('/'))) + url = '/painel' + url + '/dados' + return url + }, + fetchData () { + // TODO: how to get no hardcoded URL? + $.get(this.converterUrl(window.location.pathname), function (response) { + this.brasao = response.brasao + this.painel_aberto = response.status_painel + this.sessao_finalizada = response.sessao_finalizada + this.sessao_plenaria = response.sessao_plenaria + this.sessao_plenaria_data = 'Data Início: ' + response.sessao_plenaria_data + this.sessao_plenaria_hora_inicio = 'Hora Início: ' + response.sessao_plenaria_hora_inicio + this.sessao_solene = response.sessao_solene + this.sessao_solene_tema = response.sessao_solene_tema + + this.presentes = response.presentes + this.presentes.forEach(parlamentar => { + this.atribuiColor(parlamentar) + }) + + this.oradores = response.oradores + + this.materia_legislativa_texto = response.materia_legislativa_texto + this.numero_votos_sim = response.numero_votos_sim + this.numero_votos_nao = response.numero_votos_nao + this.numero_abstencoes = response.numero_abstencoes + this.num_presentes = response.num_presentes + this.total_votos = response.total_votos + + this.materia_legislativa_texto = response.materia_legislativa_texto + this.materia_legislativa_ementa = response.materia_legislativa_ementa + this.observacao_materia = this.capObservacao(response.observacao_materia) + + this.tipo_resultado = response.tipo_resultado + this.tipo_votacao = response.tipo_votacao + this.mat_em_votacao = this.msgMateria() + + // Cronometros + cronometroStart[0] = response.cronometro_discurso + cronometroStart[1] = response.cronometro_aparte + cronometroStart[2] = response.cronometro_ordem + cronometroStart[3] = response.cronometro_consideracoes + + if (time === null) { + // Pegar data atual + this.cronometro_discurso = new Date() + this.cronometro_aparte = this.cronometro_discurso + this.cronometro_ordem = this.cronometro_discurso + this.cronometro_consideracoes = this.cronometro_discurso + + // Setar cada Cronometro + var temp = new Date() + temp.setSeconds(this.cronometro_discurso.getSeconds() + cronometroStart[0]) + var res = new Date(temp - this.cronometro_discurso) + this.cronometro_discurso = this.formatTime(res) + + temp = new Date() + temp.setSeconds(this.cronometro_aparte.getSeconds() + cronometroStart[1]) + res = new Date(temp - this.cronometro_aparte) + this.cronometro_aparte = this.formatTime(res) + + temp = new Date() + temp.setSeconds(this.cronometro_ordem.getSeconds() + cronometroStart[2]) + res = new Date(temp - this.cronometro_ordem) + this.cronometro_ordem = this.formatTime(res) + + temp = new Date() + temp.setSeconds(this.cronometro_consideracoes.getSeconds() + cronometroStart[3]) + res = new Date(temp - this.cronometro_consideracoes) + this.cronometro_consideracoes = this.formatTime(res) + } + }.bind(this)) + }, + formatTime (time) { + var tempo = '00:' + time.getMinutes().toLocaleString('en-US', { + minimumIntegerDigits: 2, + useGrouping: false + }) + ':' + time.getSeconds().toLocaleString('en-US', { + minimumIntegerDigits: 2, + useGrouping: false + }) + return tempo + }, + stop: function stop (crono) { + if (crono === 5) { + audioAlertFinish.play() + } + + this.running = 0 + clearInterval(this.started) + this.stopped = setInterval(() => { + this.timeStopped() + }, 100) + }, + timeStopped () { + timeEnd.setMilliseconds(timeEnd.getMilliseconds() + 100) + }, + reset: function reset () { + this.running = 0 + time = null + clearInterval(this.started) + clearInterval(this.stopped) + }, + clockRunning (crono) { + var now = new Date() + time = new Date(timeEnd - now) + + // Definir propriamento o tempo + time.setHours(timeEnd.getHours() - now.getHours()) + + if (timeEnd > now) { + if (crono === 1) { + this.cronometro_discurso = this.formatTime(time) + } else if (crono === 2) { + this.cronometro_aparte = this.formatTime(time) + } else if (crono === 3) { + this.cronometro_ordem = this.formatTime(time) + } else { + this.cronometro_consideracoes = this.formatTime(time) + } + } else { + audioAlertFinish.play() + this.alert = setTimeout(() => { + this.reset() + }, 5000) + } + }, + start: function startStopWatch (temp_crono) { + if (this.running !== 0) return + + crono = temp_crono + if (time === null) { + time = cronometroStart[crono - 1] + console.log(time) + timeEnd = new Date() + timeEnd.setSeconds(timeEnd.getSeconds() + time) + } else { + clearInterval(this.stopped) + } + this.running = crono + + this.started = setInterval(() => { + this.clockRunning(crono) + }, 100) + }, + pollData () { + this.fetchData() + + this.polling = setInterval(() => { + console.info('Fetching data from backend') + this.fetchData() + }, 100) + } + }, + beforeDestroy () { + console.info('Destroying polling.') + clearInterval(this.polling) + }, + created () { + console.info('Start polling data...') + this.pollData() + } +}) diff --git a/sapl/painel/views.py b/sapl/painel/views.py index 75f5a1b97..6718683cd 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -352,6 +352,18 @@ def get_cronometro_status(request, name): cronometro = '' return cronometro +def get_cronometro_value(request, name): + if name == 'discurso': + result = ConfiguracoesAplicacao.objects.first().cronometro_discurso + if name == 'aparte': + result = ConfiguracoesAplicacao.objects.first().cronometro_aparte + if name == 'ordem': + result = ConfiguracoesAplicacao.objects.first().cronometro_ordem + if name == 'consideracoes': + result = ConfiguracoesAplicacao.objects.first().cronometro_consideracoes + + return result.total_seconds() + def get_materia_aberta(pk): return OrdemDia.objects.filter( @@ -558,10 +570,10 @@ def get_dados_painel(request, pk): 'sessao_solene': sessao.tipo.nome == "Solene", 'sessao_finalizada': sessao.finalizada, 'tema_solene': sessao.tema_solene, - 'cronometro_aparte': get_cronometro_status(request, 'aparte'), - 'cronometro_discurso': get_cronometro_status(request, 'discurso'), - 'cronometro_ordem': get_cronometro_status(request, 'ordem'), - 'cronometro_consideracoes': get_cronometro_status(request, 'consideracoes'), + 'cronometro_aparte': get_cronometro_value(request, 'aparte'), + 'cronometro_discurso': get_cronometro_value(request, 'discurso'), + 'cronometro_ordem': get_cronometro_value(request, 'ordem'), + 'cronometro_consideracoes': get_cronometro_value(request, 'consideracoes'), 'status_painel': sessao.painel_aberto, 'brasao': brasao } diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html index 1cb2e2c83..35f8f3430 100644 --- a/sapl/templates/painel/index.html +++ b/sapl/templates/painel/index.html @@ -1,495 +1,231 @@ {% load i18n %} {% load common_tags %} +{% load staticfiles %} {% load render_bundle from webpack_loader %} {% load webpack_static from webpack_loader %} - - - - - - - - {% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %} - - {% block webpack_loader_css %} - {% render_chunk_vendors 'css' %} - {% render_bundle 'global' 'css' %} - {% render_bundle 'painel' 'css' %} - {% endblock webpack_loader_css %} - - - - - - - -
-

-
-
-
- -
-
- + + + + + + {% block head_title %}{% trans 'SAPL - Sistema de Apoio ao Processo Legislativo' %}{% endblock %} + + {% block webpack_loader_css %} + {% render_chunk_vendors 'css' %} + {% render_bundle 'global' 'css' %} + {% render_bundle 'painel' 'css' %} + {% endblock webpack_loader_css %} + + + + +
+ + +
+ Logo
-
- -
-
- + +
+

[[ sessao_plenaria ]]

-
- -
-

-
- -
-
-
-
- - -
-
-
-
-

Parlamentares

- -
+ +
+
+ [[ sessao_plenaria_data ]] +
+
+ [[ sessao_plenaria_hora_inicio ]]
-
-
-

Oradores

- -
+
+ +
+

PAINEL ENCONTRA-SE FECHADO

+
+ +
+
+
+
-
-

Cronômetros

-
- Discurso:
- Aparte:
- Questão de Ordem:
- Considerações Finais: +
+
+
+
+
+

Parlamentares

+
+ + + + + + + + +
+ [[p.nome]] + + [[p.partido]] + + [[p.voto]] +
+
+
+ +
A listagem de parlamentares só aparecerá quando o painel estiver aberto.
+
+
+
+
+
+
+

Oradores

+
+ + + + + + +
+ [[ o.numero]]º  [[o.nome]] +
+
+
+ +
A listagem de oradores só aparecerá quando o painel estiver aberto.
+
+
- -
-

Resultado

- -

-

- -
-

Matéria em Votação

- -
- -
- +
+
+
+
+
+

Cronômetros

+
+ Discurso:[[ cronometro_discurso ]] + + +
+ + Aparte:[[ cronometro_aparte ]] + + +
+ + Questão de Ordem: [[ cronometro_ordem ]] + + +
+ + Considerações Finais: [[ cronometro_consideracoes ]] + + +
- - +
+
+

Tema da Sessão Solene

+ [[ sessao_solene_tema ]]
+
+
+
+

Resultado

+
+ +
  • Sim: [[ numero_votos_sim ]]
  • +
  • Não: [[ numero_votos_nao ]]
  • +
  • Abstenções: [[ numero_abstencoes ]]
  • +
  • Presentes: [[ num_presentes ]]
  • +
  • Total votos: [[ total_votos ]]
  • +
    +

    [[ tipo_resultado ]]

    +
    +
    +
    Não há votação, pois não há nenhuma matéria aberta ou já votada.
    +
    +
    +
    +
    +

    [[ mat_em_votacao ]]

    +
    + [[ materia_legislativa_texto ]] +
    + [[ materia_legislativa_ementa ]] +
    + [[ observacao_materia ]] +
    +
    + Não há nenhuma matéria votada ou para votação. +
    +
    +
    +
    + A Matéria em votação só aparecerá quando o painel estiver aberto +
    +
    +
    +
    +

    Resultado

    + +

    A votação só aparecerá quando o painel estiver aberto

    +
    +
    +
    -
    -
    - - - {% block webpack_loader_js %} - {% render_chunk_vendors 'js' %} - {% render_bundle 'global' 'js' %} - {% render_bundle 'painel' 'js' %} - {% endblock webpack_loader_js %} +
    +
    + - {% block webpack_loader_chunks_js %} - {% endblock webpack_loader_chunks_js %} + {% block webpack_loader_js %} + {% render_chunk_vendors 'js' %} + {% render_bundle 'global' 'js' %} + {% render_bundle 'painel' 'js' %} + {% endblock webpack_loader_js %} - - - + // As constantes decisões sobre a existência ou não do horário de verão, + // assim como que data de início e termino do mesmo, fizeram com que fosse necessário + // substituir a chamada a Date() por um esquema mais elaborado, onde se + // recupera o offset do UTC (-3 GMT, no caso de Brasília) e seta-se + // manualmente. Esta informação vem do servidor, desta forma não ficamos + // na dependência da atualização de browser, pois tanto o Date() em JS + // quanto as libs python (django.utils.timezone, datetime, pytz, etc) + // lêem do tzdata, que precisa ser atualizado toda vez que o governo + // brasileiro modifica alguma coisa relacionada ao horário de verão. + // Recuperando essa informação do servidor só teremos que atualizar as + // libs tzdata (Linux) e pytz (Python) uma vez. Além disso, o uso da + // biblioteca moment.js é recomendada, pois ela trata data e hora + // melhor que o Date() do JS. + + $("#date").append(moment().format("DD/MM/YY")); + + }) + + \ No newline at end of file