github.com/benoitkugler/goacve@v0.0.0-20201217100549-151ce6e55dc8/server/frontend/directeurs/src/views/Lettre.vue (about)

     1  <template>
     2    <div class="ma-3">
     3      <v-dialog
     4        v-model="showPreview"
     5        content-class="content-lettre"
     6        max-height="98%"
     7      >
     8        <object
     9          type="application/pdf"
    10          v-if="showPreview"
    11          :data="urlDownload"
    12          class="object"
    13        >
    14          <p>
    15            Vous ne pouvez pas visualiser de pdfs. Merci de mettre à jour votre
    16            navigateur (Chrome, Firefox ou Safari sont conseillés).
    17          </p>
    18        </object>
    19      </v-dialog>
    20  
    21      <v-dialog v-model="showInfoLettre">
    22        <info-lettre
    23          :paveEspacePerso="paveEspacePerso"
    24          :disabledAdd="disabledAddPave"
    25          @add="addPaveEspacePerso"
    26          @done="doneInfoLettre"
    27        ></info-lettre>
    28      </v-dialog>
    29  
    30      <v-dialog v-model="showOptions" max-width="800px">
    31        <v-card>
    32          <v-card-title>Options de l'entête</v-card-title>
    33          <v-card-text>
    34            <v-row>
    35              <v-col>
    36                <v-switch
    37                  v-model="lettre.use_coord_centre"
    38                  hint="Activer pour remplacer les coordonnées du directeur par ceux du centre, dans l'entête de la lettre."
    39                  persistent-hint
    40                  label="Coordonnées du centre"
    41                ></v-switch>
    42              </v-col>
    43              <v-col cols="5">
    44                <v-switch
    45                  v-show="!lettre.use_coord_centre"
    46                  v-model="lettre.show_adresse_postale"
    47                  hint="Afficher l'adresse postale du directeur."
    48                  persistent-hint
    49                  label="Ajouter l'adresse postale"
    50                ></v-switch>
    51              </v-col>
    52            </v-row>
    53            <v-row class="mt-2">
    54              <v-col cols="6">
    55                <color-field
    56                  label="Couleur du texte de l'entête"
    57                  v-model="lettre.color_coord"
    58                  :swatches="swatches"
    59                ></color-field>
    60              </v-col>
    61            </v-row>
    62          </v-card-text>
    63        </v-card>
    64      </v-dialog>
    65  
    66      <v-toolbar dense id="toolbar-lettre">
    67        <v-toolbar-title>
    68          <v-btn icon small @click="showInfoLettre = !showInfoLettre">
    69            <v-icon>{{ $icons["mdi-information-outline"] }}</v-icon>
    70          </v-btn>
    71          Lettre aux parents
    72        </v-toolbar-title>
    73        <div class="mx-3 font-italic body-2" v-html="descriptionDocument"></div>
    74        <v-spacer></v-spacer>
    75  
    76        <v-toolbar-items>
    77          <tooltip-btn
    78            tooltip="Afficher les options"
    79            @click="showOptions = true"
    80            text
    81          >
    82            <v-icon>{{ $icons["mdi-cog"] }}</v-icon>
    83            Options
    84          </tooltip-btn>
    85          <v-divider vertical></v-divider>
    86          <tooltip-btn
    87            tooltip="Sauvegarder et prévisualiser"
    88            @click="save"
    89            icon
    90            :disabled="loading"
    91          >
    92            <v-icon>{{ $icons["mdi-content-save"] }}</v-icon>
    93          </tooltip-btn>
    94        </v-toolbar-items>
    95      </v-toolbar>
    96      <tinymce-editor
    97        v-if="tinymceActive"
    98        id="myEditor"
    99        v-model="lettre.html"
   100        :init="tinyMceOptions"
   101      ></tinymce-editor>
   102    </div>
   103  </template>
   104  
   105  <script lang="ts">
   106  import Vue from "vue";
   107  import Component from "vue-class-component";
   108  import { PublicDocument, Lettredirecteur, Time } from "../logic/types";
   109  import { C } from "../logic/controller";
   110  import { Formatter } from "../logic/formatter";
   111  import InfoLettre from "@/components/lettre/InfoLettre.vue";
   112  import TooltipBtn from "@/components/TooltipBtn.vue";
   113  
   114  import Editor from "@tinymce/tinymce-vue";
   115  import "tinymce"; //side effect
   116  
   117  import "tinymce/themes/silver/theme";
   118  import "tinymce/langs/fr_FR";
   119  import "tinymce/plugins/lists";
   120  import "tinymce/plugins/advlist";
   121  import "tinymce/plugins/image";
   122  import "tinymce/plugins/paste";
   123  import "tinymce/plugins/code";
   124  import "tinymce/plugins/link";
   125  import ToolbarSwitch from "../components/ToolbarSwitch.vue";
   126  import ColorField from "@/components/ColorField.vue";
   127  
   128  /** Colors proposed by tinymce, should be kept in sync */
   129  const swatchColors = [
   130    "#BFEDD2",
   131    "#FBEEB8",
   132    "#F8CAC6",
   133    "#ECCAFA",
   134    "#C2E0F4",
   135    "#2DC26B",
   136    "#F1C40F",
   137    "#E03E2D",
   138    "#B96AD9",
   139    "#3598DB",
   140    "#169179",
   141    "#E67E23",
   142    "#BA372A",
   143    "#843FA1",
   144    "#236FA1",
   145    "#ECF0F1",
   146    "#CED4D9",
   147    "#95A5A6",
   148    "#7E8C8D",
   149    "#34495E",
   150    "#000000",
   151    "#ffffff"
   152  ];
   153  
   154  // Bloc à ajouter à la lettre.
   155  // Attention, en cas de modification, vérifier la mise à page via tinmyce + htmltopdf
   156  const paveEspacePerso = `<p><span style="font-size: 14pt; color: #3598db;" data-mce-style="font-size: 14pt; color: #3598db;">ESPACE PERSONNEL</span> &nbsp;</p><p>Lors de l'inscription de votre enfant, un espace personnel <em>Parents</em> vous a été attribué et un lien vers celui-ci envoyé dans le mail de confirmation (<span style="background-color: #ffffff;" data-mce-style="background-color: #ffffff;">Mon</span> <span style="background-color: #ffffff;" data-mce-style="background-color: #ffffff;">Dossier</span>). Dans cet espace vous trouverez :</p><ul><li>le <strong>suivi financier</strong> : vous pourrez alors joindre en ligne les aides auxquelles vous avez le droit (bons CAF, Comité d'entreprise...), afin que le centre d'inscription puisse les déduire de la facture finale.</li><li>les <strong>documents liés au séjour</strong> : liste de vêtement, lettre aux parents, plan d’accès au site ....</li><li>les <strong>documents à compléter</strong> ou joindre en ligne : test d'aisance aquatique si besoin ...</li><li>l’accès à l'<strong>album photo</strong> du séjour</li><li>la <strong>fiche sanitaire</strong> à compléter en ligne avec les allergies alimentaires.</li></ul><p><em>TOUTES LES INFOS ET DOCUMENTS DU SÉJOUR SE TROUVENT DANS VOTRE ESPACE DÉDIÉ !</em></p>`;
   157  
   158  const LettreProps = Vue.extend({
   159    props: {}
   160  });
   161  
   162  @Component({
   163    components: {
   164      InfoLettre,
   165      TinymceEditor: Editor,
   166      ToolbarSwitch,
   167      TooltipBtn,
   168      ColorField
   169    }
   170  })
   171  export default class Lettre extends LettreProps {
   172    tinymceActive = true;
   173    pdfBuffer = null;
   174    lettre: Lettredirecteur = {
   175      id_camp: 0,
   176      html: "",
   177      use_coord_centre: false,
   178      show_adresse_postale: false,
   179      color_coord: ""
   180    };
   181    publicDocument: PublicDocument = {
   182      url_download: "",
   183      id_crypted: "",
   184      nom_client: "",
   185      taille: 0,
   186      date_heure_modif: "" as Time,
   187      url_miniature: ""
   188    };
   189    showPreview = false;
   190    showInfoLettre = false;
   191  
   192    showOptions = false;
   193    get swatches() {
   194      const out: string[][] = [];
   195      let N = swatchColors.length;
   196      let chunk = 5;
   197      for (let i = 0; i < N; i += chunk) {
   198        out.push(swatchColors.slice(i, i + chunk));
   199      }
   200      return out;
   201    }
   202  
   203    disabledAddPave = false;
   204    paveEspacePerso = paveEspacePerso;
   205    C = C;
   206  
   207    get tinyMceOptions() {
   208      return {
   209        language: "fr_FR",
   210        height: "75vh",
   211        plugins: "lists advlist image paste code link",
   212        menubar: false,
   213        statusbar: false,
   214        paste_data_images: true,
   215        image_advtab: false, // style_format permet d'ajouter une marge à droite
   216        browser_spellcheck: true,
   217        contextmenu: false,
   218        font_formats: "Arial=arial;",
   219        toolbar: [
   220          "undo redo | cut copy paste | bold italic underline strikethrough | alignleft aligncenter alignright | fontsizeselect | bullist numlist outdent indent | forecolor backcolor current_backcolor | image styleselect link"
   221        ],
   222        target_list: [{ title: "Nouvelle page", value: "_blank" }],
   223        link_title: false,
   224        link_assume_external_targets: true,
   225        relative_urls: false,
   226        remove_script_host: false,
   227        images_upload_url: C.getUrlUploadImage(),
   228        automatic_uploads: true,
   229        formats: {
   230          imageMargin: { selector: "img", styles: { marginRight: "20px" } }
   231        },
   232        style_formats: [{ title: "Espacer à droite", format: "imageMargin" }]
   233      };
   234    }
   235  
   236    get descriptionDocument() {
   237      if (!this.publicDocument.id_crypted) {
   238        return "<i>(aucune lettre enregistrée)</i>";
   239      }
   240      return `modifiée le ${Formatter.date_heure(
   241        this.publicDocument.date_heure_modif
   242      )} <br/> taille : ${Formatter.taille(this.publicDocument.taille)}`;
   243    }
   244    get urlDownload() {
   245      let url = this.publicDocument.url_download;
   246      url = url + "&no-attachment=ok";
   247      return url;
   248    }
   249  
   250    deactivated() {
   251      // tinymce BUG
   252      this.tinymceActive = false;
   253    }
   254    activated() {
   255      // tinymce BUG
   256      this.tinymceActive = true;
   257    }
   258  
   259    get loading() {
   260      return C.notifications.progress;
   261    }
   262  
   263    async created() {
   264      const data = await C.getLettreDirecteur();
   265      if (data == undefined) return;
   266      this.lettre = data.lettre;
   267      this.publicDocument = data.document;
   268      C.notifications.success = "Lettre chargée.";
   269      if (!this.publicDocument.id_crypted) {
   270        // aucune lettre d'enregistrée, on affiche l'info
   271        // et on ajoute par défaut le bloc EspacePerso
   272        this.lettre.html += paveEspacePerso;
   273        // du coup on désactive l'ajout additionnel
   274        this.disabledAddPave = true;
   275        this.showInfoLettre = true;
   276      }
   277    }
   278  
   279    addPaveEspacePerso() {
   280      this.lettre.html += paveEspacePerso;
   281      this.showInfoLettre = false;
   282    }
   283    doneInfoLettre() {
   284      // on re active la fonction ajout pave
   285      this.showInfoLettre = false;
   286      this.disabledAddPave = false;
   287    }
   288    async save() {
   289      const data = await C.updateLettreDirecteur(this.lettre);
   290      if (data == undefined) return;
   291      this.lettre = data.lettre;
   292      this.publicDocument = data.document;
   293      C.notifications.success = "Lettre mise à jour avec succès.";
   294      this.showPreview = true;
   295    }
   296  }
   297  </script>
   298  
   299  <style>
   300  .content-lettre {
   301    height: 90vh;
   302  }
   303  </style>