|
@@ -0,0 +1,153 @@
|
|
|
+import {
|
|
|
+ defineComponent,
|
|
|
+ onMounted,
|
|
|
+ onUnmounted,
|
|
|
+ PropType,
|
|
|
+ reactive,
|
|
|
+ ref
|
|
|
+} from 'vue'
|
|
|
+import styles from './index.module.less'
|
|
|
+import iconPause from '../images/audio-pause.png'
|
|
|
+import iconPlay from '../images/audio-play.png'
|
|
|
+import audioBg from '../images/audio-bg.png'
|
|
|
+// import { Slider } from 'vant'
|
|
|
+import 'vant/es/slider/style'
|
|
|
+import Plyr from 'plyr'
|
|
|
+import { ElSlider } from 'element-plus'
|
|
|
+
|
|
|
+type fileType = {
|
|
|
+ url: string
|
|
|
+ name: string
|
|
|
+}
|
|
|
+
|
|
|
+export default defineComponent({
|
|
|
+ name: 'listen-audio',
|
|
|
+ props: {
|
|
|
+ fileInfo: {
|
|
|
+ type: Object as PropType<fileType>
|
|
|
+ }
|
|
|
+ },
|
|
|
+ setup(props) {
|
|
|
+ const audioRef = ref()
|
|
|
+ const audioProtoType = reactive({
|
|
|
+ audioPause: true,
|
|
|
+ duration: 0.01,
|
|
|
+ currentTime: 0
|
|
|
+ })
|
|
|
+
|
|
|
+ const onChangePlay = () => {
|
|
|
+ if (!audioRef.value) return
|
|
|
+ if (audioProtoType.audioPause) {
|
|
|
+ audioRef.value?.play()
|
|
|
+ } else {
|
|
|
+ audioRef.value?.pause()
|
|
|
+ }
|
|
|
+ audioProtoType.audioPause = audioRef.value.paused
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleChangeTime = (val: any) => {
|
|
|
+ if(!audioRef.value) return
|
|
|
+ audioRef.value.currentTime = val
|
|
|
+ }
|
|
|
+
|
|
|
+ // 秒转分
|
|
|
+ const getSecondRPM = (second: number, type?: string) => {
|
|
|
+ if (isNaN(second)) return '00:00'
|
|
|
+ const mm = Math.floor(second / 60)
|
|
|
+ .toString()
|
|
|
+ .padStart(2, '0')
|
|
|
+ const dd = Math.floor(second % 60)
|
|
|
+ .toString()
|
|
|
+ .padStart(2, '0')
|
|
|
+ if (type === 'cn') {
|
|
|
+ return mm + '分' + dd + '秒'
|
|
|
+ } else {
|
|
|
+ return mm + ':' + dd
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ if (!props.fileInfo?.url) return
|
|
|
+ audioRef.value = new Plyr('#audioSrc', {
|
|
|
+ controls: [
|
|
|
+ 'play-large',
|
|
|
+ 'play',
|
|
|
+ 'progress',
|
|
|
+ 'current-time',
|
|
|
+ 'duration'
|
|
|
+ ],
|
|
|
+ fullscreen: { enabled: false }
|
|
|
+ })
|
|
|
+ audioRef.value.on('loadedmetadata', () => {
|
|
|
+ audioProtoType.duration = audioRef.value.duration
|
|
|
+ })
|
|
|
+ audioRef.value.on('timeupdate', () => {
|
|
|
+ audioProtoType.currentTime = audioRef.value.currentTime || 0
|
|
|
+ })
|
|
|
+ audioRef.value.on('ended', () => {
|
|
|
+ audioProtoType.currentTime = 0
|
|
|
+ audioRef.value.currentTime = 0
|
|
|
+ audioProtoType.audioPause = true
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ onUnmounted(() => {
|
|
|
+ audioRef.value?.destroy()
|
|
|
+ })
|
|
|
+ return () => (
|
|
|
+ <div class={styles.listenAudio}>
|
|
|
+ <h2 class={styles.title}>
|
|
|
+ <span>
|
|
|
+ <span>预览音频</span>
|
|
|
+ </span>
|
|
|
+ </h2>
|
|
|
+
|
|
|
+ <div class={styles.container}>
|
|
|
+ <div class={styles.img} onClick={onChangePlay}>
|
|
|
+ <img src={audioBg} class={styles.audioBg} />
|
|
|
+ <img
|
|
|
+ src={audioProtoType.audioPause ? iconPause : iconPlay}
|
|
|
+ class={styles.iconImg}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class={styles.audioInfo}>
|
|
|
+ <audio
|
|
|
+ crossorigin="anonymous"
|
|
|
+ id="audioSrc"
|
|
|
+ src={props.fileInfo?.url}
|
|
|
+ controls="false"
|
|
|
+ preload="metadata"
|
|
|
+ playsinline
|
|
|
+ />
|
|
|
+ <div class={styles.name}>{props.fileInfo?.name}</div>
|
|
|
+ <div class={styles.slider}>
|
|
|
+ {/* <Slider
|
|
|
+ step={0.01}
|
|
|
+ class={styles.timeProgress}
|
|
|
+ v-model={audioProtoType.currentTime}
|
|
|
+ max={audioProtoType.duration}
|
|
|
+ onUpdate:modelValue={val => {
|
|
|
+ handleChangeTime(val)
|
|
|
+ }}
|
|
|
+ /> */}
|
|
|
+ <ElSlider
|
|
|
+ step={0.01}
|
|
|
+ showTooltip={false}
|
|
|
+ max={audioProtoType.duration}
|
|
|
+ v-model={audioProtoType.currentTime}
|
|
|
+ onUpdate:modelValue={val => {
|
|
|
+ handleChangeTime(val)
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class={styles.time}>
|
|
|
+ <div>{getSecondRPM(audioProtoType.currentTime)}</div>
|
|
|
+ <div>{getSecondRPM(audioProtoType.duration)}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+ }
|
|
|
+})
|