implement report feature
This commit is contained in:
parent
4218ee6b7d
commit
d6d47f714a
31 changed files with 2472 additions and 8 deletions
104
app/templates/admin/reports/automatic_report_confirm_delete.html
Normal file
104
app/templates/admin/reports/automatic_report_confirm_delete.html
Normal file
|
@ -0,0 +1,104 @@
|
|||
{% extends "admin/reports/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Automatischen Report löschen" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="report-content">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>{% trans "Automatischen Report löschen" %}</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-warning">
|
||||
<strong>{% trans "Achtung!" %}</strong>
|
||||
{% trans "Sind Sie sicher, dass Sie den automatischen Report" %}
|
||||
<strong>"{{ object.name }}"</strong>
|
||||
{% trans "löschen möchten?" %}
|
||||
</div>
|
||||
|
||||
<div class="report-details">
|
||||
<h4>{% trans "Report-Details:" %}</h4>
|
||||
<ul>
|
||||
<li><strong>{% trans "Name:" %}</strong> {{ object.name }}</li>
|
||||
<li><strong>{% trans "Häufigkeit:" %}</strong> {{ object.get_frequency_display }}</li>
|
||||
<li><strong>{% trans "Status:" %}</strong>
|
||||
{% if object.is_active %}
|
||||
<span class="badge badge-success">{% trans "Aktiv" %}</span>
|
||||
{% else %}
|
||||
<span class="badge badge-secondary">{% trans "Inaktiv" %}</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
<li><strong>{% trans "Erstellt am:" %}</strong> {{ object.created_at|date:"d.m.Y H:i" }}</li>
|
||||
<li><strong>{% trans "E-Mail-Adressen:" %}</strong>
|
||||
<ul>
|
||||
{% for email in object.email_addresses.all %}
|
||||
<li>{{ email.email }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info">
|
||||
<strong>{% trans "Hinweis:" %}</strong>
|
||||
{% trans "Das Löschen des automatischen Reports stoppt alle zukünftigen automatischen Versendungen. Bereits gesendete Reports bleiben im Report-Log erhalten." %}
|
||||
</div>
|
||||
|
||||
<form method="post" class="delete-form">
|
||||
{% csrf_token %}
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-danger">
|
||||
<i class="fas fa-trash"></i> {% trans "Ja, löschen" %}
|
||||
</button>
|
||||
<a href="{% url 'reports:automatic_reports' %}" class="btn btn-secondary">
|
||||
<i class="fas fa-arrow-left"></i> {% trans "Abbrechen" %}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.report-details {
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
margin: 15px 0;
|
||||
}
|
||||
|
||||
.report-details ul {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.report-details ul li {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.report-details ul ul {
|
||||
margin-top: 5px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.delete-form {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background-color: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.badge-secondary {
|
||||
background-color: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
145
app/templates/admin/reports/automatic_report_form.html
Normal file
145
app/templates/admin/reports/automatic_report_form.html
Normal file
|
@ -0,0 +1,145 @@
|
|||
{% extends "admin/reports/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}
|
||||
{% if object %}
|
||||
{% trans "Automatischen Report bearbeiten" %}
|
||||
{% else %}
|
||||
{% trans "Automatischen Report erstellen" %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="report-content">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>
|
||||
{% if object %}
|
||||
{% trans "Automatischen Report bearbeiten" %}
|
||||
{% else %}
|
||||
{% trans "Automatischen Report erstellen" %}
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" class="report-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="{{ form.name.id_for_label }}">{{ form.name.label }}</label>
|
||||
{{ form.name }}
|
||||
{% if form.name.help_text %}
|
||||
<small class="form-text text-muted">{{ form.name.help_text }}</small>
|
||||
{% endif %}
|
||||
{% if form.name.errors %}
|
||||
<div class="error-messages">
|
||||
{% for error in form.name.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="{{ form.email_addresses.id_for_label }}">{{ form.email_addresses.label }}</label>
|
||||
{{ form.email_addresses }}
|
||||
{% if form.email_addresses.help_text %}
|
||||
<small class="form-text text-muted">{{ form.email_addresses.help_text }}</small>
|
||||
{% endif %}
|
||||
{% if form.email_addresses.errors %}
|
||||
<div class="error-messages">
|
||||
{% for error in form.email_addresses.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="{{ form.frequency.id_for_label }}">{{ form.frequency.label }}</label>
|
||||
{{ form.frequency }}
|
||||
{% if form.frequency.errors %}
|
||||
<div class="error-messages">
|
||||
{% for error in form.frequency.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label for="{{ form.is_active.id_for_label }}">{{ form.is_active.label }}</label>
|
||||
<div class="checkbox-wrapper">
|
||||
{{ form.is_active }}
|
||||
</div>
|
||||
{% if form.is_active.errors %}
|
||||
<div class="error-messages">
|
||||
{% for error in form.is_active.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<h4>{% trans "Filter-Optionen" %}</h4>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<div class="checkbox-wrapper">
|
||||
{{ form.include_naturschutzbehörde }}
|
||||
<label for="{{ form.include_naturschutzbehörde.id_for_label }}">{{ form.include_naturschutzbehörde.label }}</label>
|
||||
</div>
|
||||
{% if form.include_naturschutzbehörde.errors %}
|
||||
<div class="error-messages">
|
||||
{% for error in form.include_naturschutzbehörde.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<div class="checkbox-wrapper">
|
||||
{{ form.include_jagdbehörde }}
|
||||
<label for="{{ form.include_jagdbehörde.id_for_label }}">{{ form.include_jagdbehörde.label }}</label>
|
||||
</div>
|
||||
{% if form.include_jagdbehörde.errors %}
|
||||
<div class="error-messages">
|
||||
{% for error in form.include_jagdbehörde.errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if form.non_field_errors %}
|
||||
<div class="error-messages">
|
||||
{% for error in form.non_field_errors %}
|
||||
<div class="error">{{ error }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{% if object %}
|
||||
{% trans "Speichern" %}
|
||||
{% else %}
|
||||
{% trans "Erstellen" %}
|
||||
{% endif %}
|
||||
</button>
|
||||
<a href="{% url 'reports:automatic_reports' %}" class="btn btn-secondary">
|
||||
{% trans "Abbrechen" %}
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
157
app/templates/admin/reports/automatic_reports.html
Normal file
157
app/templates/admin/reports/automatic_reports.html
Normal file
|
@ -0,0 +1,157 @@
|
|||
{% extends "admin/reports/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block reports_content %}
|
||||
<div class="automatic-reports">
|
||||
<h1>⚙️ Automatische Reports</h1>
|
||||
<p>Verwalten Sie automatische Reports, die regelmäßig versendet werden.</p>
|
||||
|
||||
<div class="actions">
|
||||
<a href="{% url 'reports:create_automatic_report' %}" class="btn btn-primary">➕ Neuen automatischen Report erstellen</a>
|
||||
</div>
|
||||
|
||||
{% if reports %}
|
||||
<div class="reports-table">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Häufigkeit</th>
|
||||
<th>Filter</th>
|
||||
<th>E-Mail-Adressen</th>
|
||||
<th>Status</th>
|
||||
<th>Zuletzt gesendet</th>
|
||||
<th>Aktionen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for report in reports %}
|
||||
<tr>
|
||||
<td>
|
||||
<strong>{{ report.name }}</strong>
|
||||
{% if report.description %}<br><small>{{ report.description|truncatechars:50 }}</small>{% endif %}
|
||||
</td>
|
||||
<td>{{ report.get_frequency_display }}</td>
|
||||
<td>
|
||||
{% if report.include_naturschutzbehoerde %}
|
||||
<span class="badge badge-naturschutz">Naturschutzbehörde</span>
|
||||
{% endif %}
|
||||
{% if report.include_jagdbehoerde %}
|
||||
<span class="badge badge-jagd">Jagdbehörde</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ report.email_addresses.count }} Adresse(n)</td>
|
||||
<td>
|
||||
{% if report.is_active %}
|
||||
<span class="status status-active">✅ Aktiv</span>
|
||||
{% else %}
|
||||
<span class="status status-inactive">❌ Inaktiv</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if report.last_sent %}
|
||||
{{ report.last_sent|date:"d.m.Y H:i" }}
|
||||
{% else %}
|
||||
<em>Noch nie gesendet</em>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="actions-cell">
|
||||
<a href="{% url 'reports:edit_automatic_report' report.id %}" class="btn btn-small btn-edit">✏️ Bearbeiten</a>
|
||||
<a href="{% url 'reports:delete_automatic_report' report.id %}" class="btn btn-small btn-delete">🗑️ Löschen</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<h3>Keine automatischen Reports konfiguriert</h3>
|
||||
<p>Sie haben noch keine automatischen Reports erstellt. Klicken Sie auf den Button oben, um Ihren ersten automatischen Report zu erstellen.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.actions {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.reports-table {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.reports-table table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.reports-table th {
|
||||
background: #417690;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
.reports-table td {
|
||||
padding: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
vertical-align: top;
|
||||
}
|
||||
.reports-table tr:hover {
|
||||
background: #f8f9fa;
|
||||
}
|
||||
.badge {
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.8em;
|
||||
font-weight: bold;
|
||||
margin: 2px;
|
||||
}
|
||||
.badge-naturschutz {
|
||||
background: #e8f5e8;
|
||||
color: #2e7d32;
|
||||
}
|
||||
.badge-jagd {
|
||||
background: #fff3e0;
|
||||
color: #f57c00;
|
||||
}
|
||||
.status {
|
||||
font-weight: bold;
|
||||
}
|
||||
.status-active {
|
||||
color: #2e7d32;
|
||||
}
|
||||
.status-inactive {
|
||||
color: #d32f2f;
|
||||
}
|
||||
.actions-cell {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.btn-small {
|
||||
padding: 6px 12px;
|
||||
font-size: 0.9em;
|
||||
margin: 2px;
|
||||
}
|
||||
.btn-edit {
|
||||
background: #1976d2;
|
||||
color: white;
|
||||
}
|
||||
.btn-delete {
|
||||
background: #d32f2f;
|
||||
color: white;
|
||||
}
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
color: #666;
|
||||
}
|
||||
.empty-state h3 {
|
||||
color: #417690;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
72
app/templates/admin/reports/base.html
Normal file
72
app/templates/admin/reports/base.html
Normal file
|
@ -0,0 +1,72 @@
|
|||
{% extends "admin/base_site.html" %}
|
||||
{% load i18n admin_urls static admin_list %}
|
||||
|
||||
{% block title %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
|
||||
|
||||
{% block branding %}
|
||||
<h1 id="site-name"><a href="{% url 'admin:index' %}">Django FBF Administration</a></h1>
|
||||
{% endblock %}
|
||||
|
||||
{% block nav-global %}
|
||||
<div class="nav-global">
|
||||
<a href="{% url 'reports:dashboard' %}" class="{% if request.resolver_match.url_name == 'dashboard' %}current{% endif %}">📊 Dashboard</a>
|
||||
<a href="{% url 'reports:manual_report' %}" class="{% if request.resolver_match.url_name == 'manual_report' %}current{% endif %}">📝 Report erstellen</a>
|
||||
<a href="{% url 'reports:automatic_reports' %}" class="{% if request.resolver_match.url_name == 'automatic_reports' %}current{% endif %}">⚙️ Automatischer Report</a>
|
||||
<a href="{% url 'reports:report_logs' %}" class="{% if request.resolver_match.url_name == 'report_logs' %}current{% endif %}">📋 Protokoll</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="reports-content">
|
||||
{% if messages %}
|
||||
<div class="messagelist">
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{{ message.tags }}">{{ message }}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block reports_content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrahead %}
|
||||
{{ block.super }}
|
||||
<style>
|
||||
.nav-global {
|
||||
background: #417690;
|
||||
padding: 10px 20px;
|
||||
margin: 0 -20px 20px -20px;
|
||||
}
|
||||
.nav-global a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-right: 20px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.nav-global a:hover, .nav-global a.current {
|
||||
background: rgba(255,255,255,0.2);
|
||||
}
|
||||
.reports-content {
|
||||
max-width: 1200px;
|
||||
}
|
||||
.alert {
|
||||
padding: 12px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.alert-success {
|
||||
color: #155724;
|
||||
background-color: #d4edda;
|
||||
border-color: #c3e6cb;
|
||||
}
|
||||
.alert-error {
|
||||
color: #721c24;
|
||||
background-color: #f8d7da;
|
||||
border-color: #f5c6cb;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
85
app/templates/admin/reports/dashboard.html
Normal file
85
app/templates/admin/reports/dashboard.html
Normal file
|
@ -0,0 +1,85 @@
|
|||
{% extends "admin/reports/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block reports_content %}
|
||||
<div class="dashboard">
|
||||
<h1>📊 Reports Dashboard</h1>
|
||||
<p>Willkommen zum Reports-System der Django FBF Anwendung. Hier können Sie Berichte über gefallene Vögel erstellen und verwalten.</p>
|
||||
|
||||
<div class="dashboard-modules">
|
||||
<div class="module">
|
||||
<h2>📝 Report erstellen</h2>
|
||||
<p>Erstellen Sie sofort einen benutzerdefinierten Report für einen bestimmten Zeitraum.</p>
|
||||
<ul>
|
||||
<li>Zeitraum auswählen (Standard: letzte 3 Monate)</li>
|
||||
<li>Filter nach Naturschutzbehörde/Jagdbehörde</li>
|
||||
<li>E-Mail versenden oder als CSV herunterladen</li>
|
||||
</ul>
|
||||
<a href="{% url 'reports:manual_report' %}" class="btn btn-primary">Report erstellen</a>
|
||||
</div>
|
||||
|
||||
<div class="module">
|
||||
<h2>⚙️ Automatischer Report</h2>
|
||||
<p>Konfigurieren Sie automatische Reports, die regelmäßig versendet werden.</p>
|
||||
<ul>
|
||||
<li>Wöchentliche, monatliche oder vierteljährliche Reports</li>
|
||||
<li>Vordefinierte E-Mail-Empfänger</li>
|
||||
<li>Automatische Zeitraum-Berechnung</li>
|
||||
</ul>
|
||||
<a href="{% url 'reports:automatic_reports' %}" class="btn btn-primary">Automatische Reports verwalten</a>
|
||||
</div>
|
||||
|
||||
<div class="module">
|
||||
<h2>📋 Report-Protokoll</h2>
|
||||
<p>Übersicht über alle erstellten und versendeten Reports.</p>
|
||||
<ul>
|
||||
<li>Historie aller Reports</li>
|
||||
<li>Status der E-Mail-Versendung</li>
|
||||
<li>Filter und Statistiken</li>
|
||||
</ul>
|
||||
<a href="{% url 'reports:report_logs' %}" class="btn btn-primary">Protokoll anzeigen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.dashboard-modules {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
.module {
|
||||
background: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
.module h2 {
|
||||
color: #417690;
|
||||
margin-top: 0;
|
||||
}
|
||||
.module ul {
|
||||
margin: 15px 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
.module li {
|
||||
margin-bottom: 8px;
|
||||
color: #666;
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
background: #417690;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.btn:hover {
|
||||
background: #2e5a70;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
178
app/templates/admin/reports/manual_report.html
Normal file
178
app/templates/admin/reports/manual_report.html
Normal file
|
@ -0,0 +1,178 @@
|
|||
{% extends "admin/reports/base.html" %}
|
||||
{% load i18n crispy_forms_tags %}
|
||||
|
||||
{% block reports_content %}
|
||||
<div class="manual-report">
|
||||
<h1>📝 Report erstellen</h1>
|
||||
<p>Erstellen Sie einen benutzerdefinierten Report für einen bestimmten Zeitraum.</p>
|
||||
|
||||
<form method="post" class="report-form">
|
||||
{% csrf_token %}
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend>📅 Zeitraum</legend>
|
||||
<div class="form-row">
|
||||
<div class="form-group">
|
||||
<label for="{{ form.date_from.id_for_label }}">{{ form.date_from.label }}</label>
|
||||
{{ form.date_from }}
|
||||
{% if form.date_from.help_text %}<p class="help">{{ form.date_from.help_text }}</p>{% endif %}
|
||||
{% if form.date_from.errors %}<ul class="errorlist">{% for error in form.date_from.errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.date_to.id_for_label }}">{{ form.date_to.label }}</label>
|
||||
{{ form.date_to }}
|
||||
{% if form.date_to.help_text %}<p class="help">{{ form.date_to.help_text }}</p>{% endif %}
|
||||
{% if form.date_to.errors %}<ul class="errorlist">{% for error in form.date_to.errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend>🎯 Filter</legend>
|
||||
<div class="form-row">
|
||||
<div class="form-group checkbox-group">
|
||||
{{ form.include_naturschutzbehoerde }}
|
||||
<label for="{{ form.include_naturschutzbehoerde.id_for_label }}">{{ form.include_naturschutzbehoerde.label }}</label>
|
||||
{% if form.include_naturschutzbehoerde.help_text %}<p class="help">{{ form.include_naturschutzbehoerde.help_text }}</p>{% endif %}
|
||||
</div>
|
||||
<div class="form-group checkbox-group">
|
||||
{{ form.include_jagdbehoerde }}
|
||||
<label for="{{ form.include_jagdbehoerde.id_for_label }}">{{ form.include_jagdbehoerde.label }}</label>
|
||||
{% if form.include_jagdbehoerde.help_text %}<p class="help">{{ form.include_jagdbehoerde.help_text }}</p>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.include_naturschutzbehoerde.errors or form.include_jagdbehoerde.errors %}
|
||||
<ul class="errorlist">
|
||||
{% for error in form.include_naturschutzbehoerde.errors %}<li>{{ error }}</li>{% endfor %}
|
||||
{% for error in form.include_jagdbehoerde.errors %}<li>{{ error }}</li>{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend>📧 E-Mail-Adressen</legend>
|
||||
<div class="form-group">
|
||||
<label>{{ form.email_addresses.label }}</label>
|
||||
{{ form.email_addresses }}
|
||||
{% if form.email_addresses.help_text %}<p class="help">{{ form.email_addresses.help_text }}</p>{% endif %}
|
||||
{% if form.email_addresses.errors %}<ul class="errorlist">{% for error in form.email_addresses.errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="{{ form.custom_email.id_for_label }}">{{ form.custom_email.label }}</label>
|
||||
{{ form.custom_email }}
|
||||
{% if form.custom_email.help_text %}<p class="help">{{ form.custom_email.help_text }}</p>{% endif %}
|
||||
{% if form.custom_email.errors %}<ul class="errorlist">{% for error in form.custom_email.errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="fieldset">
|
||||
<legend>🎬 Aktion</legend>
|
||||
<div class="form-group">
|
||||
{{ form.action }}
|
||||
{% if form.action.errors %}<ul class="errorlist">{% for error in form.action.errors %}<li>{{ error }}</li>{% endfor %}</ul>{% endif %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{% if form.non_field_errors %}
|
||||
<div class="form-errors">
|
||||
{{ form.non_field_errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Report erstellen</button>
|
||||
<a href="{% url 'reports:dashboard' %}" class="btn btn-secondary">Abbrechen</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.report-form {
|
||||
max-width: 800px;
|
||||
}
|
||||
.fieldset {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
background: white;
|
||||
}
|
||||
.fieldset legend {
|
||||
font-weight: bold;
|
||||
color: #417690;
|
||||
padding: 0 10px;
|
||||
}
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.form-group label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
margin-bottom: 5px;
|
||||
color: #333;
|
||||
}
|
||||
.form-group input, .form-group select {
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.checkbox-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
.checkbox-group input {
|
||||
width: auto;
|
||||
}
|
||||
.checkbox-group label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.help {
|
||||
font-size: 0.9em;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.errorlist {
|
||||
color: #d32f2f;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 5px 0;
|
||||
}
|
||||
.form-errors {
|
||||
background: #ffebee;
|
||||
border: 1px solid #f5c6cb;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.form-actions {
|
||||
margin-top: 30px;
|
||||
}
|
||||
.btn {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.btn-primary {
|
||||
background: #417690;
|
||||
color: white;
|
||||
}
|
||||
.btn-secondary {
|
||||
background: #6c757d;
|
||||
color: white;
|
||||
}
|
||||
.btn:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
278
app/templates/admin/reports/report_logs.html
Normal file
278
app/templates/admin/reports/report_logs.html
Normal file
|
@ -0,0 +1,278 @@
|
|||
{% extends "admin/reports/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Report-Protokoll" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="report-content">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h3>{% trans "Report-Protokoll" %}</h3>
|
||||
<div class="header-actions">
|
||||
<span class="badge badge-info">{{ report_logs|length }} {% trans "Einträge" %}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if report_logs %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>{% trans "Datum/Zeit" %}</th>
|
||||
<th>{% trans "Typ" %}</th>
|
||||
<th>{% trans "Name" %}</th>
|
||||
<th>{% trans "Zeitraum" %}</th>
|
||||
<th>{% trans "Anzahl Patienten" %}</th>
|
||||
<th>{% trans "E-Mail gesendet an" %}</th>
|
||||
<th>{% trans "Status" %}</th>
|
||||
<th>{% trans "Aktionen" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in report_logs %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="datetime-cell">
|
||||
<div class="date">{{ log.created_at|date:"d.m.Y" }}</div>
|
||||
<div class="time text-muted">{{ log.created_at|time:"H:i" }}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
{% if log.automatic_report %}
|
||||
<span class="badge badge-primary">
|
||||
<i class="fas fa-clock"></i> {% trans "Automatisch" %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="badge badge-secondary">
|
||||
<i class="fas fa-hand-paper"></i> {% trans "Manuell" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if log.automatic_report %}
|
||||
{{ log.automatic_report.name }}
|
||||
{% else %}
|
||||
{% trans "Manueller Report" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="date-range">
|
||||
<div>{{ log.date_from|date:"d.m.Y" }}</div>
|
||||
<div class="text-muted">{% trans "bis" %}</div>
|
||||
<div>{{ log.date_to|date:"d.m.Y" }}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="patient-count">{{ log.patient_count }}</span>
|
||||
</td>
|
||||
<td>
|
||||
{% if log.email_sent_to %}
|
||||
<div class="email-list">
|
||||
{% for email in log.email_sent_to %}
|
||||
<span class="email-badge">{{ email }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<span class="text-muted">{% trans "Download" %}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if log.email_sent_to %}
|
||||
<span class="badge badge-success">
|
||||
<i class="fas fa-envelope"></i> {% trans "Gesendet" %}
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="badge badge-info">
|
||||
<i class="fas fa-download"></i> {% trans "Heruntergeladen" %}
|
||||
</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="action-buttons">
|
||||
{% if log.csv_file %}
|
||||
<a href="{{ log.csv_file.url }}" class="btn btn-sm btn-outline-primary" title="{% trans 'CSV herunterladen' %}">
|
||||
<i class="fas fa-download"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
<button class="btn btn-sm btn-outline-info"
|
||||
onclick="showReportDetails({{ log.id }})"
|
||||
title="{% trans 'Details anzeigen' %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination (falls notwendig) -->
|
||||
{% if is_paginated %}
|
||||
<nav aria-label="Report log pagination">
|
||||
<ul class="pagination justify-content-center">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="page-item active">
|
||||
<span class="page-link">{{ num }}</span>
|
||||
</li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="page-item">
|
||||
<a class="page-link" href="?page={{ page_obj.next_page_number }}">
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="empty-state">
|
||||
<div class="text-center py-5">
|
||||
<i class="fas fa-file-alt fa-3x text-muted mb-3"></i>
|
||||
<h4 class="text-muted">{% trans "Noch keine Reports erstellt" %}</h4>
|
||||
<p class="text-muted">{% trans "Erstellen Sie Ihren ersten Report über das Dashboard." %}</p>
|
||||
<a href="{% url 'reports:dashboard' %}" class="btn btn-primary">
|
||||
<i class="fas fa-plus"></i> {% trans "Report erstellen" %}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Report Details Modal -->
|
||||
<div class="modal fade" id="reportDetailsModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans "Report-Details" %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="reportDetailsContent">
|
||||
<!-- Content wird via JavaScript geladen -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">
|
||||
{% trans "Schließen" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.datetime-cell .date {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.datetime-cell .time {
|
||||
font-size: 0.875em;
|
||||
}
|
||||
|
||||
.date-range {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.patient-count {
|
||||
font-weight: 600;
|
||||
color: #007bff;
|
||||
}
|
||||
|
||||
.email-list {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.email-badge {
|
||||
display: inline-block;
|
||||
background-color: #e9ecef;
|
||||
color: #495057;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.8em;
|
||||
margin: 1px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
min-height: 300px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.75em;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.badge-primary {
|
||||
background-color: #007bff;
|
||||
}
|
||||
|
||||
.badge-secondary {
|
||||
background-color: #6c757d;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.badge-info {
|
||||
background-color: #17a2b8;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function showReportDetails(logId) {
|
||||
// Placeholder für AJAX-Aufruf zum Laden der Report-Details
|
||||
// In einer vollständigen Implementierung würde hier ein AJAX-Request
|
||||
// an eine entsprechende View gemacht werden
|
||||
const modal = $('#reportDetailsModal');
|
||||
const content = $('#reportDetailsContent');
|
||||
|
||||
content.html(`
|
||||
<div class="text-center">
|
||||
<i class="fas fa-spinner fa-spin fa-2x"></i>
|
||||
<p class="mt-2">{% trans "Lade Details..." %}</p>
|
||||
</div>
|
||||
`);
|
||||
|
||||
modal.modal('show');
|
||||
|
||||
// Simulierter Inhalt (in echter Implementierung via AJAX)
|
||||
setTimeout(() => {
|
||||
content.html(`
|
||||
<div class="alert alert-info">
|
||||
<strong>{% trans "Hinweis:" %}</strong>
|
||||
{% trans "Die Detail-Ansicht wird in einer zukünftigen Version implementiert." %}
|
||||
</div>
|
||||
`);
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
32
app/templates/reports/email/report_message.txt
Normal file
32
app/templates/reports/email/report_message.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
{% load i18n %}{% autoescape off %}
|
||||
Hallo,
|
||||
|
||||
anbei erhalten Sie den angeforderten Report der Wildvogelhilfe Jena.
|
||||
|
||||
Report-Details:
|
||||
- Zeitraum: {{ date_from }} bis {{ date_to }}
|
||||
- Anzahl Patienten: {{ patient_count }}
|
||||
{% if filter_naturschutzbehörde and filter_jagdbehörde %}
|
||||
- Filter: Naturschutzbehörde und Jagdbehörde
|
||||
{% elif filter_naturschutzbehörde %}
|
||||
- Filter: Nur Naturschutzbehörde
|
||||
{% elif filter_jagdbehörde %}
|
||||
- Filter: Nur Jagdbehörde
|
||||
{% endif %}
|
||||
{% if automatic_report %}
|
||||
- Automatischer Report: {{ automatic_report.name }}
|
||||
{% else %}
|
||||
- Report-Typ: Manuell erstellt
|
||||
{% endif %}
|
||||
|
||||
Der Report liegt als CSV-Datei im Anhang bei und kann in Excel oder anderen Tabellenkalkulationsprogrammen geöffnet werden.
|
||||
|
||||
Bei Fragen zum Report wenden Sie sich bitte an das Team der Wildvogelhilfe Jena.
|
||||
|
||||
Mit freundlichen Grüßen
|
||||
Wildvogelhilfe Jena e.V.
|
||||
|
||||
---
|
||||
Diese E-Mail wurde automatisch generiert.
|
||||
Erstellt am: {{ created_at }}
|
||||
{% endautoescape %}
|
1
app/templates/reports/email/report_subject.txt
Normal file
1
app/templates/reports/email/report_subject.txt
Normal file
|
@ -0,0 +1 @@
|
|||
{% load i18n %}{% autoescape off %}{% blocktrans with site_name=current_site.name %}Wildvogelhilfe Jena Report von {{ date_from }} bis {{ date_to }}{% endblocktrans %}{% endautoescape %}
|
Loading…
Add table
Add a link
Reference in a new issue