feat: Import-Seite mit Drag-and-Drop und Planungs-Seite
Ersetzt die Platzhalter-Routen aus Task 12 durch echte GUI-Seiten: /import mit Drop-Zone (Fetch-Upload), gepollter Importliste (Status-Badges, aufklappbarer Vorschau samt Saldo-/Duplikat-Anzeige, Uebernehmen/Verwerfen) und /planung mit den vier Abschnitten Fixposten (inkl. Vorschlaege), Einmalposten, Kredite (Tilgungsplan-Aufklapper) und Szenarien (Kredit-Zuordnung, Modifikatoren, Durchrechnen mit Ergebnisanzeige). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,5 +2,68 @@
|
||||
{% block title %}Import – Finanzberatung{% endblock %}
|
||||
{% block content %}
|
||||
<h1>Import</h1>
|
||||
<p>Der Kontoauszug-Import (Upload, Vorschau, Bestätigen) folgt in einem späteren Ausbauschritt.</p>
|
||||
|
||||
<div id="dropzone">
|
||||
Kontoauszug-PDF hier ablegen oder klicken zum Hochladen
|
||||
<input type="file" id="file-input" accept="application/pdf" style="display:none">
|
||||
</div>
|
||||
<p id="upload-message"></p>
|
||||
|
||||
<h2>Importe</h2>
|
||||
<div id="imports" hx-get="/import/list" hx-trigger="every 5s, refresh" hx-swap="innerHTML">
|
||||
{% include "_import_list.html" %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
var dropzone = document.getElementById('dropzone');
|
||||
var fileInput = document.getElementById('file-input');
|
||||
var message = document.getElementById('upload-message');
|
||||
|
||||
function refreshImports() {
|
||||
htmx.trigger(document.getElementById('imports'), 'refresh');
|
||||
}
|
||||
|
||||
function uploadFile(file) {
|
||||
if (!file) return;
|
||||
var fd = new FormData();
|
||||
fd.append('file', file);
|
||||
message.textContent = 'Lade hoch: ' + file.name + ' …';
|
||||
fetch('/api/imports/upload', { method: 'POST', body: fd })
|
||||
.then(function (resp) {
|
||||
return resp.json().then(function (data) { return { ok: resp.ok, data: data }; });
|
||||
})
|
||||
.then(function (result) {
|
||||
if (result.ok) {
|
||||
message.textContent = 'Hochgeladen: ' + file.name + ' – Status: ' + result.data.status;
|
||||
} else {
|
||||
message.textContent = 'Fehler beim Hochladen: ' + (result.data.detail || 'unbekannter Fehler');
|
||||
}
|
||||
refreshImports();
|
||||
})
|
||||
.catch(function (err) {
|
||||
message.textContent = 'Fehler beim Hochladen: ' + err;
|
||||
});
|
||||
}
|
||||
|
||||
dropzone.addEventListener('click', function () { fileInput.click(); });
|
||||
fileInput.addEventListener('change', function () {
|
||||
uploadFile(fileInput.files[0]);
|
||||
fileInput.value = '';
|
||||
});
|
||||
dropzone.addEventListener('dragover', function (e) {
|
||||
e.preventDefault();
|
||||
dropzone.classList.add('dragover');
|
||||
});
|
||||
dropzone.addEventListener('dragleave', function () {
|
||||
dropzone.classList.remove('dragover');
|
||||
});
|
||||
dropzone.addEventListener('drop', function (e) {
|
||||
e.preventDefault();
|
||||
dropzone.classList.remove('dragover');
|
||||
var file = e.dataTransfer.files && e.dataTransfer.files[0];
|
||||
uploadFile(file);
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user