Mark.vue 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div class="my-container">
  3. <mark-header />
  4. <div class="tw-flex tw-gap-1">
  5. <mark-history :should-reload="shouldReloadHistory" />
  6. <mark-body @error="removeBrokenTask" />
  7. <mark-board-track v-if="showMarkBoardTrack" @submit="saveTaskToServer" />
  8. <mark-board-key-board
  9. v-if="showMarkBoardKeyBoard"
  10. @submit="saveTaskToServer"
  11. />
  12. <mark-board-mouse v-if="showMarkBoardMouse" @submit="saveTaskToServer" />
  13. </div>
  14. </div>
  15. </template>
  16. <script lang="ts">
  17. import { computed, defineComponent, onMounted, ref, watch } from "vue";
  18. import {
  19. clearMarkTask,
  20. getGroup,
  21. getSetting,
  22. getStatus,
  23. getTask,
  24. saveTask,
  25. updateUISetting,
  26. } from "@/api/markPage";
  27. import {
  28. findCurrentTaskMarkResult,
  29. removeCurrentMarkResult,
  30. store,
  31. } from "./store";
  32. import MarkHeader from "./MarkHeader.vue";
  33. import MarkBody from "./MarkBody.vue";
  34. import { useTimers } from "@/setups/useTimers";
  35. import MarkHistory from "./MarkHistory.vue";
  36. import MarkBoardTrack from "./MarkBoardTrack.vue";
  37. import { ModeEnum, Setting } from "@/types";
  38. import MarkBoardKeyBoard from "./MarkBoardKeyBoard.vue";
  39. import MarkBoardMouse from "./MarkBoardMouse.vue";
  40. import { isEmpty } from "lodash";
  41. import { message } from "ant-design-vue";
  42. export default defineComponent({
  43. name: "Mark",
  44. components: {
  45. MarkHeader,
  46. MarkBody,
  47. MarkHistory,
  48. MarkBoardTrack,
  49. MarkBoardKeyBoard,
  50. MarkBoardMouse,
  51. },
  52. setup: () => {
  53. const { addInterval } = useTimers();
  54. async function updateMarkTask() {
  55. const settingRes = await clearMarkTask();
  56. }
  57. async function updateSetting() {
  58. const settingRes = await getSetting();
  59. // 初次使用时,重置并初始化uisetting
  60. if (isEmpty(settingRes.data.uiSetting)) {
  61. settingRes.data.uiSetting = {
  62. "answer.paper.scale": 1,
  63. "score.board.collapse": false,
  64. "normal.mode": "keyboard",
  65. } as Setting["uiSetting"];
  66. }
  67. store.setting = settingRes.data;
  68. }
  69. async function updateStatus() {
  70. const res = await getStatus();
  71. store.status = res.data;
  72. }
  73. async function updateGroups() {
  74. const res = await getGroup();
  75. store.groups = res.data;
  76. }
  77. async function updateTask() {
  78. const res = await getTask();
  79. if (res.data.libraryId) {
  80. store.tasks.push(res.data);
  81. if (!store.historyOpen) {
  82. // 回评中,不能替换task
  83. // TODO: 疑似替换多次引起重新渲染
  84. if (store.currentTask?.studentId !== store.tasks[0].studentId)
  85. store.currentTask = store.tasks[0];
  86. }
  87. // 如果是评完后,再取到的任务,则此时要更新一下status
  88. if (store.status.totalCount - store.status.markedCount === 0) {
  89. await updateStatus();
  90. }
  91. } else {
  92. store.message = res.data.message;
  93. }
  94. }
  95. // 5秒更新一次tasks
  96. addInterval(() => {
  97. // console.log("get task", store.tasks);
  98. if (store.tasks.length < (store.setting.prefetchCount ?? 3)) {
  99. updateTask();
  100. }
  101. }, 5 * 1000);
  102. // TODO: 后续改掉,不需要
  103. addInterval(() => {
  104. updateStatus();
  105. }, 5 * 60 * 1000);
  106. onMounted(async () => {
  107. await updateMarkTask();
  108. updateSetting();
  109. updateStatus();
  110. updateGroups();
  111. updateTask();
  112. });
  113. watch(
  114. () => [store.setting.uiSetting, store.setting.mode],
  115. () => {
  116. updateUISetting(store.setting.mode, store.setting.uiSetting);
  117. },
  118. { deep: true }
  119. );
  120. // 切换currentTask的同时,切换currentMarkResult
  121. watch(
  122. () => store.currentTask,
  123. () => {
  124. store.currentMarkResult = findCurrentTaskMarkResult();
  125. // 重置当前选择的quesiton和score
  126. store.currentQuestion = undefined;
  127. store.currentScore = undefined;
  128. }
  129. );
  130. const showMarkBoardTrack = computed(() => {
  131. return store.setting.mode === ModeEnum.TRACK;
  132. });
  133. const showMarkBoardKeyBoard = computed(() => {
  134. return (
  135. store.setting.mode === ModeEnum.COMMON &&
  136. store.setting.uiSetting["normal.mode"] === "keyboard"
  137. );
  138. });
  139. const showMarkBoardMouse = computed(() => {
  140. return (
  141. store.setting.mode === ModeEnum.COMMON &&
  142. store.setting.uiSetting["normal.mode"] === "mouse"
  143. );
  144. });
  145. const removeBrokenTask = () => {
  146. removeCurrentMarkResult();
  147. store.currentTask = undefined;
  148. store.tasks.shift();
  149. };
  150. const shouldReloadHistory = ref(0);
  151. const saveTaskToServer = async () => {
  152. const markResult = findCurrentTaskMarkResult();
  153. if (!markResult) return;
  154. if (
  155. markResult.scoreList.length !== store.currentTask?.questionList.length
  156. ) {
  157. message.error({ content: "还有题目没有评分", duration: 5 });
  158. return;
  159. }
  160. console.log("save task to server");
  161. const mkey = "save_task_key";
  162. message.loading({ content: "保存评卷任务...", key: mkey });
  163. const res = (await saveTask()) as any;
  164. updateStatus();
  165. if (res.data.success && store.currentTask) {
  166. message.success({ content: "保存成功", key: mkey, duration: 2 });
  167. if (!store.historyOpen) {
  168. removeCurrentMarkResult();
  169. store.currentTask = undefined;
  170. store.tasks.shift();
  171. } else {
  172. shouldReloadHistory.value = Date.now();
  173. }
  174. } else {
  175. if (markResult) {
  176. markResult.spent = Date.now() - markResult.spent;
  177. }
  178. console.log(res.data.message);
  179. message.error({ content: res.data.message, duration: 10 });
  180. }
  181. };
  182. return {
  183. store,
  184. updateTask,
  185. saveTaskToServer,
  186. showMarkBoardTrack,
  187. showMarkBoardKeyBoard,
  188. showMarkBoardMouse,
  189. shouldReloadHistory,
  190. removeBrokenTask,
  191. };
  192. },
  193. });
  194. </script>
  195. <style scoped>
  196. .my-container {
  197. width: 100%;
  198. }
  199. a {
  200. color: #42b983;
  201. }
  202. label {
  203. margin: 0 0.5em;
  204. font-weight: bold;
  205. }
  206. code {
  207. background-color: #eee;
  208. padding: 2px 4px;
  209. border-radius: 4px;
  210. color: #304455;
  211. }
  212. </style>