github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/frontend/bv/src/pages/vote/admin/Votes.vue (about) 1 <template> 2 <b-overlay :show="loading"> 3 <b-card> 4 <b-card-title> 5 <b-row> 6 <b-col> Votes en cours</b-col> 7 <b-col class="text-right"> 8 <b-button variant="success" @click="createVote"> 9 <b-icon-plus></b-icon-plus> 10 Ajouter un vote</b-button 11 > 12 <b-button 13 :href="urlExportVotes" 14 target="_blank" 15 variant="info" 16 class="ml-2" 17 title="Télécharger les votes clôturés au format PDF" 18 :disabled="exportDisabled" 19 > 20 <b-icon-download></b-icon-download> 21 Bilan des votes 22 </b-button> 23 <b-button 24 @click="refresh" 25 variant="light" 26 title="Rafraichir les données" 27 class="ml-2" 28 > 29 <b-icon-arrow-repeat></b-icon-arrow-repeat> 30 </b-button> 31 </b-col> 32 </b-row> 33 </b-card-title> 34 <b-card v-for="(vote, i) in votes" :key="i" class="my-1 border-secondary"> 35 <b-card-text> 36 <b-form> 37 <b-row> 38 <b-col cols="8"> 39 <b-form-group label="Nom" label-cols="3"> 40 <b-form-input 41 v-model="vote.nom" 42 required 43 :disabled="!editModes[vote.id]" 44 ></b-form-input> 45 </b-form-group> 46 </b-col> 47 <b-col cols="4" class="text-right"> 48 <b-button 49 v-if="!editModes[vote.id] && isVoteEditable(vote)" 50 @click="editVote(vote)" 51 size="sm" 52 v-b-tooltip.hover 53 title="Modifier les paramètres du vote..." 54 > 55 <b-icon-pencil></b-icon-pencil> 56 Editer 57 </b-button> 58 <b-button 59 v-else-if="isVoteEditable(vote)" 60 @click="save(vote)" 61 size="sm" 62 v-b-tooltip.hover 63 title="Enregistrer les modifications" 64 > 65 <b-icon-check></b-icon-check> 66 Enregistrer 67 </b-button> 68 69 <b-button 70 v-if="vote.participation > 0 && !vote.is_locked" 71 @click="clear(vote)" 72 size="sm" 73 v-b-tooltip.hover 74 variant="danger" 75 title="Supprimer les suffrages déjà exprimés" 76 class="ml-2" 77 > 78 Remettre à zéro 79 </b-button> 80 <b-button 81 @click="lockVote(vote)" 82 size="sm" 83 v-b-tooltip.hover 84 variant="outline-warning" 85 :title=" 86 vote.is_locked ? 'Ré-ouvrir ce vote' : 'Cloturer ce vote' 87 " 88 :disabled="editModes[vote.id]" 89 class="ml-2" 90 > 91 <b-icon-unlock v-if="vote.is_locked"></b-icon-unlock> 92 <b-icon-lock v-else></b-icon-lock> 93 <b-badge v-if="vote.is_locked" variant="warning" class="ml-2" 94 >Vote cloturé</b-badge 95 > 96 </b-button> 97 <b-button 98 @click="deleteVote(vote)" 99 size="sm" 100 v-b-tooltip.hover 101 variant="danger" 102 title="Supprimer ce vote" 103 class="ml-2" 104 > 105 <b-icon-trash></b-icon-trash> 106 </b-button> 107 </b-col> 108 </b-row> 109 <b-form-group label="Choix multiples" label-cols="2"> 110 <b-form-checkbox 111 v-model="vote.is_qcm" 112 :disabled="!editModes[vote.id]" 113 >Permet plusieurs choix par personne.</b-form-checkbox 114 > 115 </b-form-group> 116 <b-form-group label="Description" label-cols="2"> 117 <b-form-textarea 118 v-model="vote.description" 119 placeholder="Optionnel" 120 :disabled="!editModes[vote.id]" 121 ></b-form-textarea> 122 </b-form-group> 123 <b-form-group 124 label-cols="2" 125 label="Choix possibles" 126 v-if="!editModes[vote.id]" 127 > 128 <b-list-group horizontal class="flex-wrap"> 129 <b-list-group-item 130 v-for="candidat in vote.candidats || []" 131 :key="candidat.id" 132 class="border rounded py-2 px-3" 133 style="width: 33%" 134 > 135 <b-row no-gutters> 136 <b-col>{{ candidat.label }}</b-col> 137 <b-col cols="3" class="text-right"> 138 <b-badge variant="info"> 139 {{ (vote.voix || {})[candidat.id] }} voix 140 </b-badge> 141 </b-col> 142 </b-row> 143 </b-list-group-item> 144 <b-list-group-item v-if="(vote.candidats || []).length == 0"> 145 Aucun choix possible. 146 </b-list-group-item> 147 </b-list-group> 148 </b-form-group> 149 <b-form-group label="Choix possibles" label-cols="2" v-else> 150 <edit-candidats 151 :vote="vote" 152 :completion="completion" 153 ></edit-candidats> 154 </b-form-group> 155 </b-form> 156 </b-card-text> 157 </b-card> 158 </b-card> 159 </b-overlay> 160 </template> 161 162 <script lang="ts"> 163 import Vue from "vue"; 164 import Component from "vue-class-component"; 165 import EditCandidats from "./EditCandidats.vue"; 166 167 import { C, BASE_URL } from "./controller"; 168 import { VoteAdmin, Candidat, Vote, LockVote } from "@/shared/logic/types"; 169 170 const VotesProps = Vue.extend({ 171 props: {} 172 }); 173 174 @Component({ 175 components: { EditCandidats } 176 }) 177 export default class Votes extends VotesProps { 178 loading = false; 179 votes: VoteAdmin[] = []; 180 editModes: { [key: number]: boolean } = {}; 181 C = C; 182 183 urlExportVotes = BASE_URL + "/votes/export"; 184 185 created() { 186 this.refresh(); 187 } 188 189 async refresh() { 190 this.loading = true; 191 const data = await C.getVotes(); 192 this.loading = false; 193 if (data == undefined) return; 194 this.votes = data || []; 195 this.editModes = {}; 196 C.notifications.success = { 197 title: "Votes", 198 message: "Liste des votes en cours chargées." 199 }; 200 } 201 202 async createVote() { 203 this.loading = true; 204 const data = await C.createVote({ 205 id: -1, 206 nom: "", 207 description: "", 208 is_qcm: true, 209 is_locked: false, 210 candidats: [] 211 }); 212 this.loading = false; 213 if (data == undefined) return; 214 this.votes = data || []; 215 this.editModes = {}; 216 C.notifications.success = { 217 title: "Nouveau vote", 218 message: "Vote ajouté avec succés." 219 }; 220 } 221 222 get completion() { 223 return C.membres.map(m => m.nom_prenom); 224 } 225 226 /** si aucun vote n'est verrouillé, le document sera vide */ 227 get exportDisabled() { 228 return this.votes.filter(v => v.is_locked).length == 0; 229 } 230 231 isVoteEditable(vote: VoteAdmin) { 232 return !vote.is_locked && vote.participation == 0; 233 } 234 235 editVote(vote: VoteAdmin) { 236 this.$set(this.editModes, vote.id, true); 237 } 238 239 async save(vote: VoteAdmin) { 240 this.loading = true; 241 const data = await C.updateVote(vote); 242 this.loading = false; 243 this.editModes[vote.id] = false; 244 if (data == undefined) return; 245 this.votes = data || []; 246 this.editModes = {}; 247 C.notifications.success = { 248 title: "Vote", 249 message: "Vote modifié avec succés." 250 }; 251 } 252 253 async lockVote(vote: VoteAdmin) { 254 this.loading = true; 255 // on inverse l'état actuel 256 const params: LockVote = { id_vote: vote.id, is_locked: !vote.is_locked }; 257 const data = await C.lockVote(params); 258 this.loading = false; 259 if (data == undefined) return; 260 this.votes = data || []; 261 this.editModes = {}; 262 let message = "Vote cloturé avec succès."; 263 if (vote.is_locked) { 264 message = "Vote ouvert à nouveau."; 265 } 266 C.notifications.success = { 267 title: "Verrou", 268 message 269 }; 270 } 271 272 async doDeleteVote(vote: VoteAdmin) { 273 this.loading = true; 274 const data = await C.deleteVote(vote.id); 275 this.loading = false; 276 this.editModes = {}; 277 if (data === undefined) return; 278 this.votes = data || []; 279 C.notifications.success = { 280 title: "Suppression", 281 message: "Vote supprimé avec succés." 282 }; 283 } 284 285 deleteVote(vote: VoteAdmin) { 286 this.$bvModal 287 .msgBoxConfirm("Confirmer la suppression du vote", { 288 title: "Suppression", 289 okVariant: "danger", 290 cancelTitle: "Retour" 291 }) 292 .then(value => { 293 if (value) { 294 this.doDeleteVote(vote); 295 } 296 }); 297 } 298 299 async doClear(vote: VoteAdmin) { 300 this.loading = true; 301 const data = await C.clearVote(vote.id); 302 this.loading = false; 303 this.editModes = {}; 304 305 if (data === undefined) return; 306 this.votes = data || []; 307 C.notifications.success = { 308 title: "Suppression", 309 message: "Voix supprimées avec succés." 310 }; 311 } 312 313 clear(vote: VoteAdmin) { 314 this.$bvModal 315 .msgBoxConfirm("Confirmer la suppression des suffrages", { 316 title: "Suppression", 317 okVariant: "danger", 318 cancelTitle: "Retour" 319 }) 320 .then(value => { 321 if (value) { 322 this.doClear(vote); 323 } 324 }); 325 } 326 } 327 </script> 328 329 <style scoped></style>