Feature: KI-Berichte einzeln durchblättern (‹ Älter / Neuer ›), Navigation per Index (SW by-v809)

This commit is contained in:
rene 2026-05-09 21:50:27 +02:00
parent 3acb7aa874
commit b4879d615f
5 changed files with 39 additions and 24 deletions

View file

@ -341,7 +341,7 @@ MEDIA_DIR = os.getenv("MEDIA_DIR", "/data/media")
os.makedirs(MEDIA_DIR, exist_ok=True)
app.mount("/media", StaticFiles(directory=MEDIA_DIR), name="media")
APP_VER = "808" # muss mit APP_VER in app.js übereinstimmen
APP_VER = "809" # muss mit APP_VER in app.js übereinstimmen
@app.get("/.well-known/assetlinks.json")
async def assetlinks():

View file

@ -96,9 +96,9 @@
</script>
<!-- CSS: Reihenfolge ist wichtig — ?v= zwingt Browser zur Neuladung -->
<link rel="stylesheet" href="/css/design-system.css?v=808">
<link rel="stylesheet" href="/css/layout.css?v=808">
<link rel="stylesheet" href="/css/components.css?v=808">
<link rel="stylesheet" href="/css/design-system.css?v=809">
<link rel="stylesheet" href="/css/layout.css?v=809">
<link rel="stylesheet" href="/css/components.css?v=809">
</head>
<body>
@ -578,10 +578,10 @@
<div id="modal-container"></div>
<!-- JS: Reihenfolge ist wichtig — erst Basis, dann Features -->
<script src="/js/api.js?v=808"></script>
<script src="/js/ui.js?v=808"></script>
<script src="/js/app.js?v=808"></script>
<script src="/js/worlds.js?v=808"></script>
<script src="/js/api.js?v=809"></script>
<script src="/js/ui.js?v=809"></script>
<script src="/js/app.js?v=809"></script>
<script src="/js/worlds.js?v=809"></script>
<!-- Feature-Seiten werden lazy geladen -->

View file

@ -3,7 +3,7 @@
Router, State-Management, Navigation, Initialisierung.
============================================================ */
const APP_VER = '808'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VER = '809'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.5.0'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING = location.hostname === 'staging.banyaro.app';
// Cache-Bust-Parameter nach Update-Reload sofort entfernen

View file

@ -2346,19 +2346,34 @@ window.Page_health = (() => {
${berichte.length > 1 ? `<div style="font-size:var(--text-xs);color:var(--c-accent,#c4843a);margin-top:var(--space-1)">${berichte.length} Berichte gespeichert — zum Öffnen tippen</div>` : ''}
</div>`;
el.querySelector('.health-ki-bericht-banner').addEventListener('click', () => {
const listeHtml = berichte.map((b, i) => {
const d = b.erstellt_at
? new Date(b.erstellt_at).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })
: '';
return `<div style="${i > 0 ? 'border-top:1px solid var(--c-border);padding-top:var(--space-3);margin-top:var(--space-3)' : ''}">
${d ? `<div style="font-size:var(--text-xs);color:var(--c-text-muted);margin-bottom:var(--space-1)">${d}</div>` : ''}
<div style="white-space:pre-wrap;line-height:1.7;font-size:var(--text-sm)">${_esc(b.bericht)}</div>
</div>`;
}).join('');
UI.modal.open({
title: `${UI.icon('star')} KI-Gesundheitsberichte`,
body: listeHtml,
});
let idx = 0;
const fmtDate = b => b.erstellt_at
? new Date(b.erstellt_at).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })
: '';
function showBericht() {
const b = berichte[idx];
const nav = berichte.length > 1 ? `
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">
<button onclick="window._kiPrev()" style="padding:6px 16px;border-radius:999px;
border:1.5px solid var(--c-border);background:var(--c-surface);cursor:pointer;
font-size:var(--text-sm);${idx >= berichte.length-1 ? 'opacity:.3;pointer-events:none' : ''}"> Älter</button>
<span style="font-size:var(--text-xs);color:var(--c-text-muted)">${idx+1} / ${berichte.length}</span>
<button onclick="window._kiNext()" style="padding:6px 16px;border-radius:999px;
border:1.5px solid var(--c-border);background:var(--c-surface);cursor:pointer;
font-size:var(--text-sm);${idx <= 0 ? 'opacity:.3;pointer-events:none' : ''}">Neuer </button>
</div>` : '';
UI.modal.open({
title: `${UI.icon('star')} KI-Gesundheitsberichte`,
body: `${nav}
<div style="font-size:var(--text-xs);color:var(--c-text-muted);text-align:center;margin-bottom:8px">${fmtDate(b)}</div>
<div style="white-space:pre-wrap;line-height:1.7;font-size:var(--text-sm)">${_esc(b.bericht)}</div>`,
});
}
window._kiPrev = () => { if (idx < berichte.length - 1) { idx++; showBericht(); } };
window._kiNext = () => { if (idx > 0) { idx--; showBericht(); } };
showBericht();
});
} catch (_) {
// Silently ignore — Berichte sind optional
@ -2796,7 +2811,7 @@ window.Page_health = (() => {
const res = await API.health.kiZusammenfassung(_appState.activeDog.id);
const zusammenfassung = res.zusammenfassung ?? res;
if (res.save_error) UI.toast.warning(`Speichern fehlgeschlagen: ${res.save_error}`);
else if (res.saved_count !== undefined) UI.toast.info(`${res.saved_count} Bericht(e) gespeichert`);
else if (res.saved_count !== undefined) UI.toast.info(`${res.saved_count} Bericht(e) in DB`, { duration: 8000 });
UI.modal.open({
title: `${UI.icon('star')} KI-Gesundheitsbericht`,
body: `<div style="white-space:pre-wrap;line-height:1.7;font-size:var(--text-sm)">${_esc(zusammenfassung)}</div>`,

View file

@ -3,7 +3,7 @@
Offline-Cache + Push Notifications + Tile-Cache
============================================================ */
const CACHE_VERSION = 'by-v808';
const CACHE_VERSION = 'by-v809';
const CACHE_STATIC = `${CACHE_VERSION}-static`;
const CACHE_TILES = 'ban-yaro-tiles-v1'; // bleibt über SW-Updates erhalten
const CACHE_API = 'ban-yaro-api-v1'; // API-Response-Cache