Feature: KI-Jahresberichte speichern + Archiv + Download — SW by-v505, APP_VER 482
This commit is contained in:
parent
b4de0aa27c
commit
9832cd24d8
6 changed files with 146 additions and 17 deletions
|
|
@ -692,6 +692,8 @@ const API = (() => {
|
|||
},
|
||||
hundBeschreibung(hundId) { return post('/zucht-ki/hund-beschreibung', { hund_id: hundId }); },
|
||||
jahresbericht() { return post('/zucht-ki/jahresbericht', {}); },
|
||||
jahresberichtList() { return get('/zucht-ki/jahresbericht'); },
|
||||
jahresberichtGet(id) { return get(`/zucht-ki/jahresbericht/${id}`); },
|
||||
};
|
||||
|
||||
const osm = {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
Router, State-Management, Navigation, Initialisierung.
|
||||
============================================================ */
|
||||
|
||||
const APP_VER = '481'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
const APP_VER = '482'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
|
||||
|
||||
const App = (() => {
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ window.Page_zuchthunde = (() => {
|
|||
${_appState?.user?.ki_zucht_jahresbericht !== 0 ? `
|
||||
<a class="btn btn-ghost btn-sm" id="zh-jahresbericht-btn">
|
||||
${UI.icon('chart-bar')} Jahresbericht
|
||||
</a>
|
||||
<a class="btn btn-ghost btn-sm" id="zh-jahresbericht-archiv-btn" title="Frühere Berichte">
|
||||
${UI.icon('archive')}
|
||||
</a>` : ''}
|
||||
</div>
|
||||
<div style="padding:0 0 var(--space-3)">
|
||||
|
|
@ -132,6 +135,7 @@ window.Page_zuchthunde = (() => {
|
|||
document.getElementById('zh-new-btn')?.addEventListener('click', () => _showHundForm(null));
|
||||
document.getElementById('zh-trial-btn')?.addEventListener('click', () => _showTrialMatingModal());
|
||||
document.getElementById('zh-jahresbericht-btn')?.addEventListener('click', () => _showJahresbericht());
|
||||
document.getElementById('zh-jahresbericht-archiv-btn')?.addEventListener('click', () => _showJahresberichtArchiv());
|
||||
|
||||
document.getElementById('zh-search')?.addEventListener('input', e => {
|
||||
_query = e.target.value.toLowerCase().trim();
|
||||
|
|
@ -1285,7 +1289,7 @@ window.Page_zuchthunde = (() => {
|
|||
}
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// KI: Jahresbericht
|
||||
// KI: Jahresbericht generieren
|
||||
// ----------------------------------------------------------
|
||||
async function _showJahresbericht() {
|
||||
UI.modal.open({
|
||||
|
|
@ -1294,10 +1298,12 @@ window.Page_zuchthunde = (() => {
|
|||
footer: '',
|
||||
});
|
||||
|
||||
let text = '';
|
||||
let text = '', savedId = null, jahr = new Date().getFullYear();
|
||||
try {
|
||||
const result = await API.zuchtKi.jahresbericht();
|
||||
text = result.text || result.content || result.bericht || JSON.stringify(result);
|
||||
text = result.text || result.content || result.bericht || JSON.stringify(result);
|
||||
savedId = result.saved_id;
|
||||
jahr = result.jahr || jahr;
|
||||
} catch (err) {
|
||||
UI.modal.open({
|
||||
title: `${UI.icon('chart-bar')} KI-Jahresbericht`,
|
||||
|
|
@ -1307,23 +1313,93 @@ window.Page_zuchthunde = (() => {
|
|||
return;
|
||||
}
|
||||
|
||||
_renderBerichtModal(text, jahr, savedId);
|
||||
}
|
||||
|
||||
function _renderBerichtModal(text, jahr, savedId) {
|
||||
UI.modal.open({
|
||||
title: `${UI.icon('chart-bar')} KI-Jahresbericht`,
|
||||
body: `<div style="white-space:pre-wrap;font-size:var(--text-sm);line-height:1.6">${_esc(text)}</div>`,
|
||||
title: `${UI.icon('chart-bar')} KI-Jahresbericht ${jahr}`,
|
||||
body: `
|
||||
${savedId ? `<p style="font-size:var(--text-xs);color:var(--c-success);margin:0 0 var(--space-3);display:flex;align-items:center;gap:4px">
|
||||
${UI.icon('check-circle')} Automatisch gespeichert</p>` : ''}
|
||||
<div style="white-space:pre-wrap;font-size:var(--text-sm);line-height:1.6">${_esc(text)}</div>`,
|
||||
footer: `
|
||||
<button class="btn btn-secondary flex-1" id="ki-bericht-copy">
|
||||
<button class="btn btn-ghost btn-sm" id="ki-bericht-copy">
|
||||
${UI.icon('clipboard-text')} Kopieren
|
||||
</button>
|
||||
<button class="btn btn-primary flex-1" data-modal-close>Schließen</button>`,
|
||||
<button class="btn btn-ghost btn-sm" id="ki-bericht-download">
|
||||
${UI.icon('download-simple')} Herunterladen
|
||||
</button>
|
||||
<button class="btn btn-primary" data-modal-close>Schließen</button>`,
|
||||
});
|
||||
|
||||
document.getElementById('ki-bericht-copy')?.addEventListener('click', async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
UI.toast.success('Bericht kopiert.');
|
||||
} catch {
|
||||
UI.toast.error('Kopieren nicht möglich.');
|
||||
}
|
||||
try { await navigator.clipboard.writeText(text); UI.toast.success('Bericht kopiert.'); }
|
||||
catch { UI.toast.error('Kopieren nicht möglich.'); }
|
||||
});
|
||||
|
||||
document.getElementById('ki-bericht-download')?.addEventListener('click', () => {
|
||||
const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url; a.download = `ban-yaro-jahresbericht-${jahr}.txt`;
|
||||
a.click(); URL.revokeObjectURL(url);
|
||||
});
|
||||
}
|
||||
|
||||
// KI: Archiv früherer Berichte
|
||||
// ----------------------------------------------------------
|
||||
async function _showJahresberichtArchiv() {
|
||||
UI.modal.open({
|
||||
title: `${UI.icon('archive')} Gespeicherte Jahresberichte`,
|
||||
body: `<p style="color:var(--c-text-secondary);text-align:center;padding:var(--space-4)">Lädt…</p>`,
|
||||
footer: `<button class="btn btn-secondary" data-modal-close>Schließen</button>`,
|
||||
});
|
||||
|
||||
let berichte = [];
|
||||
try { berichte = await API.zuchtKi.jahresberichtList(); }
|
||||
catch { UI.toast.error('Berichte konnten nicht geladen werden.'); return; }
|
||||
|
||||
if (!berichte.length) {
|
||||
UI.modal.open({
|
||||
title: `${UI.icon('archive')} Gespeicherte Jahresberichte`,
|
||||
body: `<p style="color:var(--c-text-muted);text-align:center;padding:var(--space-6)">Noch keine Berichte gespeichert.</p>`,
|
||||
footer: `<button class="btn btn-secondary" data-modal-close>Schließen</button>`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const listHtml = berichte.map(b => `
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;
|
||||
padding:var(--space-3) 0;border-bottom:1px solid var(--c-border-light)">
|
||||
<div>
|
||||
<div style="font-weight:var(--weight-semibold);font-size:var(--text-sm)">
|
||||
Jahresbericht ${b.jahr}
|
||||
</div>
|
||||
<div style="font-size:var(--text-xs);color:var(--c-text-muted)">
|
||||
${new Date(b.created_at).toLocaleDateString('de', {day:'2-digit',month:'2-digit',year:'numeric',hour:'2-digit',minute:'2-digit'})}
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-ghost btn-sm" data-bericht-id="${b.id}" data-bericht-jahr="${b.jahr}">
|
||||
${UI.icon('eye')} Lesen
|
||||
</button>
|
||||
</div>`).join('');
|
||||
|
||||
UI.modal.open({
|
||||
title: `${UI.icon('archive')} Gespeicherte Jahresberichte`,
|
||||
body: `<div style="padding:0 var(--space-1)">${listHtml}</div>`,
|
||||
footer: `<button class="btn btn-secondary" data-modal-close>Schließen</button>`,
|
||||
});
|
||||
|
||||
document.querySelectorAll('[data-bericht-id]').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = Number(btn.dataset.berichtId);
|
||||
const jahr = Number(btn.dataset.berichtJahr);
|
||||
try {
|
||||
const r = await API.zuchtKi.jahresberichtGet(id);
|
||||
_renderBerichtModal(r.text, r.jahr || jahr, r.id);
|
||||
} catch { UI.toast.error('Bericht konnte nicht geladen werden.'); }
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue