github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/frontend/directeurs/src/views/Equipiers.vue (about) 1 <template> 2 <v-container fluid> 3 <v-dialog 4 v-model="showAddEquipier" 5 max-width="1200px" 6 @keydown.esc="showAddEquipier = false" 7 > 8 <add-equipier @ajoute-equipier="ajouteEquipier"></add-equipier> 9 </v-dialog> 10 11 <v-dialog v-model="showEditDialog" max-width="1200px" persistent> 12 <form-equipier 13 :equipier="editEquipier" 14 withButtons 15 withDetails 16 @reject="showEditDialog = false" 17 @accept="updateEquipier" 18 ></form-equipier> 19 </v-dialog> 20 21 <v-dialog v-model="confirmeSupprime" max-width="400px"> 22 <v-card v-if="equipierSupprime != null"> 23 <v-card-title class="headline">Suppression d'un équipier</v-card-title> 24 <v-card-text> 25 Etes vous sur de retirer 26 <b>{{ equipierSupprime.prenom }} {{ equipierSupprime.nom }}</b> de 27 votre équipe ? 28 </v-card-text> 29 <v-card-actions> 30 <v-btn @click="confirmeSupprime = false">Annuler</v-btn> 31 <v-spacer></v-spacer> 32 <v-btn @click="supprimeEquipier" class="error--text"> 33 Retirer de l'équipe 34 </v-btn> 35 </v-card-actions> 36 </v-card> 37 </v-dialog> 38 39 <v-dialog v-model="showDocuments" eager> 40 <documents ref="documents"></documents> 41 </v-dialog> 42 43 <v-dialog v-model="showInviteFormulaires"> 44 <formulaires v-model="items"></formulaires> 45 </v-dialog> 46 47 <v-toolbar dense> 48 <v-menu open-on-hover bottom offset-y> 49 <template v-slot:activator="{ on }"> 50 <v-btn v-on="on" icon> 51 <v-icon>{{ $icons["mdi-information-outline"] }}</v-icon> 52 </v-btn> 53 </template> 54 <v-card> 55 <v-card-text> 56 <b>{{ nbMembres }}</b> équipier(s) 57 <br /> 58 <b>{{ nbAnims }}</b> animateur(s) 59 </v-card-text> 60 </v-card> 61 </v-menu> 62 <v-toolbar-title>Liste des équipiers </v-toolbar-title> 63 <v-spacer></v-spacer> 64 <v-toolbar-items> 65 <tooltip-btn 66 tooltip="Rechercher et déclarer un nouvel équipier" 67 @click="showAddEquipier = true" 68 text 69 small 70 > 71 <v-icon class="mr-1" color="success">{{ $icons["mdi-plus"] }}</v-icon 72 >Ajouter un équipier 73 </tooltip-btn> 74 <v-divider vertical></v-divider> 75 <tooltip-btn 76 tooltip="Inviter les équipiers à remplir leur formulaire..." 77 @click="showInviteFormulaires = true" 78 text 79 small 80 > 81 <v-icon class="mr-1">{{ $icons["mdi-account-details"] }}</v-icon 82 >Formulaires 83 </tooltip-btn> 84 <!-- Export rapides des mails --> 85 <v-menu> 86 <template v-slot:activator="{ on: menu }"> 87 <v-tooltip bottom> 88 <template v-slot:activator="{ on: tooltip }"> 89 <v-btn v-on="{ ...tooltip, ...menu }" depressed>Mails</v-btn> 90 </template> 91 Envoyer un mail à l'équipe... 92 </v-tooltip> 93 </template> 94 <v-list> 95 <v-list-item> 96 <v-list-item-content> 97 <a :href="mailtoEquipe"> Mail à toute l'équipe</a> 98 </v-list-item-content> 99 <v-list-item-action> 100 <tooltip-btn 101 tooltip="Copier les adresses" 102 @click="copyMailsToClipboard(false)" 103 icon 104 > 105 <v-icon>{{ $icons["mdi-content-copy"] }} </v-icon> 106 </tooltip-btn> 107 </v-list-item-action> 108 </v-list-item> 109 <v-list-item> 110 <v-list-item-content> 111 <a :href="mailtoAnims"> 112 Mail à l'équipe d'animation 113 </a> 114 </v-list-item-content> 115 <v-list-item-action> 116 <tooltip-btn 117 tooltip="Copier les adresses" 118 @click="copyMailsToClipboard(true)" 119 icon 120 > 121 <v-icon>{{ $icons["mdi-content-copy"] }} </v-icon> 122 </tooltip-btn> 123 </v-list-item-action> 124 </v-list-item> 125 </v-list> 126 </v-menu> 127 <v-divider vertical></v-divider> 128 <tooltip-btn 129 tooltip="Télécharger une liste au format Excel" 130 @click="exportListe()" 131 text 132 small 133 > 134 <v-icon class="mr-1">{{ $icons["mdi-download"] }}</v-icon 135 >Exporter 136 </tooltip-btn> 137 <tooltip-btn 138 tooltip="Afficher les pièces justificatives des membres de l'équipe" 139 text 140 small 141 @click="loadAndShowDocuments" 142 > 143 <v-icon class="mr-1">{{ $icons["mdi-folder"] }}</v-icon 144 >Documents 145 </tooltip-btn> 146 </v-toolbar-items> 147 </v-toolbar> 148 <v-data-table 149 :headers="header" 150 :items="items" 151 hide-default-footer 152 class="mt-2" 153 fixed-header 154 height="72vh" 155 dense 156 :items-per-page="9999" 157 id="equipiers" 158 @click:row=" 159 item => { 160 editEquipier = item; 161 showEditDialog = true; 162 } 163 " 164 > 165 <template v-slot:no-data> 166 <v-alert :value="true" type="warning"> 167 Aucun membre de l'équipe n'est déclaré pour le moment. 168 <br /> 169 <i>(Vous pouvez ajouter un équipier avec le bouton "Ajouter".)</i> 170 </v-alert> 171 </template> 172 173 <template v-slot:[`item.delete`]="{ item }"> 174 <tooltip-btn 175 :tooltip="'Enlever ' + item.prenom + ' ' + item.nom + ` de l'équipe`" 176 icon 177 small 178 class="mr-2" 179 color="red" 180 @click.stop=" 181 () => { 182 equipierSupprime = item; 183 confirmeSupprime = true; 184 } 185 " 186 > 187 <v-icon> 188 {{ $icons["mdi-delete"] }} 189 </v-icon> 190 </tooltip-btn> 191 </template> 192 <template v-slot:[`item.nom`]="{ item }"> 193 <div style="width: 100px;"> 194 {{ item.nom }} 195 </div> 196 </template> 197 <template v-slot:[`item.prenom`]="{ item }"> 198 <div style="width: 100px;"> 199 {{ item.prenom }} 200 </div> 201 </template> 202 <template v-slot:[`item.date_naissance`]="{ item }"> 203 <div style="width: 120px;"> 204 {{ fmt.date(item.date_naissance) }} 205 </div> 206 </template> 207 <template v-slot:[`item.roles`]="{ item }"> 208 {{ fmt.roles(item.roles) }} 209 </template> 210 <template v-slot:[`item.diplome`]="{ item }"> 211 {{ fmt.diplome(item.diplome) }} 212 </template> 213 <template v-slot:[`item.appro`]="{ item }"> 214 {{ fmt.approfondissement(item.appro) }} 215 </template> 216 <template v-slot:[`item.sexe`]="{ item }"> 217 {{ fmt.sexe(item.sexe) }} 218 </template> 219 <template v-slot:[`item.ville`]="{ item }"> 220 <div style="width: 150px;"> 221 {{ item.ville }} 222 </div> 223 </template> 224 <template v-slot:[`item.departement_naissance`]="{ item }"> 225 <div style="width: 120px;"> 226 {{ fmt.departement(item.departement_naissance) }} 227 </div> 228 </template> 229 <template v-slot:[`item.tels`]="{ item }"> 230 {{ fmt.telephones(item.tels) }} 231 </template> 232 <template v-slot:[`item.etudiant`]="{ item }"> 233 {{ fmt.bool(item.etudiant) }} 234 </template> 235 <template v-slot:[`item.fonctionnaire`]="{ item }"> 236 {{ fmt.bool(item.fonctionnaire) }} 237 </template> 238 </v-data-table> 239 </v-container> 240 </template> 241 242 <script lang="ts"> 243 import Vue from "vue"; 244 import Component from "vue-class-component"; 245 import AddEquipier from "@/components/equipiers/AddEquipier.vue"; 246 import { C } from "../logic/controller"; 247 import { CreateEquipierIn, EquipierDirecteur, Role } from "../logic/types"; 248 import FormEquipier from "../components/equipiers/FormEquipier.vue"; 249 import { Formatter } from "@/logic/formatter"; 250 import Documents from "../components/equipiers/Documents.vue"; 251 import Formulaires from "../components/equipiers/Formulaires.vue"; 252 import TooltipBtn from "@/components/TooltipBtn.vue"; 253 254 const EquipiersProps = Vue.extend({ 255 props: {} 256 }); 257 258 @Component({ 259 components: { AddEquipier, FormEquipier, Documents, Formulaires, TooltipBtn } 260 }) 261 export default class Equipiers extends EquipiersProps { 262 showAddEquipier = false; 263 items: EquipierDirecteur[] = []; 264 265 confirmeSupprime = false; 266 equipierSupprime: EquipierDirecteur | null = null; 267 showEditDialog = false; 268 editEquipier: EquipierDirecteur | null = null; 269 showDocuments = false; 270 showInviteFormulaires = false; 271 header = [ 272 { text: "", value: "delete", sortable: false }, 273 { text: "Nom", value: "nom", align: "center", sortable: true }, 274 { 275 text: "Prénom", 276 value: "prenom", 277 align: "center", 278 sortable: true 279 }, 280 { text: "Rôle", value: "roles", sortable: true }, 281 { text: "Diplôme", value: "diplome", sortable: true, width: "180px" }, 282 { text: "Approfondissement", value: "appro", sortable: true }, 283 { 284 text: "Sexe", 285 value: "sexe", 286 sortable: true 287 }, 288 { 289 text: "Nom de jeune fille", 290 value: "nom_jeune_fille", 291 sortable: true 292 }, 293 { 294 text: "Date de naissance", 295 value: "date_naissance", 296 sortable: true, 297 align: "center", 298 width: "120px" 299 }, 300 { 301 text: "Département de naissance", 302 value: "departement_naissance", 303 sortable: true, 304 width: "40%" 305 }, 306 { 307 text: "Ville de naissance", 308 value: "ville_naissance", 309 sortable: true, 310 width: "180px" 311 }, 312 { text: "Mail", value: "mail", sortable: true }, 313 { text: "Téléphone(s)", value: "tels", sortable: true }, 314 { 315 text: "Adresse postale", 316 value: "adresse", 317 sortable: true, 318 width: "200px" 319 }, 320 { text: "Code postal", value: "code_postal", sortable: true }, 321 { text: "Ville", value: "ville", sortable: true }, 322 { 323 text: "Sécurité sociale", 324 value: "securite_sociale", 325 sortable: true, 326 width: "180px" 327 }, 328 { text: "Profession", value: "profession", sortable: true, width: "180px" }, 329 { text: "Etudiant", value: "etudiant", sortable: true }, 330 { 331 text: "Fonctionnaire", 332 value: "fonctionnaire", 333 sortable: true 334 } 335 ]; 336 337 fmt = Formatter; 338 339 $refs!: { 340 documents: Documents; 341 }; 342 343 get nbMembres() { 344 return this.items.length; 345 } 346 get nbAnims() { 347 return this.items.filter(r => { 348 return ( 349 (r.roles || []).includes(Role.RAnimation) || 350 (r.roles || []).includes(Role.RAideAnimation) 351 ); 352 }).length; 353 } 354 355 private getMails(restrictToAnims: boolean) { 356 const filtered = restrictToAnims 357 ? this.items.filter(eq => { 358 const roles = eq.roles || []; 359 return ( 360 roles.includes(Role.RDirecteur) || 361 roles.includes(Role.RAdjoint) || 362 roles.includes(Role.RAnimation) || 363 roles.includes(Role.RAideAnimation) 364 ); 365 }) 366 : this.items; 367 return filtered 368 .map(eq => eq.mail.trim()) 369 .filter(m => m != "") 370 .join(","); 371 } 372 373 get mailtoEquipe() { 374 return "mailto:" + this.getMails(false); 375 } 376 377 get mailtoAnims() { 378 return "mailto:" + this.getMails(true); 379 } 380 381 async copyMailsToClipboard(restrictToAnims: boolean) { 382 C.exportMailsToClipboard(this.getMails(restrictToAnims)); 383 } 384 385 async created() { 386 const data = await C.getEquipiers(); 387 if (data == undefined) return; 388 this.items = data.equipe || []; 389 C.notifications.success = "Equipe chargée"; 390 } 391 392 async ajouteEquipier(params: CreateEquipierIn) { 393 const data = await C.ajouteEquier(params); 394 if (data == undefined) return; 395 this.items = data.equipe || []; 396 C.notifications.success = "Equipier ajouté avec succès."; 397 } 398 399 async updateEquipier(item: EquipierDirecteur) { 400 this.showEditDialog = false; 401 const data = await C.updateEquipier(item); 402 if (data == undefined) return; 403 this.items = data.equipe || []; 404 C.notifications.success = "Equipier modifié avec succès."; 405 } 406 407 async supprimeEquipier() { 408 if (this.equipierSupprime == null) return; 409 // confirmation déjà demandée 410 this.confirmeSupprime = false; 411 const data = await C.deleteEquipier(this.equipierSupprime.id); 412 if (data == undefined) return; 413 this.items = data.equipe || []; 414 C.notifications.success = "Equipier supprimé avec succès."; 415 } 416 417 async exportListe() { 418 const fn = await C.export("equipe", {}); 419 if (fn == undefined) return; 420 C.notifications.success = "Liste des équipiers téléchargée avec succès."; 421 } 422 423 loadAndShowDocuments() { 424 this.showDocuments = true; 425 this.$refs.documents.refresh(false); 426 } 427 } 428 </script> 429 430 <style> 431 #equipiers tr:hover { 432 cursor: pointer; 433 } 434 </style>