feat: consolidate datastore into sleep, nutrition, mila databases
This commit is contained in:
@@ -197,10 +197,18 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
today_night_h, today_night_m = divmod(today_night_min, 60)
|
||||
today_night_dur_str = f"{today_night_h} h {today_night_m:02d} min" if today_night_h > 0 else f"{today_night_m} min"
|
||||
|
||||
# 3. Today's Feedings (conditional)
|
||||
# 3. Today's Feedings & Nutrition (Bottles + Brei/Beikost)
|
||||
today_feedings = con.execute(
|
||||
f"""
|
||||
SELECT strftime(local_time, '%H:%M'), consumed_ml, milk_type, note
|
||||
SELECT
|
||||
strftime(local_time, '%H:%M') AS time_str,
|
||||
consumed_ml,
|
||||
milk_type,
|
||||
item,
|
||||
solid_g,
|
||||
kcal,
|
||||
kind,
|
||||
note
|
||||
FROM v_feeding
|
||||
WHERE subject = 'mila' AND log_date = '{today_str}'
|
||||
ORDER BY start ASC
|
||||
@@ -209,7 +217,12 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
|
||||
today_feeding_agg = con.execute(
|
||||
f"""
|
||||
SELECT bottle_count, total_consumed_ml
|
||||
SELECT
|
||||
bottle_count,
|
||||
total_consumed_ml,
|
||||
solid_count,
|
||||
total_solid_g,
|
||||
total_kcal
|
||||
FROM v_feeding_daily
|
||||
WHERE subject = 'mila' AND log_date = '{today_str}'
|
||||
"""
|
||||
@@ -218,6 +231,9 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
has_feeding_today = bool(today_feedings and len(today_feedings) > 0)
|
||||
today_bottle_count = today_feeding_agg[0] if today_feeding_agg else 0
|
||||
today_bottle_ml = int(today_feeding_agg[1]) if today_feeding_agg else 0
|
||||
today_solid_count = today_feeding_agg[2] if today_feeding_agg else 0
|
||||
today_solid_g = int(today_feeding_agg[3]) if today_feeding_agg else 0
|
||||
today_feeding_kcal = int(today_feeding_agg[4]) if today_feeding_agg else 0
|
||||
|
||||
# 4. Today's Diapers (conditional)
|
||||
today_diapers = con.execute(
|
||||
@@ -272,6 +288,8 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
s.nap_sleep_minutes,
|
||||
COALESCE(f.total_consumed_ml, 0) AS feed_ml,
|
||||
COALESCE(f.bottle_count, 0) AS feed_bottles,
|
||||
COALESCE(f.total_solid_g, 0) AS feed_solid_g,
|
||||
COALESCE(f.solid_count, 0) AS feed_solid_count,
|
||||
COALESCE(d.total_changes, 0) AS diaper_cnt,
|
||||
COALESCE(d.dirty_count, 0) AS diaper_dirty
|
||||
FROM v_sleep_daily s
|
||||
@@ -311,8 +329,15 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
night_h, night_m = divmod(r[2], 60)
|
||||
night_str = f"{night_h} h {night_m:02d} min" if night_h > 0 else f"{night_m} min"
|
||||
nap_str = f"{r[3]} ({r[4]} min)"
|
||||
feed_str = f"{int(r[5])} ml ({r[6]}x)" if r[6] > 0 else "—"
|
||||
diaper_str = f"{r[7]} ({r[8]} Stuhl)" if r[7] > 0 else "—"
|
||||
|
||||
feed_parts = []
|
||||
if r[6] > 0: # feed_bottles
|
||||
feed_parts.append(f"{int(r[5])} ml ({r[6]}x)")
|
||||
if r[8] > 0: # feed_solid_count
|
||||
feed_parts.append(f"{int(r[7])} g Brei ({r[8]}x)")
|
||||
feed_str = " + ".join(feed_parts) if feed_parts else "—"
|
||||
|
||||
diaper_str = f"{r[9]} ({r[10]} Stuhl)" if r[9] > 0 else "—"
|
||||
|
||||
# Detailed breakdown of sessions for this day
|
||||
day_sess = sessions_by_date.get(d_str, [])
|
||||
@@ -339,7 +364,7 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
<td class="py-3.5 px-4 font-bold text-purple-300">{tot_h}</td>
|
||||
<td class="py-3.5 px-4 text-sky-400 font-semibold">{night_str}</td>
|
||||
<td class="py-3.5 px-4 text-emerald-400">{nap_str}</td>
|
||||
<td class="py-3.5 px-4 text-zinc-400">{feed_str}</td>
|
||||
<td class="py-3.5 px-4 text-amber-300 font-medium">{feed_str}</td>
|
||||
<td class="py-3.5 px-4 text-zinc-400">{diaper_str}</td>
|
||||
</tr>
|
||||
<tr class="border-b border-zinc-800/30 bg-zinc-950/30 text-xs">
|
||||
@@ -421,25 +446,62 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
# Conditional feeding card HTML
|
||||
feeding_section_html = ""
|
||||
if has_feeding_today:
|
||||
bottles_pills = []
|
||||
feeding_pills = []
|
||||
for f in today_feedings:
|
||||
ml_val = f"{int(f[1])} ml" if f[1] else "—"
|
||||
bottles_pills.append(f'<span class="px-2 py-1 rounded bg-amber-500/10 border border-amber-500/20 text-amber-300 text-xs">{f[0]} Uhr ({ml_val})</span>')
|
||||
time_str = f[0]
|
||||
ml_val = f[1]
|
||||
milk_type = f[2]
|
||||
item_name = f[3]
|
||||
solid_g = f[4]
|
||||
kcal_val = f[5]
|
||||
kind = f[6]
|
||||
if kind == "bottle" or (ml_val is not None and ml_val > 0):
|
||||
ml_str = f"{int(ml_val)} ml"
|
||||
milk_desc = f" · {milk_type}" if milk_type else ""
|
||||
feeding_pills.append(
|
||||
f'<span class="px-2.5 py-1 rounded-lg bg-amber-500/10 border border-amber-500/20 text-amber-300 text-xs flex items-center gap-1.5 font-medium">'
|
||||
f'<span>🍼</span> <span>{time_str} Uhr: <strong>{ml_str}</strong>{milk_desc}</span></span>'
|
||||
)
|
||||
else:
|
||||
food_title = item_name or "Brei"
|
||||
details = []
|
||||
if solid_g:
|
||||
details.append(f"{int(solid_g)} g")
|
||||
if kcal_val:
|
||||
details.append(f"~{int(kcal_val)} kcal")
|
||||
detail_str = f" ({', '.join(details)})" if details else ""
|
||||
feeding_pills.append(
|
||||
f'<span class="px-2.5 py-1 rounded-lg bg-orange-500/10 border border-orange-500/20 text-orange-300 text-xs flex items-center gap-1.5 font-medium">'
|
||||
f'<span>🥣</span> <span>{time_str} Uhr: <strong>{food_title}</strong>{detail_str}</span></span>'
|
||||
)
|
||||
|
||||
feed_summary_parts = []
|
||||
if today_bottle_count > 0:
|
||||
feed_summary_parts.append(
|
||||
f'<span class="font-mono font-bold text-amber-400 text-base">{today_bottle_ml} ml <span class="text-xs text-zinc-400 font-normal">({today_bottle_count}x Flasche)</span></span>'
|
||||
)
|
||||
if today_solid_count > 0:
|
||||
feed_summary_parts.append(
|
||||
f'<span class="font-mono font-bold text-orange-400 text-base">{today_solid_g} g <span class="text-xs text-zinc-400 font-normal">({today_solid_count}x Brei)</span></span>'
|
||||
)
|
||||
feed_summary_html = " · ".join(feed_summary_parts) if feed_summary_parts else '<span class="text-zinc-500 text-sm">—</span>'
|
||||
|
||||
feeding_section_html = f"""
|
||||
<div class="bg-zinc-900/80 border border-amber-500/20 rounded-2xl p-5 shadow-lg space-y-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="text-xl">🍼</span>
|
||||
<h3 class="font-semibold text-zinc-200">Fläschchen heute</h3>
|
||||
<span class="text-xl">🍼🥣</span>
|
||||
<h3 class="font-semibold text-zinc-200">Ernährung heute</h3>
|
||||
</div>
|
||||
<span class="font-mono font-bold text-amber-400 text-lg">{today_bottle_ml} ml <span class="text-xs text-zinc-400 font-normal">({today_bottle_count}x)</span></span>
|
||||
<div>{feed_summary_html}</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-2 pt-1">
|
||||
{' '.join(bottles_pills)}
|
||||
{' '.join(feeding_pills)}
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
# Conditional diaper card HTML
|
||||
diaper_section_html = ""
|
||||
if has_diapers_today:
|
||||
@@ -999,7 +1061,7 @@ def generate_dashboard_html(engine: DatastoreEngine) -> str:
|
||||
<th class="py-2.5 px-4">24h Gesamt</th>
|
||||
<th class="py-2.5 px-4">Nacht</th>
|
||||
<th class="py-2.5 px-4">Schläfchen</th>
|
||||
<th class="py-2.5 px-4">Fläschchen</th>
|
||||
<th class="py-2.5 px-4">Ernährung (Milch & Brei)</th>
|
||||
<th class="py-2.5 px-4 rounded-r-lg">Windeln</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
Reference in New Issue
Block a user