|
@@ -0,0 +1,232 @@
|
|
|
+<template>
|
|
|
+ <div class="sound-record-wrapper">
|
|
|
+ <template v-if="wavBlob">
|
|
|
+ <SvgIcon
|
|
|
+ v-if="audio.paused"
|
|
|
+ icon-class="audio"
|
|
|
+ :class="['audio-play-btn', wavBlob ? '' : 'not-url']"
|
|
|
+ @click="playMicrophone"
|
|
|
+ />
|
|
|
+ <img v-else :src="require('@/assets/fill/voice-play-gray.png')" class="voice-play" @click="playMicrophone" />
|
|
|
+ <span :class="['record-time', microphoneStatus ? 'record-ing' : '']"
|
|
|
+ >{{ audio.paused ? '' : '-' }}{{ secondFormatConversion(recordTimes) }}</span
|
|
|
+ >
|
|
|
+ <SvgIcon icon-class="delete-back-line" :class="['delete-btn', wavBlob ? '' : 'not-url']" @click="deleteWav" />
|
|
|
+ </template>
|
|
|
+ <div v-else class="sound-microphone" @click="microphone">
|
|
|
+ <img v-if="microphoneStatus" :src="require('@/assets/fill/record-ing.png')" class="voice-play" />
|
|
|
+ <SvgIcon v-else icon-class="mic-line" class="record" />
|
|
|
+ <span class="auto-btn">录制音频</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <audio ref="audio" :src="file_url" preload="metadata"></audio>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import Recorder from 'js-audio-recorder'; // 录音插件
|
|
|
+import { secondFormatConversion } from '@/utils/transform';
|
|
|
+import { GetStaticResources, GetFileStoreInfo } from '@/api/app';
|
|
|
+export default {
|
|
|
+ name: 'SoundRecord',
|
|
|
+ props: {
|
|
|
+ wavBlob: {
|
|
|
+ type: String,
|
|
|
+ default: '',
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ secondFormatConversion,
|
|
|
+ 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: 0,
|
|
|
+ file_url: '',
|
|
|
+ recordTime: 0,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {},
|
|
|
+ watch: {
|
|
|
+ wavBlob: {
|
|
|
+ handler(val) {
|
|
|
+ if (!val) return;
|
|
|
+ GetFileStoreInfo({ file_id: val }).then(({ file_url, media_duration }) => {
|
|
|
+ this.file_url = file_url;
|
|
|
+ this.recordTime = media_duration;
|
|
|
+ this.recordTimes = JSON.parse(JSON.parse(media_duration));
|
|
|
+ });
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ 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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 开始录音
|
|
|
+ microphone() {
|
|
|
+ if (this.microphoneStatus) {
|
|
|
+ this.hasMicro = 'normal';
|
|
|
+ this.recorder.stop();
|
|
|
+ clearInterval(this.timer);
|
|
|
+ // 录音结束,获取取录音数据
|
|
|
+ let wav = this.recorder.getWAVBlob(); // 获取 WAV 数据
|
|
|
+ this.microphoneStatus = false;
|
|
|
+ let reader = new window.FileReader();
|
|
|
+ reader.readAsDataURL(wav);
|
|
|
+ reader.onloadend = () => {
|
|
|
+ let MethodName = 'file_store_manager-SaveFileByteBase64Text';
|
|
|
+ let data = {
|
|
|
+ base64_text: reader.result.replace('data:audio/wav;base64,', ''),
|
|
|
+ file_suffix_name: 'mp3',
|
|
|
+ };
|
|
|
+ GetStaticResources(MethodName, data).then((res) => {
|
|
|
+ if (res.status === 1) {
|
|
|
+ this.$emit('update:wavBlob', res.file_id);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ this.hasMicro = '';
|
|
|
+ this.$emit('update:wavBlob', '');
|
|
|
+ // 开始录音
|
|
|
+ this.recorder.start();
|
|
|
+ this.microphoneStatus = true;
|
|
|
+ this.recordTimes = 0;
|
|
|
+ clearInterval(this.timer);
|
|
|
+ this.timer = setInterval(() => {
|
|
|
+ this.recordTimes += 1;
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 删除录音
|
|
|
+ deleteWav() {
|
|
|
+ this.$refs.audio.pause();
|
|
|
+ this.hasMicro = '';
|
|
|
+ this.microphoneStatus = false;
|
|
|
+ this.playtime = 0;
|
|
|
+ this.recordTimes = 0;
|
|
|
+ clearInterval(this.timer);
|
|
|
+ this.$emit('update:wavBlob', '');
|
|
|
+ },
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.sound-record-wrapper {
|
|
|
+ display: flex;
|
|
|
+ column-gap: 12px;
|
|
|
+ align-items: center;
|
|
|
+ width: 200px;
|
|
|
+ padding: 5px 12px;
|
|
|
+ background: $fill-color;
|
|
|
+ border-radius: 2px;
|
|
|
+
|
|
|
+ .audio-play-btn {
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &.not-url {
|
|
|
+ color: #a1a1a1;
|
|
|
+ cursor: not-allowed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .record-time {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 52px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 22px;
|
|
|
+ color: #a1a1a1;
|
|
|
+
|
|
|
+ &.record-ing {
|
|
|
+ color: #000;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .record {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .voice-play {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .delete-btn {
|
|
|
+ margin-left: 12px;
|
|
|
+ color: #4e4e4e;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &.not-url {
|
|
|
+ color: #a1a1a1;
|
|
|
+ cursor: not-allowed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .auto-btn {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 22px;
|
|
|
+ color: #1d2129;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .sound-microphone {
|
|
|
+ display: flex;
|
|
|
+ column-gap: 12px;
|
|
|
+ align-items: center;
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|