Batch-Analyse UI: Button im Prüfen-Tab mit BL-Auswahl + Limit + Queue-Polling

This commit is contained in:
Dotty Dotter 2026-04-10 23:08:49 +02:00
parent cfe36cbd65
commit 5f5d9edf83

View File

@ -889,6 +889,33 @@
</div> </div>
<div id="analysis-result" style="display: none; margin-top: 1rem;"></div> <div id="analysis-result" style="display: none; margin-top: 1rem;"></div>
<!-- Batch-Analyse -->
<div style="margin-top: 2rem; padding-top: 1.5rem; border-top: 2px solid var(--color-lightgray);">
<h2 style="margin-bottom: 0.5rem; color: var(--color-blue);">📦 Batch-Analyse</h2>
<p style="font-size: 0.85rem; color: #666; margin-bottom: 1rem;">
Analysiert automatisch die neuesten ungeprüften Anträge eines Bundeslandes.
</p>
<div style="display:flex;gap:0.5rem;align-items:center;flex-wrap:wrap;">
<select id="batch-bundesland" style="padding:0.4rem;border:1px solid #ddd;border-radius:4px;">
{% for bl in bundeslaender if bl.code != 'ALL' and bl.active %}
<option value="{{ bl.code }}">{{ bl.name }}</option>
{% endfor %}
</select>
<select id="batch-limit" style="padding:0.4rem;border:1px solid #ddd;border-radius:4px;">
<option value="5">5 Anträge</option>
<option value="10" selected>10 Anträge</option>
<option value="20">20 Anträge</option>
<option value="50">50 Anträge</option>
</select>
<button id="batch-btn" onclick="startBatch()"
${currentUser ? '' : 'disabled title="Nur nach Anmeldung"'}
style="padding:0.4rem 1rem;background:var(--color-green);color:white;border:none;border-radius:4px;cursor:pointer;">
🚀 Batch starten
</button>
</div>
<div id="batch-status" style="margin-top:0.75rem;font-size:0.85rem;"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -1318,6 +1345,64 @@
} }
} }
// ─── Batch-Analyse ──────────────────────────────────────────
async function startBatch() {
const bl = document.getElementById('batch-bundesland').value;
const limit = document.getElementById('batch-limit').value;
const btn = document.getElementById('batch-btn');
const status = document.getElementById('batch-status');
btn.disabled = true;
btn.textContent = '⏳ Wird gestartet...';
status.innerHTML = '';
try {
const resp = await fetch('/api/batch-analyze', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: `bundesland=${bl}&limit=${limit}`
});
if (resp.status === 401) {
status.innerHTML = '<span style="color:#dc3545;">🔒 Bitte zuerst anmelden.</span>';
btn.disabled = false; btn.textContent = '🚀 Batch starten';
return;
}
const data = await resp.json();
if (data.status === 'batch_enqueued') {
status.innerHTML = `
<span style="color:var(--color-green);">✓ ${data.enqueued} Anträge in die Queue eingereiht</span>
${data.skipped_existing > 0 ? `<br><span style="color:#888;">${data.skipped_existing} bereits bewertet (übersprungen)</span>` : ''}
<br><span style="color:#888;">Die Analyse läuft im Hintergrund. Ergebnisse erscheinen nach und nach in der Liste.</span>
`;
// Queue-Status pollen
pollBatchQueue(status);
} else {
status.innerHTML = `<span style="color:#dc3545;">❌ ${data.detail || 'Fehler'}</span>`;
}
} catch (e) {
status.innerHTML = `<span style="color:#dc3545;">❌ ${e.message}</span>`;
}
btn.disabled = false; btn.textContent = '🚀 Batch starten';
}
async function pollBatchQueue(statusEl) {
for (let i = 0; i < 200; i++) {
await new Promise(r => setTimeout(r, 5000));
try {
const qs = await fetch('/api/queue/status').then(r => r.json());
if (qs.pending === 0) {
statusEl.innerHTML += `<br><span style="color:var(--color-green);">✓ Alle Jobs abgeschlossen (${qs.processed_total} verarbeitet)</span>`;
loadAssessments(); // Liste aktualisieren
return;
}
statusEl.querySelector('.queue-progress')?.remove();
statusEl.insertAdjacentHTML('beforeend',
`<span class="queue-progress"><br>⏳ ${qs.pending} Jobs in der Queue, ~${Math.round(qs.estimated_wait_seconds/60)} Min. verbleibend</span>`
);
} catch { break; }
}
}
// ─── Merkliste (#94) ──────────────────────────────────────── // ─── Merkliste (#94) ────────────────────────────────────────
async function loadBookmarksList() { async function loadBookmarksList() {
const container = document.getElementById('bookmarks-content'); const container = document.getElementById('bookmarks-content');