Files
stiftung-management-system/app/templates/portal/upload_formular.html
SysAdmin Agent 4d751d861d
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
Code Quality / quality (push) Has been cancelled
CI/CD Pipeline / deploy (push) Has been cancelled
DSGVO-Compliance: Einwilligung, Datenschutzerklärung & Consent-Logging im Upload-Portal (STI-89)
- Datenschutzerklärung unter /portal/datenschutz/ öffentlich erreichbar
- Link zur Datenschutzerklärung in Nachweis-Aufforderungs-E-Mails (HTML + TXT)
- Einwilligungs-Checkbox vor Upload mit Server-Side-Validierung
- Consent-Logging: einwilligung_erteilt_am auf UploadToken (Art. 7 Abs. 1 DSGVO)
- Regelsatz-Korrektur: 449€→563€ in Onboarding-Template (Stand 01/2024)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 22:43:01 +00:00

185 lines
10 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Unterlagen hochladen vHTV-Stiftung</title>
<style>
*, *::before, *::after { box-sizing: border-box; }
body { font-family: Arial, sans-serif; font-size: 15px; color: #222; background: #f4f6f8; margin: 0; padding: 0; }
.container { max-width: 720px; margin: 40px auto; padding: 0 16px 40px; }
.header { background: #1a3a5c; color: #fff; padding: 24px 28px; border-radius: 8px 8px 0 0; }
.header h1 { margin: 0 0 4px; font-size: 20px; }
.header p { margin: 0; font-size: 13px; opacity: 0.8; }
.card { background: #fff; border-radius: 0 0 8px 8px; padding: 28px; box-shadow: 0 2px 10px rgba(0,0,0,0.08); }
.badge { display: inline-block; background: #e8f0fb; color: #1a3a5c; font-weight: bold; padding: 4px 12px; border-radius: 20px; font-size: 13px; margin-bottom: 12px; }
.info-box { background: #f0f6ff; border: 1px solid #b0cce8; border-radius: 6px; padding: 14px 16px; margin-bottom: 20px; font-size: 14px; }
.error-box { background: #fff3f3; border: 1px solid #e88; border-radius: 6px; padding: 12px 16px; margin-bottom: 16px; color: #c00; }
/* Category sections */
.kategorie { border: 1px solid #dde4ed; border-radius: 8px; padding: 20px; margin-bottom: 20px; }
.kategorie h3 { margin: 0 0 4px; font-size: 16px; color: #1a3a5c; }
.kategorie .hinweis { font-size: 13px; color: #666; margin: 0 0 12px; }
.kategorie.pflicht { border-left: 3px solid #1a3a5c; }
label { display: block; font-weight: bold; margin-bottom: 6px; font-size: 14px; }
.upload-area { border: 2px dashed #b0cce8; border-radius: 6px; padding: 20px; text-align: center; cursor: pointer; background: #fafcff; transition: border-color 0.2s; position: relative; }
.upload-area:hover, .upload-area.dragover { border-color: #1a3a5c; background: #e8f0fb; }
.upload-area input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; }
.upload-area .icon { font-size: 28px; margin-bottom: 4px; }
.upload-area p { margin: 2px 0; color: #555; font-size: 13px; }
.upload-area .hint { font-size: 11px; color: #888; }
.file-list { margin: 8px 0 0; font-size: 13px; color: #444; list-style: none; padding: 0; }
.file-list li { padding: 3px 0; border-bottom: 1px solid #f0f0f0; }
.oder-text { text-align: center; color: #999; font-size: 13px; margin: 10px 0; font-style: italic; }
textarea { width: 100%; border: 1px solid #ccc; border-radius: 5px; padding: 10px; font-family: inherit; font-size: 14px; resize: vertical; min-height: 60px; }
textarea:focus { border-color: #1a3a5c; outline: none; }
.submit-btn { display: block; width: 100%; background: #1a3a5c; color: #fff; border: none; border-radius: 5px; padding: 14px; font-size: 16px; font-weight: bold; cursor: pointer; margin-top: 20px; }
.submit-btn:hover { background: #14304e; }
.deadline { font-size: 13px; color: #888; margin-top: 16px; text-align: center; }
.footer { text-align: center; margin-top: 24px; font-size: 12px; color: #aaa; }
.pflicht-hinweis { font-size: 12px; color: #888; margin-bottom: 16px; }
.einwilligung-box { background: #f0f6ff; border: 1px solid #b0cce8; border-radius: 6px; padding: 14px 16px; margin: 20px 0; font-size: 14px; }
.einwilligung-box label { font-weight: normal; display: flex; align-items: flex-start; gap: 10px; cursor: pointer; }
.einwilligung-box input[type="checkbox"] { margin-top: 2px; flex-shrink: 0; width: 16px; height: 16px; cursor: pointer; }
.einwilligung-box .einwilligung-fehler { color: #c00; font-size: 13px; margin-top: 6px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>van Hees-Theyssen-Vogel'sche Stiftung</h1>
<p>Sicheres Dokumenten-Upload-Portal</p>
</div>
<div class="card">
<div class="badge">{{ halbjahr_label }}</div>
<p>Guten Tag, <strong>{{ destinataer.vorname }} {{ destinataer.nachname }}</strong>,</p>
<p>bitte laden Sie hier Ihre Unterlagen für das <strong>{{ halbjahr_label }}</strong> hoch.
Für jede Kategorie können Sie eine Datei hochladen und/oder einen Text eingeben.</p>
<p class="pflicht-hinweis">Pro Kategorie muss mindestens eine Datei <em>oder</em> ein Texteintrag eingereicht werden.</p>
{% if fehler %}
<div class="error-box">{{ fehler }}</div>
{% endif %}
<form method="post" enctype="multipart/form-data" action="">
{% csrf_token %}
<!-- 1. Studiennachweis -->
<div class="kategorie pflicht">
<h3>Studiennachweis</h3>
<p class="hinweis">Semesterbescheinigung, Ausbildungsnachweis, Leistungsnachweise (Zeugnisse, Kreditpunkte etc.)</p>
<label for="studiennachweis">Datei hochladen:</label>
<div class="upload-area" data-target="studiennachweis">
<input type="file" name="studiennachweis" id="studiennachweis" accept=".pdf,.jpg,.jpeg,.png,.tiff,.tif">
<div class="icon">&#128196;</div>
<p>Datei hierher ziehen oder klicken</p>
<p class="hint">PDF, JPG, PNG, TIFF &bull; max. {{ max_dateigroesse_mb }} MB</p>
</div>
<ul class="file-list" data-list="studiennachweis"></ul>
<p class="oder-text">— oder Texteintrag —</p>
<textarea name="studiennachweis_text" placeholder="z.B. 'Semesterbescheinigung liegt bei' oder 'Kein Studium/Ausbildung mehr seit ...'">{{ studiennachweis_text|default:"" }}</textarea>
</div>
<!-- 2. Einkommenssituation -->
<div class="kategorie pflicht">
<h3>Einkommenssituation</h3>
<p class="hinweis">Einkommensteuerbescheid, Lohn-/Gehaltsnachweis, Rentenbescheid, Bescheinigung Pflegegrad etc.</p>
<label for="einkommenssituation">Datei hochladen:</label>
<div class="upload-area" data-target="einkommenssituation">
<input type="file" name="einkommenssituation" id="einkommenssituation" accept=".pdf,.jpg,.jpeg,.png,.tiff,.tif">
<div class="icon">&#128196;</div>
<p>Datei hierher ziehen oder klicken</p>
<p class="hint">PDF, JPG, PNG, TIFF &bull; max. {{ max_dateigroesse_mb }} MB</p>
</div>
<ul class="file-list" data-list="einkommenssituation"></ul>
<p class="oder-text">— oder Texteintrag —</p>
<textarea name="einkommenssituation_text" placeholder="z.B. 'Keine Änderungen seit letzter Meldung' oder Details zu Änderungen">{{ einkommenssituation_text|default:"" }}</textarea>
</div>
<!-- 3. Vermögenssituation -->
<div class="kategorie pflicht">
<h3>Vermögenssituation</h3>
<p class="hinweis">Angaben zu Spar-/Festgeldguthaben, Aktien, Immobilien etc.</p>
<label for="vermogenssituation">Datei hochladen:</label>
<div class="upload-area" data-target="vermogenssituation">
<input type="file" name="vermogenssituation" id="vermogenssituation" accept=".pdf,.jpg,.jpeg,.png,.tiff,.tif">
<div class="icon">&#128196;</div>
<p>Datei hierher ziehen oder klicken</p>
<p class="hint">PDF, JPG, PNG, TIFF &bull; max. {{ max_dateigroesse_mb }} MB</p>
</div>
<ul class="file-list" data-list="vermogenssituation"></ul>
<p class="oder-text">— oder Texteintrag —</p>
<textarea name="vermogenssituation_text" placeholder="z.B. 'Keine Änderungen seit letzter Meldung' oder Details zu Änderungen">{{ vermogenssituation_text|default:"" }}</textarea>
</div>
<!-- 4. Weitere Dokumente (optional) -->
<div class="kategorie">
<h3>Weitere Dokumente (optional)</h3>
<p class="hinweis">Mietvertrag, Unterhaltsbelege, sonstige Nachweise</p>
<label for="weitere_dokumente">Datei hochladen:</label>
<div class="upload-area" data-target="weitere_dokumente">
<input type="file" name="weitere_dokumente" id="weitere_dokumente" accept=".pdf,.jpg,.jpeg,.png,.tiff,.tif">
<div class="icon">&#128196;</div>
<p>Datei hierher ziehen oder klicken</p>
<p class="hint">PDF, JPG, PNG, TIFF &bull; max. {{ max_dateigroesse_mb }} MB</p>
</div>
<ul class="file-list" data-list="weitere_dokumente"></ul>
<p class="oder-text">— oder Texteintrag —</p>
<textarea name="weitere_dokumente_text" placeholder="Optionale Anmerkungen oder Beschreibung">{{ weitere_dokumente_text|default:"" }}</textarea>
</div>
<div class="einwilligung-box">
<label>
<input type="checkbox" name="einwilligung" id="einwilligung" required {% if einwilligung_erteilt %}checked{% endif %}>
<span>Ich willige ein, dass die van Hees-Theyssen-Vogel'sche Stiftung die von mir hochgeladenen Dokumente und eingegebenen Daten zum Zweck der Förderprüfung verarbeitet und speichert. Ich habe die <a href="{% url 'portal:datenschutzerklaerung' %}" target="_blank">Datenschutzerklärung</a> gelesen und stimme ihr zu. Die Einwilligung kann ich jederzeit widerrufen (stiftung@vhtv-stiftung.de).
</span>
</label>
{% if einwilligung_fehler %}
<p class="einwilligung-fehler">{{ einwilligung_fehler }}</p>
{% endif %}
</div>
<button type="submit" class="submit-btn">Unterlagen jetzt einreichen</button>
</form>
<p class="deadline">&#9201; Gültig bis: {{ gueltig_bis|date:"d.m.Y" }}</p>
</div>
<div class="footer">
van Hees-Theyssen-Vogel'sche Stiftung &bull; Raesfelder Str. 3 &bull; 46499 Hamminkeln<br>
Fragen? Tel. 02858/836780
</div>
</div>
<script>
document.querySelectorAll('.upload-area').forEach(area => {
const input = area.querySelector('input[type="file"]');
const target = area.dataset.target;
const list = document.querySelector(`[data-list="${target}"]`);
function updateList(files) {
list.innerHTML = '';
Array.from(files).forEach(f => {
const li = document.createElement('li');
li.textContent = `\u2714 ${f.name} (${(f.size/1024/1024).toFixed(2)} MB)`;
list.appendChild(li);
});
}
input.addEventListener('change', () => updateList(input.files));
area.addEventListener('dragover', e => { e.preventDefault(); area.classList.add('dragover'); });
area.addEventListener('dragleave', () => area.classList.remove('dragover'));
area.addEventListener('drop', e => {
e.preventDefault();
area.classList.remove('dragover');
input.files = e.dataTransfer.files;
updateList(e.dataTransfer.files);
});
});
</script>
</body>
</html>