|
@@ -0,0 +1,404 @@
|
|
|
+<!-- eslint-disable vue/no-v-html -->
|
|
|
+<template>
|
|
|
+ <div :class="['AudioNNPE']">
|
|
|
+ <div class="audioLine">
|
|
|
+ <div class="playBox" @click="PlayAudio">
|
|
|
+ <div class="play" :class="[audio.loading ? 'loadBtn' : audio.playing ? 'playBtn' : 'pauseBtn']">
|
|
|
+ <SvgIcon v-if="audio.playing" icon-class="pause-large-fill" />
|
|
|
+ <SvgIcon v-else icon-class="play-large-fill" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <template v-if="!isRepeat">
|
|
|
+ <el-slider
|
|
|
+ v-model="playValue"
|
|
|
+ :style="{ width: sliderWidth + 'px', height: '2px' }"
|
|
|
+ :format-tooltip="formatProcessToolTip"
|
|
|
+ @change="changeCurrentTime"
|
|
|
+ />
|
|
|
+ <span
|
|
|
+ ><template v-if="audio.playing">-</template
|
|
|
+ >{{ audio.maxTime ? realFormatSecond(audio.maxTime - audio.currentTime) : '' }}</span
|
|
|
+ >
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <audio
|
|
|
+ :id="audioId"
|
|
|
+ :ref="audioId"
|
|
|
+ :src="mp3"
|
|
|
+ preload="metadata"
|
|
|
+ @loadedmetadata="onLoadedmetadata"
|
|
|
+ @timeupdate="onTimeupdate"
|
|
|
+ @canplaythrough="oncanplaythrough"
|
|
|
+ ></audio>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+export default {
|
|
|
+ props: [
|
|
|
+ 'mp3',
|
|
|
+ 'mp3Source',
|
|
|
+ 'getCurTime',
|
|
|
+ 'stopAudio',
|
|
|
+ 'width',
|
|
|
+ 'isRepeat',
|
|
|
+ 'themeColor',
|
|
|
+ 'hideSlider',
|
|
|
+ 'ed',
|
|
|
+ 'bg',
|
|
|
+ 'audioId',
|
|
|
+ 'type',
|
|
|
+ 'audioData',
|
|
|
+ ],
|
|
|
+ data() {
|
|
|
+ // 这里存放数据
|
|
|
+ return {
|
|
|
+ playValue: 0,
|
|
|
+ audio: {
|
|
|
+ // 该字段是音频是否处于播放状态的属性
|
|
|
+ playing: false,
|
|
|
+ // 音频当前播放时长
|
|
|
+ currentTime: 0,
|
|
|
+ // 音频最大播放时长
|
|
|
+ maxTime: 0,
|
|
|
+ isPlaying: false,
|
|
|
+ loading: false,
|
|
|
+ },
|
|
|
+ audioAllTime: null, // 展示总时间
|
|
|
+ duioCurrentTime: null, // 剩余时间
|
|
|
+ count: 0,
|
|
|
+ isClick: false,
|
|
|
+ activeIndex: null,
|
|
|
+ activeContent: 1,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 计算属性 类似于data概念
|
|
|
+ computed: {
|
|
|
+ sliderWidth() {
|
|
|
+ let width = 0;
|
|
|
+ if (this.width) {
|
|
|
+ width = this.width;
|
|
|
+ } else {
|
|
|
+ width = 662;
|
|
|
+ }
|
|
|
+ return width;
|
|
|
+ },
|
|
|
+ },
|
|
|
+ // 监控data中数据变化
|
|
|
+ watch: {
|
|
|
+ stopAudio: {
|
|
|
+ handler(val) {
|
|
|
+ if (val) {
|
|
|
+ this.$refs[this.audioId].pause();
|
|
|
+ this.audio.playing = false;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 深度观察监听
|
|
|
+ deep: true,
|
|
|
+ },
|
|
|
+ 'audio.playing': {
|
|
|
+ handler(val) {
|
|
|
+ this.$emit('playChange', val);
|
|
|
+ if (val) this.$emit('handleChangeStopAudio');
|
|
|
+ },
|
|
|
+ },
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ let audioId = this.audioId;
|
|
|
+ this.$refs[audioId].addEventListener('loadstart', () => {});
|
|
|
+ this.$refs[audioId].addEventListener('play', () => {
|
|
|
+ this.audio.playing = true;
|
|
|
+ this.audio.isPlaying = true;
|
|
|
+ this.audio.loading = false;
|
|
|
+ });
|
|
|
+ this.$refs[audioId].addEventListener('pause', () => {
|
|
|
+ this.audio.playing = false;
|
|
|
+ if (this.hideSlider && this.audio.currentTime * 1000 + 500 > this.ed) {
|
|
|
+ this.$emit('sentPause', true);
|
|
|
+ }
|
|
|
+ this.$emit('handleListenRead', false);
|
|
|
+ });
|
|
|
+ this.$refs[audioId].addEventListener('ended', () => {
|
|
|
+ this.audio.playing = false;
|
|
|
+ this.audio.isPlaying = false;
|
|
|
+ this.isClick = false;
|
|
|
+ this.$emit('handleListenRead', false);
|
|
|
+ });
|
|
|
+
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (
|
|
|
+ document.getElementsByClassName('el-slider__button-wrapper') &&
|
|
|
+ document.getElementsByClassName('el-slider__button-wrapper')[0]
|
|
|
+ ) {
|
|
|
+ document.getElementsByClassName('el-slider__button-wrapper')[0].addEventListener('mousedown', () => {
|
|
|
+ this.$refs[audioId].pause();
|
|
|
+ this.audio.playing = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ PlayAudio() {
|
|
|
+ let audioId = this.audioId;
|
|
|
+ let audio = document.getElementsByTagName('audio');
|
|
|
+ if (audio && audio.length > 0) {
|
|
|
+ Array.from(audio).forEach((item) => {
|
|
|
+ if (item.src === this.mp3) {
|
|
|
+ if (item.id !== audioId) {
|
|
|
+ item.pause();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ item.pause();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ if (this.audio.playing) {
|
|
|
+ this.$refs[audioId].pause();
|
|
|
+ this.audio.playing = false;
|
|
|
+ this.$emit('handleListenRead', false);
|
|
|
+ this.isClick = false;
|
|
|
+ } else {
|
|
|
+ if (this.count === 0) {
|
|
|
+ this.audio.loading = true;
|
|
|
+ this.count += 1;
|
|
|
+ }
|
|
|
+ if (this.hideSlider) {
|
|
|
+ this.$refs[audioId].play();
|
|
|
+ this.onTimeupdateTime(this.bg / 1000);
|
|
|
+ } else {
|
|
|
+ this.$refs[audioId].pause();
|
|
|
+ this.$refs[audioId].play();
|
|
|
+ }
|
|
|
+
|
|
|
+ this.$emit('handleChangeStopAudio');
|
|
|
+ this.$emit('handleListenRead', true);
|
|
|
+ this.isClick = true;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ oncanplaythrough() {
|
|
|
+ this.audio.loading = false;
|
|
|
+ },
|
|
|
+ // 点击 拖拽播放音频
|
|
|
+ changeCurrentTime(value) {
|
|
|
+ let audioId = this.audioId;
|
|
|
+ this.$refs[audioId].play();
|
|
|
+ this.audio.playing = true;
|
|
|
+ this.$refs[audioId].currentTime = parseInt((value / 100) * this.audio.maxTime);
|
|
|
+ },
|
|
|
+ mousedown() {
|
|
|
+ let audioId = this.audioId;
|
|
|
+ this.$refs[audioId].pause();
|
|
|
+ this.audio.playing = false;
|
|
|
+ },
|
|
|
+ // 进度条格式化toolTip
|
|
|
+ formatProcessToolTip(index) {
|
|
|
+ return this.realFormatSecond(parseInt((this.audio.maxTime / 100) * index));
|
|
|
+ },
|
|
|
+ // 音频加载完之后
|
|
|
+ onLoadedmetadata(res) {
|
|
|
+ this.audio.maxTime = parseInt(res.target.duration);
|
|
|
+ this.audioAllTime = this.realFormatSecond(this.audio.maxTime);
|
|
|
+ },
|
|
|
+ // 当音频当前时间改变后,进度条也要改变
|
|
|
+ onTimeupdate(res) {
|
|
|
+ let audioId = this.audioId;
|
|
|
+ this.audio.currentTime = res.target.currentTime;
|
|
|
+ this.getCurTime(res.target.currentTime);
|
|
|
+ this.playValue = (this.audio.currentTime / this.audio.maxTime) * 100;
|
|
|
+ if (this.type === 'audioLine') {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (!this.isClick && this.audio.currentTime * 1000 > this.ed) {
|
|
|
+ if (this.$refs[audioId]) {
|
|
|
+ this.$refs[audioId].pause();
|
|
|
+ this.$emit('emptyEd');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 50);
|
|
|
+ } else if (this.hideSlider) {
|
|
|
+ if (this.audio.currentTime * 1000 + 500 > this.ed) {
|
|
|
+ this.$refs[audioId].pause();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onTimeupdateTime(res, playFlag) {
|
|
|
+ if (!res && res !== 0) return;
|
|
|
+ let audioId = this.audioId;
|
|
|
+ this.$refs[audioId].currentTime = res;
|
|
|
+ this.playValue = (res / this.audio.maxTime) * 100;
|
|
|
+ if (playFlag) {
|
|
|
+ let audio = document.getElementsByTagName('audio');
|
|
|
+ if (audio && audio.length > 0 && window.location.href.indexOf('GCLS-Learn') === -1) {
|
|
|
+ audio.forEach((item) => {
|
|
|
+ if (item.id !== audioId) {
|
|
|
+ item.pause();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.$refs[audioId].play();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 将整数转换成 时:分:秒的格式
|
|
|
+ realFormatSecond(value) {
|
|
|
+ let theTime = parseInt(value); // 秒
|
|
|
+ let theTime1 = 0; // 分
|
|
|
+ let theTime2 = 0; // 小时
|
|
|
+ if (theTime > 60) {
|
|
|
+ theTime1 = parseInt(theTime / 60);
|
|
|
+ theTime = parseInt(theTime % 60);
|
|
|
+ if (theTime1 > 60) {
|
|
|
+ theTime2 = parseInt(theTime1 / 60);
|
|
|
+ theTime1 = parseInt(theTime1 % 60);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let result = String(parseInt(theTime));
|
|
|
+ if (result < 10) {
|
|
|
+ result = `0${result}`;
|
|
|
+ }
|
|
|
+ if (theTime1 > 0) {
|
|
|
+ result = `${String(parseInt(theTime1))}:${result}`;
|
|
|
+ if (theTime1 < 10) {
|
|
|
+ result = `0${result}`;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ result = `00:${result}`;
|
|
|
+ }
|
|
|
+ if (theTime2 > 0) {
|
|
|
+ result = `${String(parseInt(theTime2))}:${result}`;
|
|
|
+ if (theTime2 < 10) {
|
|
|
+ result = `0${result}`;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // result = "00:" + result;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+ showPopover(e) {
|
|
|
+ this.activeIndex = e;
|
|
|
+ },
|
|
|
+ hidePopover() {
|
|
|
+ this.activeIndex = null;
|
|
|
+ this.activeContent = 1;
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.AudioNNPE {
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ .audioLine {
|
|
|
+ box-sizing: border-box;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ height: 40px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 8px;
|
|
|
+
|
|
|
+ .playBox {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ margin-right: 7px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .play {
|
|
|
+ display: block;
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ font-size: 0;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ span {
|
|
|
+ min-width: 56px;
|
|
|
+ margin-right: 12px;
|
|
|
+ margin-left: 8px;
|
|
|
+ font-size: 16px;
|
|
|
+ line-height: 19px;
|
|
|
+ color: #000;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .audioLine2 {
|
|
|
+ .play-icon {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &-big {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.playBtn-icon {
|
|
|
+ background: url('@/assets/voice_matrix/pauseC-16-normal-blue.png') no-repeat left top;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.pauseBtn-icon {
|
|
|
+ background: url('@/assets/voice_matrix/compare-pause-blue.png') no-repeat left top;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .loadBtn {
|
|
|
+ background: url('@/assets/voice_matrix/loading-blue.png') no-repeat left top;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.Audio-tts {
|
|
|
+ .audioLine {
|
|
|
+ .playBtn {
|
|
|
+ background: url('@/assets/voice_matrix/tts-play-blue.png') no-repeat left top;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .pauseBtn {
|
|
|
+ background: url('@/assets/voice_matrix/tts-blue.png') no-repeat left top;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style lang="scss">
|
|
|
+.AudioNNPE {
|
|
|
+ .el-slider__button-wrapper {
|
|
|
+ position: relative;
|
|
|
+ z-index: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-slider__button {
|
|
|
+ position: absolute;
|
|
|
+ top: 12px;
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ background: #165dff;
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-slider__runway {
|
|
|
+ height: 2px;
|
|
|
+ padding: 0;
|
|
|
+ margin: 0;
|
|
|
+ background: #e5e5e5;
|
|
|
+ border-radius: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-slider {
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-slider__bar {
|
|
|
+ height: 2px;
|
|
|
+ background: #165dff;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|