e329d3398a
Add FastAPI/React app with Docker deployment, Ubuntu one-click install, and docs for junior/senior high score tracking and mistake bank. Co-authored-by: Cursor <cursoragent@cursor.com>
55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
import csv
|
|
import io
|
|
import uuid
|
|
|
|
from fastapi import APIRouter, Depends
|
|
from fastapi.responses import StreamingResponse
|
|
from sqlalchemy.orm import Session, joinedload
|
|
|
|
from app.core.database import get_db
|
|
from app.core.deps import get_current_user
|
|
from app.models.user import ExamRecord, SubjectScore, User
|
|
from app.services.student_access import get_student_for_user
|
|
|
|
router = APIRouter(tags=["export"])
|
|
|
|
|
|
@router.get("/students/{student_id}/scores/export")
|
|
def export_scores_csv(
|
|
student_id: uuid.UUID,
|
|
db: Session = Depends(get_db),
|
|
current_user: User = Depends(get_current_user),
|
|
):
|
|
student = get_student_for_user(db, student_id, current_user.id)
|
|
exams = (
|
|
db.query(ExamRecord)
|
|
.options(joinedload(ExamRecord.scores).joinedload(SubjectScore.subject))
|
|
.filter(ExamRecord.student_id == student_id)
|
|
.order_by(ExamRecord.exam_date.asc())
|
|
.all()
|
|
)
|
|
|
|
output = io.StringIO()
|
|
writer = csv.writer(output)
|
|
writer.writerow(["考试日期", "考试类型", "标题", "科目", "总分", "得分", "占比"])
|
|
type_map = {"weekly": "周考", "monthly": "月考", "final": "期末"}
|
|
for exam in exams:
|
|
for score in exam.scores:
|
|
writer.writerow([
|
|
exam.exam_date.isoformat(),
|
|
type_map.get(exam.exam_type.value, exam.exam_type.value),
|
|
exam.title or "",
|
|
score.subject.name if score.subject else "",
|
|
float(score.total_score),
|
|
float(score.obtained_score),
|
|
f"{float(score.ratio) * 100:.2f}%",
|
|
])
|
|
|
|
output.seek(0)
|
|
filename = f"{student.name}_scores.csv"
|
|
return StreamingResponse(
|
|
iter([output.getvalue().encode("utf-8-sig")]),
|
|
media_type="text/csv",
|
|
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
|
|
)
|