BooleanQuestionView.vue 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. <script setup lang="ts">
  2. import { store } from "@/store/store";
  3. import { onMounted, onUnmounted } from "vue";
  4. import QuestionBody from "./QuestionBody.vue";
  5. let isShowAnswer = $ref(false);
  6. function toggleShowAnswer() {
  7. isShowAnswer = !isShowAnswer;
  8. }
  9. const examQuestion = $computed(() => store.exam.currentQuestion);
  10. onMounted(() => {
  11. window.addEventListener("keyup", keyup);
  12. });
  13. onUnmounted(() => {
  14. window.removeEventListener("keyup", keyup);
  15. });
  16. function keyup(e: KeyboardEvent) {
  17. const { tagName = "" } = document?.activeElement || {};
  18. if (
  19. examQuestion.questionType === "TRUE_OR_FALSE" &&
  20. ["BODY", "A", "BUTTON", "DIV"].includes(tagName)
  21. ) {
  22. if ("KeyY" === e.code) {
  23. answerQuestion("true");
  24. }
  25. if ("KeyN" === e.code) {
  26. answerQuestion("false");
  27. }
  28. }
  29. }
  30. function answerQuestion(studentAnswer: "true" | "false") {
  31. store.updateExamQuestion({
  32. order: examQuestion.order,
  33. studentAnswer,
  34. });
  35. }
  36. const optionWithNames: Record<string, string> = {
  37. true: "正确",
  38. false: "错误",
  39. "": "",
  40. };
  41. </script>
  42. <template>
  43. <div class="question-view">
  44. <question-body :questionBody="examQuestion.body" />
  45. <div class="ops">
  46. <div class="stu-answer">
  47. {{ optionWithNames[examQuestion.studentAnswer ?? ""] }}
  48. </div>
  49. <div class="score">({{ examQuestion.questionScore }}分)</div>
  50. </div>
  51. <div
  52. :class="[
  53. examQuestion.studentAnswer === 'true' && 'row-selected',
  54. 'option',
  55. ]"
  56. class="tw-flex tw-items-center"
  57. @click="() => answerQuestion('true')"
  58. >
  59. <input
  60. type="radio"
  61. name="question"
  62. value="true"
  63. :checked="examQuestion.studentAnswer === 'true'"
  64. />
  65. <span class="question-options">正确</span>
  66. </div>
  67. <div
  68. :class="[
  69. examQuestion.studentAnswer === 'false' && 'row-selected',
  70. 'option',
  71. ]"
  72. class="tw-flex tw-items-center"
  73. @click="() => answerQuestion('false')"
  74. >
  75. <input
  76. type="radio"
  77. name="question"
  78. value="false"
  79. :checked="examQuestion.studentAnswer === 'false'"
  80. />
  81. <div class="question-options">错误</div>
  82. </div>
  83. <div class="reset">
  84. <span v-if="store.examShouldShowAnswer">
  85. <n-button type="success" @click="toggleShowAnswer">
  86. {{ isShowAnswer ? "隐藏" : "显示" }}答案
  87. </n-button>
  88. </span>
  89. <div v-if="isShowAnswer" class="tw-mt-2">
  90. 正确答案:
  91. <div>
  92. {{ optionWithNames[examQuestion.rightAnswer + ""] }}
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. </template>
  98. <style scoped>
  99. .question-view {
  100. display: grid;
  101. grid-row-gap: 10px;
  102. }
  103. .ops {
  104. display: flex;
  105. align-items: flex-end;
  106. }
  107. .stu-answer {
  108. width: 100px;
  109. border-bottom: 1px solid black;
  110. text-align: center;
  111. height: 20px;
  112. }
  113. .option {
  114. display: flex;
  115. cursor: pointer;
  116. border-radius: 5px;
  117. height: 26px;
  118. }
  119. .option:hover {
  120. background-color: aliceblue;
  121. }
  122. .row-selected {
  123. background-color: aliceblue;
  124. width: 100%;
  125. }
  126. .question-options {
  127. text-align: left;
  128. margin-left: 10px;
  129. }
  130. </style>