MarkBoardTrack.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. <template>
  2. <div
  3. v-if="store.currentTask"
  4. :style="{ display: store.MarkBoardTrackCollapse ? 'none' : 'block' }"
  5. style="
  6. max-width: 250px;
  7. min-width: 250px;
  8. border: 1px solid grey;
  9. padding-left: 6px;
  10. padding-right: 6px;
  11. "
  12. >
  13. <div>
  14. <h1 class="tw-text-3xl tw-text-center">
  15. 总分:{{ store.currentMarkResult?.markerScore || 0 }}
  16. </h1>
  17. </div>
  18. <div>
  19. <div class="tw-text-2xl tw-text-center" @click="submit">提交</div>
  20. </div>
  21. <div
  22. v-if="store.currentTask && store.currentTask.questionList"
  23. class="tw-flex tw-gap-1 tw-flex-wrap tw-justify-between"
  24. >
  25. <template
  26. v-for="(question, index) in store.currentTask?.questionList"
  27. :key="index"
  28. >
  29. <div
  30. @click="chooseQuestion(question)"
  31. class="question tw-rounded tw-p-1"
  32. style="min-width: 100px"
  33. :class="isCurrentQuestion(question) && 'current-question'"
  34. >
  35. <div>
  36. {{ question.title }} {{ question.mainNumber }}-{{
  37. question.subNumber
  38. }}
  39. </div>
  40. <div class="tw-text-center">
  41. {{ question.score || 0 }}
  42. </div>
  43. </div>
  44. </template>
  45. </div>
  46. <div class="tw-flex tw-gap-1 tw-flex-wrap tw-mt-5">
  47. <div
  48. v-for="(s, i) in questionScoreSteps"
  49. :key="i"
  50. @click="chooseScore(s)"
  51. class="single-score"
  52. :class="isCurrentScore(s) && 'current-score'"
  53. >
  54. {{ s }}
  55. </div>
  56. </div>
  57. </div>
  58. </template>
  59. <script lang="ts">
  60. import { Question } from "@/types";
  61. import { isNumber } from "lodash";
  62. import { computed, defineComponent, onMounted, onUnmounted, watch } from "vue";
  63. import { findCurrentTaskMarkResult, store } from "./store";
  64. export default defineComponent({
  65. name: "MarkBoardTrack",
  66. emits: ["submit"],
  67. setup(props, { emit }) {
  68. const markResult = findCurrentTaskMarkResult();
  69. const questionScoreSteps = computed(() => {
  70. const question = store.currentQuestion;
  71. if (!question) return [];
  72. const steps = [];
  73. for (
  74. let i = 0;
  75. i <= question.maxScore - question.score;
  76. i += question.intervalScore
  77. ) {
  78. steps.push(i);
  79. }
  80. if ((question.maxScore - question.score) % question.intervalScore !== 0) {
  81. steps.push(question.maxScore - question.score);
  82. }
  83. return steps;
  84. });
  85. function isCurrentQuestion(question: Question) {
  86. return (
  87. store.currentQuestion?.mainNumber === question.mainNumber &&
  88. store.currentQuestion?.subNumber === question.subNumber
  89. );
  90. }
  91. watch(
  92. () => store.currentTask,
  93. () => {
  94. store.currentQuestion = undefined;
  95. store.currentScore = undefined;
  96. }
  97. );
  98. watch(
  99. () => store.currentQuestion,
  100. () => {
  101. store.currentScore = undefined;
  102. }
  103. );
  104. function chooseQuestion(question: Question) {
  105. store.currentQuestion = question;
  106. }
  107. function isCurrentScore(score: number) {
  108. return store.currentScore === score;
  109. }
  110. function chooseScore(score: number) {
  111. store.currentScore = score;
  112. }
  113. let keyPressTimestamp = 0;
  114. let keys: string[] = [];
  115. function numberKeyListener(event: KeyboardEvent) {
  116. // console.log(event);
  117. if (!store.currentQuestion) return;
  118. if (event.timeStamp - keyPressTimestamp > 1.5 * 1000) {
  119. keys = [];
  120. }
  121. keyPressTimestamp = event.timeStamp;
  122. keys.push(event.key);
  123. if (isNaN(parseFloat(keys.join("")))) {
  124. keys = [];
  125. }
  126. if (event.key === "Escape") {
  127. keys = [];
  128. }
  129. const score = parseFloat(keys.join(""));
  130. if (isNumber(score) && questionScoreSteps.value.includes(score)) {
  131. chooseScore(score);
  132. }
  133. }
  134. onMounted(() => {
  135. document.addEventListener("keydown", numberKeyListener);
  136. });
  137. onUnmounted(() => {
  138. document.removeEventListener("keydown", numberKeyListener);
  139. });
  140. function submit() {
  141. const errors: any = [];
  142. store.currentTask?.questionList.forEach((question, index) => {
  143. if (!isNumber(question.score)) {
  144. errors.push({ question, index, error: "没有赋分不能提交" });
  145. }
  146. });
  147. if (errors.length === 0) {
  148. emit("submit");
  149. } else {
  150. console.log(errors);
  151. }
  152. }
  153. return {
  154. store,
  155. markResult,
  156. isCurrentQuestion,
  157. chooseQuestion,
  158. isCurrentScore,
  159. chooseScore,
  160. questionScoreSteps,
  161. submit,
  162. };
  163. },
  164. });
  165. </script>
  166. <style scoped>
  167. .question {
  168. min-width: 80px;
  169. border: 1px solid grey;
  170. }
  171. .current-question {
  172. border: 1px solid yellowgreen;
  173. background-color: lightblue;
  174. }
  175. .single-score {
  176. width: 30px;
  177. height: 30px;
  178. display: grid;
  179. place-content: center;
  180. border: 1px solid black;
  181. border-radius: 5px;
  182. }
  183. .current-score {
  184. border: 1px solid yellowgreen;
  185. background-color: lightblue;
  186. }
  187. </style>