Browse Source

Merge branch 'master' of http://60.205.254.193:3000/GCLS/GCLS_Page_Exercise

dusenyao 1 year ago
parent
commit
225d5218cb

+ 12 - 6
src/views/exercise_questions/create/components/common/AudioPlay.vue

@@ -12,7 +12,7 @@
         class="voice-play"
       />
     </span>
-    <audio ref="audio" :src="url" preload="metadata"></audio>
+    <audio :id="fileId" :ref="fileId" :src="url" preload="metadata"></audio>
   </div>
 </template>
 
@@ -56,24 +56,30 @@ export default {
     },
   },
   mounted() {
-    this.$refs.audio.addEventListener('ended', () => {
+    this.$refs[this.fileId].addEventListener('ended', () => {
       this.audio.paused = true;
     });
-    this.$refs.audio.addEventListener('pause', () => {
+    this.$refs[this.fileId].addEventListener('pause', () => {
       this.audio.paused = true;
     });
-    this.$refs.audio.addEventListener('play', () => {
+    this.$refs[this.fileId].addEventListener('play', () => {
       this.audio.paused = false;
     });
   },
   methods: {
     playAudio() {
       if (!this.url) return;
-      const audio = this.$refs.audio;
+      const audio = this.$refs[this.fileId];
       let audioArr = document.getElementsByTagName('audio');
       if (audioArr && audioArr.length > 0) {
         for (let i = 0; i < audioArr.length; i++) {
-          audioArr[i].pause();
+          if (audioArr[i].src === this.url) {
+            if (audioArr[i].id !== this.fileId) {
+              audioArr[i].pause();
+            }
+          } else {
+            audioArr[i].pause();
+          }
         }
       }
       audio.paused ? audio.play() : audio.pause();

+ 11 - 7
src/views/exercise_questions/create/components/exercises/RepeatQuestion.vue

@@ -36,12 +36,12 @@
             </div>
             <UploadAudio
               :key="item.audio_file_id || i"
-              :file-id="item.file_id_list?.[0]"
+              :file-id="item.audio_file_id"
               :item-index="i"
               @upload="uploads"
               @deleteFile="deleteFiles"
             />
-            <SvgIcon icon-class="delete" class="delete pointer" @click="deleteOption(i)" />
+            <SvgIcon icon-class="delete" class="delete pointer" @click="deleteOption(i, item.audio_file_id)" />
           </li>
         </ul>
       </div>
@@ -146,13 +146,17 @@ export default {
       this.data.option_list.push(getOption());
     },
     uploads(file_id, index) {
-      this.data.option_list[index].file_id_list.push(file_id);
+      this.data.option_list[index].audio_file_id = file_id;
+      this.data.file_id_list.push(file_id);
     },
     deleteFiles(file_id, itemIndex) {
-      let index = this.data.option_list[itemIndex].file_id_list.indexOf(file_id);
-      if (index !== -1) {
-        this.data.option_list[itemIndex].file_id_list.splice(index, 1);
-      }
+      this.data.option_list[itemIndex].audio_file_id = '';
+      this.data.file_id_list.splice(this.data.file_id_list.indexOf(file_id), 1);
+    },
+    // 删除小题
+    deleteOption(i, file_id) {
+      this.data.option_list.splice(i, 1);
+      this.data.file_id_list.splice(this.data.file_id_list.indexOf(file_id), 1);
     },
   },
 };

+ 7 - 7
src/views/exercise_questions/data/repeat.js

@@ -2,7 +2,7 @@ import { optionTypeList, stemTypeList, scoreTypeList, questionNumberTypeList } f
 import { getRandomNumber } from '@/utils/index';
 
 export function getOption(content = '') {
-  return { content, mark: getRandomNumber(), file_id_list: [] };
+  return { content, mark: getRandomNumber(), audio_file_id: '' };
 }
 
 // 听后训练数据模板
@@ -12,17 +12,17 @@ export const repeatData = {
   option_number_show_mode: optionTypeList[0].value, // 选项类型
   description: '', // 描述
   option_list: [
-    { content: '', mark: getRandomNumber(), file_id_list: [] },
-    { content: '', mark: getRandomNumber(), file_id_list: [] },
-    { content: '', mark: getRandomNumber(), file_id_list: [] },
+    { content: '', mark: getRandomNumber(), audio_file_id: '' },
+    { content: '', mark: getRandomNumber(), audio_file_id: '' },
+    { content: '', mark: getRandomNumber(), audio_file_id: '' },
   ], // 选项
-
-  answer: { answer_list: [], score: 0, score_type: scoreTypeList[0].value }, // 答案
+  file_id_list: [],
+  answer: { score: 0, score_type: scoreTypeList[0].value }, // 答案
   // 题型属性
   property: {
     stem_type: stemTypeList[0].value, // 题干类型
     question_number: 1, // 题号
-    is_enable_description: false, // 描述
+    is_enable_description: 'false', // 描述
     score: 1, // 分值
     score_type: scoreTypeList[0].value, // 分值类型
   },

+ 1 - 1
src/views/exercise_questions/preview/ChooseTonePreview.vue

@@ -266,7 +266,7 @@ export default {
 
   .option-list {
     display: flex;
-    flex-flow: column wrap;
+    flex-wrap: wrap;
     row-gap: 16px;
 
     .option-item {

+ 83 - 2
src/views/exercise_questions/preview/RepeatPreview.vue

@@ -6,19 +6,70 @@
       <span v-html="sanitizeHTML(data.stem)"></span>
     </div>
     <div v-if="isEnable(data.property.is_enable_description)" class="description">{{ data.description }}</div>
+    <div class="option-list">
+      <li v-for="(item, i) in data.option_list" :key="i" :class="['option-item']">
+        <span>{{ computeOptionMethods[data.option_number_show_mode](i) }}. </span>
+        <AudioPlay v-if="item.audio_file_id" :file-id="item.audio_file_id" />
+        <div class="option-content" v-html="sanitizeHTML(item.content)"></div>
+        <div class="sound-box">
+          <SoundRecordPreview
+            :wav-blob="answer_list[i].audio_file_id"
+            :record-time="answer_list[i].audio_wav_time"
+            :item-index="i"
+            :type="'small'"
+            @deleteWav="deleteWav"
+            @updateWav="updateWav"
+          />
+        </div>
+      </li>
+    </div>
   </div>
 </template>
 
 <script>
 import PreviewMixin from './components/PreviewMixin';
+import { computeOptionMethods } from '@/views/exercise_questions/data/common';
+import SoundRecordPreview from './components/common/SoundRecordPreview.vue';
 
 export default {
   name: 'RepeatPreview',
+  components: {
+    SoundRecordPreview,
+  },
   mixins: [PreviewMixin],
   data() {
-    return {};
+    return {
+      computeOptionMethods,
+      answer_list: [],
+    };
+  },
+  created() {
+    this.handleData();
+  },
+  methods: {
+    // 初始化数据
+    handleData() {
+      this.answer_list = [];
+      this.data.option_list.forEach((item) => {
+        let obj = {
+          mark: item.mark,
+          audio_file_id: '',
+          audio_wav_time: 0,
+        };
+        this.answer_list.push(obj);
+      });
+    },
+    // 清除录音
+    deleteWav(index) {
+      this.answer_list[index].audio_file_id = '';
+      this.answer_list[index].audio_wav_time = 0;
+    },
+    // 更新录音内容和时间
+    updateWav(wav, time, index) {
+      this.answer_list[index].audio_file_id = wav;
+      this.answer_list[index].audio_wav_time = time;
+    },
   },
-  methods: {},
 };
 </script>
 
@@ -27,5 +78,35 @@ export default {
 
 .repeat-preview {
   @include preview;
+
+  .option-list {
+    display: flex;
+    flex-wrap: wrap;
+    row-gap: 16px;
+
+    .option-item {
+      display: flex;
+      column-gap: 16px;
+      align-items: center;
+      min-width: 40%;
+      max-width: 50%;
+      padding-right: 24px;
+
+      .option-content {
+        flex: 1;
+        max-width: 306px;
+        padding: 12px 24px;
+        color: #706f78;
+        background-color: #f9f8f9;
+        border-radius: 40px;
+      }
+
+      .sound-box {
+        padding: 4px;
+        background: #f9f8f9;
+        border-radius: 40px;
+      }
+    }
+  }
 }
 </style>

+ 46 - 11
src/views/exercise_questions/preview/components/common/SoundRecordPreview.vue

@@ -1,5 +1,5 @@
 <template>
-  <div class="sound-record-wrapper">
+  <div :class="['sound-record-wrapper', 'sound-record-wrapper-' + type]">
     <div class="sound-item sound-item-luyin">
       <img
         v-if="microphoneStatus"
@@ -8,24 +8,28 @@
         @click="microphone"
       />
       <span v-else class="sound-item-span" @click="microphone">
-        <SvgIcon icon-class="mic-line" :size="24" class="record" />
+        <SvgIcon icon-class="mic-line" :size="type === 'big' ? 24 : 16" class="record" />
       </span>
 
+      <label v-if="type === 'big'" :class="['record-time', microphoneStatus ? 'record-ing' : '']">{{
+        handleDateTime(recordTimes)
+      }}</label>
+    </div>
+    <div v-if="type === 'small'" class="sound-item">
       <label :class="['record-time', microphoneStatus ? 'record-ing' : '']">{{ handleDateTime(recordTimes) }}</label>
     </div>
     <div class="sound-item">
       <span :class="['sound-item-span', wavBlob ? '' : 'not-url']" @click="playMicrophone">
-        <SvgIcon :icon-class="iconClass" :size="24" :class="['audio-play-btn']" />
+        <SvgIcon :icon-class="iconClass" :size="type === 'big' ? 24 : 16" :class="['audio-play-btn']" />
       </span>
-      <label class="tips">回放</label>
+      <label v-if="type === 'big'" class="tips">回放</label>
     </div>
     <div class="sound-item">
       <span :class="['sound-item-span', wavBlob ? '' : 'not-url']" @click="delectWav">
-        <SvgIcon icon-class="delete-back-line" :size="24" :class="['delete-btn']" />
+        <SvgIcon icon-class="delete-back-line" :size="type === 'big' ? 24 : 16" :class="['delete-btn']" />
       </span>
-      <label class="tips">删除</label>
+      <label v-if="type === 'big'" class="tips">删除</label>
     </div>
-
     <audio ref="audio" :src="wavBlob" preload="metadata"></audio>
   </div>
 </template>
@@ -43,6 +47,14 @@ export default {
       type: Number,
       default: 0,
     },
+    itemIndex: {
+      type: Number,
+      default: null,
+    },
+    type: {
+      type: String,
+      default: 'big',
+    },
   },
   data() {
     return {
@@ -137,11 +149,11 @@ export default {
         let reader = new window.FileReader();
         reader.readAsDataURL(wav);
         reader.onloadend = () => {
-          this.$emit('updateWav', reader.result, Math.floor(tolTime));
+          this.$emit('updateWav', reader.result, Math.floor(tolTime), this.itemIndex);
         };
       } else {
         this.hasMicro = '';
-        this.$emit('updateWav', '', 0);
+        this.$emit('updateWav', '', 0, this.itemIndex);
         // 开始录音
         this.recorder.start();
         this.microphoneStatus = true;
@@ -160,7 +172,7 @@ export default {
       this.playtime = 0;
       this.recordTimes = 0;
       clearInterval(this.timer);
-      this.$emit('deleteWav');
+      this.$emit('deleteWav', this.itemIndex);
     },
   },
 };
@@ -169,10 +181,10 @@ export default {
 <style lang="scss" scoped>
 .sound-record-wrapper {
   display: flex;
+  column-gap: 18px;
   align-items: center;
 
   .sound-item {
-    margin-right: 16px;
     text-align: center;
 
     .sound-item-span {
@@ -223,5 +235,28 @@ export default {
     line-height: 20px;
     color: #000;
   }
+
+  &-small {
+    column-gap: 8px;
+
+    .sound-item {
+      .sound-item-span {
+        width: 32px;
+        height: 32px;
+        padding: 8px;
+      }
+
+      .voice-play {
+        width: 32px;
+        height: 32px;
+      }
+    }
+
+    .record-time {
+      min-width: 40px;
+      margin-top: 0;
+      text-align: center;
+    }
+  }
 }
 </style>