diff --git a/frontend/src/__apps/painel-controle/main.js b/frontend/src/__apps/painel-controle/main.js
new file mode 100644
index 000000000..8e405475c
--- /dev/null
+++ b/frontend/src/__apps/painel-controle/main.js
@@ -0,0 +1,38 @@
+import './scss/painel.scss'
+import Vue from 'vue'
+import { FormSelectPlugin } from 'bootstrap-vue'
+import axios from 'axios'
+
+//TODO: incluir painel-controle dentro da app de painel, colocando rotas diferentes
+
+axios.defaults.xsrfCookieName = 'csrftoken'
+axios.defaults.xsrfHeaderName = 'X-CSRFToken'
+
+Vue.use(FormSelectPlugin)
+
+console.log('painel controle main.js carregado')
+
+const v = new Vue({ // eslint-disable-line
+ delimiters: ['[[', ']]'],
+ el: '#painel-controle',
+ data () {
+ return {
+ sessao_plenaria: "74ª Sessão Ordinária da 1ª Sessão Legislativa da 18ª Legislatura",
+ message: "",
+ }
+ },
+
+ watch: {},
+
+ computed: {
+
+ },
+
+ created () {},
+
+ methods: {},
+
+ mounted () {
+ console.log("Painel controle app mounted!")
+ }
+})
diff --git a/frontend/src/__apps/painel-controle/scss/painel.scss b/frontend/src/__apps/painel-controle/scss/painel.scss
new file mode 100644
index 000000000..aa3c060a1
--- /dev/null
+++ b/frontend/src/__apps/painel-controle/scss/painel.scss
@@ -0,0 +1,43 @@
+
+.painel-principal {
+ background: #1c1b1b;
+ font-family: Verdana;
+ font-size: x-large;
+ .text-title {
+ color: #4fa64d;
+ margin: 0.5rem;
+ font-weight: bold;
+ }
+ .text-subtitle {
+ color: #459170;
+ font-weight: bold;
+ }
+ .data-hora {
+ font-size: 180%;
+ }
+
+ .text-value {
+ color: white;
+ }
+
+ .logo-painel {
+ max-width: 100%;
+ }
+ .painels {
+ flex-wrap: wrap;
+ }
+ .painel{
+ margin-top: 1rem;
+ table {
+ width: 100%;
+ }
+ h2 {
+ margin-bottom: 0.5rem;
+ }
+ #votacao, #oradores_list {
+ text-align: left;
+ display: inline-block;
+ margin-bottom: 1rem;
+ }
+ }
+}
\ No newline at end of file
diff --git a/frontend/src/__apps/painel/main.js b/frontend/src/__apps/painel/main.js
index def3ca411..c78642a91 100644
--- a/frontend/src/__apps/painel/main.js
+++ b/frontend/src/__apps/painel/main.js
@@ -6,13 +6,13 @@ import Vuex from 'vuex'
import { mapState } from 'vuex';
import { mapMutations } from 'vuex'
-import Cronometro from '../../components/Cronometro.vue'
-import CronometroList from '../../components/CronometroList.vue'
-import PainelHeader from '../../components/PainelHeader.vue'
-import PainelParlamentares from '../../components/PainelParlamentares.vue'
-import PainelOradores from '../../components/PainelOradores.vue'
-import PainelMateria from '../../components/PainelMateria.vue'
-import PainelResultado from '../../components/PainelResultado.vue'
+import Cronometro from '../../components/painel/Cronometro.vue'
+import CronometroList from '../../components/painel/CronometroList.vue'
+import PainelHeader from '../../components/painel/PainelHeader.vue'
+import PainelParlamentares from '../../components/painel/PainelParlamentares.vue'
+import PainelOradores from '../../components/painel/PainelOradores.vue'
+import PainelMateria from '../../components/painel/PainelMateria.vue'
+import PainelResultado from '../../components/painel/PainelResultado.vue'
import alarm from '../../assets/audio/ring.mp3'
// register components
@@ -49,11 +49,13 @@ const store = new Vuex.Store({
state.parlamentares = parlamentares;
},
updateParlamentares(state, votos_parlamentares) {
- state.parlamentares.forEach((p)=>{
- if (p.parlamentar_id in votos_parlamentares) {
- p.voto = votos_parlamentares[p.parlamentar_id].voto
- }
- });
+ if (votos_parlamentares) {
+ state.parlamentares.forEach((p)=>{
+ if (p.parlamentar_id in votos_parlamentares) {
+ p.voto = votos_parlamentares[p.parlamentar_id].voto
+ }
+ });
+ }
},
setOradores(state, oradores) {
state.oradores = oradores;
@@ -85,17 +87,6 @@ new Vue({
data() {
return {
controllerId: null,
- // TODO: state here is really needed?
- state: {
- sessao_plenaria: '',
- sessao_plenaria_data: '',
- sessao_plenaria_hora_inicio: '',
- votacao: [],
- parlamentares: [],
- oradores: [],
- materia: {},
- resultado: {},
- },
ws: null,
isOpen: false,
error: null,
@@ -104,6 +95,7 @@ new Vue({
}
},
mounted() {
+ console.log('Painel principal mounted!')
// $el is guaranteed here
const el = this.$el
// prefer data-attr; fallback to global if you set it
@@ -206,12 +198,12 @@ new Vue({
}
// RESULTADO
- if (data.resultado) {
- this.setResultado(data.resultado);
+ if (data.materia.resultado) {
+ this.setResultado(data.materia.resultado);
}
- if (data.votos_parlamentares) {
- this.updateParlamentares(data.votos_parlamentares);
+ if (data.materia.resultado.votos_parlamentares) {
+ this.updateParlamentares(data.materia.resultado.votos_parlamentares);
}
} catch (e) {
console.error('Error', e);
@@ -225,12 +217,12 @@ new Vue({
this.isOpen = true;
this.error = null
- console.log(`✅ WebSocket connected: ${url}`);
+ console.log(`✅ WebSocket connected to ${url}`);
// send an initial message to the server
this.ws.send(JSON.stringify({ type: "echo", message: "Client connected" }));
- // Ping keep-alive
+ // ping keep-alive timer
this.pingTimer = setInterval(() => {
const ping = JSON.stringify({ type: "ping", ts: Date.now()});
console.log(`Sending ping ${ping}`)
diff --git a/frontend/src/__apps/votacao/main.js b/frontend/src/__apps/votacao/main.js
new file mode 100644
index 000000000..07069d600
--- /dev/null
+++ b/frontend/src/__apps/votacao/main.js
@@ -0,0 +1,237 @@
+import './scss/votacao.scss'
+import Vue from 'vue'
+import { FormSelectPlugin } from 'bootstrap-vue'
+import axios from 'axios'
+
+axios.defaults.xsrfCookieName = 'csrftoken'
+axios.defaults.xsrfHeaderName = 'X-CSRFToken'
+
+Vue.use(FormSelectPlugin)
+
+console.log('votacao main.js carregado')
+
+const v = new Vue({ // eslint-disable-line
+ delimiters: ['[[', ']]'],
+ el: '#votacao',
+ data () {
+ return {
+ votacao_aberta: true,
+ edit_votes: true,
+ disable_resultado: false,
+ resultado_selected: "",
+ observacoes: "",
+ error_message: "",
+ tipo_votacao: "Votação Nominal",
+ materia: "Projeto de Lei Ordinária nº 3 de 2025",
+ ementa: "Institui no Município de Pato Branco o Projeto Chá de Fralda Social. ",
+ parlamentares: [
+ {
+ "parlamentar_id": 197,
+ "nome_parlamentar": "Alexandre Zoche",
+ "filiacao": "PRD"
+ },
+ {
+ "parlamentar_id": 196,
+ "nome_parlamentar": "Anne Cristine Gomes da Silva Cavali",
+ "filiacao": "PSD"
+ },
+ {
+ "parlamentar_id": 194,
+ "nome_parlamentar": "Diogo Domingos Grando",
+ "filiacao": "PRD"
+ },
+ {
+ "parlamentar_id": 186,
+ "nome_parlamentar": "Eduardo Albani Dala Costa",
+ "filiacao": "Republicanos"
+ },
+ {
+ "parlamentar_id": 3,
+ "nome_parlamentar": "Fabricio Preis de Mello",
+ "filiacao": "PL"
+ },
+ {
+ "parlamentar_id": 6,
+ "nome_parlamentar": "Joecir Bernardi",
+ "filiacao": "PSD"
+ },
+ {
+ "parlamentar_id": 187,
+ "nome_parlamentar": "Lindomar Rodrigo Brandão",
+ "filiacao": "PP"
+ },
+ {
+ "parlamentar_id": 195,
+ "nome_parlamentar": "Rafael Foss",
+ "filiacao": "União"
+ },
+ {
+ "parlamentar_id": 11,
+ "nome_parlamentar": "Rodrigo José Correia",
+ "filiacao": "União"
+ },
+ {
+ "parlamentar_id": 192,
+ "nome_parlamentar": "Thania Maria Caminski Gehlen",
+ "filiacao": "PP"
+ }
+ ],
+ //TODO: check if votos_parlamentares is null
+ votos_parlamentares: {
+ 186: {
+ "voto": "Não",
+ "materia_id": 31919,
+ "parlamentar_id": 186,
+ "parlamentar_nome": "Eduardo Albani Dala Costa"
+ },
+ 195: {
+ "voto": "Não",
+ "materia_id": 31919,
+ "parlamentar_id": 195,
+ "parlamentar_nome": "Rafael Foss"
+ },
+ 196: {
+ "voto": "Não",
+ "materia_id": 31919,
+ "parlamentar_id": 196,
+ "parlamentar_nome": "Anne Cristine Gomes da Silva Cavali"
+ },
+ 3: {
+ "voto": "Sim",
+ "materia_id": 31919,
+ "parlamentar_id": 3,
+ "parlamentar_nome": "Fabricio Preis de Mello"
+ },
+ 11: {
+ "voto": "Não",
+ "materia_id": 31919,
+ "parlamentar_id": 11,
+ "parlamentar_nome": "Rodrigo José Correia"
+ },
+ 194: {
+ "voto": "Não",
+ "materia_id": 31919,
+ "parlamentar_id": 194,
+ "parlamentar_nome": "Diogo Domingos Grando"
+ },
+ 197: {
+ "voto": "Não",
+ "materia_id": 31919,
+ "parlamentar_id": 197,
+ "parlamentar_nome": "Alexandre Zoche"
+ },
+ 6: {
+ "voto": "Não",
+ "materia_id": 31919,
+ "parlamentar_id": 6,
+ "parlamentar_nome": "Joecir Bernardi"
+ },
+ 187: {
+ "voto": "Abstenção",
+ "materia_id": 31919,
+ "parlamentar_id": 187,
+ "parlamentar_nome": "Lindomar Rodrigo Brandão"
+ },
+ 192: {
+ "voto": "Sim",
+ "materia_id": 31919,
+ "parlamentar_id": 192,
+ "parlamentar_nome": "Thania Maria Caminski Gehlen"
+ }
+ },
+ options: [
+ { text: 'Sim', value: 'voto_sim' },
+ { text: 'Não', value: 'voto_nao' },
+ { text: 'Abstenção', value: 'abstencao' },
+ { text: 'Não Votou', value: 'nao_votou' },
+ ],
+ tipos_resultados: [
+ {
+ "id": 13,
+ "nome": "Aprovada a retirada de pauta"
+ },
+ {
+ "id": 10,
+ "nome": "Aprovada por dois terços"
+ },
+ {
+ "id": 2,
+ "nome": "Aprovada por maioria absoluta"
+ },
+ {
+ "id": 1,
+ "nome": "Aprovada por maioria simples - conforme o art. 37 do RI o presidente não vota"
+ },
+ {
+ "id": 8,
+ "nome": "Aprovada por maioria simples - conforme o art. 37 do RI o presidente votou pelo desempate"
+ },
+ {
+ "id": 15,
+ "nome": "Aprovada."
+ },
+ {
+ "id": 7,
+ "nome": "Empate - conforme o art. 37 do RI o presidente vota para desempate"
+ },
+ {
+ "id": 16,
+ "nome": "IMPROCEDENTE"
+ },
+ {
+ "id": 12,
+ "nome": "Leitura em Plenário"
+ },
+ {
+ "id": 17,
+ "nome": "PROCEDENTE"
+ },
+ {
+ "id": 11,
+ "nome": "Prejudicada"
+ },
+ {
+ "id": 5,
+ "nome": "Rejeitada"
+ },
+ {
+ "id": 14,
+ "nome": "Rejeitada a retirada de pauta"
+ },
+ {
+ "id": 9,
+ "nome": "Rejeitada por maioria simples - conforme o art. 37 do RI o presidente votou pelo desempate"
+ }
+ ],
+ }
+ },
+
+ watch: {},
+
+ computed: {
+ total_votos() {
+ // TODO: use number index instead of string ("sim", "não") as keys.
+ var groupedVotes = Map.groupBy(Object.values(this.votos_parlamentares), ({ voto }) => voto )
+ // initialize total_votos
+ total_votos = [
+ {"tipo": "Sim", "total": 0},
+ {"tipo": "Não", "total": 0},
+ {"tipo": "Abstenção", "total": 0},
+ {"tipo": "Não Votou", total: 0}
+ ]
+ for (const [key, value] of groupedVotes.entries()) {
+ const index = total_votos.findIndex(item => item.tipo === key);
+ total_votos[index].total = value.length
+ }
+ return total_votos
+ }
+ },
+
+ created () {},
+
+ methods: {},
+
+ mounted () {
+ console.log("Votacao app mounted!")
+ }
+})
diff --git a/frontend/src/__apps/votacao/scss/votacao.scss b/frontend/src/__apps/votacao/scss/votacao.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/frontend/src/components/Cronometro.vue b/frontend/src/components/painel/Cronometro.vue
similarity index 100%
rename from frontend/src/components/Cronometro.vue
rename to frontend/src/components/painel/Cronometro.vue
diff --git a/frontend/src/components/CronometroList.vue b/frontend/src/components/painel/CronometroList.vue
similarity index 100%
rename from frontend/src/components/CronometroList.vue
rename to frontend/src/components/painel/CronometroList.vue
diff --git a/frontend/src/components/PainelHeader.vue b/frontend/src/components/painel/PainelHeader.vue
similarity index 95%
rename from frontend/src/components/PainelHeader.vue
rename to frontend/src/components/painel/PainelHeader.vue
index c7376d4c8..38b13bd6d 100644
--- a/frontend/src/components/PainelHeader.vue
+++ b/frontend/src/components/painel/PainelHeader.vue
@@ -16,7 +16,7 @@
-