Files
dvcp_v2_webapp/ui/packages/basic/AiAudio.vue
2022-12-01 09:35:20 +08:00

239 lines
4.6 KiB
Vue

<template>
<section class="ai-audio">
<div class="controller" :class="skinClassName">
<el-row :gutter="10" type="flex">
<el-col>
<i class="play-icon" :class="playIcon" @click="play"></i>
</el-col>
<el-col class="play-progress">
<el-slider
:format-tooltip="getDateFormat"
v-model="currentTime"
:max="totalDuration"
@change="audio.currentTime = currentTime">
</el-slider>
<span class="total" v-if="skin === 'flat'">{{ getDateFormat(currentTime) }}</span>
<span class="total" v-else>{{ [getDateFormat(currentTime), getDateFormat(totalDuration)].join('/') }}</span>
</el-col>
</el-row>
<audio
ref="audio"
style="display: none;"
:src="src"
preload="metadata"
@pause="playState = false"
@playing="playing"
@loadedmetadata="loadedmetadata"
@timeupdate="timeupdate"
></audio>
</div>
</section>
</template>
<script>
import moment from 'dayjs'
export default {
name: 'AiAudio',
props: {
/**
* 播放资源url
*/
src: {
type: String,
required: true,
},
/**
* 同时只允许一个播放
*/
singlePlay: {type: Boolean, default: false},
/**
* 播放器风格
* default 旧版样式,flat 新版样式
* @values default,flat
*/
skin: {
type: String,
default: 'default'
}
},
data() {
return {
audio: null,
playState: false,
currentTime: 0,
totalTime: 0
}
},
computed: {
playIcon() {
if (this.skin === 'flat') {
return this.playState ? 'iconfont iconMediaPlayer_Stop' : 'iconfont iconMediaPlayer_Play'
}
return this.playState ? 'el-icon-video-pause' : 'el-icon-video-play'
},
totalDuration() {
return Math.round(this.totalTime)
},
skinClassName() {
return this.skin === 'default' ? '' : this.skin
}
},
mounted() {
this.audio = this.$refs.audio
},
methods: {
play() {
if (this.audio) {
if (this.audio.paused) {
if (this.singlePlay) this.stopAllAudio()
this.audio.play()
} else {
this.audio.pause()
}
}
},
stopAllAudio() {
let audios = document.getElementsByTagName('audio')
for (let i = 0; i < audios.length; i++) {
if (audios[i]) audios[i].pause()
}
},
playing() {
this.playState = true
},
loadedmetadata() {
this.totalTime = this.$refs.audio.duration || 0
},
getDateFormat(val) {
const time = moment.duration(val, 'seconds')
return [
this.prefixNum(time.minutes(), 2),
this.prefixNum(time.seconds(), 2),
].join(':')
},
prefixNum(val, num) {
return (Array(num).join('0') + val).slice(-num)
},
timeupdate() {
this.currentTime = parseInt(this.audio.currentTime)
}
},
destroyed() {
this.audio.pause()
}
}
</script>
<style lang="scss" scoped>
.ai-audio {
display: flex;
flex: 1;
.controller {
width: 205px;
height: 40px;
padding: 0 5px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 99px;
.el-col {
width: auto;
}
.play-icon {
color: #4c84ff;
cursor: pointer;
line-height: 40px;
font-size: 32px;
transition: color 0.3s;
&:hover {
color: #b3d8ff;
}
}
.play-progress {
display: flex;
flex: 1;
.el-slider {
width: 60px;
}
.total {
margin-left: 15px;
font-size: 12px;
line-height: 40px;
}
}
}
.flat {
height: 32px;
background: rgba(239, 246, 255, 1);
border: 1px solid rgba(132, 181, 255, 1);
border-radius: 5px;
box-shadow: none;
.play-icon {
position: relative;
padding-left: 3px;
color: #4c84ff;
cursor: pointer;
line-height: 32px;
font-size: 20px;
transition: color 0.3s;
&:hover {
color: #b3d8ff;
}
}
:deep(.el-slider__button ){
width: 8px;
height: 8px;
background: #1365DD;
}
:deep(.el-slider__bar ){
height: 2px;
}
:deep(.el-slider__button-wrapper ){
height: 32px;
}
:deep(.el-slider__runway ){
height: 2px;
margin: 15px 0;
}
.play-progress {
display: flex;
.el-slider {
width: 84px;
}
.total {
margin-left: 8px;
font-size: 12px;
line-height: 32px;
}
}
}
}
</style>