tasks.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import os
  4. from fastapi.background import BackgroundTasks
  5. from pydantic import Field
  6. from sqlalchemy.ext.asyncio import AsyncSession
  7. from crud.mark import crud_mark, crud_studentmark
  8. from crud.school import crud_grade, crud_system, crud_class
  9. from crud.user import crud_teacher, crud_student
  10. from models.mark import StudentMarkTask, StudentAnswer
  11. from models.school import SchoolGrade, SchoolClass
  12. from models.user import Teacher, Student
  13. from schemas.app.task import BgUpdateTaskReviewInfo, BgUpdateStudentTaskInfo
  14. from schemas.school.school import NewGrade
  15. async def delete_related_object(db: AsyncSession,
  16. *,
  17. sid: int = 0,
  18. gid: int = 0,
  19. cid: int = 0):
  20. # 根据学校删除年级、班级、教师、学生等
  21. if sid and (not gid) and (not cid):
  22. # 1、删除年级
  23. await crud_grade.delete(db,
  24. where_clauses=[SchoolGrade.school_id == sid])
  25. # 2、删除班级
  26. await crud_class.delete(db,
  27. where_clauses=[SchoolClass.school_id == sid])
  28. # TODO: 删除教师、学生、作业、考试、阅卷任务等
  29. await crud_teacher.delete(db, where_clauses=[Teacher.school_id == sid])
  30. await crud_student.delete(db, where_clauses=[Student.school_id == sid])
  31. elif gid and (not cid): # 如果是年级被删除,则删除该年级下的所有班级
  32. await crud_class.delete(db, where_clauses=[SchoolClass.grade_id == gid])
  33. # TODO: 删除学生、作业、考试、阅卷任务等
  34. await crud_student.delete(db, where_clauses=[Student.grade_id == gid])
  35. elif cid: # 如果班级被删除了,则删除该班级下的所有学生
  36. # TODO: 删除学生、作业、考试、阅卷任务等
  37. await crud_student.delete(db, where_clauses=[Student.class_id == cid])
  38. else:
  39. pass
  40. async def delete_remote_file(filepath: str):
  41. urls = [x.strip() for x in filepath.split(";")]
  42. try:
  43. for url in urls:
  44. os.remove(url)
  45. except Exception as ex:
  46. print(f"[Error] Delete file: {str(ex)}")
  47. async def rank_score(db: AsyncSession,
  48. task_id: int = Field(..., description="阅卷任务ID")):
  49. # 根据 task_id 查询 StudentMarkTask
  50. stmt = f"""SELECT id,
  51. CASE
  52. WHEN @prevRank = score THEN @curRank
  53. WHEN @prevRank := score THEN @curRank := @curRank + 1
  54. END AS rank
  55. FROM {StudentMarkTask.__tablename__},
  56. (SELECT @curRank :=0, @prevRank := NULL) rb
  57. WHERE task_id={task_id}
  58. ORDER BY score desc;
  59. """
  60. ranks = await crud_studentmark.execute(db, stmt)
  61. for idx, sid in enumerate(ranks):
  62. stmt = f"UPDATE {StudentMarkTask.__tablename__} SET rank={idx+1} WHERE id={sid};"
  63. await crud_studentmark.execute(db, stmt)
  64. async def update_mark_task(db: AsyncSession,
  65. bg_task: BackgroundTasks,
  66. task_id: int = Field(..., description="学生阅卷任务ID"),
  67. qtype: int = Field(...,
  68. description="试题类型,0:客观题,1: 主观题"),
  69. score: int = Field(..., description="得分"),
  70. editor_id: int = Field(..., description="最后编辑人ID"),
  71. editor_name: str = Field(...,
  72. description="最后编辑人姓名")):
  73. """
  74. 数据更新流程:
  75. 1、根据task_id更新StudentMarkTask,
  76. 2、如果该学生的所有试题已经被批阅完,则根据StudentMarkTask.task_id 更新 MarkTask 的最高分/最低分/平均分...等信息。
  77. 3、如果MarkTask批阅完成,则对StudentMarkTask进行排名。
  78. """
  79. # ------------------ 更新学生阅卷任-----------------------------------
  80. student_task = await crud_studentmark.find_one(db, filters={"id": task_id})
  81. # 判断该学生是否已经被批阅完成
  82. marked_amount = student_task.marked_amount + 1
  83. smt = BgUpdateStudentTaskInfo(
  84. marked_amount=marked_amount,
  85. is_completed=marked_amount == student_task.question_amount,
  86. score=student_task.score + score,
  87. editor_id=editor_id,
  88. editor_name=editor_name,
  89. )
  90. # 按题型统计得分
  91. if qtype:
  92. smt.subjective_score = student_task.subjective_score + score
  93. else:
  94. smt.objective_score = student_task.objective_score + score
  95. # 开始更新
  96. student_task = await crud_studentmark.update(db, student_task, smt)
  97. # ------------------ 更新学生阅卷任务结束 ---------------------------
  98. # ------------------ 更新阅卷任务 ---------------------------------
  99. if student_task.is_completed:
  100. # 查询MarkTask是否存在
  101. db_obj = await crud_mark.find_one(db,
  102. filters={"id": student_task.task_id})
  103. # 批阅完成学生数量
  104. marked_amount = db_obj.marked_amount + 1
  105. if marked_amount == db_obj.student_amount:
  106. bg_task.add_task(rank_score, db, student_task.task_id)
  107. # 最高分 / 最低分
  108. high_score = student_task.score if student_task.score > db_obj.high_score else db_obj.high_score
  109. low_score = student_task.score if student_task.score <= db_obj.low_score else db_obj.low_score
  110. # 平均分
  111. avg_score = round(
  112. ((db_obj.avg_score * db_obj.marked_amount) + score) / marked_amount,
  113. 2)
  114. # 及格人数
  115. if student_task.score >= 60:
  116. pass_amount = db_obj.pass_amount + 1
  117. else:
  118. pass_amount = db_obj.pass_amount
  119. pass_rate = round(pass_amount / marked_amount, 2)
  120. # 批阅状态
  121. status = 2 if marked_amount == db_obj.student_amount else 1
  122. # 更新
  123. mt = BgUpdateTaskReviewInfo(marked_amount=marked_amount,
  124. high_score=high_score,
  125. low_score=low_score,
  126. avg_score=avg_score,
  127. pass_amount=pass_amount,
  128. pass_rate=pass_rate,
  129. status=status)
  130. await crud_mark.update(db, db_obj, mt)
  131. print("Async Update MarkTask OK!")
  132. async def async_create_grade(db: AsyncSession, sid: int, category: int):
  133. # 年级列表
  134. school_system = await crud_system.find_one(db,
  135. filters={"id": category},
  136. return_fields={"grades"})
  137. grade_set = set(school_system.grades.split(","))
  138. # 查询学校是否存在
  139. _, db_grades = await crud_grade.find_all(db, filters={"school_id": sid})
  140. db_grade_set = set([x.name for x in db_grades])
  141. diff_grades = grade_set - db_grade_set
  142. new_grades = [NewGrade(sid=sid, name=x) for x in diff_grades]
  143. try:
  144. await crud_grade.insert_many(db, new_grades)
  145. except Exception as ex:
  146. print(f"AutoCreateGradeError: {str(ex)}")
  147. return
  148. async def delete_student_task_question(db: AsyncSession, task_id: int):
  149. # 查询学生任务ID列表
  150. _, student_tasks = await crud_studentmark.find_all(
  151. db, filters={"task_id": task_id}, return_fields=["id"])
  152. student_task_ids = ",".join([str(x.id) for x in student_tasks])
  153. # 删除学生任务和答题
  154. task_stmt = "DELETE FROM `{}` WHERE task_id={};".format(
  155. StudentMarkTask.__tablename__, task_id)
  156. await crud_studentmark.execute(db, task_stmt)
  157. question_stmt = "DELETE FROM `{}` WHERE task_id IN ({});".format(
  158. StudentAnswer.__tablename__, student_task_ids)
  159. await crud_studentmark.execute(db, question_stmt)