MarkBoardMouse.vue 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. <template>
  2. <div
  3. v-if="store.currentTask"
  4. class="mark-board-track-container"
  5. :class="[store.isScoreBoardCollapsed ? 'hide' : 'show']"
  6. >
  7. <div class="tw-my-2 tw-flex">
  8. <a-dropdown class="tw-self-end">
  9. <template #overlay>
  10. <a-menu>
  11. <a-menu-item key="1" @click="toggleKeyMouse">
  12. 键盘给分
  13. </a-menu-item>
  14. </a-menu>
  15. </template>
  16. <a-button>
  17. 鼠标给分
  18. <DownOutlined style="display: inline-flex" />
  19. </a-button>
  20. </a-dropdown>
  21. </div>
  22. <div
  23. class="
  24. tw-flex tw-rounded tw-justify-between tw-p-2 tw-pl-5
  25. top-container
  26. tw-mb-4
  27. "
  28. >
  29. <div class="tw-flex tw-flex-col">
  30. <div class="tw-flex tw-items-center tw-gap-2">
  31. <img
  32. src="./images/totalscore.png"
  33. style="width: 13px; height: 16px"
  34. />
  35. 总分
  36. </div>
  37. <div class="total-score tw-ml-5 tw-font-bold">
  38. {{ store.currentTask?.markResult.markerScore }}
  39. </div>
  40. </div>
  41. <div class="tw-flex tw-place-content-center tw-items-center tw-gap-2">
  42. <div class="tw-flex tw-flex-col tw-gap-1">
  43. <a-popconfirm
  44. v-if="store.setting.enableAllZero"
  45. title="确定给全零分?"
  46. ok-text="确定"
  47. cancel-text="取消"
  48. @confirm="$emit('allZeroSubmit')"
  49. :overlayStyle="{ width: '200px' }"
  50. >
  51. <a-button
  52. type="primary"
  53. size="middle"
  54. class="all-zero-unselective-button"
  55. >
  56. <span>全零分</span>
  57. </a-button>
  58. </a-popconfirm>
  59. <a-popconfirm
  60. v-if="store.setting.selective"
  61. title="确定是未选做?"
  62. ok-text="确定"
  63. cancel-text="取消"
  64. @confirm="$emit('unselectiveSubmit')"
  65. :overlayStyle="{ width: '200px' }"
  66. >
  67. <a-button
  68. type="primary"
  69. size="middle"
  70. class="all-zero-unselective-button"
  71. >
  72. <span>未选做</span>
  73. </a-button>
  74. </a-popconfirm>
  75. </div>
  76. <qm-button
  77. type="primary"
  78. shape="round"
  79. size="middle"
  80. style="height: 76px; border-radius: 10px; padding: 12px"
  81. @click="submit"
  82. >
  83. 提交
  84. </qm-button>
  85. </div>
  86. </div>
  87. <div
  88. v-if="store.currentTask && store.currentTask.questionList"
  89. style="
  90. height: calc(100vh - 56px - 200px);
  91. overflow: auto;
  92. user-select: none;
  93. position: relative;
  94. "
  95. >
  96. <template
  97. v-for="(question, index) in store.currentTask?.questionList"
  98. :key="index"
  99. >
  100. <div class="question tw-rounded tw-mb-2">
  101. <div>
  102. <div>
  103. {{ question.title }} {{ question.mainNumber }}-{{
  104. question.subNumber
  105. }}
  106. </div>
  107. <div class="tw-flex tw-flex-wrap tw-gap-2">
  108. <div
  109. v-for="(s, i) in questionScoreSteps(question)"
  110. :key="i"
  111. @click="chooseScore(question, s)"
  112. class="single-score tw-cursor-pointer"
  113. :class="isCurrentScore(question, s) && 'current-score'"
  114. >
  115. {{ s }}
  116. <div
  117. v-if="isCurrentScore(question, s)"
  118. class="current-score-indicator"
  119. ></div>
  120. </div>
  121. </div>
  122. </div>
  123. </div>
  124. </template>
  125. </div>
  126. </div>
  127. </template>
  128. <script setup lang="ts">
  129. import type { Question } from "@/types";
  130. import { isNumber } from "lodash";
  131. import { store } from "@/store/store";
  132. import { keyMouse } from "./use/keyboardAndMouse";
  133. import { message } from "ant-design-vue";
  134. import { DownOutlined } from "@ant-design/icons-vue";
  135. const emit = defineEmits(["submit", "allZeroSubmit", "unselectiveSubmit"]);
  136. const { toggleKeyMouse } = keyMouse();
  137. function chooseScore(question: Question, score: number) {
  138. store.currentQuestion = question;
  139. const { __index } = store.currentQuestion;
  140. store.currentTask &&
  141. (store.currentTask.markResult.scoreList[__index] = score);
  142. }
  143. function isCurrentScore(question: Question, score: number) {
  144. const { __index } = question;
  145. const questionScore =
  146. store.currentTask && store.currentTask.markResult.scoreList[__index];
  147. return questionScore === score;
  148. }
  149. function questionScoreSteps(question: Question) {
  150. if (!question) return [];
  151. const remainScore = Math.round(question.maxScore * 100) / 100;
  152. const steps = [];
  153. for (
  154. let i = 0;
  155. i <= remainScore;
  156. i = Math.round(i * 100 + question.intervalScore * 100) / 100
  157. ) {
  158. steps.push(i);
  159. }
  160. if (
  161. Math.round(remainScore * 100) % Math.round(question.intervalScore * 100) !==
  162. 0
  163. ) {
  164. steps.push(remainScore);
  165. }
  166. return steps;
  167. }
  168. function submit() {
  169. if (!store.currentTask) return;
  170. const errors: any = [];
  171. store.currentTask.markResult.scoreList.forEach((s, index) => {
  172. if (!isNumber(s) && store.currentTask) {
  173. const question = store.currentTask.questionList[index];
  174. errors.push({
  175. question,
  176. index,
  177. error: `${question.mainNumber}-${question.subNumber} 没有赋分不能提交。`,
  178. });
  179. }
  180. });
  181. if (errors.length === 0) {
  182. emit("submit");
  183. } else {
  184. console.log(errors);
  185. message.error({
  186. content: errors.map((e: any) => `${e.error}`).join("\n"),
  187. duration: 10,
  188. });
  189. }
  190. }
  191. let buttonHeightForSelective = $computed(() =>
  192. store.setting.selective && store.setting.enableAllZero ? "36px" : "76px"
  193. );
  194. </script>
  195. <style scoped>
  196. .mark-board-track-container {
  197. max-width: 290px;
  198. min-width: 290px;
  199. padding: 20px;
  200. max-height: calc(100vh - 56px - 0px);
  201. overflow: auto;
  202. z-index: 1001;
  203. transition: margin-right 0.5s;
  204. color: var(--app-small-header-text-color);
  205. }
  206. .mark-board-track-container.show {
  207. margin-right: 0;
  208. }
  209. .mark-board-track-container.hide {
  210. margin-right: -290px;
  211. }
  212. .top-container {
  213. background-color: var(--app-container-bg-color);
  214. }
  215. .total-score {
  216. color: var(--app-main-text-color);
  217. font-size: 32px;
  218. }
  219. .question {
  220. min-width: 80px;
  221. }
  222. .single-score {
  223. position: relative;
  224. width: 32px;
  225. height: 32px;
  226. font-size: var(--app-secondary-font-size);
  227. display: grid;
  228. place-content: center;
  229. background-color: var(--app-container-bg-color);
  230. border-radius: 30px;
  231. }
  232. .current-score {
  233. color: var(--app-score-color);
  234. }
  235. .current-score-indicator {
  236. position: absolute;
  237. top: 0;
  238. left: 0;
  239. width: 5px;
  240. height: 5px;
  241. background-color: #5c69f6;
  242. }
  243. .all-zero-unselective-button {
  244. height: v-bind(buttonHeightForSelective);
  245. border-radius: 10px;
  246. padding: 7px;
  247. background-color: #4db9ff;
  248. border: none;
  249. }
  250. </style>