Commit 49aa0832 authored by hypsug0's avatar hypsug0
Browse files

feat: improve study details sheet

parent 0b872e56
......@@ -983,3 +983,15 @@ BS Full screen Modal
-o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
}
.scroll-y-auto {
overflow-y: auto;
}
.scroll-y {
overflow-y: scroll;
}
.study-data-panel {
max-height: 500px;
}
// // For Bootstrap dropdown-submenu
// (function ($) {
// $(document).ready(function () {
......@@ -1729,7 +1730,6 @@ const sigthingFormApp = (id_session, type_contact) => {
},
getAutocompleteData(obj) {
this.data.user = obj
console.warn(obj)
},
sumCountDetails(is) {
const CountSum = (a, c) => a + parseInt(c.count)
......@@ -1813,7 +1813,67 @@ const sigthingFormApp = (id_session, type_contact) => {
}
}
Vue.component('session-group-item', {
props: ['data'],
template: `<div class="list-group-item">
<h3 class="list-group-item-heading">
<span class="pull-right label label-info label-lg">{{data.properties.sessions.length}} sessions</span>
<i class="fa fa-map-marker fa-fw"></i><a :href="'/place/'+data.id+'/detail'" target="_blank">{{data.properties.name}}</a>
</h3>
<div class="list-group">
<div v-for="(se, ie) in data.properties.sessions" class="list-group-item">
<h4 class="list-group-item-heading">
<span class="pull-right label label-default label-lg">{{se.contact.descr}}</span>
<span class="text-info"><a :href="'/session/'+se.id_session+'/detail'">{{se.date_start}}</a></span>
</h4>
<p class="list-group-item-text">
<dl class="dl-horizontal">
<dt>Observateur principal</dt>
<dd>
{{se.main_observer?.get_full_name}}</dd>
<dt>Observations</dt>
<dd>
<ul class="list-unstyled">
<li v-for='(o, io) in se.observations' :class="{'text-muted':!o.codesp.sp_true}">
<i v-show="o.breed_colo" class="fas fa-baby fa-fw text-success"></i>
<strong>{{o.codesp.common_name_fr}}</strong>
(<i>{{o.codesp.sci_name}}</i>)
: {{o.total_count ? o.total_count: '-'}}
</li>
</ul>
</dd>
</dl>
</p>
</div>
</div>
</div>`,
})
const studyDataApp = (pk) => {
// Vue.component('pie-chart', {
// extends: Pie,
// data() {
// return {
// options: {
// parsing: {
// xAxisKey: 'label',
// yAxisKey: 'value',
// },
// },
// }
// },
// props: {
// chartData: {
// type: Object,
// default: null,
// },
// },
// mounted() {
// this.renderChart(this.chartData, this.options)
// },
// })
return {
el: '#StudyData',
delimiters: ['[[', ']]'],
......@@ -1824,8 +1884,17 @@ const studyDataApp = (pk) => {
placeData: [],
sessionData: [],
sightingData: [],
dataSource: 'observations',
dataSource: 'stats',
//sessions: [],
loading: true,
contactSessionsChartOptions: {
options: {
parsing: {
xAxisKey: 'label',
yAxisKey: 'value',
},
},
}
}
},
methods: {
......@@ -1835,11 +1904,61 @@ const studyDataApp = (pk) => {
.then((r) => {
console.debug(r)
this.sightingData = r.data.results.features
console.log(this.sightingData)
//this.countSessions()
this.loading = false
})
.catch((error) => console.error(error))
},
countPlaces() {
return this.sightingData.length
},
// countSessions2() {
// this.sessions = []
// console.error('TypeOf Fata', typeof(this.sightingData));
// console.error('Data', this.sightingData);
// this.sessions = [...this.sightingData.forEach(e => this.sessions.push(...e.properties.sessions))]
// }
},
computed: {
sessions() {
return Array.prototype.concat.apply(
[],
this.sightingData.map((e) => e.properties.sessions)
)
},
minDate() {
//return this.sessions.map(a=> e.date_start).reduce((a, b) => { return a < b ? a : b; })
return new Date(
Math.min(
...this.sessions.map((e) => new Date(e.date_start))
)
).toLocaleDateString()
},
maxDate() {
return new Date(
Math.max(
...this.sessions.map(
(e) =>
new Date(e.date_end ? e.date_end : e.date_start)
)
)
).toLocaleDateString()
},
contacts() {
const contacts = [
...new Set(this.sessions.map((e) => e.contact.descr)),
]
const data = []
contacts.forEach((e) => {
data.push({
label: e,
value: this.sessions.filter(
(se) => se.contact.descr == e
).length,
})
})
return data
},
},
mounted() {
this.getSightings()
......
......@@ -4,7 +4,7 @@ import logging
from django.db.models import Prefetch
from rest_framework.generics import ListAPIView
from sights.models import Place
from sights.models import Place, Session
from sights.observation.api import GeoJSONSighting
from ..models import Study
......@@ -27,7 +27,6 @@ class StudyDatas(ListAPIView):
queryset = (
Place.objects.select_related("created_by")
.select_related("updated_by")
.prefetch_related("sessions")
.prefetch_related("sessions__study")
.prefetch_related(Prefetch("sessions__observations"))
.prefetch_related(Prefetch("sessions__contact"))
......@@ -37,8 +36,25 @@ class StudyDatas(ListAPIView):
)
def get_queryset(self, *args, **kwargs):
qs = super().get_queryset()
# qs = super().get_queryset()7
pk = self.kwargs.get("pk")
qs = (
Place.objects.select_related("created_by")
.select_related("updated_by")
.prefetch_related(
Prefetch(
"sessions",
queryset=Session.objects.filter(study=pk),
to_attr="study_sessions",
)
)
.prefetch_related("study_sessions__study")
.prefetch_related(Prefetch("study_sessions__observations"))
.prefetch_related(Prefetch("study_sessions__contact"))
.prefetch_related(Prefetch("study_sessions__observations__codesp"))
.prefetch_related(Prefetch("study_sessions__main_observer"))
# .prefetch_related(Prefetch("sessions__other_observer"))
)
logger.debug(f"pk is {pk}")
study = Study.objects.get(pk=pk)
logger.debug(f"study is {study}")
......
import logging
from rest_framework.serializers import ModelSerializer, SerializerMethodField
from rest_framework.serializers import ModelSerializer
from rest_framework_gis.serializers import GeoFeatureModelSerializer
from accounts.serializer import ProfileSearchSerializer
......@@ -42,13 +42,13 @@ class SessionSerializer(ModelSerializer):
class StudyDataSerializer(GeoFeatureModelSerializer):
sessions = SessionSerializer(many=True)
sessions = SessionSerializer(source="study_sessions", many=True, read_only=True)
class Meta:
model = Place
geo_field = "geom"
depth = 0
fields = ("name", "sessions")
fields = ("name", "id_place", "sessions")
# def get_sessions(self, instance):
# queryset = instance.sessions.order_by("-date_start")
......
......@@ -68,64 +68,61 @@
<div class="panel-heading">
<h4 class="panel-title">
<select class="pull-right input-sm" v-model="dataSource">
<option value="stats">statistiques générales</option>
<option value="stats">Données générales</option>
<option value="observations" default>Observations</option>
</select>
<i class="fas fa-clipboard-list fa-fw"></i>Données
</h4>
</div>
<div style="overflow-y: auto; max-height: 500px;">
<div v-if="dataSource=='stats'" class="row" style="text-align:center;font-size:2rem;">
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="statBlock">
<i class="text-muted fas fa-map-marked-alt fa-2x"></i><br>
<span class="statCount">{{ object.sessions.place.count }}</span><br>
<span class="statDesc text-muted"> localités</span><br>
<div v-if="loading" class="panel-body study-data-panel">
<div align="center" style="height: 200px;">Chargement en cours...</div>
<div id="spinner"></div>
</div>
<div v-else>
<div v-if="dataSource=='stats'" class="panel-body">
<div class="row" style="text-align:center;font-size:2rem;">
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="statBlock">
<i class="text-muted fas fa-map-marked-alt fa-2x"></i><br>
<span class="statCount">[[sightingData.length]]</span><br>
<span class="statDesc text-muted"> localités</span><br>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="statBlock">
<i class="text-muted fas fa-calendar-check fa-2x "></i><br>
<span class="statCount">{{ object.sessions.count }}</span><br>
<span class="statDesc text-muted"> sessions}</span><br>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="statBlock">
<i class="text-muted fas fa-calendar-check fa-2x "></i><br>
<span class="statCount">[[sessions.length]]</span><br>
<span class="statDesc text-muted"> sessions</span><br>
</div>
</div>
</div>
</div>
</div>
<div v-if="dataSource=='observations'" class="list-group">
<div v-for="(sp, ip) in sightingData" class="list-group-item">
<h3 class="list-group-item-heading"><i class="fa fa-map-marker fa-fw"></i>[[sp.properties.name]]</h3>
<div class="list-group">
<div v-for="(se, ie) in sp.properties.sessions" class="list-group-item">
<h4 class="list-group-item-heading">
<span class="pull-right label label-default label-lg">[[se.contact.descr]]</span>
<span class="text-info">[[se.date_start]]</span>
</h4>
<p class="list-group-item-text">
<dl class="dl-horizontal">
<dt>Observateur principal</dt>
<dd>
[[se.main_observer?.get_full_name]]</dd>
<dt>Observations</dt>
<dd>
<ul class="list-unstyled">
<li v-for='(o, io) in se.observations' :class="{'text-muted':!o.codesp.sp_true}">
<i v-show="o.breed_colo" class="fas fa-baby fa-fw text-success"></i>
<strong>[[o.codesp.common_name_fr]]</strong>
(<i>[[o.codesp.sci_name]]</i>)
: [[o.total_count ? o.total_count: '-']]
</li>
</ul>
</dd>
</dl>
</p>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="statBlock">
<i class="text-muted fas fa-calendar-check fa-2x "></i><br>
<span class="statCount">[[minDate]]</span><br>
<span class="statDesc text-muted"> Date mini</span><br>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-3">
<div class="statBlock">
<i class="text-muted fas fa-calendar-check fa-2x "></i><br>
<span class="statCount">[[maxDate]]</span><br>
<span class="statDesc text-muted"> Date max</span><br>
</div>
</div>
</div>
{% comment %} <pie-chart :chart-data="contacts">
</pie-chart> {% endcomment %}
[[contacts]]
</div>
</div>
<div v-if="dataSource=='observations'" class="list-group scroll-y-auto study-data-panel">
<session-group-item v-for=" (d, i) in sightingData" :data="d" :key="i">
</session-detail>
</div>
</div>
</div>
</div>
</div>
<script>
const studyId = parseInt('{{object.pk}}')
......
......@@ -13,6 +13,7 @@
}
}
})();
</script>
<link rel="shortcut icon" href="{% static 'img/favicon.ico' %}" />
<link rel="stylesheet" href="{% static 'css/font/source-sans-pro/source-sans-pro.css' %}" />
......@@ -28,15 +29,17 @@
<link rel="stylesheet" href="{% static 'css/vue-select.css' %}" />
<script src="{% static 'js/jquery/jquery.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}" defer></script>
<script src="{% static 'js/vue.js' %}" defer ></script>
<script src="{% static 'js/vue.js' %}" defer></script>
<script src="{% static 'js/vee-validate.js' %}" defer></script>
<script src="{% static 'js/vue-select.js' %}" defer></script>
<script src="{% static 'js/vue-select.js' %}" defer></script>
<script src="{% static 'js/axios.min.js' %}" defer></script>
<script src="{% static 'js/preload_app.js' %}" defer></script>
<script src="{% static 'js/datatables.min.js' %} " defer></script>
<script src="{% static 'js/moment.min.js' %} " defer></script>
<script src="{% static 'js/bootstrap-datetimepicker.min.js' %} " defer></script>
<script src="{% static 'js/what-input.js' %} " defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<script src="https://unpkg.com/vue-chartjs/dist/vue-chartjs.min.js"></script>
<script src="{% static 'js/app.js' %} " defer></script>
{% if form %} {{ form.media }} {% endif %}
<!-- filter tag is for django filter -->
......
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment