MultipleQuestionView.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <template>
  2. <div v-if="isSyncState && examQuestion.questionType === 'MULTIPLE_CHOICE'" class="question-view">
  3. <question-body :questionBody="question.body" :examQuestion="examQuestion"></question-body>
  4. <div class="ops">
  5. <div class="stu-answer"> {{oldIndexToABCD}}</div>
  6. <div class="score">({{examQuestion.questionScore}}分)</div>
  7. </div>
  8. <div v-for="(option, index) in newQuestionOptions" :key="index" class="option" @click="toggleAnswer(option.oldIndex)">
  9. <input type="checkbox" name="question" value="option.oldIndex" :checked="studentAnswer && studentAnswer.includes(option.oldIndex)" />
  10. <span style="padding: 0 10px;">{{optionName[index]}}: </span>
  11. <span class="question-options" v-if="option.value" v-html="option.value.body"></span>
  12. </div>
  13. <div class="reset">
  14. <i-button type="warning" size="large" @click="() => answerQuestion(null)">重置答案</i-button>
  15. <span v-if="question.rightAnswer">
  16. &nbsp;&nbsp;&nbsp;<i-button type="info" size="large" @click="showAnswer">显示答案</i-button>
  17. </span>
  18. <div v-if="question.rightAnswer && isShowAnswer">
  19. 正确答案:<div>{{rightAnswerTransform}}</div>
  20. </div>
  21. </div>
  22. </div>
  23. </template>
  24. <script>
  25. import QuestionBody from "./QuestionBody";
  26. import { createNamespacedHelpers } from "vuex";
  27. const { mapMutations } = createNamespacedHelpers("examingHomeModule");
  28. const optionName = "ABCDEF".split("");
  29. export default {
  30. name: "MultipleQuestionView",
  31. data() {
  32. return {
  33. questionBody: this.question.body,
  34. optionName,
  35. studentAnswer: this.examQuestion.studentAnswer || "",
  36. isShowAnswer: false
  37. };
  38. },
  39. props: {
  40. question: Object,
  41. examQuestion: Object
  42. },
  43. created: function() {
  44. window.addEventListener("keyup", this.keyup);
  45. },
  46. beforeDestroy() {
  47. window.removeEventListener("keyup", this.keyup);
  48. },
  49. beforeUpdate() {
  50. this.answerQuestion(this.studentAnswer);
  51. },
  52. methods: {
  53. ...mapMutations(["updateExamQuestion"]),
  54. keyup(e) {
  55. if (
  56. ["BODY", "A", "BUTTON", "DIV"].includes(
  57. document.activeElement.tagName
  58. ) ||
  59. (["INPUT"].includes(document.activeElement.tagName) &&
  60. ["checkbox", "radio"].includes(document.activeElement.type))
  61. ) {
  62. if (
  63. ["KeyA", "KeyB", "KeyC", "KeyD", "KeyE", "KeyF", "KeyG"]
  64. .slice(0, this.question.questionOptionList.length)
  65. .includes(e.code)
  66. ) {
  67. const selectedOldIndex =
  68. "" +
  69. this.newQuestionOptions.find(v => v.name == e.code[3]).oldIndex;
  70. if (this.studentAnswer.includes(selectedOldIndex)) {
  71. this.studentAnswer = this.studentAnswer.replace(
  72. selectedOldIndex,
  73. ""
  74. );
  75. } else {
  76. this.studentAnswer = this.studentAnswer
  77. .concat(selectedOldIndex)
  78. .split("")
  79. .sort()
  80. .join("");
  81. }
  82. }
  83. }
  84. },
  85. toggleAnswer: function(selectedOldIndex) {
  86. if (this.studentAnswer.includes(selectedOldIndex)) {
  87. this.studentAnswer = this.studentAnswer.replace(selectedOldIndex, "");
  88. } else {
  89. this.studentAnswer = this.studentAnswer
  90. .concat(selectedOldIndex)
  91. .split("")
  92. .sort()
  93. .join("");
  94. }
  95. },
  96. async answerQuestion(studentAnswer) {
  97. let realAnswer = studentAnswer;
  98. if (studentAnswer === "") {
  99. realAnswer = null;
  100. }
  101. if (realAnswer !== this.examQuestion.studentAnswer) {
  102. this.updateExamQuestion({
  103. order: this.examQuestion.order,
  104. studentAnswer: realAnswer
  105. });
  106. }
  107. },
  108. showAnswer() {
  109. this.isShowAnswer = !this.isShowAnswer;
  110. }
  111. },
  112. watch: {
  113. examQuestion: function() {
  114. this.studentAnswer = this.examQuestion.studentAnswer || "";
  115. }
  116. },
  117. computed: {
  118. isSyncState() {
  119. return this.examQuestion.order == this.$route.params.order;
  120. },
  121. newQuestionOptions() {
  122. return this.question.questionOptionList.map((v, i) => {
  123. return {
  124. value: this.question.questionOptionList[
  125. this.examQuestion.optionPermutation[i]
  126. ],
  127. oldIndex: "" + this.examQuestion.optionPermutation[i],
  128. name: optionName[i]
  129. };
  130. });
  131. },
  132. oldIndexToABCD() {
  133. return (
  134. this.examQuestion.studentAnswer &&
  135. this.newQuestionOptions
  136. .filter(v => this.examQuestion.studentAnswer.includes(v.oldIndex))
  137. .map(v => v.name)
  138. .join("")
  139. );
  140. },
  141. rightAnswerTransform() {
  142. return (
  143. this.question.rightAnswer &&
  144. this.newQuestionOptions
  145. .filter(v => this.question.rightAnswer.includes(v.oldIndex))
  146. .map(v => v.name)
  147. .join("")
  148. );
  149. }
  150. },
  151. components: {
  152. QuestionBody
  153. }
  154. };
  155. </script>
  156. <style scoped>
  157. .question-view {
  158. display: grid;
  159. grid-row-gap: 10px;
  160. }
  161. .question-body {
  162. font-size: 18px;
  163. margin-bottom: 10px;
  164. }
  165. .ops {
  166. display: flex;
  167. align-items: flex-end;
  168. }
  169. .stu-answer {
  170. width: 100px;
  171. border-bottom: 1px solid black;
  172. text-align: center;
  173. height: 20px;
  174. }
  175. .option {
  176. display: flex;
  177. }
  178. .question-options {
  179. text-align: left;
  180. }
  181. </style>