Add Schadenprotokoll SPA with Python Flask API
New tool for processing damage protocols: - Tab 1: Generate pre-filled PDF from Schadenlaufzettel.docx - Tab 2: Analyze filled PDF forms and extract dropdown selections - Tab 3: Generate Vorbericht.docx from filled PDF data Backend: Flask API with pypdf and python-docx Frontend: Vanilla JS SPA with drag-drop file upload 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
174
schadenprotokoll/app.js
Normal file
174
schadenprotokoll/app.js
Normal file
@@ -0,0 +1,174 @@
|
||||
// Tab Navigation
|
||||
document.querySelectorAll(".tab").forEach(tab => {
|
||||
tab.addEventListener("click", () => {
|
||||
document.querySelectorAll(".tab").forEach(t => t.classList.remove("active"));
|
||||
document.querySelectorAll(".tab-content").forEach(c => c.classList.remove("active"));
|
||||
tab.classList.add("active");
|
||||
document.getElementById(tab.dataset.tab).classList.add("active");
|
||||
});
|
||||
});
|
||||
|
||||
// Upload Zone Setup
|
||||
function setupUploadZone(zoneId, inputId, infoId, btnId) {
|
||||
const zone = document.getElementById(zoneId);
|
||||
const input = document.getElementById(inputId);
|
||||
const info = document.getElementById(infoId);
|
||||
const btn = document.getElementById(btnId);
|
||||
|
||||
zone.addEventListener("click", () => input.click());
|
||||
zone.addEventListener("dragover", (e) => { e.preventDefault(); zone.classList.add("dragover"); });
|
||||
zone.addEventListener("dragleave", () => zone.classList.remove("dragover"));
|
||||
zone.addEventListener("drop", (e) => {
|
||||
e.preventDefault();
|
||||
zone.classList.remove("dragover");
|
||||
if (e.dataTransfer.files.length) {
|
||||
input.files = e.dataTransfer.files;
|
||||
updateFileInfo(input, info, btn);
|
||||
}
|
||||
});
|
||||
input.addEventListener("change", () => updateFileInfo(input, info, btn));
|
||||
}
|
||||
|
||||
function updateFileInfo(input, info, btn) {
|
||||
if (input.files.length) {
|
||||
const file = input.files[0];
|
||||
info.innerHTML = `<strong>✓ ${file.name}</strong> (${(file.size / 1024).toFixed(1)} KB)`;
|
||||
info.classList.add("visible");
|
||||
btn.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function showStatus(id, type, message) {
|
||||
const status = document.getElementById(id);
|
||||
status.className = `status visible ${type}`;
|
||||
status.textContent = message;
|
||||
}
|
||||
|
||||
// Setup all upload zones
|
||||
setupUploadZone("laufzettel-zone", "laufzettel-input", "laufzettel-info", "generate-btn");
|
||||
setupUploadZone("pdf-zone", "pdf-input", "pdf-info", "analyze-btn");
|
||||
setupUploadZone("vorbericht-zone", "vorbericht-input", "vorbericht-info", "vorbericht-btn");
|
||||
|
||||
// API Base URL
|
||||
const API_BASE = "/schadenprotokoll/api";
|
||||
|
||||
// Generate Button
|
||||
document.getElementById("generate-btn").addEventListener("click", async () => {
|
||||
showStatus("generate-status", "loading", "⏳ Verarbeite Laufzettel...");
|
||||
|
||||
const file = document.getElementById("laufzettel-input").files[0];
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/generate`, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (\!response.ok) {
|
||||
const err = await response.json();
|
||||
throw new Error(err.error || "Unbekannter Fehler");
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "Schadenprotokoll_vorbefuellt.pdf";
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
showStatus("generate-status", "success", "✓ PDF erfolgreich generiert und heruntergeladen");
|
||||
} catch (err) {
|
||||
showStatus("generate-status", "error", `❌ Fehler: ${err.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Analyze Button
|
||||
document.getElementById("analyze-btn").addEventListener("click", async () => {
|
||||
showStatus("analyze-status", "loading", "⏳ Analysiere PDF...");
|
||||
|
||||
const file = document.getElementById("pdf-input").files[0];
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/analyze`, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (\!response.ok) {
|
||||
const err = await response.json();
|
||||
throw new Error(err.error || "Unbekannter Fehler");
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
displayAnalysisResult(result.data);
|
||||
showStatus("analyze-status", "success", "✓ Analyse abgeschlossen");
|
||||
} catch (err) {
|
||||
showStatus("analyze-status", "error", `❌ Fehler: ${err.message}`);
|
||||
}
|
||||
});
|
||||
|
||||
function displayAnalysisResult(data) {
|
||||
const container = document.getElementById("analyze-data");
|
||||
let html = "";
|
||||
|
||||
// Textfelder
|
||||
if (Object.keys(data.textfields).length > 0) {
|
||||
html += `<div class="field-group"><h5>Textfelder</h5><div class="field-list">`;
|
||||
for (const [key, value] of Object.entries(data.textfields)) {
|
||||
if (value) html += `<div class="dropdown-item"><strong>${key}:</strong> ${value}</div>`;
|
||||
}
|
||||
html += `</div></div>`;
|
||||
}
|
||||
|
||||
// Dropdowns
|
||||
if (Object.keys(data.dropdowns).length > 0) {
|
||||
html += `<div class="field-group"><h5>Dropdown-Auswahlen (Sachverhalt)</h5><div class="field-list">`;
|
||||
for (const [key, val] of Object.entries(data.dropdowns)) {
|
||||
if (val.selected) {
|
||||
html += `<div class="dropdown-item"><strong>${key}:</strong> ${val.selected}</div>`;
|
||||
}
|
||||
}
|
||||
html += `</div></div>`;
|
||||
}
|
||||
|
||||
container.innerHTML = html || "<p>Keine ausgefüllten Felder gefunden.</p>";
|
||||
document.getElementById("analyze-result").classList.add("visible");
|
||||
}
|
||||
|
||||
// Vorbericht Button
|
||||
document.getElementById("vorbericht-btn").addEventListener("click", async () => {
|
||||
showStatus("vorbericht-status", "loading", "⏳ Erstelle Vorbericht...");
|
||||
|
||||
const file = document.getElementById("vorbericht-input").files[0];
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/vorbericht`, {
|
||||
method: "POST",
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (\!response.ok) {
|
||||
const err = await response.json();
|
||||
throw new Error(err.error || "Unbekannter Fehler");
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "Vorbericht.docx";
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
showStatus("vorbericht-status", "success", "✓ Vorbericht erfolgreich erstellt und heruntergeladen");
|
||||
} catch (err) {
|
||||
showStatus("vorbericht-status", "error", `❌ Fehler: ${err.message}`);
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user