ReadPreview.vue 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <!-- eslint-disable vue/no-v-html -->
  2. <template>
  3. <div class="read-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. <div class="container">
  16. <div class="article rich-text" v-html="sanitizeHTML(data.article)"></div>
  17. <div class="question-list">
  18. <template v-if="isAnswer">
  19. <component
  20. :is="previewComponents[item.type]"
  21. v-for="(item, i) in question_list"
  22. :key="i"
  23. ref="preview"
  24. class="preview"
  25. :data="item"
  26. :is-enable-manual-modify="data.property.is_enable_manual_modify"
  27. @change="changeAnswer(i, item.type, $event)"
  28. />
  29. </template>
  30. <template v-else>
  31. <component
  32. :is="previewComponents[item.type]"
  33. v-for="(item, i) in childPreviewData"
  34. :key="i"
  35. class="preview"
  36. :data="item"
  37. :is-enable-manual-modify="data.property.is_enable_manual_modify"
  38. @change="changeAnswer(i, item.type, $event)"
  39. />
  40. </template>
  41. </div>
  42. </div>
  43. </div>
  44. </template>
  45. <script>
  46. import PreviewMixin from './components/PreviewMixin';
  47. import SelectPreview from '@/views/exercise_questions/preview/SelectPreview.vue';
  48. import JudgePreview from '@/views/exercise_questions/preview/JudgePreview.vue';
  49. import MatchingPreview from '@/views/exercise_questions/preview/MatchingPreview.vue';
  50. import FillPreview from '../preview/FillPreview.vue';
  51. import EssayQuestionPreview from './EssayQuestionPreview.vue';
  52. import { GetQuestionInfo } from '@/api/exercise';
  53. export default {
  54. name: 'ReadPreview',
  55. mixins: [PreviewMixin],
  56. props: {
  57. childPreviewData: {
  58. type: Array,
  59. default: () => [],
  60. },
  61. },
  62. data() {
  63. return {
  64. previewComponents: {
  65. select: SelectPreview,
  66. judge: JudgePreview,
  67. matching: MatchingPreview,
  68. fill: FillPreview,
  69. essay_question: EssayQuestionPreview,
  70. },
  71. question_list: [],
  72. };
  73. },
  74. computed: {
  75. // 是否答题
  76. isAnswer() {
  77. return this.childPreviewData.length === 0 && this.childPreviewData.length !== this.data.question_list;
  78. },
  79. },
  80. watch: {
  81. isAnswer: {
  82. handler(val) {
  83. if (val) {
  84. const promises = this.data.question_list.map(({ id }) => {
  85. return GetQuestionInfo({ question_id: id });
  86. });
  87. Promise.all(promises).then((res) => {
  88. this.question_list = res.map(({ question }) => {
  89. let content = JSON.parse(question.content);
  90. if (!question.content) return { answer_list: [] };
  91. content.id = question.id;
  92. return content;
  93. });
  94. });
  95. }
  96. },
  97. immediate: true,
  98. },
  99. },
  100. created() {
  101. this.$set(
  102. this.answer,
  103. 'question_list',
  104. this.data.question_list.map((item) => {
  105. return { id: item.id, type: item.type, answer_list: [] };
  106. }),
  107. );
  108. },
  109. methods: {
  110. /**
  111. * 改变答案
  112. * @param {number} i 序号
  113. * @param {string} type 类型
  114. * @param {object} param2
  115. * @param {array} param2.answer_list 答案列表
  116. */
  117. changeAnswer(i, type, { answer_list }) {
  118. if (this.disabled) return;
  119. if (this.answer.question_list[i] === undefined) return;
  120. this.answer.question_list[i].answer_list = answer_list;
  121. this.answer.question_list[i].type = type;
  122. },
  123. /**
  124. * 显示答案
  125. * @param {boolean} isJudgingRightWrong 是否判断对错
  126. * @param {boolean} isShowRightAnswer 是否显示正确答案
  127. * @param {Object} userAnswer 用户答案
  128. * @param {boolean} disabled 是否禁用
  129. */
  130. showAnswer(isJudgingRightWrong, isShowRightAnswer, userAnswer, disabled) {
  131. this.isJudgingRightWrong = isJudgingRightWrong;
  132. this.isShowRightAnswer = isShowRightAnswer;
  133. this.disabled = disabled;
  134. if (userAnswer) this.answer = userAnswer;
  135. if (this.question_list.length === this.answer.question_list.length) {
  136. return this.fillAnswer(isJudgingRightWrong, isShowRightAnswer, disabled);
  137. }
  138. this.$watch('question_list', (val) => {
  139. if (val.length !== this.answer.question_list.length) return;
  140. this.fillAnswer(isJudgingRightWrong, isShowRightAnswer, disabled);
  141. });
  142. },
  143. /**
  144. * 填充答案
  145. * @param {boolean} isJudgingRightWrong 是否判断对错
  146. * @param {boolean} isShowRightAnswer 是否显示正确答案
  147. * @param {boolean} disabled 是否禁用
  148. */
  149. fillAnswer(isJudgingRightWrong, isShowRightAnswer, disabled) {
  150. this.answer.question_list.forEach(({ id, answer_list }) => {
  151. const index = this.question_list.findIndex((item) => item.id === id);
  152. if (index !== -1) {
  153. this.$refs.preview[index].showAnswer(isJudgingRightWrong, isShowRightAnswer, { answer_list }, disabled);
  154. }
  155. });
  156. },
  157. },
  158. };
  159. </script>
  160. <style lang="scss" scoped>
  161. @use '@/styles/mixin.scss' as *;
  162. .read-preview {
  163. @include preview;
  164. .container {
  165. display: flex;
  166. flex-direction: column;
  167. column-gap: 24px;
  168. .article {
  169. padding: 24px 40px;
  170. color: #2f3742;
  171. background-color: $content-color;
  172. border-radius: 16px;
  173. :deep p {
  174. margin: 0;
  175. }
  176. }
  177. .question-list {
  178. display: flex;
  179. flex: 1;
  180. flex-direction: column;
  181. row-gap: 24px;
  182. .preview {
  183. min-height: 0;
  184. padding: 0;
  185. margin: 0;
  186. }
  187. }
  188. }
  189. }
  190. </style>