Erste lauffähige Version
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}Serienbrief{% endblock %}</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; max-width: 960px; margin: 2rem auto; padding: 0 1rem; color: #222; }
|
||||
nav { display: flex; gap: 1rem; padding-bottom: 1rem; border-bottom: 1px solid #ddd; margin-bottom: 1.5rem; }
|
||||
nav a { text-decoration: none; color: #0366d6; }
|
||||
h1, h2 { color: #111; }
|
||||
table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
|
||||
th, td { text-align: left; padding: 0.5rem; border-bottom: 1px solid #eee; }
|
||||
.status-pending { color: #888; }
|
||||
.status-running { color: #d97706; }
|
||||
.status-done { color: #059669; }
|
||||
.status-failed { color: #dc2626; }
|
||||
.btn { display: inline-block; padding: 0.4rem 0.8rem; background: #0366d6; color: white; border-radius: 4px; text-decoration: none; border: none; cursor: pointer; }
|
||||
.messages li { padding: 0.5rem 1rem; background: #fef3c7; border-left: 4px solid #f59e0b; margin: 0.5rem 0; list-style: none; }
|
||||
.log { font-family: monospace; font-size: 0.85rem; background: #f6f8fa; padding: 0.75rem; border-radius: 4px; }
|
||||
.log .level-error { color: #dc2626; }
|
||||
.log .level-warning { color: #d97706; }
|
||||
form p { margin: 0.75rem 0; }
|
||||
label { display: block; font-weight: 600; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<a href="{% url 'dashboard' %}">Übersicht</a>
|
||||
<a href="{% url 'template-upload' %}">Neue Vorlage</a>
|
||||
<a href="{% url 'job-create' %}">Neuer Serienbrief</a>
|
||||
<span style="margin-left:auto">
|
||||
{% if user.is_authenticated %}
|
||||
{{ user.username }} · <a href="{% url 'logout' %}">Abmelden</a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</nav>
|
||||
{% if messages %}<ul class="messages">{% for m in messages %}<li>{{ m }}</li>{% endfor %}</ul>{% endif %}
|
||||
{% block content %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,25 @@
|
||||
<div hx-get="{% url 'job-detail' job.id %}" hx-trigger="every 2s" hx-swap="outerHTML">
|
||||
<p><strong>Vorlage:</strong> {{ job.template.name }}</p>
|
||||
<p><strong>Status:</strong>
|
||||
<span class="status-{{ job.status }}">{{ job.get_status_display }}</span>
|
||||
</p>
|
||||
<p><strong>Fortschritt:</strong> {{ job.processed_rows }} / {{ job.total_rows }}</p>
|
||||
|
||||
{% if job.status == "done" %}
|
||||
<p><a class="btn" href="{% url 'job-download' job.id %}">PDF herunterladen</a></p>
|
||||
{% endif %}
|
||||
{% if job.error_message %}
|
||||
<p style="color:#dc2626"><strong>Fehler:</strong> {{ job.error_message }}</p>
|
||||
{% endif %}
|
||||
|
||||
<h3>Log</h3>
|
||||
<div class="log">
|
||||
{% for entry in logs %}
|
||||
<div class="level-{{ entry.level }}">
|
||||
[{{ entry.timestamp|date:"H:i:s" }}] {{ entry.level|upper }} – {{ entry.message }}
|
||||
</div>
|
||||
{% empty %}
|
||||
<em>Keine Einträge.</em>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Übersicht</h1>
|
||||
|
||||
<h2>Vorlagen</h2>
|
||||
<a class="btn" href="{% url 'template-upload' %}">Neue Vorlage hochladen</a>
|
||||
<table>
|
||||
<thead><tr><th>Name</th><th>Platzhalter</th><th>Erstellt</th></tr></thead>
|
||||
<tbody>
|
||||
{% for t in templates %}
|
||||
<tr>
|
||||
<td><a href="{% url 'template-detail' t.id %}">{{ t.name }}</a></td>
|
||||
<td>{{ t.placeholders|join:", " }}</td>
|
||||
<td>{{ t.created_at|date:"d.m.Y H:i" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="3"><em>Noch keine Vorlagen vorhanden.</em></td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<h2>Aufträge</h2>
|
||||
<a class="btn" href="{% url 'job-create' %}">Neuen Serienbrief erstellen</a>
|
||||
<table>
|
||||
<thead><tr><th>ID</th><th>Vorlage</th><th>Status</th><th>Fortschritt</th><th>Erstellt</th></tr></thead>
|
||||
<tbody>
|
||||
{% for j in jobs %}
|
||||
<tr>
|
||||
<td><a href="{% url 'job-detail' j.id %}">{{ j.id|stringformat:"s"|slice:":8" }}…</a></td>
|
||||
<td>{{ j.template.name }}</td>
|
||||
<td class="status-{{ j.status }}">{{ j.get_status_display }}</td>
|
||||
<td>{{ j.processed_rows }} / {{ j.total_rows }}</td>
|
||||
<td>{{ j.created_at|date:"d.m.Y H:i" }}</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="5"><em>Noch keine Aufträge.</em></td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Auftrag {{ job.id|stringformat:"s"|slice:":8" }}…</h1>
|
||||
|
||||
<div hx-get="{% url 'job-detail' job.id %}"
|
||||
hx-trigger="every 2s"
|
||||
hx-swap="outerHTML">
|
||||
{% include "mailmerge/_job_status.html" %}
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/htmx.org@2.0.3" integrity="sha384-0895/pl2MU10Hqc6jd4RvrthNlDiE9U1tWmX7WRESftEDRosgxNsQG/Ze9YMRzHq" crossorigin="anonymous"></script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Neuer Serienbrief</h1>
|
||||
<p>Vorlage und Empfänger-CSV auswählen. Die Spaltennamen der CSV müssen mit den Platzhaltern der Vorlage übereinstimmen (erste Zeile = Spaltennamen).</p>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit" class="btn">Erstellen und starten</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,11 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>{{ template.name }}</h1>
|
||||
<p>{{ template.description }}</p>
|
||||
<p><strong>Datei:</strong> {{ template.file.name }}</p>
|
||||
<p><strong>Erkannte Platzhalter:</strong></p>
|
||||
<ul>
|
||||
{% for p in template.placeholders %}<li><code>{{ p }}</code></li>{% empty %}<li><em>Keine gefunden.</em></li>{% endfor %}
|
||||
</ul>
|
||||
<a class="btn" href="{% url 'job-create' %}">Serienbrief mit dieser Vorlage erstellen</a>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Neue Vorlage hochladen</h1>
|
||||
<p>DOCX-Datei mit Platzhaltern wie <code>{{ vorname }}</code>, <code>{{ nachname }}</code>, … Die Spaltennamen der späteren CSV müssen mit den Platzhaltern übereinstimmen.</p>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit" class="btn">Hochladen</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Anmelden{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Anmelden</h1>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit" class="btn">Anmelden</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user