mirror of https://github.com/interlegis/sapl.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
137 lines
4.5 KiB
137 lines
4.5 KiB
import './scss/votacao-simbolica.scss'
|
|
import Vue from 'vue'
|
|
import VueCompositionApi from '@vue/composition-api'
|
|
import { PiniaVuePlugin, createPinia } from 'pinia'
|
|
import axios from 'axios'
|
|
|
|
import { usePainelStore } from '../painel/store/painelStore'
|
|
import { isPermanentCloseCode, permanentCloseMessage, nextBackoffDelay, INITIAL_BACKOFF_MS, DISCONNECTED_MESSAGE } from '../painel/ws/painelSocket'
|
|
import VotacaoSimbolica from '../../components/votacao-simbolica/VotacaoSimbolica.vue'
|
|
import WsStatusBanner from '../../components/painel/WsStatusBanner.vue'
|
|
|
|
Vue.component('votacao-simbolica', VotacaoSimbolica)
|
|
Vue.component('ws-status-banner', WsStatusBanner)
|
|
|
|
axios.defaults.xsrfCookieName = 'csrftoken'
|
|
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
|
|
|
|
Vue.use(VueCompositionApi)
|
|
Vue.use(PiniaVuePlugin)
|
|
const pinia = createPinia()
|
|
|
|
new Vue({ // eslint-disable-line
|
|
pinia,
|
|
delimiters: ['[[', ']]'],
|
|
el: '#votacao-simbolica',
|
|
data () {
|
|
return {
|
|
sessaoId: null,
|
|
oid: null,
|
|
mid: null,
|
|
fase: 'ordem',
|
|
totalPresentes: 0,
|
|
totalVotantes: 0,
|
|
ws: null,
|
|
reconnectTimer: null,
|
|
reconnectDelay: INITIAL_BACKOFF_MS,
|
|
wsStatus: 'connecting',
|
|
wsErrorMessage: 'Conectando ao servidor de tempo real…',
|
|
error_message: ''
|
|
}
|
|
},
|
|
mounted () {
|
|
const el = this.$el
|
|
this.sessaoId = el.dataset.sessaoId
|
|
this.oid = el.dataset.oid
|
|
this.mid = el.dataset.mid
|
|
this.fase = el.dataset.fase || 'ordem'
|
|
this.totalPresentes = el.dataset.totalPresentes
|
|
this.totalVotantes = el.dataset.totalVotantes
|
|
|
|
const tiposResultadoEl = document.getElementById('tipos-resultado')
|
|
if (tiposResultadoEl) {
|
|
try {
|
|
this.painelStore().tipos_resultado = JSON.parse(tiposResultadoEl.textContent)
|
|
} catch (e) {
|
|
console.error('Erro ao ler tipos-resultado:', e)
|
|
}
|
|
}
|
|
|
|
if (this.sessaoId) {
|
|
this.connectWS()
|
|
}
|
|
},
|
|
methods: {
|
|
painelStore () {
|
|
return usePainelStore()
|
|
},
|
|
actionUrl () {
|
|
// Mesma URL da tela legada (VotacaoView/VotacaoExpedienteView) —
|
|
// sessao/urls.py: continua sendo quem grava o voto (só o shell/GET
|
|
// mudou pra v2); fase decide ordem do dia ou expediente, mesmo
|
|
// discriminador usado pelo shell (votacao_simbolica_v2_view).
|
|
const etapa = this.fase === 'expediente' ? 'expediente' : 'ordemdia'
|
|
return `/sessao/${this.sessaoId}/materia/${etapa}/votacao/simbolica/${this.oid}/${this.mid}`
|
|
},
|
|
wsURL () {
|
|
const proto = location.protocol === 'https:' ? 'wss' : 'ws'
|
|
return `${proto}://${location.host}/ws/painel/${this.sessaoId}/`
|
|
},
|
|
connectWS () {
|
|
this.ws = new WebSocket(this.wsURL())
|
|
this.ws.addEventListener('open', () => {
|
|
this.wsStatus = 'open'
|
|
this.wsErrorMessage = ''
|
|
this.reconnectDelay = INITIAL_BACKOFF_MS
|
|
})
|
|
this.ws.addEventListener('message', (message) => {
|
|
try {
|
|
const data = JSON.parse(message.data)
|
|
if (data.type === 'data') {
|
|
// applyData() espera o payload cru, não o envelope {type,
|
|
// payload} (mesmo ajuste de painel/votacao/voto-individual
|
|
// main.js).
|
|
this.painelStore().applyData(data.payload)
|
|
}
|
|
} catch (e) {
|
|
console.error('Votacao simbolica WS parse error:', e)
|
|
}
|
|
})
|
|
this.ws.addEventListener('close', (e) => {
|
|
if (isPermanentCloseCode(e.code)) {
|
|
this.wsStatus = 'error'
|
|
this.wsErrorMessage = permanentCloseMessage(e.code)
|
|
return
|
|
}
|
|
this.wsStatus = 'reconnecting'
|
|
this.wsErrorMessage = DISCONNECTED_MESSAGE
|
|
this.reconnectTimer = setTimeout(() => this.connectWS(), this.reconnectDelay)
|
|
this.reconnectDelay = nextBackoffDelay(this.reconnectDelay)
|
|
})
|
|
},
|
|
postAction (payload) {
|
|
axios.post(this.actionUrl(), payload, {
|
|
headers: { 'Content-Type': 'application/json' }
|
|
})
|
|
.then(response => {
|
|
if (response.data.redirect_url) {
|
|
window.location.href = response.data.redirect_url
|
|
}
|
|
})
|
|
.catch(error => {
|
|
const data = error.response && error.response.data
|
|
this.error_message = (data && data.message) || 'Erro ao processar a votação. Tente novamente.'
|
|
})
|
|
},
|
|
onCancelar () {
|
|
this.postAction({ 'cancelar-votacao': '1' })
|
|
},
|
|
onSalvar (data) {
|
|
this.postAction(data)
|
|
},
|
|
beforeDestroy () {
|
|
if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
|
|
if (this.ws) this.ws.close()
|
|
}
|
|
}
|
|
})
|
|
|