repeat-question.vue 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <template>
  2. <!-- 听说训练 -->
  3. <view class="repeat-area" v-model="questionData">
  4. <view class="question_title">
  5. <text class="question_number">
  6. {{ questionNumberEndIsBracket(questionData.property.question_number) }}
  7. </text>
  8. <text class="question_stem" v-html="sanitizeHTML(questionData.stem)"
  9. :ref="'richText-1-1'+questionData.question_id"
  10. @longpress="previewByRichTextImg(-1,-1,questionData.question_id)"></text>
  11. </view>
  12. <view class="description"
  13. v-if="isEnable(questionData.property.is_enable_description)&&questionData.description.length > 0"
  14. v-html="sanitizeHTML(questionData.description)" :ref="'richText-2-2'+questionData.question_id"
  15. @longpress="previewByRichTextImg(-2,-2,questionData.question_id)">
  16. </view>
  17. <view class="option-area">
  18. <view class="option-item" v-for="(item, i) in answer_list" :key="i">
  19. <text class="option-serial">{{ computedQuestionNumber(i,questionData.option_number_show_mode) }}</text>
  20. <view class="option-box">
  21. <AudioPlay v-if="questionData.option_list[i].audio_file_id"
  22. :file-id="questionData.option_list[i].audio_file_id" :showProgress="true" :showSlider="true"
  23. :isPlaying="questionData.option_list[i].isPlaying" :questionId="questionData.question_id" />
  24. <view class="option-content" v-if="questionData.option_list[i].content.length>0"
  25. v-html="sanitizeHTML(questionData.option_list[i].content)" :ref="'richText'+i+1+questionData.question_id"
  26. @longpress="previewByRichTextImg(i,1,questionData.question_id)"></view>
  27. <view class="sound-box">
  28. <SoundRecord :disabled="answer_control[questionData.question_id].isReadOnly"
  29. :wav-blob.sync="item.audio_file_id" type="small" />
  30. </view>
  31. </view>
  32. </view>
  33. </view>
  34. </view>
  35. </template>
  36. <script>
  37. import {
  38. questionData,
  39. sanitizeHTML,
  40. isEnable,
  41. computedQuestionNumber,
  42. answer_control,
  43. } from '@/pages/answer_question/common/data/common.js';
  44. import {
  45. GetFileStoreInfo
  46. } from '@/api/api.js';
  47. import SoundRecord from '@/components/sound-record/sound-record.vue';
  48. import AnswerControlMixin from '@/pages/answer_question/common/data/AnswerControlMixin.js';
  49. export default {
  50. name: "repeat-question",
  51. mixins: [AnswerControlMixin],
  52. props: {
  53. questionData: questionData
  54. },
  55. components: {
  56. SoundRecord
  57. },
  58. data() {
  59. return {
  60. sanitizeHTML,
  61. isEnable,
  62. computedQuestionNumber,
  63. answer_control,
  64. answer_list: [],
  65. curMark: '',
  66. };
  67. },
  68. watch: {
  69. answer_list: {
  70. handler(val) {
  71. if (this.isAnswerReady)
  72. this.saveUserAnswer();
  73. },
  74. deep: true,
  75. immediate: true,
  76. },
  77. 'questionData.question_id': {
  78. handler(val) {
  79. this.commonComputedAnswerControl(val);
  80. this.isAnswerReady = true;
  81. this.setUserAnswer();
  82. },
  83. immediate: true,
  84. deep: true
  85. }
  86. },
  87. created() {
  88. this.handleData();
  89. },
  90. mounted() {
  91. uni.$on('setOtherAudioPlaying', this.otherAudioPlaying);
  92. },
  93. onUnload() {
  94. uni.$off('setOtherAudioPlaying', this.otherAudioPlaying);
  95. },
  96. methods: {
  97. // 初始化数据
  98. handleData() {
  99. this.answer_list = [];
  100. this.questionData.option_list.forEach((item) => {
  101. item.isPlaying = false;
  102. let obj = {
  103. mark: item.mark,
  104. audio_file_id: '' //用户答案录音
  105. };
  106. this.answer_list.push(obj);
  107. if (!item.audio_file_id) return false;
  108. GetFileStoreInfo({
  109. file_id: item.audio_file_id
  110. }).then((res) => {
  111. item.audio_file_url = res.file_url; //题目音频
  112. });
  113. });
  114. },
  115. //播放当前音频的时候暂停其他音频
  116. otherAudioPlaying(audio_file_id, playing) {
  117. this.questionData.option_list.forEach(p => {
  118. p.isPlaying = false;
  119. if (p.audio_file_id == audio_file_id) {
  120. p.isPlaying = true;
  121. }
  122. });
  123. this.$forceUpdate();
  124. },
  125. //填写答案后保存答案
  126. saveUserAnswer: function() {
  127. var that = this;
  128. var questionId = this.questionData.question_id;
  129. this.questionData.user_answer[questionId].isEdit = true;
  130. var ansed = that.answer_list;
  131. this.questionData.user_answer[questionId].is_fill_answer =
  132. ansed.filter(p => p.audio_file_id).length > 0;
  133. this.questionData.user_answer[questionId].content = JSON.stringify(ansed);
  134. this.questionData.user_answer[questionId].answer_list = ansed;
  135. },
  136. //获取用户答案
  137. setUserAnswer: function() {
  138. var that = this;
  139. var callback = function() {
  140. var questionId = that.questionData.question_id;
  141. if (that.questionData.user_answer[questionId].answer_list.length > 0)
  142. that.answer_list = that.questionData.user_answer[questionId].answer_list;
  143. }
  144. this.$emit("getUserAnswer", this.questionData.question_id, callback);
  145. },
  146. },
  147. }
  148. </script>
  149. <style lang="scss" scoped>
  150. .repeat-area {
  151. .option-area {
  152. margin-top: 32rpx;
  153. display: flex;
  154. flex-direction: column;
  155. row-gap: 32rpx;
  156. .option-item {
  157. display: flex;
  158. align-items: flex-start;
  159. justify-content: left;
  160. column-gap: 16rpx;
  161. .option-serial {
  162. font-size: $font-size-serial;
  163. width: 36rpx;
  164. margin-top: 10rpx;
  165. }
  166. .option-box {
  167. width: 100%;
  168. display: flex;
  169. flex-direction: column;
  170. row-gap: 16rpx;
  171. .option-content {
  172. background-color: $uni-bg-color-grey;
  173. padding: 16rpx 32rpx;
  174. border-radius: 40rpx;
  175. font-size: $font-size-serial;
  176. font-weight: 500;
  177. }
  178. /deep/ .sound-record-wrapper {
  179. background-color: $uni-bg-color-grey;
  180. padding: 8rpx;
  181. border-radius: 80rpx;
  182. margin-top: 0;
  183. width: fit-content;
  184. }
  185. }
  186. }
  187. }
  188. .audio-wrapper {
  189. margin: 0;
  190. }
  191. }
  192. </style>