diff --git a/frontend/src/components/wealth/AssetRefreshControl.vue b/frontend/src/components/wealth/AssetRefreshControl.vue index 5950cea..43b0888 100644 --- a/frontend/src/components/wealth/AssetRefreshControl.vue +++ b/frontend/src/components/wealth/AssetRefreshControl.vue @@ -7,12 +7,17 @@

Jobstatus: {{ statusLabel(job.status) }}

+

Ein Teil der Preise wurde aktualisiert. Die übrigen Vermögenswerte bleiben mit ihrem letzten bekannten Kurs sichtbar.

+

Es konnte keine verwertbare Preisquelle verarbeitet werden. Bestehende Bewertungen wurden nicht verändert.

+

{{ job.successful_assets }} aktualisiert · {{ job.fresh_unchanged_assets }} bereits aktuell · {{ job.stale_assets }} weiterhin veraltet · {{ job.failed_assets }} mit Fehler

+

Nächste Aktion: {{ job.next_action }}

@@ -31,9 +36,10 @@ const running = computed(() => job.value?.status === 'queued' || job.value?.stat function statusLabel(value: string) { return ({ queued: 'Eingeplant', pending: 'Ausstehend', running: 'Läuft', complete: 'Abgeschlossen', skipped: 'Aktuell', partial: 'Teilweise abgeschlossen', failed: 'Fehlgeschlagen' } as Record)[value] ?? value } function sourceLabel(value: AssetRefreshSourceStatus['source']) { return ({ equity: 'Aktien / ETF', crypto: 'Krypto', fx: 'FX' } as const)[value] } function progress(source: AssetRefreshSourceStatus) { return ['complete', 'failed', 'skipped'].includes(source.status) ? 100 : source.status === 'running' ? 50 : 0 } -async function start() { if (starting.value || running.value) return; starting.value = true; error.value = null; try { job.value = await startAssetRefreshJob(); if (running.value) schedulePoll(); else emit('completed') } catch (cause) { error.value = cause instanceof Error ? cause.message : 'Aktualisierung konnte nicht gestartet werden.' } finally { starting.value = false } } +function friendlyError(cause: unknown, fallback: string) { const message=cause instanceof Error?cause.message:''; return message.includes('valuation source observation conflicts')?'Die Preisaktualisierung konnte nicht sicher abgeschlossen werden. Bestehende Bewertungen bleiben erhalten.':message||fallback } +async function start() { if (starting.value || running.value) return; starting.value = true; error.value = null; try { job.value = await startAssetRefreshJob(); if (running.value) schedulePoll(); else emit('completed') } catch (cause) { error.value = friendlyError(cause, 'Aktualisierung konnte nicht gestartet werden.') } finally { starting.value = false } } function schedulePoll() { if (pollTimer) clearTimeout(pollTimer); pollTimer = setTimeout(() => { void poll() }, 1000) } -async function poll() { if (!job.value) return; try { job.value = await getAssetRefreshJob(job.value.job_id, true); if (running.value) schedulePoll(); else emit('completed') } catch (cause) { error.value = cause instanceof Error ? cause.message : 'Jobstatus konnte nicht geladen werden.' } } +async function poll() { if (!job.value) return; try { job.value = await getAssetRefreshJob(job.value.job_id, true); if (running.value) schedulePoll(); else emit('completed') } catch (cause) { error.value = friendlyError(cause, 'Jobstatus konnte nicht geladen werden.') } } onBeforeUnmount(() => { if (pollTimer) clearTimeout(pollTimer) }) defineExpose({ start, poll, job }) diff --git a/frontend/src/components/wealth/WealthCockpitPanel.vue b/frontend/src/components/wealth/WealthCockpitPanel.vue index 47a7461..b66a1f4 100644 --- a/frontend/src/components/wealth/WealthCockpitPanel.vue +++ b/frontend/src/components/wealth/WealthCockpitPanel.vue @@ -4,35 +4,40 @@

Vermögen

-

Modellierte Wertentwicklung

-

Geschätzte Entwicklung aus bestätigten Ankern, gespeicherten Tagesbewertungen und fortgeschriebenen bekannten Kontoständen. Keine verifizierte TTWROR oder XIRR.

+

Geschätzte Vermögensentwicklung

+

Seit dem letzten bestätigten Stand mit verfügbaren Marktpreisen fortgeschrieben.

+
Wie entsteht diese Schätzung?

FinanceManager bewertet die zuletzt bestätigten Bestände mit verfügbaren Tageskursen weiter. Noch nicht importierte Käufe, Verkäufe, Dividenden, Gebühren oder andere Kontobewegungen können vorübergehend fehlen. Beim nächsten Import wird die Schätzung mit dem tatsächlichen Stand abgeglichen.