You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.9 KiB
Python

# backend/app/routers/dashboard.py
from fastapi import APIRouter, Depends
from sqlmodel import Session, select
from ..db import get_session
from ..models import Approval, Briefing, Event, Goal, InboxItem, Person, Project, Task
from ..routers.inbox import latest_cls
from ..schemas import (
ApprovalSummaryOut,
BadgesOut,
BriefingOut,
DashboardOut,
EventOut,
GoalOut,
InboxRecentOut,
TaskSummaryItem,
TaskSummaryOut,
UserOut,
WeatherOut,
)
router = APIRouter() # prefix 없음. main.py 에서 prefix="/api" 등록.
# 날씨 아이콘 저장값 → 표시값 매핑(cloudSun 저장 → sun 표시)
WEATHER_ICON_MAP = {"cloudSun": "sun"}
@router.get("/dashboard", response_model=DashboardOut)
def dashboard(s: Session = Depends(get_session)):
me = s.exec(select(Person).where(Person.is_me == True)).first() # noqa: E712
user = UserOut(name=me.name, initial=me.initial) if me else UserOut(name="", initial="")
br = s.exec(select(Briefing)).first()
if br:
weather = WeatherOut(
temp=br.weather_temp, cond=br.weather_cond,
icon=WEATHER_ICON_MAP.get(br.weather_icon, br.weather_icon),
)
briefing = BriefingOut(
today=br.today, weather=weather, commute=br.commute, sleep=br.sleep, note=br.note
)
saved_today, today_routed = br.saved_today, br.today_routed
else:
briefing = BriefingOut(
today="", weather=WeatherOut(temp=0, cond="", icon="sun"),
commute="", sleep="", note="",
)
saved_today, today_routed = "", 0
schedule = [
EventOut(
id=e.id, time=e.time, title=e.title, tag=e.tag, dur=e.dur, tone=e.tone, soon=e.soon
)
for e in s.exec(select(Event).order_by(Event.sort_order)).all()
]
tasks = s.exec(select(Task)).all()
proj_name = {p.id: p.name for p in s.exec(select(Project)).all()}
# 요약은 최상위(parent_id=None) 미완료 작업만, 상위 5건. open_count=최상위 미완료 수.
open_tasks = sorted(
[t for t in tasks if t.parent_id is None and t.status.value != "done"],
key=lambda t: t.sort_order,
)
items = [
TaskSummaryItem(
id=t.id, title=t.title, prio=t.prio.value, project=proj_name.get(t.project_id, "")
)
for t in open_tasks[:5]
]
task_summary = TaskSummaryOut(open_count=len(open_tasks), items=items)
goals = [
GoalOut(id=g.id, title=g.title, pct=g.pct, sub=g.sub, tone=g.tone)
for g in s.exec(select(Goal).order_by(Goal.sort_order)).all()
]
apprs = s.exec(select(Approval).order_by(Approval.sort_order)).all()
high = [a for a in apprs if a.risk == "high"]
approvals_summary = [
ApprovalSummaryOut(id=a.id, icon=a.icon, tone=a.tone, title=a.title, time=a.time)
for a in high[:3]
] # high-risk 만, 최대 3건
recent = s.exec(select(InboxItem).order_by(InboxItem.created_at.desc()).limit(3)).all()
# 평탄화: 각 항목의 최신 classification 에서 type/proj_label/tone 을 끌어와 채운다.
inbox_recent = []
for it in recent:
c = latest_cls(s, it.id)
inbox_recent.append(
InboxRecentOut(
id=it.id,
kind=it.kind.value if hasattr(it.kind, "value") else it.kind,
raw=it.raw,
type=(c.type.value if c and hasattr(c.type, "value") else (c.type if c else "")),
proj_label=c.proj_label if c else "",
tone=c.tone if c else "ink",
)
)
badges = BadgesOut(appr=len(high), task=len(open_tasks), noti=6)
return DashboardOut(
user=user, briefing=briefing, saved_today=saved_today, today_routed=today_routed,
schedule=schedule, task_summary=task_summary, goals=goals,
approvals_summary=approvals_summary, inbox_recent=inbox_recent, badges=badges,
)