let the year be changeable
This commit is contained in:
parent
1368217187
commit
e047dade4d
2 changed files with 121 additions and 12 deletions
|
@ -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;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
@ -295,11 +316,40 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 1. Übersicht aktuelles Jahr -->
|
||||
<div class="section-header">
|
||||
<!-- 1. Übersicht ausgewähltes Jahr mit Navigation -->
|
||||
<div class="section-header d-flex justify-content-between align-items-center">
|
||||
<h2 class="mb-0">
|
||||
<i class="fas fa-calendar-alt"></i> Übersicht {{ current_year }}
|
||||
<i class="fas fa-calendar-alt"></i> Übersicht {{ selected_year }}
|
||||
</h2>
|
||||
<div class="year-navigation d-flex align-items-center">
|
||||
{% if can_go_previous %}
|
||||
<a href="?year={{ previous_year }}" class="btn btn-outline-light me-2" title="Vorheriges Jahr ({{ previous_year }})">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-outline-light me-2" disabled title="Keine Daten vor {{ earliest_year }}">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
<span class="mx-3 fw-bold">{{ selected_year }}</span>
|
||||
|
||||
{% if can_go_next %}
|
||||
<a href="?year={{ next_year }}" class="btn btn-outline-light ms-2" title="Nächstes Jahr ({{ next_year }})">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="btn btn-outline-light ms-2" disabled title="Aktuelles Jahr erreicht">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% if selected_year != current_year %}
|
||||
<a href="?year={{ current_year }}" class="btn btn-light ms-3" title="Zurück zu {{ current_year }}">
|
||||
<i class="fas fa-calendar-day me-1"></i>{{ current_year }}
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4 mb-4">
|
||||
|
@ -441,7 +491,7 @@
|
|||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">{{ current_year }}</h5>
|
||||
<h5 class="mb-0">{{ selected_year }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if circumstances_this_year %}
|
||||
|
@ -456,7 +506,7 @@
|
|||
</div>
|
||||
{% else %}
|
||||
<div class="text-center text-muted">
|
||||
<p>Keine Daten für {{ current_year }} verfügbar</p>
|
||||
<p>Keine Daten für {{ selected_year }} verfügbar</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue