|
@@ -0,0 +1,253 @@
|
|
|
+<template>
|
|
|
+ <div class="audio-wrapper">
|
|
|
+ <template v-if="'big' === viewSize">
|
|
|
+ <div class="audio-icon">
|
|
|
+ <SvgIcon icon-class="pre" />
|
|
|
+ <SvgIcon :icon-class="iconClass" size="30" @click="playAudio" />
|
|
|
+ <SvgIcon icon-class="next" />
|
|
|
+ <SvgIcon icon-class="1x" size="12" />
|
|
|
+ </div>
|
|
|
+ <div v-if="showSlider" class="slider-area">
|
|
|
+ <span class="audio-time">{{ secondFormatConversion(audio.current_time) }} / {{ audio_allTime }}</span>
|
|
|
+ <el-slider
|
|
|
+ v-model="play_value"
|
|
|
+ class="audio-slider"
|
|
|
+ :format-tooltip="formatProcessToolTip"
|
|
|
+ @change="changeCurrentTime"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div v-else>
|
|
|
+ <div class="audio-small">
|
|
|
+ <span>{{ audioIndex + 1 }}.</span>
|
|
|
+ <SvgIcon
|
|
|
+ v-if="(audioIndex === curAudioIndex && 'list' != viewMethod) || 'list' === viewMethod"
|
|
|
+ :icon-class="iconClass"
|
|
|
+ size="14"
|
|
|
+ @click="playAudio"
|
|
|
+ />
|
|
|
+ <span class="audio-time">{{ audio_allTime }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <audio
|
|
|
+ :id="fileId"
|
|
|
+ :ref="fileId"
|
|
|
+ :src="url"
|
|
|
+ preload="metadata"
|
|
|
+ @loadedmetadata="onLoadedmetadata"
|
|
|
+ @timeupdate="onTimeupdate"
|
|
|
+ @canplaythrough="oncanplaythrough"
|
|
|
+ ></audio>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { GetFileURLMap } from '@/api/app';
|
|
|
+import { secondFormatConversion } from '@/utils/transform';
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: 'AudioPlay',
|
|
|
+ props: {
|
|
|
+ fileId: {
|
|
|
+ type: String,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ viewSize: {
|
|
|
+ type: String,
|
|
|
+ required: true,
|
|
|
+ },
|
|
|
+ viewMethod: {
|
|
|
+ type: String,
|
|
|
+ default: 'independent',
|
|
|
+ },
|
|
|
+ audioIndex: {
|
|
|
+ type: Number,
|
|
|
+ default: 0,
|
|
|
+ },
|
|
|
+ curAudioIndex: {
|
|
|
+ type: Number,
|
|
|
+ default: 0,
|
|
|
+ },
|
|
|
+ showSlider: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ },
|
|
|
+ // 是否显示音频进度条
|
|
|
+ showProgress: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ secondFormatConversion,
|
|
|
+ url: '',
|
|
|
+ audio: {
|
|
|
+ paused: true,
|
|
|
+ playing: false,
|
|
|
+ // 音频当前播放时长
|
|
|
+ current_time: 0,
|
|
|
+ // 音频最大播放时长
|
|
|
+ max_time: 0,
|
|
|
+ isPlaying: false,
|
|
|
+ loading: false,
|
|
|
+ },
|
|
|
+ play_value: 0,
|
|
|
+ audio_allTime: null, // 展示总时间
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ iconClass() {
|
|
|
+ return this.audio.paused ? 'paused' : 'playing';
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ fileId: {
|
|
|
+ handler(val) {
|
|
|
+ if (!val) return;
|
|
|
+ GetFileURLMap({ file_id_list: [val] }).then(({ url_map }) => {
|
|
|
+ this.url = url_map[val];
|
|
|
+ });
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ if (!this.fileId) return;
|
|
|
+ this.$refs[this.fileId].addEventListener('ended', () => {
|
|
|
+ this.audio.paused = true;
|
|
|
+ });
|
|
|
+ this.$refs[this.fileId].addEventListener('pause', () => {
|
|
|
+ this.audio.paused = true;
|
|
|
+ });
|
|
|
+ this.$refs[this.fileId].addEventListener('play', () => {
|
|
|
+ this.audio.paused = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ playAudio() {
|
|
|
+ if (!this.url) return;
|
|
|
+ const audio = this.$refs[this.fileId];
|
|
|
+ let audioArr = document.getElementsByTagName('audio');
|
|
|
+ if (audioArr && audioArr.length > 0) {
|
|
|
+ for (let i = 0; i < audioArr.length; i++) {
|
|
|
+ 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();
|
|
|
+ },
|
|
|
+ // 进度条格式化toolTip
|
|
|
+ formatProcessToolTip(index) {
|
|
|
+ let _index = parseInt((this.audio.max_time / 100) * index);
|
|
|
+ return secondFormatConversion(_index);
|
|
|
+ },
|
|
|
+ // 点击 拖拽播放音频
|
|
|
+ changeCurrentTime(value) {
|
|
|
+ let audioId = this.fileId;
|
|
|
+ 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.fileId;
|
|
|
+ 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.audioId;
|
|
|
+ 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>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.audio-wrapper {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ row-gap: 38px;
|
|
|
+
|
|
|
+ .audio-icon {
|
|
|
+ display: flex;
|
|
|
+ column-gap: 80px;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: end;
|
|
|
+
|
|
|
+ .svg-icon {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .slider-area {
|
|
|
+ font-size: 14px;
|
|
|
+ text-align: left;
|
|
|
+
|
|
|
+ .audio-slider {
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ :deep .el-slider__runway {
|
|
|
+ height: 4px;
|
|
|
+ margin-top: 4px;
|
|
|
+ background-color: #fff;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep .el-slider__button {
|
|
|
+ width: 4px;
|
|
|
+ height: 4px;
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep .el-slider__bar {
|
|
|
+ height: 4px;
|
|
|
+ background-color: #1853c6;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep .el-slider__button-wrapper {
|
|
|
+ top: -16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .audio-small {
|
|
|
+ display: flex;
|
|
|
+ column-gap: 8px;
|
|
|
+ align-items: center;
|
|
|
+ padding: 13px;
|
|
|
+ background-color: #d9d9d9;
|
|
|
+
|
|
|
+ .svg-icon {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|