Geoparsing als Hintergrund-Task mit Fortschrittsanzeige
- Endpunkt startet async Background-Task statt synchron zu warten
- Batch-Verarbeitung (50 Artikel pro Batch)
- Neuer Status-Endpunkt GET /incidents/{id}/geoparse-status
- Frontend pollt alle 3s und zeigt Fortschritt im Button (z.B. "150/427 Artikel...")
- Kein Timeout-Problem mehr bei grossen Lagen
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dieser Commit ist enthalten in:
@@ -1429,24 +1429,57 @@ const App = {
|
||||
}
|
||||
},
|
||||
|
||||
_geoparsePolling: null,
|
||||
|
||||
async triggerGeoparse() {
|
||||
if (!this.currentIncidentId) return;
|
||||
const btn = document.getElementById('geoparse-btn');
|
||||
if (btn) { btn.disabled = true; btn.textContent = 'Erkennung...'; }
|
||||
if (btn) { btn.disabled = true; btn.textContent = 'Wird gestartet...'; }
|
||||
try {
|
||||
const result = await API.triggerGeoparse(this.currentIncidentId);
|
||||
UI.showToast(result.message, result.new_locations > 0 ? 'success' : 'info');
|
||||
if (result.new_locations > 0) {
|
||||
const locations = await API.getLocations(this.currentIncidentId).catch(() => []);
|
||||
UI.renderMap(locations);
|
||||
if (result.status === 'done') {
|
||||
UI.showToast(result.message, 'info');
|
||||
if (btn) { btn.disabled = false; btn.textContent = 'Orte erkennen'; }
|
||||
return;
|
||||
}
|
||||
UI.showToast(result.message, 'info');
|
||||
this._pollGeoparse(this.currentIncidentId);
|
||||
} catch (err) {
|
||||
UI.showToast('Geoparsing fehlgeschlagen: ' + err.message, 'error');
|
||||
} finally {
|
||||
if (btn) { btn.disabled = false; btn.textContent = 'Orte erkennen'; }
|
||||
}
|
||||
},
|
||||
|
||||
_pollGeoparse(incidentId) {
|
||||
if (this._geoparsePolling) clearInterval(this._geoparsePolling);
|
||||
const btn = document.getElementById('geoparse-btn');
|
||||
this._geoparsePolling = setInterval(async () => {
|
||||
try {
|
||||
const st = await API.getGeoparseStatus(incidentId);
|
||||
if (st.status === 'running') {
|
||||
if (btn) btn.textContent = `${st.processed}/${st.total} Artikel...`;
|
||||
} else {
|
||||
clearInterval(this._geoparsePolling);
|
||||
this._geoparsePolling = null;
|
||||
if (btn) { btn.disabled = false; btn.textContent = 'Orte erkennen'; }
|
||||
if (st.status === 'done' && st.locations > 0) {
|
||||
UI.showToast(`${st.locations} Orte aus ${st.processed} Artikeln erkannt`, 'success');
|
||||
const locations = await API.getLocations(incidentId).catch(() => []);
|
||||
UI.renderMap(locations);
|
||||
} else if (st.status === 'done') {
|
||||
UI.showToast('Keine neuen Orte gefunden', 'info');
|
||||
} else if (st.status === 'error') {
|
||||
UI.showToast('Geoparsing fehlgeschlagen: ' + (st.error || ''), 'error');
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
clearInterval(this._geoparsePolling);
|
||||
this._geoparsePolling = null;
|
||||
if (btn) { btn.disabled = false; btn.textContent = 'Orte erkennen'; }
|
||||
}
|
||||
}, 3000);
|
||||
},
|
||||
|
||||
_formatInterval(minutes) {
|
||||
if (minutes >= 10080 && minutes % 10080 === 0) {
|
||||
const w = minutes / 10080;
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren