Something went wrong on our end
-
Timothee P authoredTimothee P authored
Feature_detail.vue 20.00 KiB
<template>
<div v-frag>
<div v-frag v-if="feature">
<div class="row">
<div class="fourteen wide column">
<h1 class="ui header">
<div class="content">
{{ feature.title || feature.feature_id }}
<div class="ui icon right floated compact buttons">
<router-link
v-if="permissions.can_create_feature"
:to="{
name: 'ajouter-signalement',
params: {
slug_type_signal: $route.params.slug_type_signal,
},
}"
class="ui button button-hover-orange"
data-tooltip="Ajouter un signalement"
data-position="bottom left"
>
<i class="plus fitted icon"></i>
</router-link>
<router-link
v-if="permissions.can_update_feature"
:to="{
name: 'editer-signalement',
params: {
slug_signal: $route.params.slug_signal,
slug_type_signal: $route.params.slug_type_signal,
},
}"
class="ui button button-hover-orange"
>
<i class="inverted grey pencil alternate icon"></i>
</router-link>
<a
v-if="permissions.can_delete_feature"
@click="isCanceling = true"
id="feature-delete"
class="ui button button-hover-red"
>
<i class="inverted grey trash alternate icon"></i>
</a>
</div>
<div class="ui hidden divider"></div>
<div class="sub header">
{{ feature.description }}
</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>
<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>
<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_display }}
<router-link
v-if="link.feature_to.feature_type_slug"
:to="{
name: 'details-signalement',
params: {
slug_type_signal: link.feature_to.feature_type_slug,
slug_signal: link.feature_to.feature_id,
},
}"
>{{ link.feature_to.title }}</router-link
>
({{ link.feature_to.display_creator }} -
{{ link.feature_to.created_on }})
</td>
</tr>
</tbody>
</table>
</div>
<div class="seven wide column">
<div id="map"></div>
</div>
</div>
<div class="row">
<div class="seven wide column">
<h2 class="ui header">Pièces jointes</h2>
<div v-for="pj in attachments" :key="pj.id" class="ui divided items">
<div class="item">
<a
class="ui tiny image"
target="_blank"
:href="DJANGO_BASE_URL + pj.attachment_file"
>
<img
:src="
pj.extension === '.pdf'
? require('@/assets/img/pdf.png')
: DJANGO_BASE_URL + pj.attachment_file
"
/>
</a>
<div class="middle aligned content">
<a
class="header"
target="_blank"
:href="DJANGO_BASE_URL + pj.attachment_file"
>{{ pj.title }}</a
>
<div class="description">
{{ pj.info }}
</div>
</div>
</div>
</div>
<i v-if="attachments.length === 0"
>Aucune pièce jointe associée au signalement.</i
>
</div>
<div class="seven wide column">
<h2 class="ui header">Activité et commentaires</h2>
<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>
</div>
</div>
<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.attachment">
<br /><a
:href="
DJANGO_BASE_URL +
event.related_comment.attachment.url
"
tarrget="_blank"
><i class="paperclip fitted icon"></i>
{{ event.related_comment.attachment.title }}</a
>
</div>
</div>
</div>
</div>
</div>
<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>
</div>
</div>
</div>
</div>
<div v-if="permissions.can_create_feature" class="ui segment">
<form
id="form-comment"
class="ui form"
method="POST"
enctype="multipart/form-data"
>
<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>
</div>
<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>
<input
type="file"
accept="application/pdf, image/jpeg, image/png"
style="display: none"
name="attachment_file"
id="attachment_file"
@change="getAttachmentFileData($event)"
/>
</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>
</div>
<button
@click="postComment"
type="button"
class="ui compact green icon button"
>
<i class="plus icon"></i> Poster le commentaire
</button>
</form>
</div>
</div>
</div>
<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>
</div>
<div v-frag v-else>Pas de signalement correspondant trouvé</div>
</div>
</template>
<script>
import frag from "vue-frag";
import { mapGetters, mapState } from "vuex";
import { mapUtil } from "@/assets/js/map-util.js";
import featureAPI from "@/services/feature-api";
const axios = require("axios");
export default {
name: "Feature_detail",
directives: {
frag,
},
data() {
return {
isCanceling: false,
attachments: [],
events: [],
comment_form: {
attachment_file: {
errors: null,
value: null,
file: 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: [],
},
};
},
computed: {
...mapState(["user"]),
...mapGetters(["permissions"]),
...mapState("feature", ["linked_features"]),
DJANGO_BASE_URL: function () {
return this.$store.state.configuration.VUE_APP_DJANGO_BASE;
},
feature: function () {
return this.$store.state.feature.features.find(
(el) => el.feature_id === this.$route.params.slug_signal
);
},
},
methods: {
postComment() {
featureAPI
.postComment({
featureId: this.$route.params.slug_signal,
comment: this.comment_form.comment.value,
})
.then((response) => {
if (response && this.comment_form.attachment_file.file) {
featureAPI
.postCommentAttachment({
featureId: this.$route.params.slug_signal,
file: this.comment_form.attachment_file.file,
fileName: this.comment_form.title.file,
comment: response.data.id,
})
.then(() => {
this.confirmComment();
//this.getFeatureAttachments(); //* display new attachment from comment on the page
});
} else {
this.confirmComment();
}
});
},
confirmComment() {
this.$store.commit("DISPLAY_MESSAGE", "Ajout du commentaire confirmé");
this.getFeatureEvents(); //* display new comment on the page
this.comment_form.attachment_file.file = null;
this.comment_form.attachment_file.value = null;
this.comment_form.title.file = null;
this.comment_form.title.value = null;
this.comment_form.comment.value = null;
},
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);
const shortName = fileName.slice(0, 10) + "[...]." + fileExtension;
this.comment_form.attachment_file.file = files[0];
this.comment_form.attachment_file.value = shortName;
this.comment_form.title.value = shortName;
},
goBackToProject(message) {
this.$router.push({
name: "project_detail",
params: {
slug: this.$store.state.project_slug,
message,
},
});
},
deleteFeature() {
this.$store
.dispatch("feature/DELETE_FEATURE", this.feature.feature_id)
.then((response) => {
if (response.status === 204) {
this.$store.dispatch("feature/GET_PROJECT_FEATURES");
this.goBackToProject();
}
});
},
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 = this.$store.state.map.basemaps;
var layers = this.$store.state.map.layers;
if (baseMaps && baseMaps.length > 0) {
const basemapIndex = 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}features/${currentFeatureId}/?output=geojson`;
axios
.get(url)
.then((response) => {
const feature = response.data;
if (feature) {
const currentFeature = [feature];
const featureGroup = mapUtil.addFeatures(currentFeature);
mapUtil.getMap().fitBounds(featureGroup.getBounds());
}
})
.catch((error) => {
throw error;
});
},
getFeatureEvents() {
featureAPI
.getFeatureEvents(this.$route.params.slug_signal)
.then((data) => (this.events = data));
},
getFeatureAttachments() {
featureAPI
.getFeatureAttachments(this.$route.params.slug_signal)
.then((data) => (this.attachments = data));
},
getLinkedFeatures() {
featureAPI
.getFeatureLinks(this.$route.params.slug_signal)
.then((data) =>
this.$store.commit("feature/SET_LINKED_FEATURES", data)
);
},
},
created() {
if (!this.project) {
this.$store.dispatch("GET_PROJECT_INFO", this.$route.params.slug);
}
this.$store.commit(
"feature_type/SET_CURRENT_FEATURE_TYPE_SLUG",
this.$route.params.slug_type_signal
);
this.getFeatureEvents();
this.getFeatureAttachments();
this.getLinkedFeatures();
},
mounted() {
this.$store
.dispatch("GET_PROJECT_INFO", this.$route.params.slug)
.then((data) => {
console.log(data);
this.initMap();
});
},
beforeDestroy() {
this.$store.commit("CLEAR_MESSAGES");
},
};
</script>
<style>
#map {
width: 100%;
height: 100%;
min-height: 250px;
max-height: 70vh;
}
#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;
}
</style>