Files
stiftung-management-system/app/templates/stiftung/csv_import_list.html
2025-09-06 18:31:54 +02:00

328 lines
20 KiB
HTML

{% extends 'base.html' %}
{% block title %}CSV Import Verlauf - Stiftungsverwaltung{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1><i class="fas fa-history text-primary"></i> CSV Import Verlauf</h1>
<a href="{% url 'stiftung:csv_import_create' %}" class="btn btn-primary">
<i class="fas fa-plus"></i> Neuer Import
</a>
</div>
<!-- Statistics Cards -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card bg-primary text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">{{ page_obj.paginator.count }}</h4>
<p class="card-text">Gesamt Imports</p>
</div>
<div class="align-self-center">
<i class="fas fa-file-csv fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-success text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">
{{ page_obj.paginator.count|default:0|add:"0"|floatformat:0 }}%
</h4>
<p class="card-text">Erfolgreich</p>
</div>
<div class="align-self-center">
<i class="fas fa-check-circle fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-warning text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">
{{ page_obj.paginator.count|default:0|add:"0"|floatformat:0 }}%
</h4>
<p class="card-text">Teilweise</p>
</div>
<div class="align-self-center">
<i class="fas fa-exclamation-triangle fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card bg-danger text-white">
<div class="card-body">
<div class="d-flex justify-content-between">
<div>
<h4 class="card-title">
{{ page_obj.paginator.count|default:0|add:"0"|floatformat:0 }}%
</h4>
<p class="card-text">Fehlgeschlagen</p>
</div>
<div class="align-self-center">
<i class="fas fa-times-circle fa-2x"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Import List -->
<div class="card shadow-sm">
<div class="card-header bg-light">
<h5 class="card-title mb-0">
<i class="fas fa-list"></i> Import-Verlauf
</h5>
</div>
<div class="card-body">
{% if page_obj %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>Typ</th>
<th>Dateiname</th>
<th>Status</th>
<th>Ergebnis</th>
<th>Erstellt von</th>
<th>Gestartet</th>
<th>Dauer</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for import in page_obj %}
<tr>
<td>
<span class="badge bg-primary">
{{ import.get_import_type_display }}
</span>
</td>
<td>
<strong>{{ import.filename }}</strong>
<br>
<small class="text-muted">
{{ import.file_size|filesizeformat }}
</small>
</td>
<td>
{% if import.status == 'completed' %}
<span class="badge bg-success">
<i class="fas fa-check"></i> Abgeschlossen
</span>
{% elif import.status == 'partial' %}
<span class="badge bg-warning">
<i class="fas fa-exclamation-triangle"></i> Teilweise
</span>
{% elif import.status == 'failed' %}
<span class="badge bg-danger">
<i class="fas fa-times"></i> Fehlgeschlagen
</span>
{% elif import.status == 'processing' %}
<span class="badge bg-info">
<i class="fas fa-spinner fa-spin"></i> Wird verarbeitet
</span>
{% else %}
<span class="badge bg-secondary">
{{ import.get_status_display }}
</span>
{% endif %}
</td>
<td>
{% if import.total_rows > 0 %}
<div class="progress" style="height: 20px;">
{% widthratio import.imported_rows import.total_rows 100 as success_percent %}
<div class="progress-bar bg-success" style="width: {{ success_percent }}%">
{{ import.imported_rows }}/{{ import.total_rows }}
</div>
</div>
<small class="text-muted">
Erfolgsrate: {{ import.get_success_rate|floatformat:1 }}%
</small>
{% else %}
<span class="text-muted">Keine Daten</span>
{% endif %}
</td>
<td>
<small>{{ import.created_by|default:"Unbekannt" }}</small>
</td>
<td>
<small>{{ import.started_at|date:"d.m.Y H:i" }}</small>
</td>
<td>
{% if import.get_duration %}
<small>{{ import.get_duration|floatformat:1 }}s</small>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
<div class="btn-group btn-group-sm" role="group">
<button type="button" class="btn btn-outline-info btn-sm"
data-bs-toggle="modal"
data-bs-target="#importDetailModal{{ import.id }}">
<i class="fas fa-eye"></i>
</button>
{% if import.error_log %}
<button type="button" class="btn btn-outline-warning btn-sm"
data-bs-toggle="modal"
data-bs-target="#errorModal{{ import.id }}">
<i class="fas fa-exclamation-triangle"></i>
</button>
{% endif %}
</div>
</td>
</tr>
<!-- Import Detail Modal -->
<div class="modal fade" id="importDetailModal{{ import.id }}" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Import-Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<h6>Allgemeine Informationen</h6>
<table class="table table-sm">
<tr><td>Typ:</td><td>{{ import.get_import_type_display }}</td></tr>
<tr><td>Dateiname:</td><td>{{ import.filename }}</td></tr>
<tr><td>Dateigröße:</td><td>{{ import.file_size|filesizeformat }}</td></tr>
<tr><td>Status:</td><td>{{ import.get_status_display }}</td></tr>
<tr><td>Erstellt von:</td><td>{{ import.created_by|default:"Unbekannt" }}</td></tr>
</table>
</div>
<div class="col-md-6">
<h6>Ergebnisse</h6>
<table class="table table-sm">
<tr><td>Gesamtzeilen:</td><td>{{ import.total_rows }}</td></tr>
<tr><td>Importiert:</td><td>{{ import.imported_rows }}</td></tr>
<tr><td>Fehlgeschlagen:</td><td>{{ import.failed_rows }}</td></tr>
<tr><td>Erfolgsrate:</td><td>{{ import.get_success_rate|floatformat:1 }}%</td></tr>
<tr><td>Dauer:</td><td>{{ import.get_duration|floatformat:1 }}s</td></tr>
</table>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<h6>Zeitstempel</h6>
<p><strong>Gestartet:</strong> {{ import.started_at|date:"d.m.Y H:i:s" }}</p>
{% if import.completed_at %}
<p><strong>Abgeschlossen:</strong> {{ import.completed_at|date:"d.m.Y H:i:s" }}</p>
{% endif %}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
<!-- Error Log Modal -->
{% if import.error_log %}
<div class="modal fade" id="errorModal{{ import.id }}" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-warning text-dark">
<h5 class="modal-title">
<i class="fas fa-exclamation-triangle"></i> Fehlerprotokoll
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="alert alert-warning">
<strong>Fehler beim Import:</strong> {{ import.failed_rows }} Zeilen konnten nicht importiert werden.
</div>
<h6>Fehlerdetails:</h6>
<pre class="bg-light p-3 rounded"><code>{{ import.error_log }}</code></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if page_obj.has_other_pages %}
<nav aria-label="Import pagination">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1">&laquo; Erste</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">Zurück</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 }}">Weiter</a>
</li>
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.paginator.num_pages }}">Letzte &raquo;</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% else %}
<div class="text-center py-5">
<i class="fas fa-file-csv fa-3x text-muted mb-3"></i>
<h5 class="text-muted">Keine CSV-Imports gefunden</h5>
<p class="text-muted">Starten Sie Ihren ersten CSV-Import, um Daten zu importieren.</p>
<a href="{% url 'stiftung:csv_import_create' %}" class="btn btn-primary">
<i class="fas fa-plus"></i> Ersten Import starten
</a>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}