From e047dade4d52661268581f6e94cd1ade43c24341 Mon Sep 17 00:00:00 2001 From: NABU Jena Date: Wed, 9 Jul 2025 08:29:06 +0200 Subject: [PATCH] let the year be changeable --- .../templates/statistic/overview.html | 91 ++++++++++++++++++- app/statistic/views.py | 42 +++++++-- 2 files changed, 121 insertions(+), 12 deletions(-) diff --git a/app/statistic/templates/statistic/overview.html b/app/statistic/templates/statistic/overview.html index 21aa080..f3f59c9 100644 --- a/app/statistic/templates/statistic/overview.html +++ b/app/statistic/templates/statistic/overview.html @@ -281,6 +281,27 @@ height: 20px; border-radius: 4px; } + + /* Jahr-Navigation */ + .year-navigation .btn { + border-radius: 50%; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s ease; + } + + .year-navigation .btn:hover:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); + transform: scale(1.1); + } + + .year-navigation .btn:disabled { + opacity: 0.5; + cursor: not-allowed; + } {% endblock %} @@ -295,11 +316,40 @@ - -
+ +

- Übersicht {{ current_year }} + Übersicht {{ selected_year }}

+
+ {% if can_go_previous %} + + + + {% else %} + + {% endif %} + + {{ selected_year }} + + {% if can_go_next %} + + + + {% else %} + + {% endif %} + + {% if selected_year != current_year %} + + {{ current_year }} + + {% endif %} +
@@ -441,7 +491,7 @@
-
{{ current_year }}
+
{{ selected_year }}
{% if circumstances_this_year %} @@ -456,7 +506,7 @@
{% else %}
-

Keine Daten für {{ current_year }} verfügbar

+

Keine Daten für {{ selected_year }} verfügbar

{% endif %}
@@ -516,6 +566,37 @@ document.addEventListener('DOMContentLoaded', function() { } } }); + + // Tastatur-Navigation für Jahre + document.addEventListener('keydown', function(e) { + // Nur reagieren wenn kein Input-Element fokussiert ist + if (document.activeElement.tagName === 'INPUT' || document.activeElement.tagName === 'TEXTAREA') { + return; + } + + if (e.key === 'ArrowLeft') { + // Vorheriges Jahr + const prevButton = document.querySelector('a[href*="year={{ previous_year }}"]'); + if (prevButton) { + window.location.href = prevButton.href; + } + } else if (e.key === 'ArrowRight') { + // Nächstes Jahr + const nextButton = document.querySelector('a[href*="year={{ next_year }}"]'); + if (nextButton) { + window.location.href = nextButton.href; + } + } else if (e.key === 'Home') { + // Zurück zum aktuellen Jahr + const currentYearButton = document.querySelector('a[href*="year={{ current_year }}"]'); + if (currentYearButton) { + window.location.href = currentYearButton.href; + } else { + // Falls schon im aktuellen Jahr, zur Statistik-Hauptseite + window.location.href = window.location.pathname; + } + } + }); }); {% endblock %} diff --git a/app/statistic/views.py b/app/statistic/views.py index 72bb57b..1cf8ce4 100644 --- a/app/statistic/views.py +++ b/app/statistic/views.py @@ -1,6 +1,6 @@ from django.views.generic import TemplateView from django.contrib.auth.mixins import LoginRequiredMixin -from django.db.models import Count, Q +from django.db.models import Count, Q, Min from django.utils import timezone from datetime import datetime from bird.models import FallenBird, Bird, BirdStatus, Circumstance @@ -13,9 +13,31 @@ class StatisticView(LoginRequiredMixin, TemplateView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - # Aktuelles Jahr + # Jahr aus URL-Parameter oder aktuelles Jahr + selected_year = self.request.GET.get('year', timezone.now().year) + try: + selected_year = int(selected_year) + except (ValueError, TypeError): + selected_year = timezone.now().year + current_year = timezone.now().year + # Stelle sicher, dass das ausgewählte Jahr nicht in der Zukunft liegt + if selected_year > current_year: + selected_year = current_year + + # Finde das früheste Jahr mit Daten + earliest_year_with_data = FallenBird.objects.aggregate( + earliest=Min('date_found__year') + )['earliest'] + + if earliest_year_with_data is None: + earliest_year_with_data = current_year + + # Stelle sicher, dass das ausgewählte Jahr nicht vor dem frühesten Jahr liegt + if selected_year < earliest_year_with_data: + selected_year = earliest_year_with_data + # Lade aktive Konfiguration try: config = StatisticConfiguration.objects.get(is_active=True) @@ -31,11 +53,17 @@ class StatisticView(LoginRequiredMixin, TemplateView): context['config'] = config context['current_year'] = current_year + context['selected_year'] = selected_year + context['earliest_year'] = earliest_year_with_data + context['can_go_previous'] = selected_year > earliest_year_with_data + context['can_go_next'] = selected_year < current_year + context['previous_year'] = selected_year - 1 if context['can_go_previous'] else None + context['next_year'] = selected_year + 1 if context['can_go_next'] else None # 1. Jahresstatistik if config.show_year_total_patients: patients_this_year = FallenBird.objects.filter( - date_found__year=current_year + date_found__year=selected_year ).count() context['patients_this_year'] = patients_this_year @@ -46,7 +74,7 @@ class StatisticView(LoginRequiredMixin, TemplateView): for group in year_groups: status_ids = list(group.status_list.values_list('id', flat=True)) year_count = FallenBird.objects.filter( - date_found__year=current_year, + date_found__year=selected_year, status__id__in=status_ids ).count() @@ -144,10 +172,10 @@ class StatisticView(LoginRequiredMixin, TemplateView): context['bird_stats'] = bird_stats - # 4. Fundumstände-Statistiken (unverändert) - # Fundumstände für aktuelles Jahr + # 4. Fundumstände-Statistiken + # Fundumstände für ausgewähltes Jahr circumstances_this_year = FallenBird.objects.filter( - date_found__year=current_year, + date_found__year=selected_year, find_circumstances__isnull=False ).values('find_circumstances__name', 'find_circumstances__description').annotate( count=Count('id')