<template> <div v-frag> <div class="fourteen wide column"> <h1 v-if="$router.history.current.name === 'editer-signalement'"> Mise à jour du signalement "{{ feature.title }}" </h1> <h1 v-else-if="$router.history.current.name === 'ajouter-signalement'"> Création d'un signalement <small>[{{ feature_type.title }}]</small> </h1> <form id="form-feature-edit" action="" method="post" enctype="multipart/form-data" class="ui form" > <!-- Feature Fields --> <div class="two fields"> <div class="required field"> <label :for="feature_form.title.id_for_label">{{ feature_form.title.label }}</label> <input type="text" required :maxlength="feature_form.title.field.max_length" :name="feature_form.title.html_name" :id="feature_form.title.id_for_label" v-model="feature_form.title.value" /> {{ feature_form.title.errors }} </div> <div class="required field"> <label :for="feature_form.status.id_for_label">{{ feature_form.status.label }}</label> <Dropdown :options="feature_form.status.field.choices" :selected="feature_form.status.value" :selection.sync="feature_form.status.value" /> {{ feature_form.status.errors }} </div> </div> <div class="field"> <label :for="feature_form.description.id_for_label">{{ feature_form.description.label }}</label> <textarea :name="feature_form.description.html_name" rows="5" v-model="feature_form.description.value" ></textarea> {{ feature_form.description.errors }} </div> <!-- Geom Field --> <div class="field"> <label for="feature_form.geom.id_for_label">{{ feature_form.geom.label }}</label> <!-- Import GeoImage --> <div v-frag v-if="feature_type.geom_type === 'point'"> <p> <button id="add-geo-image" type="button" class="ui compact button" > <i class="file image icon"></i>Importer une image géoréférencée </button> Vous pouvez utiliser une image géoréférencée pour localiser le signalement. </p> <p> <button id="create-point-geoposition" type="button" class="ui compact button" > <i class="ui map marker alternate icon"></i>Positionner le signalement à partir de votre géolocalisation </button> </p> <span id="erreur-geolocalisation" style="display: none"> <div class="ui negative message"> <div class="header"> Une erreur est survenue avec la fonctionnalité de géolocalisation </div> <p id="erreur-geolocalisation-message"></p> </div> <br /> </span> </div> {{ feature_form.geom.errors }} <!-- Map --> <input type="hidden" :name="feature_form.geom.html_name" :id="feature_form.geom.id_for_label" v-model="feature_form.geom.value" /> <div class="ui tab active map-container" data-tab="map"> <div id="map"></div> // todo: ajouter carte & template sidebar-layer <!-- {% if serialized_base_maps|length > 0 %} {% include "geocontrib/map-layers/sidebar-layers.html" with basemaps=serialized_base_maps layers=serialized_layers project=project.slug%} {% endif %} --> </div> </div> <!-- Extra Fields --> <div class="ui horizontal divider">DONNÉES MÉTIER</div> // ? Les données métiers s'affichent quand ? <div v-for="field in extra_form" :key="field" class="field"> {% if field.field.widget.attrs|lookup:'field_type' == 'char' %} <label for="field.name">{{ field.label }}</label> <input type="text" :name="field.name" :id="field.name" v-model="field.value" /> {% elif field.field.widget.attrs|lookup:'field_type' == 'list' %} <label for="field.name">{{ field.label }}</label> <div class="ui selection dropdown"> <input type="hidden" :name="field.name" :id="field.name" v-model="field.value" /> <div class="default text"></div> <i class="dropdown icon"></i> <div class="menu"> {% for x,y in field.field.choices %} <div class="item" :data-value="x" :selected="field.value === x"> {{ y }} </div> {% endfor %} </div> </div> {% elif field.field.widget.attrs|lookup:'field_type' == 'integer' %} <label for="field.name">{{ field.label }}</label> <div class="ui input"> <input type="number" :name="field.name" :id="field.name" v-model="field.value" /> </div> {% elif field.field.widget.attrs|lookup:'field_type' == 'boolean' %} <div class="ui checkbox"> <input type="checkbox" :checked="field.value" :name="field.name" :id="field.name" /> <label for="field.name">{{ field.label }}</label> </div> {% elif field.field.widget.attrs|lookup:'field_type' == 'date' %} <label for="field.name">{{ field.label }}</label> <input type="date" :name="field.name" :id="field.name" v-model="field.value" /> {% elif field.field.widget.attrs|lookup:'field_type' == 'decimal' %} <label for="field.name">{{ field.label }}</label> <div class="ui input"> <input type="number" step=".01" :name="field.name" :id="field.name" v-model="field.value" /> </div> {% elif field.field.widget.attrs|lookup:'field_type' == 'text' %} <label :for="field.name">{{ field.label }}</label> <textarea :name="field.name" rows="3" v-model="field.value" ></textarea> {% endif %} {{ field.errors }} </div> {% endfor %} <!-- Pièces jointes --> <div class="ui horizontal divider">PIÈCES JOINTES</div> {{ attachment_formset.non_form_errors }} <div id="formsets-attachment"> {{ attachment_formset.management_form }} <div v-frag v-for="form in attachment_formset" :key="'attachment_formset' + form.dataKey" > <span v-for="hidden in form.hidden_fields" :key="hidden"> {{ hidden }} </span> <div class="ui teal segment"> <h4> Pièce jointe <button @click="remove_attachment_formset(form.dataKey)" class=" ui small compact right floated icon button remove-formset " type="button" > <i class="ui times icon"></i> </button> </h4> {{ form.errors }} <div class="visible-fields"> <div class="two fields"> <div class="required field"> <label :for="form.title.id_for_label">{{ form.title.label }}</label> <input type="text" required :maxlength="form.title.field.max_length" :name="form.title.html_name" :id="form.title.id_for_label" v-model="form.title.value" /> {{ form.title.errors }} </div> <div class="required field"> <label>Fichier (PDF, PNG, JPEG)</label> // todo : mettre en place la sélection de fichier <label @click="selectFile" class="ui icon button" :for="form.attachment_file.id_for_label" > <i class="file icon"></i> <span v-if="form.attachment_file.value" class="label">{{ form.attachment_file.value }}</span> <span v-else class="label" >Sélectionner un fichier ...</span > </label> // todo: récupérer cette valeur :accept="IMAGE_FORMAT" <input @change="processImgData" type="file" style="display: none" :name="form.attachment_file.html_name" class="image_file" :id="form.attachment_file.id_for_label" /> {{ form.attachment_file.errors }} </div> </div> <div class="field"> <label for="form.info.id_for_label">{{ form.info.label }}</label> <textarea name="form.info.html_name" rows="5" v-model="form.info.value" ></textarea> {{ form.info.errors }} </div> </div> </div> </div> </div> <button @click="add_attachement_formset" id="add-attachment" type="button" class="ui compact basic button button-hover-green" > <i class="ui plus icon"></i>Ajouter une pièce jointe </button> <!-- Signalements liés --> <div class="ui horizontal divider">SIGNALEMENTS LIÉS</div> {{ linked_formset.non_form_errors }} <div id="formsets-link"> {{ linked_formset.management_form }} <div v-for="form of linked_formset" :key="'linked_formset' + form.dataKey" > <div class="ui teal segment"> <h4> Liaison <button @click="remove_linked_formset" class=" ui small compact right floated icon button remove-formset " type="button" > <i class="ui times icon"></i> </button> </h4> {{ form.errors }} <div class="visible-fields"> <div class="two fields"> <div class="required field"> <label for="form.relation_type.id_for_label">{{ form.relation_type.label }}</label> <div class="ui selection dropdown"> <input type="hidden" :name="form.relation_type.html_name" :id="form.relation_type.id_for_label" v-model="form.relation_type.value" /> <div class="default text"></div> <i class="dropdown icon"></i> <div class="menu"> <div v-for="(x, y) in form.relation_type.field.choices" :key="y" class="item" :data-value="x" :selected="form.relation_type.value === x" > {{ y }} </div> </div> </div> {{ form.relation_type.errors }} </div> <div class="required field"> <label for="form.feature_to.id_for_label">{{ form.feature_to.label }}</label> <div class="ui selection search dropdown"> <input type="hidden" :name="form.feature_to.html_name" :id="form.feature_to.id_for_label" v-model="form.feature_to.value" /> <div class="default text"></div> <i class="dropdown icon"></i> <div class="menu"> <div v-for="(x, y) in form.feature_to.field.choices" :key="y" class="item" :data-value="x" :selected="form.feature_to.value === x" > {{ y }} </div> </div> </div> {{ form.feature_to.errors }} </div> </div> </div> </div> </div> </div> <button @click="add_linked_formset" id="add-link" type="button" class="ui compact basic button button-hover-green" > <i class="ui plus icon"></i>Ajouter une liaison </button> <div class="ui divider"></div> <button type="submit" class="ui teal icon button"> <i class="white save icon"></i> Enregistrer les changements </button> </form> </div> <Project-edit-modal /> </div> </template> <script> import frag from "vue-frag"; import { mapState } from "vuex"; import Project_edit_modal from "@/components/feature/Feature_edit_modal"; import Dropdown from "@/components/dropdown.vue"; let attachment_formset = { dataKey: 0, title: { errors: null, id_for_label: "titre", field: { max_length: 30, }, html_name: "titre", label: "Titre", value: "", }, attachment_file: { errors: null, id_for_label: "titre", field: { max_length: 30, }, html_name: "titre", label: "Titre", value: "", }, info: { value: "", errors: null, html_name: "?", }, }; let linked_formset = { dataKey: 0, errors: null, relation_type: { errors: null, id_for_label: "relation_type", field: { choices: ["Doublon", "Remplace", "Est remplacé par", "Dépend de"], }, html_name: "relation_type", label: "Type de liaison", value: "", }, feature_to: { errors: null, id_for_label: "feature_to", field: { max_length: 30, }, html_name: "feature_to", label: "Signalement lié", value: "", }, }; export default { name: "Feature_edit", directives: { frag, }, props: ["action", "slug_type_signal"], components: { "Project-edit-modal": Project_edit_modal, Dropdown, }, computed: { ...mapState(["project"]), /* feature: function () { // * nécessaire pour édition (si c'est ce template ...?) return this.$store.state.feature.features.find( (el) => el.title === this.slug_type_signal ); }, */ feature_type: function () { return this.$store.state.feature_type.feature_types.find( (el) => el.title === this.slug_type_signal ); }, }, data() { return { feature_form: { title: { errors: null, id_for_label: "name", field: { max_length: 30, }, html_name: "name", label: "Nom", value: "", }, status: { errors: null, id_for_label: "status", field: { choices: ["Brouillon", "Publié", "Archivé"], }, html_name: "status", label: "Statut", value: "Brouillon", }, description: { errors: null, id_for_label: "description", html_name: "description", label: "Description", value: "", }, geom: { label: "Localisation", }, }, // ? Qu'est-ce que c'est ??? extra_form: [], // * formulaire de pièces jointes, ajouter à la volée attachment_formset: [], // * formulaires pour les liaisons linked_formset: [], }; }, methods: { processImgData(e) { // * read image file const file = e.target.files[0]; if (file) { this.form.attachment_file.value = file.name; } let reader = new FileReader(); let _this = this; reader.onload = function (e) { _this.form.attachment_file.value = e.target.result; }; reader.readAsDataURL(file); // todo : send image to the back (?) }, add_attachement_formset() { this.attachment_formset.push({ ...attachment_formset }); //* spread évite de muter l'objet de départ attachment_formset.dataKey += 1; //* permet d'identifier uniquement les formulaires ajoutés }, remove_attachment_formset(dataKey) { this.attachment_formset = this.attachment_formset.filter( (form) => form.dataKey !== dataKey ); }, add_linked_formset() { this.linked_formset.push({ ...linked_formset }); //* spread évite de muter l'objet de départ linked_formset.dataKey += 1; //* permet d'identifier uniquement les formulaires ajoutés }, remove_linked_formset(dataKey) { this.linked_formset = this.linked_formset.filter( (form) => form.dataKey !== dataKey ); }, selectFile() { console.log("selectFile"); }, }, created() { if (!this.project) { this.$store.commit("SET_PROJECT_SLUG", this.$route.params.slug); } }, }; // TODO : add script from django and convert: </script> <style> #map { height: 70vh; width: 100%; border: 1px solid grey; } @media only screen and (max-width: 767px) { #map { height: 80vh; } } /* // ! missing style in semantic.min.css, je ne comprends pas comment... */ .ui.right.floated.button { float: right; margin-right: 0; margin-left: 0.25em; } </style>