JudgePreview.vue 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <!-- eslint-disable vue/no-v-html -->
  2. <template>
  3. <div class="judge-preview">
  4. <div class="stem">
  5. <span class="question-number" :style="{ fontSize: data.property.stem_question_number_font_size }">
  6. {{ questionNumberEndIsBracket(data.property.question_number) }}
  7. </span>
  8. <span v-html="sanitizeHTML(data.stem)"></span>
  9. </div>
  10. <div
  11. v-if="isEnable(data.property.is_enable_description)"
  12. class="description rich-text"
  13. v-html="sanitizeHTML(data.description)"
  14. ></div>
  15. <ul class="option-list">
  16. <li
  17. v-for="({ content, mark }, i) in data.option_list"
  18. :key="mark"
  19. :class="['option-item', { active: isAnswer(mark) }]"
  20. >
  21. <div :class="['option-content', computedIsJudgeRight(mark)]">
  22. <span class="serial-number" :style="{ fontSize: data.property.option_question_number_font_size }">
  23. {{ computedQuestionNumber(i, data.option_number_show_mode) }}
  24. </span>
  25. <div class="rich-text" v-html="sanitizeHTML(content)"></div>
  26. </div>
  27. <div class="option-type">
  28. <div
  29. v-for="option_type in data.property.option_type_list"
  30. :key="option_type"
  31. :style="{ cursor: disabled ? 'not-allowed' : 'pointer' }"
  32. :class="[
  33. 'option-type-item',
  34. {
  35. active: isAnswer(mark, option_type),
  36. },
  37. computedIsShowRightAnswer(mark, option_type),
  38. ]"
  39. @click="selectAnswer(mark, option_type)"
  40. >
  41. <SvgIcon v-if="option_type === option_type_list[0].value" icon-class="check-mark" width="17" height="12" />
  42. <SvgIcon v-if="option_type === option_type_list[1].value" icon-class="cross" size="12" />
  43. <SvgIcon v-if="option_type === option_type_list[2].value" icon-class="circle" size="20" />
  44. </div>
  45. </div>
  46. </li>
  47. </ul>
  48. </div>
  49. </template>
  50. <script>
  51. import { option_type_list } from '@/views/exercise_questions/data/judge';
  52. import { computedQuestionNumber } from '@/views/exercise_questions/data/common';
  53. import PreviewMixin from './components/PreviewMixin';
  54. export default {
  55. name: 'JudgePreview',
  56. mixins: [PreviewMixin],
  57. data() {
  58. return {
  59. computedQuestionNumber,
  60. option_type_list,
  61. };
  62. },
  63. methods: {
  64. /**
  65. * 判断是否已选中
  66. * @param {string} mark 选项标识
  67. * @param {string} option_type 选项类型
  68. */
  69. isAnswer(mark, option_type) {
  70. return this.answer.answer_list.some((li) => li.mark === mark && li.option_type === option_type);
  71. },
  72. /**
  73. * 选择答案
  74. * @param {string} mark 选项标识
  75. * @param {string} option_type 选项类型
  76. */
  77. selectAnswer(mark, option_type) {
  78. if (this.disabled) return;
  79. const index = this.answer.answer_list.findIndex((li) => li.mark === mark);
  80. if (index === -1) {
  81. this.answer.answer_list.push({ mark, option_type });
  82. } else {
  83. this.answer.answer_list[index].option_type = option_type;
  84. }
  85. },
  86. /**
  87. * 计算是否显示正确答案的样式
  88. * @param {string} mark 选项标识
  89. * @param {string} option_type 选项类型
  90. */
  91. computedIsShowRightAnswer(mark, option_type) {
  92. if (!this.isShowRightAnswer) return '';
  93. let selectOption = this.answer.answer_list.find((item) => item.mark === mark); // 查找是否已选中的选项
  94. if (!selectOption) return '';
  95. return this.data.answer.answer_list.find((item) => item.mark === mark).option_type === option_type &&
  96. !(selectOption.option_type === option_type)
  97. ? 'answer-right'
  98. : '';
  99. },
  100. /**
  101. * 计算判断题题干的样式
  102. * @param {string} mark 选项标识
  103. */
  104. computedIsJudgeRight(mark) {
  105. if (!this.isJudgingRightWrong) return '';
  106. let selectOption = this.answer.answer_list.find((item) => item.mark === mark); // 查找是否已选中的选项
  107. if (!selectOption) return 'wrong';
  108. return this.data.answer.answer_list.find((item) => item.mark === mark).option_type === selectOption.option_type
  109. ? 'right'
  110. : 'wrong';
  111. },
  112. },
  113. };
  114. </script>
  115. <style lang="scss" scoped>
  116. @use '@/styles/mixin.scss' as *;
  117. .judge-preview {
  118. @include preview;
  119. .option-list {
  120. display: flex;
  121. flex-direction: column;
  122. row-gap: 16px;
  123. .option-item {
  124. display: flex;
  125. column-gap: 16px;
  126. .option-content {
  127. display: flex;
  128. flex: 1;
  129. column-gap: 8px;
  130. align-items: center;
  131. padding: 12px 24px;
  132. background-color: $content-color;
  133. border-radius: 40px;
  134. &.right {
  135. background-color: $right-bc-color;
  136. }
  137. &.wrong {
  138. box-shadow: 0 0 0 1px $error-color;
  139. }
  140. .serial-number {
  141. font-size: 16pt;
  142. color: #000;
  143. }
  144. }
  145. .option-type {
  146. display: flex;
  147. column-gap: 8px;
  148. align-items: center;
  149. &-item {
  150. display: flex;
  151. align-items: center;
  152. justify-content: center;
  153. width: 48px;
  154. height: 48px;
  155. color: #000;
  156. cursor: pointer;
  157. background-color: $content-color;
  158. border-radius: 50%;
  159. &.active {
  160. color: #fff;
  161. background-color: $light-main-color;
  162. }
  163. &.answer-right {
  164. color: $right-color;
  165. border: 1px solid $right-color;
  166. }
  167. }
  168. }
  169. }
  170. }
  171. }
  172. </style>