from calendar import monthrange from datetime import UTC, date, datetime from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.models.goal import Goal from app.models.reminder import Reminder from app.models.task import Task, TaskPriority from app.models.todo import DailyTodo from app.models.user import User from app.routers.auth import get_current_user from app.schemas.schedule_center import ( ScheduleCenterDateOut, ScheduleCenterDaySummary, ScheduleCenterMonthOut, ) router = APIRouter(prefix="/api/schedule-center", tags=["调度中心"]) def _build_summary( target_date: str, todos: list[DailyTodo], tasks: list[Task], reminders: list[Reminder], goals: list[Goal], ) -> ScheduleCenterDaySummary: return ScheduleCenterDaySummary( date=target_date, todo_total=len(todos), todo_completed=sum(1 for item in todos if item.is_completed), task_due_total=len(tasks), high_priority_total=sum(1 for item in tasks if item.priority in {TaskPriority.HIGH, TaskPriority.URGENT}), reminder_total=len(reminders), goal_total=len(goals), ) @router.get("/month", response_model=ScheduleCenterMonthOut) async def get_month_schedule( year: int = Query(..., ge=2000, le=2100), month: int = Query(..., ge=1, le=12), current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): month_start = date(year, month, 1) days_in_month = monthrange(month_start.year, month_start.month)[1] start_key = month_start.isoformat() end_key = month_start.replace(day=days_in_month).isoformat() start_dt = datetime.combine(month_start, datetime.min.time()) end_dt = datetime.combine(month_start.replace(day=days_in_month), datetime.max.time()) todos = (await db.execute( select(DailyTodo).where(DailyTodo.user_id == current_user.id, DailyTodo.todo_date >= start_key, DailyTodo.todo_date <= end_key) )).scalars().all() tasks = (await db.execute( select(Task).where( Task.user_id == current_user.id, Task.due_date.is_not(None), Task.due_date >= start_dt, Task.due_date <= end_dt, ) )).scalars().all() reminders = (await db.execute( select(Reminder).where( Reminder.user_id == current_user.id, Reminder.reminder_at >= start_dt, Reminder.reminder_at <= end_dt, ) )).scalars().all() goals = (await db.execute( select(Goal).where(Goal.user_id == current_user.id, Goal.goal_date >= start_key, Goal.goal_date <= end_key) )).scalars().all() todo_map: dict[str, list[DailyTodo]] = {} for item in todos: todo_map.setdefault(item.todo_date, []).append(item) task_map: dict[str, list[Task]] = {} for item in tasks: key = item.due_date.date().isoformat() task_map.setdefault(key, []).append(item) reminder_map: dict[str, list[Reminder]] = {} for item in reminders: key = item.reminder_at.date().isoformat() reminder_map.setdefault(key, []).append(item) goal_map: dict[str, list[Goal]] = {} for item in goals: goal_map.setdefault(item.goal_date, []).append(item) days = [] for day in range(1, days_in_month + 1): date_key = month_start.replace(day=day).isoformat() days.append(_build_summary( date_key, todo_map.get(date_key, []), task_map.get(date_key, []), reminder_map.get(date_key, []), goal_map.get(date_key, []), )) return ScheduleCenterMonthOut(month=f"{year:04d}-{month:02d}", days=days) @router.get("/date", response_model=ScheduleCenterDateOut) async def get_date_schedule( date_str: date = Query(...), current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db), ): target_date = date_str start_dt = datetime.combine(target_date, datetime.min.time()) end_dt = datetime.combine(target_date, datetime.max.time()) date_key = target_date.isoformat() todos = (await db.execute( select(DailyTodo) .where(DailyTodo.user_id == current_user.id, DailyTodo.todo_date == date_key) .order_by(DailyTodo.created_at.desc()) )).scalars().all() tasks = (await db.execute( select(Task) .where( Task.user_id == current_user.id, Task.due_date.is_not(None), Task.due_date >= start_dt, Task.due_date <= end_dt, ) .order_by(Task.created_at.desc()) )).scalars().all() reminders = (await db.execute( select(Reminder) .where( Reminder.user_id == current_user.id, Reminder.reminder_at >= start_dt, Reminder.reminder_at <= end_dt, ) .order_by(Reminder.reminder_at.asc(), Reminder.created_at.asc()) )).scalars().all() goals = (await db.execute( select(Goal) .where(Goal.user_id == current_user.id, Goal.goal_date == date_key) .order_by(Goal.created_at.desc()) )).scalars().all() summary = _build_summary(date_key, todos, tasks, reminders, goals) return ScheduleCenterDateOut( date=date_key, todos=todos, tasks=tasks, reminders=reminders, goals=goals, summary=summary, generated_at=datetime.now(UTC), )