marktask.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import datetime
  4. import json
  5. from fastapi import Depends, Query, Path
  6. from fastapi.background import BackgroundTasks
  7. from sqlalchemy import desc, update, asc
  8. from sqlalchemy.ext.asyncio import AsyncSession
  9. from bgtask.marktask import bgtask_create_student_mark_task
  10. from bgtask.problem import bgtask_create_class_error_statistic
  11. from bgtask.tasks import bgtask_delete_student_task_question
  12. from crud.marktask import crud_task, crud_student_task
  13. from crud.paper import crud_paper
  14. from crud.resource import crud_work_category
  15. from crud.school.school import crud_school, crud_grade, crud_class
  16. from crud.user import crud_student
  17. from models.marktask import StudentMarkTask, MarkTask
  18. from models.user import Admin
  19. from schemas.base import ReturnField, OrderByField
  20. from schemas.paper import NewMarkTask, UpdateMarkTaskInfo, MarkTaskInDB, StdAnsConfigInfo
  21. from utils.depends import get_async_db, get_current_user
  22. async def create_mark_task(info: NewMarkTask,
  23. bgtask: BackgroundTasks,
  24. db: AsyncSession = Depends(get_async_db),
  25. current_user: Admin = Depends(get_current_user)):
  26. info_dict = info.dict(exclude_none=True)
  27. if not info_dict:
  28. return {"errcode": 400, "mess": "请求参数为空!"}
  29. # 如果是创建作业阅卷任务,必须选择试卷
  30. if info_dict["mtype"] == "work":
  31. if not info_dict.get("pid", None):
  32. return {"errcode": 400, "mess": "请选择试卷!"}
  33. else:
  34. db_paper = await crud_paper.find_one(db, filters={"id": info_dict["pid"]})
  35. info_dict["name"] = db_paper.name
  36. info_dict["pno"] = db_paper.pno
  37. info_dict["pname"] = db_paper.name
  38. info_dict["pages"] = db_paper.pages
  39. info_dict["stdans_config"] = json.dumps({
  40. "std_x_list": db_paper.std_x_list,
  41. "std_y_list": db_paper.std_y_list
  42. })
  43. info_dict["ans_points"] = json.dumps(db_paper.ans_points)
  44. info_dict["std_points"] = json.dumps(db_paper.points)
  45. info_dict["category_id"] = db_paper.category_id
  46. info_dict["subject"] = db_paper.subject
  47. # 查询分类的科目
  48. db_category = await crud_work_category.find_one(db,
  49. filters={"id": db_paper.category_id},
  50. return_fields=["subject"])
  51. if db_category:
  52. info_dict["subject"] = db_category.subject
  53. # 试卷信息
  54. paper = {
  55. "id": db_paper.id,
  56. "pno": db_paper.pno,
  57. "pname": db_paper.name,
  58. "imgs": db_paper.imgs,
  59. "question_amount": db_paper.question_amount
  60. }
  61. else:
  62. if not info_dict.get("pid", None):
  63. return {"errcode": 400, "mess": "请选择试卷!"}
  64. db_paper = await crud_paper.find_one(db, filters={"id": info_dict["pid"]})
  65. info_dict["name"] = db_paper.name
  66. info_dict["pno"] = db_paper.pno
  67. info_dict["pname"] = db_paper.name
  68. info_dict["pages"] = db_paper.pages
  69. info_dict["stdans_config"] = json.dumps({
  70. "std_x_list": db_paper.std_x_list,
  71. "std_y_list": db_paper.std_y_list
  72. })
  73. info_dict["ans_points"] = json.dumps(db_paper.ans_points)
  74. info_dict["std_points"] = json.dumps(db_paper.points)
  75. info_dict["category_id"] = db_paper.category_id
  76. info_dict["subject"] = db_paper.subject
  77. # 查询分类的科目
  78. db_category = await crud_work_category.find_one(db,
  79. filters={"id": db_paper.category_id},
  80. return_fields=["subject"])
  81. if db_category:
  82. info_dict["subject"] = db_category.subject
  83. # 试卷信息
  84. paper = {
  85. "id": db_paper.id,
  86. "pno": db_paper.pno,
  87. "pname": db_paper.name,
  88. "imgs": db_paper.imgs,
  89. "question_amount": db_paper.question_amount
  90. }
  91. # 查询关联对象,组装阅卷任务对象,并写入数据库
  92. db_school = await crud_school.find_one(db, filters={"id": info_dict["school_id"]})
  93. db_grade = await crud_grade.find_one(db, filters={"id": info_dict["grade_id"]})
  94. db_class = await crud_class.find_one(db, filters={"id": info_dict["class_id"]})
  95. # 阅卷任务参数
  96. info_dict["year"] = datetime.date.today().year
  97. info_dict["school_name"] = db_school.name
  98. info_dict["grade_name"] = db_grade.name
  99. info_dict["class_name"] = db_class.name
  100. info_dict["student_amount"] = db_class.student_amount
  101. info_dict["creator_id"] = info_dict["editor_id"] = current_user.id
  102. info_dict["creator_name"] = info_dict["editor_name"] = current_user.username
  103. info_dict["pimgs"] = json.dumps(info_dict["pimgs"])
  104. obj_in = MarkTaskInDB(**info_dict)
  105. db_task = await crud_task.insert_one(db, obj_in)
  106. # 查询班级所有学生
  107. _, students = await crud_student.find_all(db,
  108. filters={"class_id": db_class.id},
  109. return_fields=[
  110. "id", "sno", "name", "school_id", "grade_id",
  111. "class_id", "school_name", "grade_name",
  112. "class_name"
  113. ])
  114. # 异步生成每个学生的阅卷任务
  115. bgtask.add_task(bgtask_create_student_mark_task, db_task.id, db_task.mtype, students, paper,
  116. current_user.id, current_user.name)
  117. # 创建本次阅卷任务的错题记录
  118. bgtask.add_task(bgtask_create_class_error_statistic, db_school.id, db_grade.id, db_task.id,
  119. db_task.name, db_task.mtype, db_class.id, db_class.student_amount, paper["id"],
  120. db_school.name, db_grade.name, db_class.name)
  121. return {"data": db_task}
  122. async def update_mark_task(info: UpdateMarkTaskInfo,
  123. tid: int = Path(..., description="阅卷任务ID"),
  124. db: AsyncSession = Depends(get_async_db),
  125. current_user: Admin = Depends(get_current_user)):
  126. info_dict = info.dict(exclude_none=True)
  127. if not info_dict:
  128. return {"errcode": 400, "mess": "请求参数为空!"}
  129. # 查询阅卷任务是否存在
  130. db_task = await crud_task.find_one(db, filters={"id": tid})
  131. if not db_task:
  132. return {"errcode": 400, "mess": "阅卷任务不存在!"}
  133. # 判断学校是否更新
  134. if ("school_id" in info_dict) and (info_dict["school_id"] != db_task.school_id):
  135. db_school = await crud_school.find_one(db, filters={"id": info_dict["school_id"]})
  136. if not db_school:
  137. return {"errcode": 404, "mess": "学校不存在!"}
  138. info_dict["school_name"] = db_school.name
  139. # 判断年级是否更新
  140. if ("grade_id" in info_dict) and (info_dict["grade_id"] != db_task.grade_id):
  141. db_grade = await crud_grade.find_one(db, filters={"id": info_dict["grade_id"]})
  142. if not db_grade:
  143. return {"errcode": 404, "mess": "年级不存在!"}
  144. info_dict["grade_name"] = db_grade.name
  145. # 判断班级是否更新
  146. if ("class_id" in info_dict) and (info_dict["class_id"] != db_task.class_id):
  147. db_class = await crud_class.find_one(db, filters={"id": info_dict["class_id"]})
  148. if not db_class:
  149. return {"errcode": 404, "mess": "班级不存在!"}
  150. info_dict["class_name"] = db_class.name
  151. info_dict["student_amount"] = db_class.student_amount
  152. # 判断试卷是否更新
  153. if ("pid" in info_dict) and (info_dict["pid"] != db_task.pid):
  154. db_paper = await crud_paper.find_one(db, filters={"id": info_dict["pid"]})
  155. if not db_paper:
  156. return {"errcode": 404, "mess": "试卷不存在!"}
  157. info_dict["pno"] = db_paper.pno
  158. info_dict["pname"] = db_paper.name
  159. # 更新
  160. info_dict["editor_id"] = current_user.id
  161. info_dict["editor_name"] = current_user.username
  162. db_task = await crud_task.update(db, db_task, info)
  163. # 更新student_task
  164. if ("pid" in info_dict) and (info_dict["pid"] != db_task.pid):
  165. stmt = (update(StudentMarkTask).where(StudentMarkTask.task_id == db_task.id).values(
  166. pid=db_task.pid, pno=db_task.pno, pname=db_task.pname))
  167. await crud_student_task.execute_v2(db, stmt)
  168. return {"data": db_task}
  169. async def delete_mark_task(bgtask: BackgroundTasks,
  170. tid: int = Path(..., description="阅卷任务ID"),
  171. db: AsyncSession = Depends(get_async_db),
  172. current_user: Admin = Depends(get_current_user)):
  173. existed = await crud_task.count(db, filters={"id": tid})
  174. if not existed:
  175. return {"errcode": 400, "mess": "阅卷任务不存在!"}
  176. await crud_task.delete(db, obj_id=tid)
  177. # 删除学生阅卷任务
  178. bgtask.add_task(bgtask_delete_student_task_question, tid)
  179. return {"data": None}
  180. async def get_mark_task(tid: int = Path(..., description="阅卷任务ID"),
  181. db: AsyncSession = Depends(get_async_db),
  182. current_user: Admin = Depends(get_current_user)):
  183. db_exist = await crud_task.find_one(db, filters={"id": tid})
  184. if not db_exist:
  185. return {"errcode": 400, "mess": "角色不存在!"}
  186. # 获取阅卷任务的学生
  187. students = await crud_student_task.fetch_all(db,
  188. filters={"task_id": db_exist.id},
  189. order_by=[desc("status")])
  190. db_exist.students = students
  191. cur_students = await crud_student_task.find_one(db,
  192. filters={
  193. "task_id": db_exist.id,
  194. "status": 1
  195. })
  196. cur_imgs = cur_students.pimgs if cur_students else []
  197. db_exist.cur_imgs = cur_imgs
  198. db_exist.total = len(students)
  199. # 已完成上传
  200. finish_students = filter(lambda x: x.pimgs, students)
  201. db_exist.finish = len(list(finish_students))
  202. db_exist.ftp_path = f"T{db_exist.id}-{db_exist.pno}"
  203. db_exist.stdans_config = json.loads(db_exist.stdans_config) if db_exist.stdans_config else {}
  204. return {"data": db_exist}
  205. async def get_mark_tasks(page: int = 1,
  206. size: int = 10,
  207. name: str = "",
  208. year: int = 0,
  209. status: int = 0,
  210. mtype: str = "",
  211. order: OrderByField = Query(
  212. "-created_at", description="排序字段,用逗号分隔,升降序以-判断,默认-created_at"),
  213. res: ReturnField = Query("", description="控制返回字段,字段逗号分隔"),
  214. db: AsyncSession = Depends(get_async_db),
  215. current_user: Admin = Depends(get_current_user)):
  216. _q = []
  217. if name:
  218. _q.append(MarkTask.name.like(f"{name}%"))
  219. if year:
  220. _q.append(MarkTask.year == year)
  221. if status:
  222. _q.append(MarkTask.status == status)
  223. if mtype:
  224. _q.append(MarkTask.mtype == mtype)
  225. # 排序
  226. order_fields = []
  227. if order:
  228. for x in order.split(","):
  229. field = x.strip()
  230. if field:
  231. if field.startswith("-"):
  232. order_fields.append(desc(getattr(MarkTask, field[1:])))
  233. else:
  234. order_fields.append(asc(getattr(MarkTask, field)))
  235. # 查询
  236. total, db_tasks = await crud_task.find_all(db,
  237. filters=_q,
  238. offset=(page - 1) * size,
  239. limit=size,
  240. order_by=order_fields,
  241. return_fields=res)
  242. return {"total": total, "data": db_tasks}
  243. async def update_stdans_config(info: StdAnsConfigInfo,
  244. tid: int = Path(..., description="阅卷任务ID"),
  245. db: AsyncSession = Depends(get_async_db),
  246. current_user: Admin = Depends(get_current_user)):
  247. info_dict = info.dict(exclude_none=True)
  248. if not info_dict:
  249. return {"errcode": 400, "mess": "请求参数为空!"}
  250. # 查询阅卷任务是否存在
  251. db_task = await crud_task.find_one(db, filters={"id": tid})
  252. info_dict["stdans_config"] = json.dumps(info_dict["stdans_config"])
  253. if not db_task:
  254. return {"errcode": 400, "mess": "阅卷任务不存在!"}
  255. db_task = await crud_task.update(db, db_task, info_dict)
  256. return {"data": db_task}