| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- """导出路由"""
- from fastapi import APIRouter, Request, HTTPException, Depends
- from fastapi.responses import FileResponse
- from app.database import get_connection, get_problem
- from app.routers.auth import verify_token
- from app.services.docx_builder import build_export_docx
- router = APIRouter()
- @router.post("/export/chapter")
- def export_chapter(request: Request, body: dict, _=Depends(verify_token)):
- """按章节+类型导出"""
- config = request.app.state.config
- chapter = body.get("chapter")
- import_type = body.get("import_type")
- title = body.get("title", "章节导出")
- conn = get_connection(config.db_path)
- try:
- # 查询符合条件的题目
- conditions = []
- params = []
- if chapter:
- conditions.append("chapters LIKE ?")
- params.append(f'%"{chapter}"%')
- if import_type:
- conditions.append("import_type = ?")
- params.append(import_type)
- where = ("WHERE " + " AND ".join(conditions)) if conditions else ""
- rows = conn.execute(
- f"SELECT id, question_type, difficulty FROM problems {where} ORDER BY question_type, difficulty DESC"
- ).fetchall()
- # 题目 ID 列表
- problem_ids = [r["id"] for r in rows]
- if not problem_ids:
- raise HTTPException(status_code=404, detail={
- "error": {"code": "no_problems", "message": "没有符合条件的题目"}
- })
- # 生成学生版
- student_path = build_export_docx(
- problem_ids, config.problems_dir, title, include_solution=False
- )
- # 生成教师版
- teacher_path = build_export_docx(
- problem_ids, config.problems_dir, title, include_solution=True
- )
- return {
- "student": student_path.name,
- "teacher": teacher_path.name,
- "count": len(problem_ids),
- }
- finally:
- conn.close()
- @router.post("/export/cart/{cart_id}")
- def export_cart(request: Request, cart_id: int, body: dict | None = None, _=Depends(verify_token)):
- """导出试题篮"""
- config = request.app.state.config
- title = (body or {}).get("title", "试题篮导出")
- conn = get_connection(config.db_path)
- try:
- # 获取试题篮中的题目
- rows = conn.execute(
- "SELECT p.id, p.question_type, p.difficulty FROM cart_items ci "
- "JOIN problems p ON ci.problem_id = p.id "
- "WHERE ci.cart_id = ? ORDER BY p.question_type, p.difficulty DESC",
- (cart_id,)
- ).fetchall()
- problem_ids = [r["id"] for r in rows]
- if not problem_ids:
- raise HTTPException(status_code=404, detail={
- "error": {"code": "empty_cart", "message": "试题篮为空"}
- })
- # 获取篮子名称
- cart_row = conn.execute("SELECT name FROM carts WHERE id = ?", (cart_id,)).fetchone()
- if cart_row:
- title = f"{cart_row['name']}_{title}"
- student_path = build_export_docx(
- problem_ids, config.problems_dir, title, include_solution=False
- )
- teacher_path = build_export_docx(
- problem_ids, config.problems_dir, title, include_solution=True
- )
- return {
- "student": student_path.name,
- "teacher": teacher_path.name,
- "count": len(problem_ids),
- }
- finally:
- conn.close()
- @router.get("/exports/{filename}")
- def download_export(request: Request, filename: str, _=Depends(verify_token)):
- """下载导出文件"""
- config = request.app.state.config
- file_path = config.papers_dir / filename
- if not file_path.exists():
- raise HTTPException(status_code=404, detail={
- "error": {"code": "not_found", "message": f"文件 {filename} 不存在"}
- })
- return FileResponse(
- str(file_path),
- media_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- filename=filename,
- )
|