Ver Fonte

录音预览控制条

natasha há 1 ano atrás
pai
commit
82e084af8d

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

@@ -4,6 +4,7 @@
       :class="[url ? 'audio-play' : 'audio-play not-url']"
       :style="{
         padding: showSlider ? '4px 16px' : '',
+        width: showSlider ? 'auto' : '',
       }"
       @click="playAudio"
     >
@@ -78,7 +79,6 @@ export default {
       },
       play_value: 0,
       audio_allTime: null, // 展示总时间
-      aduio_currentTime: null, // 剩余时间
     };
   },
   computed: {
@@ -182,7 +182,7 @@ export default {
     column-gap: 8px;
     align-items: center;
     justify-content: center;
-    min-width: 40px;
+    width: 40px;
     height: 40px;
     color: #fff;
     cursor: pointer;

+ 1 - 3
src/views/exercise_questions/preview/RepeatPreview.vue

@@ -92,9 +92,7 @@ export default {
       margin-bottom: 16px;
 
       .option-content {
-        flex: 1;
-
-        // max-width: 306px;
+        width: 480px;
         padding: 8px 16px;
         color: #706f78;
         background-color: $content-color;

+ 6 - 1
src/views/exercise_questions/preview/ReplaceAnswerPreview.vue

@@ -149,6 +149,7 @@ export default {
   .option-list {
     display: flex;
     flex-wrap: wrap;
+    align-items: center;
     justify-content: center;
     width: max-content;
     margin: 0 auto;
@@ -203,7 +204,11 @@ export default {
     }
   }
 
-  .sound-record-wrapper {
+  .sound-record-preview {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: center;
+    width: 280px;
     margin-left: 80px;
   }
 }

+ 174 - 41
src/views/exercise_questions/preview/components/common/SoundRecordPreview.vue

@@ -1,38 +1,66 @@
 <template>
-  <div :class="['sound-record-wrapper', 'sound-record-wrapper-' + type]" :style="{ justifyContent: position }">
-    <div class="sound-item sound-item-luyin">
-      <img
-        v-if="microphoneStatus"
-        :src="require('../../../../../assets/record-ing-hasBg.png')"
-        class="voice-play"
-        @click="microphone"
+  <div class="sound-record-preview">
+    <div v-if="type === 'big' && file_url" class="audio-slider-box audio-slider-box-big">
+      <span class="audio-time">{{ secondFormatConversion(audio.current_time) }}</span>
+      <el-slider
+        v-model="play_value"
+        class="audio-slider"
+        :format-tooltip="formatProcessToolTip"
+        @change="changeCurrentTime"
       />
-      <span v-else class="sound-item-span" @click="microphone">
-        <SvgIcon icon-class="mic-line" :size="iconSize" class="record" />
-      </span>
-
-      <label v-if="type === 'big'" :class="['record-time', microphoneStatus ? 'record-ing' : '']">
-        {{ audio.paused ? '' : '-' }}{{ secondFormatConversion(recordTimes) }}
-      </label>
+      <span class="audio-time">{{ audio_allTime }}</span>
     </div>
-    <div v-if="type === 'small'" class="sound-item">
-      <label :class="['record-time', microphoneStatus ? 'record-ing' : '']">
+    <div :class="['sound-record-wrapper', 'sound-record-wrapper-' + type]" :style="{ justifyContent: position }">
+      <div class="sound-item sound-item-luyin">
+        <img
+          v-if="microphoneStatus"
+          :src="require('../../../../../assets/record-ing-hasBg.png')"
+          class="voice-play"
+          @click="microphone"
+        />
+        <span v-else class="sound-item-span" @click="microphone">
+          <SvgIcon icon-class="mic-line" :size="iconSize" class="record" />
+        </span>
+
+        <label v-if="type === 'big'" :class="['record-time', microphoneStatus ? 'record-ing' : '']">
+          {{ microphoneStatus ? secondFormatConversion(recordTimes) : '录音' }}
+        </label>
+      </div>
+      <div v-if="type === 'small' && file_url" class="sound-item audio-slider-box">
+        <span class="audio-time">{{ secondFormatConversion(audio.current_time) }}</span>
+        <el-slider
+          v-model="play_value"
+          class="audio-slider"
+          :format-tooltip="formatProcessToolTip"
+          @change="changeCurrentTime"
+        />
+        <span class="audio-time">{{ audio_allTime }}</span>
+      </div>
+
+      <label v-if="type === 'small' && !file_url" :class="['record-time', microphoneStatus ? 'record-ing' : '']">
         {{ audio.paused ? '' : '-' }}{{ secondFormatConversion(recordTimes) }}
       </label>
+      <div class="sound-item">
+        <span :class="['sound-item-span sound-item-btn', wavBlob ? '' : 'not-url']" @click="playMicrophone">
+          <SvgIcon :icon-class="iconClass" :size="iconSize" :class="['audio-play-btn']" />
+        </span>
+        <label v-if="type === 'big'" class="tips">回放</label>
+      </div>
+      <div class="sound-item">
+        <span :class="['sound-item-span sound-item-btn', wavBlob ? '' : 'not-url']" @click="delectWav">
+          <SvgIcon icon-class="delete-back-line" :size="iconSize" :class="['delete-btn']" />
+        </span>
+        <label v-if="type === 'big'" class="tips">删除</label>
+      </div>
     </div>
-    <div class="sound-item">
-      <span :class="['sound-item-span sound-item-btn', wavBlob ? '' : 'not-url']" @click="playMicrophone">
-        <SvgIcon :icon-class="iconClass" :size="iconSize" :class="['audio-play-btn']" />
-      </span>
-      <label v-if="type === 'big'" class="tips">回放</label>
-    </div>
-    <div class="sound-item">
-      <span :class="['sound-item-span sound-item-btn', wavBlob ? '' : 'not-url']" @click="delectWav">
-        <SvgIcon icon-class="delete-back-line" :size="iconSize" :class="['delete-btn']" />
-      </span>
-      <label v-if="type === 'big'" class="tips">删除</label>
-    </div>
-    <audio ref="audio" :src="file_url" preload="metadata"></audio>
+    <audio
+      :ref="wavBlob"
+      :src="file_url"
+      preload="metadata"
+      @loadedmetadata="onLoadedmetadata"
+      @timeupdate="onTimeupdate"
+      @canplaythrough="oncanplaythrough"
+    ></audio>
   </div>
 </template>
 
@@ -74,13 +102,22 @@ export default {
       timer: null, // 计时器
       microphoneStatus: false, // 是否录音
       hasMicro: '', // 录音后的样式class
-      audio: {
-        paused: true,
-      },
       playtime: 0, // 播放时间
       recordTimes: 0,
       file_url: '',
       recordTime: 0,
+      audio: {
+        paused: true,
+        playing: false,
+        // 音频当前播放时长
+        current_time: 0,
+        // 音频最大播放时长
+        max_time: 0,
+        isPlaying: false,
+        loading: false,
+      },
+      play_value: 0,
+      audio_allTime: null, // 展示总时间
     };
   },
   computed: {
@@ -110,13 +147,13 @@ export default {
     },
   },
   mounted() {
-    this.$refs.audio.addEventListener('ended', () => {
+    this.$refs[this.wavBlob].addEventListener('ended', () => {
       this.audio.paused = true;
     });
-    this.$refs.audio.addEventListener('pause', () => {
+    this.$refs[this.wavBlob].addEventListener('pause', () => {
       this.audio.paused = true;
     });
-    this.$refs.audio.addEventListener('play', () => {
+    this.$refs[this.wavBlob].addEventListener('play', () => {
       this.audio.paused = false;
     });
   },
@@ -128,7 +165,7 @@ export default {
           this.hasMicro = 'active';
           // this.$refs.audio.pause();
           // this.$refs.audio.load();
-          this.$refs.audio.play();
+          this.$refs[this.wavBlob].play();
           if (this.recordTimes === 0) {
             this.recordTimes = JSON.parse(JSON.stringify(this.recordTime));
             this.playtime = 0;
@@ -145,7 +182,7 @@ export default {
             }
           }, 1000);
         } else {
-          this.$refs.audio.pause();
+          this.$refs[this.wavBlob].pause();
           this.hasMicro = 'normal';
           clearInterval(this.timer);
         }
@@ -154,7 +191,7 @@ export default {
     // 开始录音
     microphone() {
       if (!this.audio.paused) {
-        this.$refs.audio.pause();
+        this.$refs[this.wavBlob].pause();
         this.audio.paused = true;
       }
       if (this.disabled) return;
@@ -194,7 +231,7 @@ export default {
     },
     // 删除录音
     delectWav() {
-      this.$refs.audio.pause();
+      this.$refs[this.wavBlob].pause();
       this.hasMicro = '';
       this.microphoneStatus = false;
       this.playtime = 0;
@@ -202,6 +239,50 @@ export default {
       clearInterval(this.timer);
       this.$emit('update:wavBlob', '');
     },
+    // 进度条格式化toolTip
+    formatProcessToolTip(index) {
+      let indexs = parseInt((this.audio.max_time / 100) * index);
+      return secondFormatConversion(indexs);
+    },
+    // 点击 拖拽播放音频
+    changeCurrentTime(value) {
+      let audioId = this.wavBlob;
+      this.$refs[audioId].play();
+      this.audio.playing = true;
+      this.$refs[audioId].currentTime = parseInt((value / 100) * this.audio.max_time);
+    },
+    // 音频加载完之后
+    onLoadedmetadata(res) {
+      this.audio.max_time = parseInt(res.target.duration);
+      this.audio_allTime = secondFormatConversion(this.audio.max_time);
+    },
+    // 当音频当前时间改变后,进度条也要改变
+    onTimeupdate(res) {
+      let audioId = this.wavBlob;
+      this.audio.current_time = res.target.currentTime;
+      this.play_value = (this.audio.current_time / this.audio.max_time) * 100;
+      if (this.audio.current_time * 1000 > this.ed) {
+        this.$refs[audioId].pause();
+      }
+    },
+    onTimeupdateTime(res, playFlag) {
+      if (!res && res !== 0) return;
+      let audioId = this.wavBlob;
+      this.$refs[audioId].currentTime = res;
+      this.play_value = (res / this.audio.max_time) * 100;
+      if (playFlag) {
+        let audio = document.getElementsByTagName('audio');
+        audio.forEach((item) => {
+          if (item.id !== audioId) {
+            item.pause();
+          }
+        });
+        this.$refs[audioId].play();
+      }
+    },
+    oncanplaythrough() {
+      this.audio.loading = false;
+    },
   },
 };
 </script>
@@ -259,9 +340,8 @@ export default {
     display: block;
     margin-top: 4px;
     font-size: 12px;
-    font-weight: 500;
     line-height: 20px;
-    color: #000;
+    color: rgba(0, 0, 0, 50%);
   }
 
   &-small {
@@ -287,4 +367,57 @@ export default {
     }
   }
 }
+
+.audio-slider-box {
+  display: flex;
+  column-gap: 8px;
+  align-items: center;
+
+  .audio-time {
+    min-width: 35px;
+    font-size: 12px;
+    font-weight: 400;
+    line-height: 20px;
+  }
+
+  .audio-slider {
+    width: 82px;
+    height: 32px;
+
+    :deep .el-slider__runway {
+      height: 4px;
+      margin: 14px 0;
+      background-color: #dadada;
+    }
+
+    :deep .el-slider__button {
+      width: 4px;
+      height: 4px;
+      background-color: #000;
+      border: none;
+    }
+
+    :deep .el-slider__bar {
+      height: 4px;
+      background-color: #000;
+    }
+
+    :deep .el-slider__button-wrapper {
+      top: -16px;
+    }
+  }
+
+  &-big {
+    width: 280px;
+    height: 40px;
+    padding: 4px 12px;
+    margin: 16px auto;
+    background-color: #ededed;
+    border-radius: 28px;
+
+    .audio-slider {
+      width: 178px;
+    }
+  }
+}
 </style>