<template>
|
<u-popup :show="show" mode="bottom" :closeOnClickOverlay="false" @close="closePopup" :zIndex="9999" :overlay="true"
|
:safeAreaInsetBottom="true">
|
<view class="voice-popup">
|
<view class="header">
|
<text class="pl-30">语音输入</text>
|
<image src="/static/Appeal/close.png" class="w-34 h-34 mr-30" mode="" @click="closePopup"></image>
|
</view>
|
<view class="record-anim">
|
<image src="/static/Appeal/step.png" class="w-153 h-119" mode=""></image>
|
</view>
|
<view class="timer">{{ time }}</view>
|
<view class="btns">
|
<image :src="getRecordButtonSrc" class="w-153 h-153 mr-14" mode="" @click="handlerOnCahnger"></image>
|
<image src="/static/Appeal/cancel.png" class="w-153 h-153 mr-14" mode="" @click="onStop"></image>
|
</view>
|
</view>
|
<mumu-recorder ref="mumuRecorder" @success="handlerSuccess" @error="handleError"></mumu-recorder>
|
</u-popup>
|
</template>
|
|
<script>
|
import { getSignature } from '../pages/index/service'
|
import MumuRecorder from '@/uni_modules/mumu-recorder/components/mumu-recorder/mumu-recorder.vue'
|
export default {
|
name: 'VoiceInputPopup',
|
components: {
|
MumuRecorder
|
},
|
props: {
|
show: {
|
type: Boolean,
|
default: false
|
}
|
},
|
data() {
|
return {
|
time: '00:00:00',
|
isRecording: false,
|
isPaused: false,
|
tempFilePath: '',
|
timer: null,
|
seconds: 0,
|
minutes: 0,
|
hours: 0,
|
recordSegments: [], // 存储录音片段
|
currentSegment: null, // 当前录音片段
|
status: false,
|
recorder: null
|
}
|
},
|
computed: {
|
getRecordButtonSrc() {
|
if (this.isPaused) {
|
return '/static/Appeal/start.png'
|
}
|
return this.isRecording ? '/static/Appeal/stop.png' : '/static/Appeal/start.png'
|
}
|
},
|
mounted() {
|
},
|
methods: {
|
handlerSave() {
|
let tag = document.createElement('a')
|
tag.href = this.recorder.localUrl
|
tag.download = '录音'
|
tag.click()
|
},
|
handlerOnCahnger() {
|
if (!this.isRecording && !this.isPaused) {
|
// 开始新的录音
|
this.startNewRecording()
|
} else if (this.isRecording) {
|
// 暂停当前录音
|
this.pauseRecording()
|
} else if (this.isPaused) {
|
// 继续录音
|
this.resumeRecording()
|
}
|
},
|
startNewRecording() {
|
this.isRecording = true
|
this.isPaused = false
|
this.startTimer()
|
this.$refs.mumuRecorder.start()
|
},
|
pauseRecording() {
|
this.isRecording = false
|
this.isPaused = true
|
this.stopTimer()
|
this.$refs.mumuRecorder.stop()
|
},
|
resumeRecording() {
|
this.isRecording = true
|
this.isPaused = false
|
this.startTimer()
|
this.$refs.mumuRecorder.start()
|
},
|
handlerSuccess(res) {
|
console.log('录音成功:', res)
|
this.recorder = res
|
// 保存当前录音片段
|
if (res.localUrl) {
|
this.recordSegments.push({
|
url: res.localUrl,
|
duration: this.seconds + this.minutes * 60 + this.hours * 3600
|
})
|
}
|
},
|
handlerError(code) {
|
switch (code) {
|
case '101':
|
uni.showModal({
|
content: '当前浏览器版本较低,请更换浏览器使用,推荐在微信中打开。'
|
})
|
break;
|
case '201':
|
uni.showModal({
|
content: '麦克风权限被拒绝,请刷新页面后授权麦克风权限。'
|
})
|
break
|
default:
|
uni.showModal({
|
content: '未知错误,请刷新页面重试'
|
})
|
break
|
}
|
},
|
closePopup() {
|
// 清空录音片段
|
this.recordSegments = []
|
// 重置计时器
|
this.seconds = 0
|
this.minutes = 0
|
this.hours = 0
|
this.updateTimeDisplay()
|
// 关闭弹窗
|
this.$emit('close')
|
},
|
startTimer() {
|
this.stopTimer();
|
this.timer = setInterval(() => {
|
this.seconds++;
|
if (this.seconds >= 60) {
|
this.seconds = 0;
|
this.minutes++;
|
if (this.minutes >= 60) {
|
this.minutes = 0;
|
this.hours++;
|
}
|
}
|
this.updateTimeDisplay();
|
}, 1000);
|
},
|
stopTimer() {
|
if (this.timer) {
|
clearInterval(this.timer);
|
this.timer = null;
|
}
|
},
|
updateTimeDisplay() {
|
this.time = `${String(this.hours).padStart(2, '0')}:${String(this.minutes).padStart(2, '0')}:${String(this.seconds).padStart(2, '0')}`;
|
},
|
onStop() {
|
// 如果正在录音,先停止当前录音
|
if (this.isRecording) {
|
this.$refs.mumuRecorder.stop()
|
}
|
|
// 停止计时
|
this.stopTimer()
|
|
// 重置状态
|
this.isRecording = false
|
this.isPaused = false
|
|
// 处理录音片段
|
if (this.recordSegments.length > 0) {
|
// 发送第一个录音片段的URL
|
this.$emit('submit', this.recordSegments[0].url)
|
this.closePopup()
|
} else {
|
uni.showToast({
|
title: '未检测到录音文件',
|
icon: 'none',
|
duration: 2000
|
})
|
}
|
}
|
},
|
beforeDestroy() {
|
this.stopTimer();
|
}
|
}
|
</script>
|
|
<style scoped lang="scss">
|
.voice-popup {
|
background: #fff;
|
border-radius: 24rpx 24rpx 0 0;
|
padding: 40rpx 0 30rpx 0;
|
position: relative;
|
z-index: 9999;
|
|
.header {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
position: relative;
|
font-size: 32rpx;
|
font-weight: bold;
|
margin-bottom: 80rpx;
|
|
text {
|
flex: 1;
|
text-align: center;
|
}
|
|
.u-icon {
|
position: absolute;
|
right: 30rpx;
|
top: 0;
|
}
|
}
|
|
.record-anim {
|
display: flex;
|
justify-content: center;
|
align-items: center;
|
margin-bottom: 57rpx;
|
|
.bars {
|
display: flex;
|
align-items: flex-end;
|
height: 60rpx;
|
|
.bar {
|
width: 10rpx;
|
margin: 0 4rpx;
|
background: linear-gradient(180deg, #ff4948 0%, #fc8d55 100%);
|
border-radius: 6rpx;
|
transition: height 0.3s;
|
}
|
}
|
}
|
|
.timer {
|
text-align: center;
|
font-size: 28rpx;
|
color: #888;
|
}
|
|
.btns {
|
display: flex;
|
justify-content: space-around;
|
align-items: center;
|
padding: 40rpx 67rpx 6rpx 67rpx;
|
}
|
}
|
|
::v-deep .uni-toast {
|
z-index: 10099 !important;
|
}
|
|
.uni-sample-toast {
|
z-index: 10099 !important;
|
}
|
|
::v-deep .uni-toast .uni-sample-toast {
|
z-index: 10099 !important;
|
}
|
|
/deep/ .u-transition.u-fade-enter-to.u-fade-enter-active {
|
z-index: 997 !important;
|
}
|
</style>
|