实现功能有:音词同步,倍速播放,拖拽播放,快进\退 ,重播,显示总 时长,关闭页面时关闭声音等功能
package.json 引入 "wavesurfer.js": "^7.7.14",
父页面引入自己封的 MyWaveSurfer.vue
<!-- waveSrc 录音地址参数 --><WaveSurfer :waveSrc="model['fsFilepath']"></WaveSurfer><script lang="ts" setup>import WaveSurfer from "@/views/recordCdr/MyWaveSurfer.vue";
MyWaveSurfer.vue
<template><a-card><Spin :tip="null" :spinning="loadLoading"><div :class="`wave-surfer`" id="waveform" ></div><!-- <div id="wave-timeline" ref="wave-timeline" style="height: 0px;"> --><!--时间轴 --></div></Spin></a-card><a-card style="height: 62px"><div style="float: left;" v-if="playMs"><div style=";float: left">播放: </div><Icon icon="ant-design:play-circle-outlined" title="播放" class="playIcon" style="font-size: 32px;color: #2e9aff" @click="playMusic()"> </Icon></div><div style="float: left;" v-if="!playMs"><div style="float: left">暂停: </div><Icon icon="ant-design:pause-circle-outlined" title="暂停" style="font-size: 30px;color: #2e9aff" @click="downMusic()"></Icon></div><div style="float: left;margin-left: 5%;"> 倍速: <a-select style="width: 90px;" :disabled="false" v-model:value="speedValue" @change="speedClick"><a-select-option value="1">1.0px</a-select-option><a-select-option v-for="item in options" :key="item.value" :value="item.value">{{ item.text }}</a-select-option></a-select></div><div style="float: left;margin-left: 5%;"><Icon icon="ant-design:notification-filled" title="声音" style="float: left;font-size: 29px;;color: #2e9aff" @click="downMusic()"></Icon><a-slider style="float: left;width: 200px" v-model:value="voiceValue" @afterChange="setVolume" /></div><div style="float: left;margin-left: 5%;"><div style="float: left;margin-top: 2px">快退/快进 : </div><Icon icon="ant-design:fast-backward-filled" title="快退" style="float: left;font-size: 29px;;color: #2e9aff" @click="rew()"></Icon><div style="float: left;margin-top: 2px"> -- </div><Icon icon="ant-design:fast-forward-filled" title="快进" style="float: left;font-size: 29px;;color: #2e9aff" @click="speed()"></Icon></div><div style="float: left;margin-left: 5%;"><div style="float: left;margin-top: 2px">重播 : </div><Icon icon="ant-design:reload-outlined" title="重播" style="float: left;font-size: 25px;color: #2e9aff" @click="replay()"></Icon></div><div style="float: left;margin-left: 5%;">总时长: <span style="color:#2e9aff">{{totalTime}}</span> 秒</div></a-card><div style="width:100%"><a-card style="width: 49%;float: left;height: 500px;overflow-y: auto"><div id="speech_feature" ref="myDiv"><div v-for="(line, index) in lyrics" class="myTextClass"><p v-if="line.user_type == 'agent'" :id="Math.round(line.begin_time/100)" class="blueColor" style="text-align:left;"><Icon icon="ant-design:customer-service-filled" title="座席" style="float: left;font-size: 22px;color: #707fe3" ></Icon>:{{ line.res }}</p><p v-else style="text-align:right" :id="Math.round(line.begin_time/100)" class="blueColor">{{line.res}} :<Icon icon="ant-design:message-filled" title="客户" style="float: right;font-size: 22px;color: #707fe3" ></Icon></p></div></div></a-card><a-card style="width: 49%;float: left;height: 500px"><a-tabs v-model:activeKey="activeKey"><a-tab-pane key="1" tab="Tab 1">Content of Tab Pane 1</a-tab-pane><a-tab-pane key="2" tab="Tab 2" force-render>Content of Tab Pane 2</a-tab-pane><a-tab-pane key="3" tab="Tab 3">Content of Tab Pane 3</a-tab-pane></a-tabs></a-card></div></template>
<script lang="ts">
import { Spin } from 'ant-design-vue';
import {defineComponent, toRefs, ref, onMounted,onUnmounted, nextTick,} from 'vue';
import { getUploadFileAccessHttpUrl } from '/@/utils/common/compUtils';
import Icon from '/@/components/Icon';import WaveSurfer from '@/ext_node_modules/wavesurfer.js/dist/wavesurfer'/*import CursorPlugin from '@/ext_node_modules/wavesurfer.js/dist/plugin/wavesurfer.cursor.js'
import Timeline from '@/ext_node_modules/wavesurfer.js/dist/plugin/wavesurfer.timeline.js'
import Regions from '@/ext_node_modules/wavesurfer.js/dist/plugin/wavesurfer.regions.js'*/import _default from "ant-design-vue/es/vc-slick/inner-slider";
import DictItemList from "@/views/system/dict/components/DictItemList.vue";export default defineComponent({name: 'WaveSurfer',components: {DictItemList, Icon, Spin },props: {waveSrc: {type: String,// default: '../../../src/assets/images/test.mp3',},index: {type: Number,},},setup(props) {const myDiv = ref(null);const activeKey = ref('1');let totalTime = ref<number>(0);const voiceValue = ref<number>(30);const playMs = ref(true);const { waveSrc } = toRefs(props);const icon = ref('icon-bofang');let wavesurfer = [];const loadLoading = ref(false);const speedValue = ref(1);const options = ref([{ value: 1.0, text: '1.0X' },{ value: 1.25, text: '1.25X' },{ value: 1.5, text: '1.5X' },{ value: 1.75, text: '1.75X' },{ value: 2.0, text: '2.0X' },])const lyrics = ref([{"res": ["有什么可以帮您?"],"end_time": 7700,"begin_time": 5900,"words_info": [],"sn": "96541708621716291667","corpus_no": "7371416581381329804","user_type": "agent"}, {"res": ["我客户想把那个会员号变更一下可以吗?"],"end_time": 17700,"begin_time": 8340,"words_info": [],"sn": "92604005381716291667","corpus_no": "7371416580911366314","user_type": "cust"}, {"res": ["嗯,可以的,还是需要给顾客自己近先联系我们。"],"end_time": 18860,"begin_time": 17000,"words_info": [],"sn": "92604005381716291667","corpus_no": "7371416580911366314","user_type": "agent"}, {"res": ["如果变更成别的号码,这个等级还在吗?"],"end_time": 19860,"begin_time":18860 ,"words_info": [],"sn": "381723455751716291667","corpus_no": "7371416581432964228","user_type": "cust"}, {"res": ["您您放心,会保留他的一个等级和这个积分的。"],"end_time": 28020,"begin_time": 26060,"words_info": [],"sn": "381723455751716291667","corpus_no": "7371416581432964228","user_type": "agent"}, {"res": ["好累,好让我让他打电话过来哈,"],"end_time": 42280,"begin_time": 33880,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "cust"}, {"res": ["请问下,可以帮您的吗?"],"end_time": 42280,"begin_time": 36880,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "agent"}, {"res": ["啊没有了,谢谢啊,我让他打过来,"],"end_time": 40280,"begin_time": 39880,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "cust"}, {"res": ["祝您生活愉快,再见,"],"end_time": 40280,"begin_time": 40000,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "agent"}, {"res": ["好的"],"end_time": 40280,"begin_time": 40080,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "cust"}, {"res": ["祝您生活愉快,再见,"],"end_time": 40280,"begin_time": 40500,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "agent"}, {"res": ["好的"],"end_time": 40280,"begin_time": 40800,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "cust"}, {"res": ["祝您生活愉快,再见,"],"end_time": 40280,"begin_time": 41000,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "agent"}, {"res": ["好的"],"end_time": 40280,"begin_time": 41200,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "cust"}, {"res": ["祝您生活愉快,再见,"],"end_time": 40280,"begin_time": 41400,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "agent"}, {"res": ["。。。。,"],"end_time": 40280,"begin_time": 41600,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "cust"}, {"res": ["祝您生活愉快,再见,"],"end_time": 40280,"begin_time": 41800,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "agent"}, {"res": ["。。。。。"],"end_time": 40280,"begin_time": 41900,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "cust"}, {"res": ["祝您生活愉快,再见,"],"end_time": 40280,"begin_time": 42200,"words_info": [],"sn": "912755075221716291667","corpus_no": "7371416581565561738","user_type": "agent"}])//点击倍速播放function speedClick() {console.info(speedValue.value)// console.log("fieldValue===============",fieldValue);playMusic();}//生成wavesurferfunction render( selector, url) {loadLoading.value = true;var domEl = document.createElement('div');document.querySelector(selector).appendChild(domEl);wavesurfer = WaveSurfer.create({container: domEl,waveColor: 'rgb(57 171 132)',progressColor: '#e0820e',cursorColor: 'rgb(57 171 132)',abnormalvolume:{"1":"violet"},/* plugins: [CursorPlugin.create({showTime: true,opacity: 0.2,customShowTimeStyle: {'background-color': '#000',color: '#fff',padding: '2px','font-size': '20px'}}),Timeline.create({container: '#wave-timeline'}),Regions.create()]*/});// url="../../../src/assets/images/test.mp3";wavesurfer.load(url);//获取当前播放进度的时间点wavesurfer.on('audioprocess', (time) => {//console.log("======time======",time)// 根据当前音频播放进度 time 来同步显示歌词Math.round(line.begin_time/100)const currentLine =Math.round(time*10) ; // 假设每行歌词对应的时间间隔为 10 秒//console.log("======currentLine======",currentLine)var mytextId=document.getElementById(currentLine);changeBackground(time);if(mytextId!=undefined){mytextId.className= "redColor";setTimeout(function(){mytextId.scrollIntoView({ behavior: "smooth", block: 'center' }); //0.1秒滑动到指定位置*},100);}});//拖拽进度条播放wavesurfer.on('seek', function () {playMusic();});wavesurfer.on('error', function (e) {console.warn(e);});//加载后事件wavesurfer.on('ready', function () {loadLoading.value = false;totalTime.value = wavesurfer.getDuration();console.log('音频总时长:', totalTime, '秒');});return wavesurfer;}//组件加载时加载录音onMounted(() => {setTimeout(()=>{if(waveSrc.value!=undefined){const fileAccessHttpUrl= getUploadFileAccessHttpUrl(waveSrc.value)nextTick(() => {render( '.wave-surfer' , fileAccessHttpUrl);});}},100)});//页面关闭时,组件关闭, 关闭录音onUnmounted(()=>{console.info( '组件关闭时 关闭录音====')wavesurfer.stop() ; //停止wavesurfer.destroy();//销毁})//设置音量大小function setVolume(val) {wavesurfer.setVolume(val / 100);//console.log(val)}//根据播放进度改编已播放的字体样式function changeBackground(nowTime) {nowTime=Math.round(nowTime*10)const elements = document.querySelectorAll('.myTextClass > *');elements.forEach(element => {if(element.id>nowTime){element.className="blueColor";}else{element.className="redColor";}});}//暂停function downMusic() {playMs.value = true;icon.value = 'icon-bofang';wavesurfer.playPause();}//播放function playMusic() {playMs.value = false;icon.value = 'icon-bofang';wavesurfer.setPlaybackRate(speedValue.value)wavesurfer.play();}// 回退function rew() {wavesurfer.skip(-3);goPlay();}// 快进function speed() {wavesurfer.skip(3);goPlay();}function goPlay() {let start = wavesurfer.getCurrentTime();wavesurfer.play(start);}// 重载function replay() {wavesurfer.stop();wavesurfer.clearRegions();wavesurfer.play(0);}return { playMusic, icon, loadLoading,playMs,speedClick,speedValue,options,downMusic,totalTime,setVolume,voiceValue,lyrics,changeBackground,myDiv,speed,rew ,replay,activeKey};},
});
</script>
<style lang="less">
.playIcon {line-height: 36px;margin-right: 8px;cursor: pointer;
}
.waveform {}
.redColor {color: #d96f00;;
}
.blueColor {color: #292a2f;
}</style>