"""导出路由""" 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, )