Initial commit: Happy Up monorepo through Sprint 5.

Document-driven MVP with FastAPI backend, Vue H5, WeChat mini shell, product demo, and Docker dev stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-07-23 11:42:40 +08:00
commit 1aaef71f52
116 changed files with 10550 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
from fastapi import APIRouter, Depends, Request
from fastapi.responses import JSONResponse, Response
from sqlalchemy.orm import Session
from app.core.response import error, ok
from app.db.models import Child, User
from app.db.session import get_db
from app.deps import get_current_user
from app.services import pdf_export, reports as report_service
router = APIRouter(prefix="/api/reports", tags=["Reports"])
@router.get("")
def list_reports(
childId: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
reports = report_service.list_reports_for_child(db, current_user.id, childId)
if reports is None:
return JSONResponse(
status_code=404,
content=error(10004, "child_not_found", request.state.request_id),
)
items = [report_service.report_to_dict(report) for report in reports]
return ok({"list": items}, request_id=request.state.request_id)
@router.get("/{report_id}")
def get_report(
report_id: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
report = report_service.get_report_for_user(db, current_user.id, report_id)
if not report:
return JSONResponse(
status_code=404,
content=error(10008, "report_not_found", request.state.request_id),
)
return ok(report_service.report_to_dict(report), request_id=request.state.request_id)
@router.get("/{report_id}/pdf")
def export_report_pdf(
report_id: int,
request: Request,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
report = report_service.get_report_for_user(db, current_user.id, report_id)
if not report:
return JSONResponse(
status_code=404,
content=error(10008, "report_not_found", request.state.request_id),
)
child = db.get(Child, report.child_id)
pdf_bytes = pdf_export.build_report_pdf(report, child)
filename = f"happy-up-report-{report_id}.pdf"
return Response(
content=pdf_bytes,
media_type="application/pdf",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)