useMarkSubmit.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. import { useMarkStore } from "@/store";
  2. import { saveTask, doUnselectiveType } from "@/api/markPage";
  3. import { message } from "ant-design-vue";
  4. import { isNumber, cloneDeep } from "lodash-es";
  5. import { h } from "vue";
  6. import EventBus from "@/plugins/eventBus";
  7. import type { Question, MarkResult } from "@/types";
  8. import useStatus from "./useStatus";
  9. import useMarkTask from "./useMarkTask";
  10. import useTaskTips from "./useTaskTips";
  11. import useTaskQuestion from "./useTaskQuestion";
  12. export default function useMarkSubmit() {
  13. const markStore = useMarkStore();
  14. const { updateStatus } = useStatus();
  15. const { nextTask } = useMarkTask();
  16. const { setPrevTips, registTaskChangeTips } = useTaskTips();
  17. const { updateQuestionStatus } = useTaskQuestion();
  18. registTaskChangeTips();
  19. // 检查分数
  20. const validateScore = (markResult: MarkResult) => {
  21. const errors: Array<{ question: Question; index: number; error: string }> =
  22. [];
  23. markResult.scoreList.forEach((score: number, index: number) => {
  24. if (!markStore.currentTask) return;
  25. const question = markStore.currentTask.questionList[index]!;
  26. // 如果是自评或者有问题的题目,不检查分数
  27. if (!question.selfMark || question.problem) return;
  28. const { maxScore, minScore, mainNumber, subNumber, questionName } =
  29. question;
  30. let error;
  31. if (!isNumber(score)) {
  32. error = `${mainNumber}-${subNumber}${
  33. questionName ? "(" + questionName + ")" : ""
  34. } 没有给分,不能提交。`;
  35. } else if (isNumber(maxScore) && score > maxScore) {
  36. error = `${mainNumber}-${subNumber}${
  37. questionName ? "(" + questionName + ")" : ""
  38. } 给分大于最高分不能提交。`;
  39. } else if (isNumber(minScore) && score < minScore) {
  40. error = `${mainNumber}-${subNumber}${
  41. questionName ? "(" + questionName + ")" : ""
  42. } 给分小于最低分不能提交。`;
  43. }
  44. if (error) {
  45. errors.push({ question, index, error });
  46. }
  47. });
  48. return errors;
  49. };
  50. // 检查评卷任务
  51. function checkMarkResult(markResult: MarkResult): boolean {
  52. const errors = validateScore(markResult);
  53. if (errors.length !== 0) {
  54. console.log(errors);
  55. const msg = errors.map((v) => h("div", `${v.error}`));
  56. void message.warning({
  57. content: h("span", ["校验失败", ...msg]),
  58. duration: 10,
  59. });
  60. return;
  61. }
  62. const allowNullQs = markStore.currentTask.questionList
  63. .filter((q) => q.problem || !q.selfMark)
  64. .map((q, i) => i);
  65. const questions = markStore.currentTask.questionList.filter(
  66. (q) => !q.problem && q.selfMark
  67. );
  68. const scoreList = markResult.scoreList.filter(
  69. (_, i) => !allowNullQs.includes(i)
  70. );
  71. if (
  72. scoreList.length !== questions.length ||
  73. !scoreList.every((s) => isNumber(s))
  74. ) {
  75. console.error({ content: "markResult格式不正确,缺少分数" });
  76. return;
  77. }
  78. if (markStore.isTrackMode) {
  79. const trackScores =
  80. markResult.markerTrackList
  81. .map((t) => Math.round((t.score || 0) * 100))
  82. .reduce((acc, s) => acc + s, 0) / 100;
  83. if (
  84. trackScores !== markResult.markerScore &&
  85. markResult.markerScore !== null
  86. ) {
  87. void message.error({
  88. content: "轨迹分与总分不一致,请检查。",
  89. duration: 3,
  90. });
  91. return;
  92. }
  93. }
  94. if (markStore.setting.forceSpecialTag) {
  95. if (
  96. markResult.markerTrackList.length === 0 &&
  97. markResult.markerTagList.length === 0
  98. ) {
  99. void message.error({
  100. content: "强制标记已开启,请至少使用一个标记。",
  101. duration: 5,
  102. });
  103. return;
  104. }
  105. }
  106. return true;
  107. }
  108. // 获取保存评卷任务的数据
  109. function getSaveTaskResult() {
  110. const datas = cloneDeep(markStore.currentTask.markResult);
  111. datas.spent = Date.now() - markStore.currentTask.__markStartTime;
  112. const allowNullQs = datas.questionList
  113. .filter((q) => !q.selfMark)
  114. .map((q, i) => i);
  115. datas.scoreList = datas.scoreList.filter(
  116. (_, i) => !allowNullQs.includes(i)
  117. );
  118. datas.questionList = datas.questionList
  119. .filter((q) => q.selfMark)
  120. .map((q) => {
  121. q.markerTrackList = datas.markerTrackList.filter(
  122. (t) => t.mainNumber === q.mainNumber && t.subNumber === q.subNumber
  123. );
  124. q.markerTagList = datas.markerTagList.filter(
  125. (t) => t.mainNumber === q.mainNumber && t.subNumber === q.subNumber
  126. );
  127. q.markerScore = q.markerTrackList.reduce((acc, t) => {
  128. return acc + (t.score || 0);
  129. }, 0);
  130. return q;
  131. }) as Question[];
  132. datas.markerTrackList = [];
  133. datas.markerTagList = [];
  134. // 单题阅模式需要告诉后台正在评卷的questionId
  135. if (markStore.isSingelQuestionModel)
  136. datas.markedQuestionId = datas.questionList[0].questionId;
  137. return datas;
  138. }
  139. // 保存评卷任务
  140. const saveTaskToServer = async () => {
  141. if (!markStore.currentTask) return;
  142. const markResult = markStore.currentTask.markResult;
  143. if (!markResult) return;
  144. if (!checkMarkResult(markResult)) return;
  145. if (!markStore.isTrackMode) {
  146. markResult.markerTrackList = [];
  147. }
  148. console.log("save task to server");
  149. void message.loading({ content: "保存评卷任务..." });
  150. const res = await saveTask(getSaveTaskResult()).catch(() => false);
  151. if (!res) return;
  152. // 故意不在此处同步等待,因为不必等待
  153. if (res.data.success && markStore.currentTask) {
  154. // 保存成功后,缓存当前评卷提示信息
  155. // 回评不缓存
  156. if (!markStore.historyOpen) setPrevTips();
  157. // 单题模式下,更新当前题目的状态
  158. if (markStore.isSingelQuestionModel) {
  159. await updateQuestionStatus(markStore.currentQuestion.questionId);
  160. } else {
  161. updateStatus().catch((e) => console.log("保存任务后获取status出错", e));
  162. }
  163. void message.success({ content: "保存成功", duration: 2 });
  164. if (!markStore.historyOpen) {
  165. markStore.currentTask = undefined;
  166. markStore.tasks.shift();
  167. markStore.currentTask = markStore.tasks[0];
  168. } else {
  169. EventBus.emit("should-reload-history");
  170. }
  171. } else if (!res.data.success) {
  172. void message.error({
  173. content: "提交失败,请刷新页面",
  174. duration: 10,
  175. });
  176. return;
  177. } else if (!markStore.currentTask) {
  178. void message.warn({ content: "暂无新任务", duration: 10 });
  179. }
  180. // 获取下一个任务
  181. void nextTask();
  182. };
  183. // 全部零分提交
  184. const allZeroSubmit = async () => {
  185. const markResult = markStore.currentTask?.markResult;
  186. if (!markResult) return;
  187. const { markerScore, scoreList, markerTrackList, markerTagList } =
  188. markResult;
  189. markResult.markerScore = 0;
  190. const ss = new Array(markStore.currentTaskEnsured.questionList.length);
  191. markResult.scoreList = ss.fill(0);
  192. markResult.markerTrackList = [];
  193. try {
  194. await saveTaskToServer();
  195. } catch (error) {
  196. console.log("error restore");
  197. } finally {
  198. markResult.markerScore = markerScore;
  199. markResult.scoreList = scoreList;
  200. markResult.markerTrackList = markerTrackList;
  201. markResult.markerTagList = markerTagList;
  202. }
  203. };
  204. // 未选做提交
  205. const unselectiveSubmit = async () => {
  206. const markResult = markStore.currentTask?.markResult;
  207. if (!markResult) return;
  208. try {
  209. const res = await doUnselectiveType();
  210. if (res?.data.success) {
  211. void message.success({ content: "未选做处理成功", duration: 3 });
  212. if (!markStore.historyOpen) {
  213. markStore.currentTask = undefined;
  214. markStore.tasks.shift();
  215. markStore.currentTask = markStore.tasks[0];
  216. }
  217. if (markStore.historyOpen) {
  218. EventBus.emit("should-reload-history");
  219. }
  220. await updateStatus();
  221. } else {
  222. void message.error({
  223. content: res?.data.message || "错误",
  224. duration: 5,
  225. });
  226. }
  227. } catch (error) {
  228. console.log("未选做处理失败", error);
  229. void message.error({ content: "网络异常", duration: 5 });
  230. await new Promise((res) => setTimeout(res, 1500));
  231. window.location.reload();
  232. }
  233. };
  234. return {
  235. saveTaskToServer,
  236. allZeroSubmit,
  237. unselectiveSubmit,
  238. };
  239. }