|
@@ -0,0 +1,228 @@
|
|
|
+<template>
|
|
|
+ <div class="sound-record-wrapper">
|
|
|
+ <div class="sound-item sound-item-luyin">
|
|
|
+ <img
|
|
|
+ v-if="microphoneStatus"
|
|
|
+ :src="require('../../../../../assets/record-ing-hasBg.png')"
|
|
|
+ class="voice-play"
|
|
|
+ @click="microphone"
|
|
|
+ />
|
|
|
+ <span v-else class="sound-item-span" @click="microphone">
|
|
|
+ <SvgIcon icon-class="mic-line" :size="24" class="record" />
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <label :class="['record-time', microphoneStatus ? 'record-ing' : '']">{{ handleDateTime(recordTimes) }}</label>
|
|
|
+ </div>
|
|
|
+ <div class="sound-item">
|
|
|
+ <span :class="['sound-item-span', wavBlob ? '' : 'not-url']" @click="playMicrophone">
|
|
|
+ <SvgIcon :icon-class="iconClass" :size="24" :class="['audio-play-btn']" />
|
|
|
+ </span>
|
|
|
+ <label class="tips">回放</label>
|
|
|
+ </div>
|
|
|
+ <div class="sound-item">
|
|
|
+ <span :class="['sound-item-span', wavBlob ? '' : 'not-url']" @click="delectWav">
|
|
|
+ <SvgIcon icon-class="delete-back-line" :size="24" :class="['delete-btn']" />
|
|
|
+ </span>
|
|
|
+ <label class="tips">删除</label>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <audio ref="audio" :src="wavBlob" preload="metadata"></audio>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import Recorder from 'js-audio-recorder'; // 录音插件
|
|
|
+export default {
|
|
|
+ name: 'SoundRecordPreview',
|
|
|
+ props: {
|
|
|
+ wavBlob: {
|
|
|
+ type: String,
|
|
|
+ default: '',
|
|
|
+ },
|
|
|
+ recordTime: {
|
|
|
+ type: Number,
|
|
|
+ default: 0,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ recorder: new Recorder({
|
|
|
+ sampleBits: 16, // 采样位数,支持 8 或 16,默认是16
|
|
|
+ sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000
|
|
|
+ numChannels: 1, // 声道,支持 1 或 2, 默认是1
|
|
|
+ }),
|
|
|
+ timer: null, // 计时器
|
|
|
+ microphoneStatus: false, // 是否录音
|
|
|
+ hasMicro: '', // 录音后的样式class
|
|
|
+ audio: {
|
|
|
+ paused: true,
|
|
|
+ },
|
|
|
+ playtime: 0, // 播放时间
|
|
|
+ recordTimes: JSON.parse(JSON.stringify(this.recordTime)),
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ iconClass() {
|
|
|
+ return this.audio.paused ? 'play-fill' : 'pause';
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {},
|
|
|
+ mounted() {
|
|
|
+ this.$refs.audio.addEventListener('ended', () => {
|
|
|
+ this.audio.paused = true;
|
|
|
+ });
|
|
|
+ this.$refs.audio.addEventListener('pause', () => {
|
|
|
+ this.audio.paused = true;
|
|
|
+ });
|
|
|
+ this.$refs.audio.addEventListener('play', () => {
|
|
|
+ this.audio.paused = false;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ playMicrophone() {
|
|
|
+ if (this.wavBlob) {
|
|
|
+ let totalTime = JSON.parse(JSON.stringify(this.recordTime));
|
|
|
+ if (this.audio.paused) {
|
|
|
+ this.hasMicro = 'active';
|
|
|
+ // this.$refs.audio.pause();
|
|
|
+ // this.$refs.audio.load();
|
|
|
+ this.$refs.audio.play();
|
|
|
+ if (this.recordTimes === 0) {
|
|
|
+ this.recordTimes = JSON.parse(JSON.stringify(this.recordTime));
|
|
|
+ this.playtime = 0;
|
|
|
+ }
|
|
|
+ clearInterval(this.timer);
|
|
|
+ this.timer = setInterval(() => {
|
|
|
+ if (this.playtime < totalTime) {
|
|
|
+ this.playtime += 1;
|
|
|
+ this.recordTimes = totalTime - this.playtime;
|
|
|
+ } else {
|
|
|
+ this.playtime = 0;
|
|
|
+ this.recordTimes = JSON.parse(JSON.stringify(this.recordTime));
|
|
|
+ clearInterval(this.timer);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ } else {
|
|
|
+ this.$refs.audio.pause();
|
|
|
+ this.hasMicro = 'normal';
|
|
|
+ clearInterval(this.timer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 格式化录音时长
|
|
|
+ handleDateTime(time) {
|
|
|
+ let times = 0;
|
|
|
+ if (parseInt(time / 60) < 10) {
|
|
|
+ times = `${`0${parseInt(time / 60)}`.substring(`0${parseInt(time / 60)}`.length - 2)}:${`0${
|
|
|
+ time % 60
|
|
|
+ }`.substring(`0${time % 60}`.length - 2)}`;
|
|
|
+ } else {
|
|
|
+ times = `${parseInt(time / 60)}:${`0${time % 60}`.substring(`0${time % 60}`.length - 2)}`;
|
|
|
+ }
|
|
|
+ return times;
|
|
|
+ },
|
|
|
+ // 开始录音
|
|
|
+ microphone() {
|
|
|
+ if (!this.audio.paused) {
|
|
|
+ this.$refs.audio.pause();
|
|
|
+ this.audio.paused = true;
|
|
|
+ }
|
|
|
+ if (this.microphoneStatus) {
|
|
|
+ this.hasMicro = 'normal';
|
|
|
+ this.recorder.stop();
|
|
|
+ clearInterval(this.timer);
|
|
|
+ let tolTime = this.recorder.duration; // 录音总时长
|
|
|
+ // 录音结束,获取取录音数据
|
|
|
+ let wav = this.recorder.getWAVBlob(); // 获取 WAV 数据
|
|
|
+ this.microphoneStatus = false;
|
|
|
+ let reader = new window.FileReader();
|
|
|
+ reader.readAsDataURL(wav);
|
|
|
+ reader.onloadend = () => {
|
|
|
+ this.$emit('updataWav', reader.result, Math.floor(tolTime));
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ this.hasMicro = '';
|
|
|
+ this.$emit('updataWav', '', 0);
|
|
|
+ // 开始录音
|
|
|
+ this.recorder.start();
|
|
|
+ this.microphoneStatus = true;
|
|
|
+ this.recordTimes = 0;
|
|
|
+ clearInterval(this.timer);
|
|
|
+ this.timer = setInterval(() => {
|
|
|
+ this.recordTimes += 1;
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 删除录音
|
|
|
+ delectWav() {
|
|
|
+ this.$refs.audio.pause();
|
|
|
+ this.hasMicro = '';
|
|
|
+ this.microphoneStatus = false;
|
|
|
+ this.playtime = 0;
|
|
|
+ this.recordTimes = 0;
|
|
|
+ clearInterval(this.timer);
|
|
|
+ this.$emit('deleteWav');
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.sound-record-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .sound-item {
|
|
|
+ margin-right: 16px;
|
|
|
+ text-align: center;
|
|
|
+
|
|
|
+ .sound-item-span {
|
|
|
+ display: block;
|
|
|
+ width: 48px;
|
|
|
+ height: 48px;
|
|
|
+ padding: 12px;
|
|
|
+ font-size: 0;
|
|
|
+ cursor: pointer;
|
|
|
+ background: #ededed;
|
|
|
+ border-radius: 80px;
|
|
|
+
|
|
|
+ &.not-url {
|
|
|
+ color: #a1a1a1;
|
|
|
+ cursor: not-allowed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &-luyin {
|
|
|
+ .sound-item-span {
|
|
|
+ color: #fff;
|
|
|
+ background-color: #7346d3;
|
|
|
+ }
|
|
|
+
|
|
|
+ .voice-play {
|
|
|
+ display: block;
|
|
|
+ width: 48px;
|
|
|
+ height: 48px;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .tips {
|
|
|
+ display: block;
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 20px;
|
|
|
+ color: rgba($color: #000, $alpha: 50%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-time {
|
|
|
+ display: block;
|
|
|
+ margin-top: 4px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ line-height: 20px;
|
|
|
+ color: #000;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|