#!/usr/bin/env python # -*- coding: utf-8 -*- import datetime import json from fastapi import Depends, Query, Path from fastapi.background import BackgroundTasks from sqlalchemy import desc, update, asc from sqlalchemy.ext.asyncio import AsyncSession from bgtask.marktask import bgtask_create_student_mark_task from bgtask.problem import bgtask_create_class_error_statistic from bgtask.tasks import bgtask_delete_student_task_question from crud.marktask import crud_task, crud_student_task from crud.paper import crud_paper from crud.resource import crud_work_category from crud.school.school import crud_school, crud_grade, crud_class from crud.user import crud_student from models.marktask import StudentMarkTask, MarkTask from models.user import Admin from schemas.base import ReturnField, OrderByField from schemas.paper import NewMarkTask, UpdateMarkTaskInfo, MarkTaskInDB, StdAnsConfigInfo from utils.depends import get_async_db, get_current_user async def create_mark_task(info: NewMarkTask, bgtask: BackgroundTasks, db: AsyncSession = Depends(get_async_db), current_user: Admin = Depends(get_current_user)): info_dict = info.dict(exclude_none=True) if not info_dict: return {"errcode": 400, "mess": "请求参数为空!"} # 如果是创建作业阅卷任务,必须选择试卷 if info_dict["mtype"] == "work": if not info_dict.get("pid", None): return {"errcode": 400, "mess": "请选择试卷!"} else: db_paper = await crud_paper.find_one(db, filters={"id": info_dict["pid"]}) info_dict["name"] = db_paper.name info_dict["pno"] = db_paper.pno info_dict["pname"] = db_paper.name info_dict["pages"] = db_paper.pages info_dict["stdans_config"] = json.dumps({ "std_x_list": db_paper.std_x_list, "std_y_list": db_paper.std_y_list }) info_dict["ans_points"] = json.dumps(db_paper.ans_points) info_dict["std_points"] = json.dumps(db_paper.points) info_dict["category_id"] = db_paper.category_id info_dict["subject"] = db_paper.subject # 查询分类的科目 db_category = await crud_work_category.find_one(db, filters={"id": db_paper.category_id}, return_fields=["subject"]) if db_category: info_dict["subject"] = db_category.subject # 试卷信息 paper = { "id": db_paper.id, "pno": db_paper.pno, "pname": db_paper.name, "imgs": db_paper.imgs, "question_amount": db_paper.question_amount } else: if not info_dict.get("pid", None): return {"errcode": 400, "mess": "请选择试卷!"} db_paper = await crud_paper.find_one(db, filters={"id": info_dict["pid"]}) info_dict["name"] = db_paper.name info_dict["pno"] = db_paper.pno info_dict["pname"] = db_paper.name info_dict["pages"] = db_paper.pages info_dict["stdans_config"] = json.dumps({ "std_x_list": db_paper.std_x_list, "std_y_list": db_paper.std_y_list }) info_dict["ans_points"] = json.dumps(db_paper.ans_points) info_dict["std_points"] = json.dumps(db_paper.points) info_dict["category_id"] = db_paper.category_id info_dict["subject"] = db_paper.subject # 查询分类的科目 db_category = await crud_work_category.find_one(db, filters={"id": db_paper.category_id}, return_fields=["subject"]) if db_category: info_dict["subject"] = db_category.subject # 试卷信息 paper = { "id": db_paper.id, "pno": db_paper.pno, "pname": db_paper.name, "imgs": db_paper.imgs, "question_amount": db_paper.question_amount } # 查询关联对象,组装阅卷任务对象,并写入数据库 db_school = await crud_school.find_one(db, filters={"id": info_dict["school_id"]}) db_grade = await crud_grade.find_one(db, filters={"id": info_dict["grade_id"]}) db_class = await crud_class.find_one(db, filters={"id": info_dict["class_id"]}) # 阅卷任务参数 info_dict["year"] = datetime.date.today().year info_dict["school_name"] = db_school.name info_dict["grade_name"] = db_grade.name info_dict["class_name"] = db_class.name info_dict["student_amount"] = db_class.student_amount info_dict["creator_id"] = info_dict["editor_id"] = current_user.id info_dict["creator_name"] = info_dict["editor_name"] = current_user.username info_dict["pimgs"] = json.dumps(info_dict["pimgs"]) obj_in = MarkTaskInDB(**info_dict) db_task = await crud_task.insert_one(db, obj_in) # 查询班级所有学生 _, students = await crud_student.find_all(db, filters={"class_id": db_class.id}, return_fields=[ "id", "sno", "name", "school_id", "grade_id", "class_id", "school_name", "grade_name", "class_name" ]) # 异步生成每个学生的阅卷任务 bgtask.add_task(bgtask_create_student_mark_task, db_task.id, db_task.mtype, students, paper, current_user.id, current_user.name) # 创建本次阅卷任务的错题记录 bgtask.add_task(bgtask_create_class_error_statistic, db_school.id, db_grade.id, db_task.id, db_task.name, db_task.mtype, db_class.id, db_class.student_amount, paper["id"], db_school.name, db_grade.name, db_class.name) return {"data": db_task} async def update_mark_task(info: UpdateMarkTaskInfo, tid: int = Path(..., description="阅卷任务ID"), db: AsyncSession = Depends(get_async_db), current_user: Admin = Depends(get_current_user)): info_dict = info.dict(exclude_none=True) if not info_dict: return {"errcode": 400, "mess": "请求参数为空!"} # 查询阅卷任务是否存在 db_task = await crud_task.find_one(db, filters={"id": tid}) if not db_task: return {"errcode": 400, "mess": "阅卷任务不存在!"} # 判断学校是否更新 if ("school_id" in info_dict) and (info_dict["school_id"] != db_task.school_id): db_school = await crud_school.find_one(db, filters={"id": info_dict["school_id"]}) if not db_school: return {"errcode": 404, "mess": "学校不存在!"} info_dict["school_name"] = db_school.name # 判断年级是否更新 if ("grade_id" in info_dict) and (info_dict["grade_id"] != db_task.grade_id): db_grade = await crud_grade.find_one(db, filters={"id": info_dict["grade_id"]}) if not db_grade: return {"errcode": 404, "mess": "年级不存在!"} info_dict["grade_name"] = db_grade.name # 判断班级是否更新 if ("class_id" in info_dict) and (info_dict["class_id"] != db_task.class_id): db_class = await crud_class.find_one(db, filters={"id": info_dict["class_id"]}) if not db_class: return {"errcode": 404, "mess": "班级不存在!"} info_dict["class_name"] = db_class.name info_dict["student_amount"] = db_class.student_amount # 判断试卷是否更新 if ("pid" in info_dict) and (info_dict["pid"] != db_task.pid): db_paper = await crud_paper.find_one(db, filters={"id": info_dict["pid"]}) if not db_paper: return {"errcode": 404, "mess": "试卷不存在!"} info_dict["pno"] = db_paper.pno info_dict["pname"] = db_paper.name # 更新 info_dict["editor_id"] = current_user.id info_dict["editor_name"] = current_user.username db_task = await crud_task.update(db, db_task, info) # 更新student_task if ("pid" in info_dict) and (info_dict["pid"] != db_task.pid): stmt = (update(StudentMarkTask).where(StudentMarkTask.task_id == db_task.id).values( pid=db_task.pid, pno=db_task.pno, pname=db_task.pname)) await crud_student_task.execute_v2(db, stmt) return {"data": db_task} async def delete_mark_task(bgtask: BackgroundTasks, tid: int = Path(..., description="阅卷任务ID"), db: AsyncSession = Depends(get_async_db), current_user: Admin = Depends(get_current_user)): existed = await crud_task.count(db, filters={"id": tid}) if not existed: return {"errcode": 400, "mess": "阅卷任务不存在!"} await crud_task.delete(db, obj_id=tid) # 删除学生阅卷任务 bgtask.add_task(bgtask_delete_student_task_question, tid) return {"data": None} async def get_mark_task(tid: int = Path(..., description="阅卷任务ID"), db: AsyncSession = Depends(get_async_db), current_user: Admin = Depends(get_current_user)): db_exist = await crud_task.find_one(db, filters={"id": tid}) if not db_exist: return {"errcode": 400, "mess": "角色不存在!"} # 获取阅卷任务的学生 students = await crud_student_task.fetch_all(db, filters={"task_id": db_exist.id}, order_by=[desc("status")]) db_exist.students = students cur_students = await crud_student_task.find_one(db, filters={ "task_id": db_exist.id, "status": 1 }) cur_imgs = cur_students.pimgs if cur_students else [] db_exist.cur_imgs = cur_imgs db_exist.total = len(students) # 已完成上传 finish_students = filter(lambda x: x.pimgs, students) db_exist.finish = len(list(finish_students)) db_exist.ftp_path = f"T{db_exist.id}-{db_exist.pno}" db_exist.stdans_config = json.loads(db_exist.stdans_config) if db_exist.stdans_config else {} return {"data": db_exist} async def get_mark_tasks(page: int = 1, size: int = 10, name: str = "", year: int = 0, status: int = 0, mtype: str = "", order: OrderByField = Query( "-created_at", description="排序字段,用逗号分隔,升降序以-判断,默认-created_at"), res: ReturnField = Query("", description="控制返回字段,字段逗号分隔"), db: AsyncSession = Depends(get_async_db), current_user: Admin = Depends(get_current_user)): _q = [] if name: _q.append(MarkTask.name.like(f"{name}%")) if year: _q.append(MarkTask.year == year) if status: _q.append(MarkTask.status == status) if mtype: _q.append(MarkTask.mtype == mtype) # 排序 order_fields = [] if order: for x in order.split(","): field = x.strip() if field: if field.startswith("-"): order_fields.append(desc(getattr(MarkTask, field[1:]))) else: order_fields.append(asc(getattr(MarkTask, field))) # 查询 total, db_tasks = await crud_task.find_all(db, filters=_q, offset=(page - 1) * size, limit=size, order_by=order_fields, return_fields=res) return {"total": total, "data": db_tasks} async def update_stdans_config(info: StdAnsConfigInfo, tid: int = Path(..., description="阅卷任务ID"), db: AsyncSession = Depends(get_async_db), current_user: Admin = Depends(get_current_user)): info_dict = info.dict(exclude_none=True) if not info_dict: return {"errcode": 400, "mess": "请求参数为空!"} # 查询阅卷任务是否存在 db_task = await crud_task.find_one(db, filters={"id": tid}) info_dict["stdans_config"] = json.dumps(info_dict["stdans_config"]) if not db_task: return {"errcode": 400, "mess": "阅卷任务不存在!"} db_task = await crud_task.update(db, db_task, info_dict) return {"data": db_task}