Skip to content
Snippets Groups Projects
Feature_detail.vue 18.8 KiB
Newer Older
Timothee P's avatar
Timothee P committed
  <div v-frag>
    <div class="row">
      <div class="fourteen wide column">
        <h1 class="ui header">
          <div class="content">
Timothee P's avatar
Timothee P committed
            {{ feature.title || feature.feature_id }}
Timothee P's avatar
Timothee P committed
            <div class="ui icon right floated compact buttons">
              <!-- {% if permissions|lookup:'can_create_feature' %} -->
Timothee P's avatar
Timothee P committed
              <router-link
                :to="{
                  name: 'ajouter-signalement',
                  params: { slug_type_signal: $route.params.slug_type_signal },
                }"
Timothee P's avatar
Timothee P committed
                class="ui button button-hover-orange"
                data-tooltip="Ajouter un signalement"
                data-position="bottom left"
              >
                <i class="plus fitted icon"></i>
Timothee P's avatar
Timothee P committed
              </router-link>
Timothee P's avatar
Timothee P committed
              <!-- {% endif %} {% if permissions|lookup:'can_update_feature' %} -->
Timothee P's avatar
Timothee P committed
              <router-link
                :to="{
                  name: 'editer-signalement',
DESPRES Damien's avatar
DESPRES Damien committed
                  params: { 
                    slug_signal: $route.params.slug_signal,
                    slug_type_signal: $route.params.slug_type_signal },
Timothee P's avatar
Timothee P committed
                }"
Timothee P's avatar
Timothee P committed
                class="ui button button-hover-orange"
              >
                <i class="inverted grey pencil alternate icon"></i>
Timothee P's avatar
Timothee P committed
              </router-link>
Timothee P's avatar
Timothee P committed
              <!-- {% endif %} {% if permissions|lookup:'can_delete_feature' %} -->
Timothee P's avatar
Timothee P committed
              <a
                @click="isCanceling = true"
                id="feature-delete"
                class="ui button button-hover-red"
              >
Timothee P's avatar
Timothee P committed
                <i class="inverted grey trash alternate icon"></i>
              </a>
              <!-- {% endif %} -->
            </div>
            <div class="ui hidden divider"></div>
            <div class="sub header">
              {{ feature.description }}
              <!--  | linebreaks -->
            </div>
          </div>
        </h1>
      </div>
    </div>

    <div class="row">
      <div class="seven wide column">
        <table class="ui very basic table">
          <tbody>
            <div
              v-frag
              v-for="(field, index) in feature.feature_data"
              :key="'field' + index"
            >
              <tr v-if="field">
                <td>
                  <b>{{ field.label }}</b>
                </td>
                <td>
                  <b>
                    <i
                      v-if="
                        field.field_type === 'boolean' && field.value === true
                      "
                      class="olive check icon"
                    ></i>
                    <i
                      v-else-if="
                        field.field_type === 'boolean' && field.value === false
                      "
                      class="red times icon"
                    ></i>
                    <span v-else>
                      {{ field.value }}
                    </span>
                  </b>
                </td>
              </tr>
            </div>
Timothee P's avatar
Timothee P committed
            <tr>
              <td>Auteur</td>
              <td>{{ feature.display_creator }}</td>
            </tr>
            <tr>
              <td>Statut</td>
              <td>
                <i
                  v-if="feature.status === 'archived'"
                  class="grey archive icon"
                ></i>
                <i
                  v-else-if="feature.status === 'pending'"
                  class="teal hourglass outline icon"
                ></i>
                <i
                  v-else-if="feature.status === 'published'"
                  class="olive check icon"
                ></i>
                <i
                  v-else-if="feature.status === 'draft'"
                  class="orange pencil alternate icon"
                ></i>
                {{ feature.get_status_display }}
              </td>
            </tr>
            <tr>
              <td>Date de création</td>
              <td v-if="feature.created_on">
                {{ feature.created_on }}
              </td>
            </tr>
            <tr>
              <td>Date de dernière modification</td>
              <td v-if="feature.updated_on">
                {{ feature.updated_on }}
              </td>
            </tr>
            <tr>
              <td>Date d'archivage automatique</td>
              <td v-if="feature.archived_on">
                {{ feature.archived_on }}
              </td>
            </tr>
            <tr>
              <td>Date de suppression automatique</td>
              <td v-if="feature.deletion_on">
                {{ feature.deletion_on }}
              </td>
            </tr>
          </tbody>
        </table>

        <!--  <small>{% for link in linked_features %} {% endfor %}</small> // ? EMPTY ?!??? -->

        <h3>Liaison entre signalements</h3>
        <table class="ui very basic table">
          <tbody>
            <tr
              v-for="(link, index) in linked_features"
              :key="link.feature_to.title + index"
            >
              <td>
                {{ link.relation_type }}
Timothee P's avatar
Timothee P committed
                <router-link
                  :to="{
                    name: 'details-signalement',
                    params: {
DESPRES Damien's avatar
DESPRES Damien committed
                      slug_type_signal: link.feature_to.feature_type.slug,
Timothee P's avatar
Timothee P committed
                      slug_signal: link.feature_to.title,
                    },
                  }"
                  >{{ link.feature_to.title }}</router-link
                >
Timothee P's avatar
Timothee P committed
                ({{ link.feature_to.creator }} -
                {{ link.feature_to.created_on }})
              </td>
            </tr>
          </tbody>
        </table>
      </div>

      <div class="seven wide column">
        <div id="map"></div>
Timothee P's avatar
Timothee P committed
      </div>
    </div>

Timothee P's avatar
Timothee P committed
    <div class="row">
      <div class="seven wide column">
        <h2 class="ui header">Pièces jointes</h2>
Timothee P's avatar
Timothee P committed

Timothee P's avatar
Timothee P committed
        <div v-for="pj in attachments" :key="pj.title" class="ui divided items">
          <div class="item">
            <a
              class="ui tiny image"
              target="_blank"
              :href="pj.attachment_file.url"
            >
              <img
                v-if="pj.extension === '.pdf'"
                src="{% static 'geocontrib/img/pdf.png' %}"
              />
              <!-- // ? que faire ? -->
              <img v-else :src="pj.attachment_file.url" />
            </a>
            <div class="middle aligned content">
              <a
                class="header"
                target="_blank"
                :href="pj.attachment_file.url"
                >{{ pj.title }}</a
              >
              <div class="description">
                {{ pj.info }}
              </div>
Timothee P's avatar
Timothee P committed
            </div>
          </div>
        </div>
Timothee P's avatar
Timothee P committed
        <i v-if="attachments.length === 0"
          >Aucune pièce jointe associée au signalement.</i
        >
      </div>
Timothee P's avatar
Timothee P committed

Timothee P's avatar
Timothee P committed
      <div class="seven wide column">
        <h2 class="ui header">Activité et commentaires</h2>
Timothee P's avatar
Timothee P committed

Timothee P's avatar
Timothee P committed
        <div id="feed-event" class="ui feed">
          <div v-frag v-for="(event, index) in events" :key="'event' + index">
            <div v-frag v-if="event.event_type === 'create'">
              <div v-if="event.object_type === 'feature'" class="event">
                <div class="content">
                  <div class="summary">
                    <div class="date">
                      {{ event.created_on }}
                    </div>
                    Création du signalement
                    <span v-if="user">par {{ event.display_user }}</span>
                  </div>
Timothee P's avatar
Timothee P committed
                </div>
              </div>
Timothee P's avatar
Timothee P committed
              <div v-else-if="event.object_type === 'comment'" class="event">
                <div class="content">
                  <div class="summary">
                    <div class="date">
                      {{ event.created_on }}
                    </div>
                    Commentaire
                    <span v-if="user">par {{ event.display_user }}</span>
                  </div>
                  <div class="extra text">
                    {{ event.related_comment.comment }}
                    <div v-frag v-if="event.related_comment.attachments">
                      <div
                        v-frag
                        v-for="att in event.related_comment.attachments"
                        :key="att.title"
                      >
                        <br /><a :href="att.url" tarrget="_blank"
                          ><i class="paperclip fitted icon"></i>
                          {{ att.title }}</a
                        >
                      </div>
                    </div>
                  </div>
Timothee P's avatar
Timothee P committed
                </div>
              </div>
            </div>
Timothee P's avatar
Timothee P committed
            <div v-else-if="event.event_type === 'update'" class="event">
              <div class="content">
                <div class="summary">
                  <div class="date">
                    {{ event.created_on }}
                  </div>
                  Signalement mis à jour
                  <span v-if="user">par {{ event.display_user }}</span>
                </div>
Timothee P's avatar
Timothee P committed
              </div>
            </div>
          </div>
        </div>

Timothee P's avatar
Timothee P committed
        <!-- {% if permissions|lookup:'can_create_feature' %} -->
        <div class="ui segment">
          <form
            id="form-comment"
            class="ui form"
            method="POST"
            enctype="multipart/form-data"
          >
            <!-- action="{% url 'geocontrib:add_comment' slug=feature.project.slug feature_type_slug=feature.feature_type.slug  feature_id=feature.feature_id%}" -->
Timothee P's avatar
Timothee P committed
            <!-- {% for hidden in comment_form.hidden_fields %}
Timothee P's avatar
Timothee P committed
            {{ hidden }}
Timothee P's avatar
Timothee P committed
            {% endfor %} -->
            <div
              v-if="comment_form.non_field_errors"
              class="alert alert-danger"
              role="alert"
            >
              <span v-for="error in comment_form.non_field_errors" :key="error">
                {{ error }}
              </span>
            </div>
            <div class="required field">
              <label :for="comment_form.comment.id_for_label"
                >Ajouter un commentaire</label
              >
              {{ comment_form.comment.errors }}
              <textarea
                v-model="comment_form.comment.value"
                :name="comment_form.comment.html_name"
                rows="2"
              ></textarea>
Timothee P's avatar
Timothee P committed
            </div>
Timothee P's avatar
Timothee P committed
            <label>Pièce jointe (facultative)</label>
            <div class="two fields">
              <div class="field">
                <label class="ui icon button" for="attachment_file">
                  <i class="paperclip icon"></i>
                  <span class="label">{{
                    comment_form.attachment_file.value
                      ? comment_form.attachment_file.value
                      : "Sélectionner un fichier ..."
                  }}</span>
                </label>
                <!--  // todo : get image from "C:\\fakepath\..." -->
Timothee P's avatar
Timothee P committed
                <input
                  type="file"
                  accept="application/pdf, image/jpeg, image/png"
                  style="display: none"
                  name="attachment_file"
                  id="attachment_file"
                  @change="getAttachmentFileData($event)"
                />
                {{ comment_form.attachment_file.errors }}
              </div>
              <div class="field">
                <input
                  v-model="comment_form.title.value"
                  type="text"
                  :name="comment_form.title.html_name"
                  :id="comment_form.title.id_for_label"
                />
                {{ comment_form.title.errors }}
              </div>
Timothee P's avatar
Timothee P committed
            </div>
Timothee P's avatar
Timothee P committed
            <button
              @click="postComment"
              type="button"
              class="ui compact green icon button"
            >
              <i class="plus icon"></i> Poster le commentaire
            </button>
          </form>
        </div>
Timothee P's avatar
Timothee P committed
      </div>
Timothee P's avatar
Timothee P committed
    </div>
Timothee P's avatar
Timothee P committed

Timothee P's avatar
Timothee P committed
    <div
      v-if="isCanceling"
      class="ui dimmer modals page transition visible active"
      style="display: flex !important"
    >
      <div
        :class="[
          'ui mini modal subscription',
          { 'active visible': isCanceling },
        ]"
      >
        <i @click="isCanceling = false" class="close icon"></i>
        <div class="ui icon header">
          <i class="trash alternate icon"></i>
          Supprimer le signalement
        </div>
        <div class="actions">
          <form
            action="{% url 'geocontrib:feature_delete' slug=feature.project.slug feature_type_slug=feature.feature_type.slug feature_id=feature.feature_id %}"
            method="POST"
          >
            <input type="hidden" name="_method" value="delete" />
            <button
              @click="deleteFeature"
              type="button"
              class="ui red compact fluid button"
            >
              Confirmer la suppression
            </button>
          </form>
        </div>
      </div>
    </div>
Timothee P's avatar
Timothee P committed
  </div>
</template>

<script>
import frag from "vue-frag";
Timothee P's avatar
Timothee P committed
import { mapState } from "vuex";
DESPRES Damien's avatar
DESPRES Damien committed
import { mapUtil } from "@/assets/js/map-util.js";
const axios = require("axios");
Timothee P's avatar
Timothee P committed

export default {
  name: "Feature_detail",

  directives: {
    frag,
  },

  data() {
    return {
Timothee P's avatar
Timothee P committed
      isCanceling: false,
Timothee P's avatar
Timothee P committed
      mock_linked_features: [
Timothee P's avatar
Timothee P committed
          relation_type: "Doublon",
          feature_to: {
Timothee P's avatar
Timothee P committed
            title: "Éolienne offshore",
Timothee P's avatar
Timothee P committed
            created_on: new Date().toDateString(),
Timothee P's avatar
Timothee P committed
            feature_type: {
              title: "Éolienne",
            },
          },
Timothee P's avatar
Timothee P committed
      ],
      attachments: [
        // TODO : Récupérer depuis l'api
Timothee P's avatar
Timothee P committed
          attachment_file: {
            url: "http://localhost:8000/media/user_1/albinoscom.jpg",
          },
          extension: "jpg",
          title: "albinos",
          info: "Drôle de bête",
Timothee P's avatar
Timothee P committed
      ],
      // TODO : Récupérer depuis l'api
Timothee P's avatar
Timothee P committed
      comment_form: {
        attachment_file: {
          errors: null,
          value: null,
        },
        title: {
          id_for_label: "title",
          html_name: "title",
          errors: null,
          value: null,
        },
        comment: {
          id_for_label: "add-comment",
          html_name: "add-comment",
          errors: null,
          value: null,
        },
        non_field_errors: [],
      },
Timothee P's avatar
Timothee P committed
    };
  },

  computed: {
Timothee P's avatar
Timothee P committed
    ...mapState(["user"]),
Timothee P's avatar
Timothee P committed
    feature: function () {
      return (
        this.$store.state.feature.features.find(
          (el) => el.feature_id === this.$route.params.slug_signal
        ) || []
Timothee P's avatar
Timothee P committed
      );
    },
    linked_features: function () {
      // todo: vérifier avec données réels si ça fonctionne correctement
      //return this.mock_linked_features.filter((el) => el.feature_to);
      return [];
Timothee P's avatar
Timothee P committed
    },
  },

Timothee P's avatar
Timothee P committed
  methods: {
    postComment() {
Timothee P's avatar
Timothee P committed
      /* const data = {
Timothee P's avatar
Timothee P committed
        comment: this.comment_form.comment.value,
        title: this.comment_form.title.value,
        attachment_file: this.comment_form.attachment_file.value,
Timothee P's avatar
Timothee P committed
      }; */
Timothee P's avatar
Timothee P committed
      this.$store.dispatch("feature/POST_COMMENT");
Timothee P's avatar
Timothee P committed
      //console.log("POST comment", data);
Timothee P's avatar
Timothee P committed
    },
    getAttachmentFileData(evt) {
      const files = evt.target.files || evt.dataTransfer.files;
      const period = files[0].name.lastIndexOf(".");
      const fileName = files[0].name.substring(0, period)
      const fileExtension = files[0].name.substring(period + 1);
Timothee P's avatar
Timothee P committed
      const shortName = fileName.slice(0, 10) + "[...]." + fileExtension;
      this.comment_form.attachment_file.value = shortName;
      this.comment_form.title.value = shortName;
    },
    deleteFeature() {
      this.$store.dispatch(
        "feature/DELETE_FEATURE",
        this.$route.params.slug_signal
      );
    },
DESPRES Damien's avatar
DESPRES Damien committed
    initMap(){
      var mapDefaultViewCenter = this.$store.state.configuration.DEFAULT_MAP_VIEW.center;
      var mapDefaultViewZoom = this.$store.state.configuration.DEFAULT_MAP_VIEW.zoom;
      this.map=mapUtil.createMap({
        mapDefaultViewCenter,
        mapDefaultViewZoom,
      });

      // Update link to feature list with map zoom and center
      mapUtil.addMapEventListener("moveend", function() {
        // update link to feature list with map zoom and center
        /*var $featureListLink = $("#feature-list-link")
        var baseUrl = $featureListLink.attr("href").split("?")[0]

        $featureListLink.attr("href", baseUrl +`?zoom=${this.map.getZoom()}&lat=${this.map.getCenter().lat}&lng=${this.map.getCenter().lng}`)*/
      });

      // Load the layers.
      // - if one basemap exists, we load the layers of the first one
      // - if not, load the default map and service options
      let layersToLoad = null;
      var baseMaps;
      var project="";
      var layers=[];
      if (baseMaps && baseMaps.length > 0) {
        // Use active one if exists, otherwise index 0 (first basemap in the list)
        const mapOptions = JSON.parse(localStorage.getItem('geocontrib-map-options')) || {};
        const basemapIndex = mapOptions && mapOptions[project] && mapOptions[project]['current-basemap-index'] ?
                                    mapOptions[project]['current-basemap-index'] : 0;
        layersToLoad = baseMaps[basemapIndex].layers;
        layersToLoad.forEach(layerToLoad => {
            layers.forEach(layer => {
              if (layer.id === layerToLoad.id) {
                layerToLoad = Object.assign(layerToLoad, layer);
              }
          });
        });
        layersToLoad.reverse()
      }
      mapUtil.addLayers(layersToLoad, this.$store.state.configuration.DEFAULT_BASE_MAP.SERVICE, this.$store.state.configuration.DEFAULT_BASE_MAP.OPTIONS);

      mapUtil.getMap().dragging.disable()
      mapUtil.getMap().doubleClickZoom.disable()
      mapUtil.getMap().scrollWheelZoom.disable()
      var currentFeatureId=this.$route.params.slug_signal;
      const url=`${this.$store.state.configuration.VUE_APP_DJANGO_API_BASE}projects/${this.$route.params.slug}/feature/?output=geojson`;
      axios.get(url)
        .then((response) => {
          const features = response.data.features;
          if (features) {
            const currentFeature = features.filter(feat => feat.id === currentFeatureId);
            const featureGroup = mapUtil.addFeatures(currentFeature);
            mapUtil.getMap().fitBounds(featureGroup.getBounds());
          }
        })
        .catch((error) => {
          throw error;
        });

      
    }
Timothee P's avatar
Timothee P committed
  created() {
    if (!this.project) {
      this.$store.dispatch("GET_PROJECT_INFO", this.$route.params.slug);
Timothee P's avatar
Timothee P committed
    }
    this.$store.commit(
      "feature_type/SET_CURRENT_FEATURE_TYPE_SLUG",
      this.$route.params.slug_type_signal
    );
  },

  mounted() {
DESPRES Damien's avatar
DESPRES Damien committed

    this.initMap();
    

Timothee P's avatar
Timothee P committed
  },
};
</script>

<style>
Timothee P's avatar
Timothee P committed
#map {
  width: 100%;
  height: 100%;
  min-height: 250px;
}
#feed-event .event {
  margin-bottom: 1em;
}
#feed-event .event .date {
  margin-right: 1em !important;
}
#feed-event .event .extra.text {
  margin-left: 107px;
  margin-top: 0;
}
Timothee P's avatar
Timothee P committed
</style>