Pflege: Fell schneiden vs. trimmen + Tagebuch Medien-Button nach oben

- dogs.py: Pflegeart-Filter (trimmen/schneiden) anhand Rassen-Beschreibung
- dog-profile.js: Badge '✂️ Schneiden' / ' Trimmen' bei Fell-Kategorie
- diary.js: Fotos/Videos-Button direkt nach Textfeld (vor Ort und Meilenstein)
- ki.py: Standardmodell auf claude-sonnet-4-6 umgestellt
This commit is contained in:
rene 2026-04-25 08:21:49 +02:00
parent 69f78219ae
commit 22225d5717
3 changed files with 49 additions and 27 deletions

View file

@ -361,8 +361,9 @@ async def get_pflege_tipps(dog_id: int, user=Depends(get_current_user)):
(f"%{dog['rasse']}%",)
).fetchone()
# Fell-Typ ableiten
# Fell-Typ und Pflegeart ableiten
fell_filter = None
fell_pflege_art_filter = None
if rasse_info:
beschr = (rasse_info["beschreibung"] or "").lower()
if any(w in beschr for w in ["lockig", "wellig", "kraus", "pudel", "doodle"]):
@ -374,6 +375,12 @@ async def get_pflege_tipps(dog_id: int, user=Depends(get_current_user)):
elif rasse_info["groesse"] in ("gross", "sehr_gross"):
fell_filter = "doppel"
# Pflegeart: Trimmen vs. Schneiden
if any(w in beschr for w in ["trimm", "hand-stripping", "stripping", "rauhhaar", "drahthaar", "rauhaar"]):
fell_pflege_art_filter = "trimmen"
elif any(w in beschr for w in ["schneid", "geschoren", "schere", "clipper"]):
fell_pflege_art_filter = "schneiden"
with db() as conn:
alle_tipps = conn.execute(
"SELECT * FROM pflege_tipps ORDER BY kategorie, titel"
@ -388,10 +395,15 @@ async def get_pflege_tipps(dog_id: int, user=Depends(get_current_user)):
result = []
for t in alle_tipps:
t = dict(t)
# Fell-Filter
# Fell-Typ-Filter
if fell_filter and t["fell_typ"] and t["fell_typ"] != "alle":
if fell_filter not in t["fell_typ"].split(","):
continue
# Pflegeart-Filter: Trimm-Tipps nicht bei Schneidehunden und umgekehrt
tipp_art = t.get("fell_pflege_art")
if tipp_art and tipp_art != "alle" and fell_pflege_art_filter:
if tipp_art != fell_pflege_art_filter:
continue
t["schritte"] = _json.loads(t["schritte"] or "[]")
t["saisonal_aktuell"] = bool(t["saison"] and heute_saison in t["saison"])
result.append(t)
@ -403,9 +415,10 @@ async def get_pflege_tipps(dog_id: int, user=Depends(get_current_user)):
tipp_des_tages = (saisonal or result)[day_hash % len(saisonal or result)] if result else None
return {
"dog_name": dog["name"],
"rasse_name": rasse_info["name"] if rasse_info else dog["rasse"],
"tipp_des_tages": tipp_des_tages,
"tipps": result,
"kategorien": list(dict.fromkeys(t["kategorie"] for t in result)),
"dog_name": dog["name"],
"rasse_name": rasse_info["name"] if rasse_info else dog["rasse"],
"tipp_des_tages": tipp_des_tages,
"tipps": result,
"kategorien": list(dict.fromkeys(t["kategorie"] for t in result)),
"fell_pflege_art": fell_pflege_art_filter, # 'schneiden' | 'trimmen' | None
}

View file

@ -700,6 +700,22 @@ window.Page_diary = (() => {
<textarea class="form-control" name="text" rows="5"
placeholder="Was ist passiert? Besonderheiten, Gedanken…">${UI.escape(entry?.text || '')}</textarea>
</div>
<div class="form-group">
<!-- Bestehende Medien (Edit-Modus) -->
<div id="diary-existing-media"></div>
<!-- Neue Medien: Vorschau-Grid -->
<div id="diary-new-media-grid" class="diary-media-grid" style="display:none"></div>
<!-- versteckter Input multiple für Mehrfachauswahl -->
<input type="file" id="diary-media-input" accept="image/*,video/*,application/pdf" multiple style="display:none">
<!-- Einzelner Button iOS zeigt nativen Picker (Mediathek / Kamera / Datei) -->
<label for="diary-media-input" class="btn btn-secondary" style="cursor:pointer;display:flex;align-items:center;gap:var(--space-2);justify-content:center">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#image"></use></svg>
Fotos / Videos hinzufügen
</label>
</div>
<div class="form-group" id="diary-location-group">
<label class="form-label">Ort <span style="color:var(--c-text-secondary)">(optional)</span></label>
@ -744,24 +760,6 @@ window.Page_diary = (() => {
<span>${entry?.is_milestone ? 'Meilenstein ✓' : 'Als Meilenstein markieren'}</span>
</button>
</div>
<div class="form-group">
<label class="form-label">Fotos / Videos <span style="color:var(--c-text-secondary)">(optional)</span></label>
<!-- Bestehende Medien (Edit-Modus) -->
<div id="diary-existing-media"></div>
<!-- Neue Medien: Vorschau-Grid -->
<div id="diary-new-media-grid" class="diary-media-grid" style="display:none"></div>
<!-- versteckter Input multiple für Mehrfachauswahl -->
<input type="file" id="diary-media-input" accept="image/*,video/*,application/pdf" multiple style="display:none">
<!-- Einzelner Button iOS zeigt nativen Picker (Mediathek / Kamera / Datei) -->
<label for="diary-media-input" class="btn btn-secondary" style="margin-top:var(--space-2);cursor:pointer;display:flex;align-items:center;gap:var(--space-2);justify-content:center">
<svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#image"></use></svg>
Fotos / Videos hinzufügen
</label>
</div>
</form>
`;

View file

@ -349,6 +349,16 @@ window.Page_dog_profile = (() => {
'Saisonal':'🌸','Gesundheitsvorsorge':'❤️','Welpen-Pflege':'🐶',
};
const pflegeArtBadge = data.fell_pflege_art === 'schneiden'
? `<span title="Dieses Fell wächst kontinuierlich und wird mit der Schere geschnitten"
style="font-size:10px;font-weight:700;padding:2px 7px;border-radius:20px;
background:#dbeafe;color:#1d4ed8;margin-left:6px"> Schneiden</span>`
: data.fell_pflege_art === 'trimmen'
? `<span title="Dieses Fell hat natürliche Wachstumsbegrenzung und wird durch Hand-Stripping gepflegt"
style="font-size:10px;font-weight:700;padding:2px 7px;border-radius:20px;
background:#fef9c3;color:#92400e;margin-left:6px"> Trimmen</span>`
: '';
el.innerHTML = `
<div class="card" style="padding:var(--space-4)">
<div style="display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-3)">
@ -396,11 +406,12 @@ window.Page_dog_profile = (() => {
<div id="dp-pflege-liste" style="display:none;margin-top:var(--space-3)">
${data.kategorien.map(kat => {
const katTipps = data.tipps.filter(t=>t.kategorie===kat);
const katBadge = kat === 'Fell' ? pflegeArtBadge : '';
return `
<div style="margin-bottom:var(--space-3)">
<div style="font-size:11px;font-weight:700;color:var(--c-text-muted);
text-transform:uppercase;margin-bottom:8px">
${kat_icons[kat]||'🐾'} ${_esc(kat)}</div>
text-transform:uppercase;margin-bottom:8px;display:flex;align-items:center">
${kat_icons[kat]||'🐾'} ${_esc(kat)}${katBadge}</div>
${katTipps.map(tip => `
<details style="background:var(--c-surface-2);border-radius:8px;
padding:10px;margin-bottom:6px">