From 06dded7ff247f64412b95f846b5012b886353e71 Mon Sep 17 00:00:00 2001 From: 董国庆 <364620639@qq.com> Date: 星期一, 19 五月 2025 22:30:35 +0800 Subject: [PATCH] 录音组件 --- H5/components/voiceInputPopup.vue | 211 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 189 insertions(+), 22 deletions(-) diff --git a/H5/components/voiceInputPopup.vue b/H5/components/voiceInputPopup.vue index 4737331..18e50be 100644 --- a/H5/components/voiceInputPopup.vue +++ b/H5/components/voiceInputPopup.vue @@ -1,25 +1,32 @@ <template> - <u-popup :show="show" mode="bottom" :closeOnClickOverlay="false" @close="closePopup" zIndex="10071"> + <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="" @click="onPlay"></image> + <image src="/static/Appeal/step.png" class="w-153 h-119" mode=""></image> </view> <view class="timer">{{ time }}</view> <view class="btns"> - <image src="/static/Appeal/start.png" class="w-153 h-153 mr-14" mode="" @click="onPlay"></image> - <image src="/static/Appeal/stop.png" class="w-153 h-153 mr-14" mode="" @click="onPause"></image> + <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, @@ -29,16 +36,160 @@ data() { return { time: '00:00:00', - barHeights: [20, 30, 40, 30, 20], // 可做动画 + 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: { - closePopup() { - this.$emit('update:show', false) + handlerSave() { + let tag = document.createElement('a') + tag.href = this.recorder.localUrl + tag.download = '录音' + tag.click() }, - onPlay() {}, - onPause() {}, - onStop() {}, + 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> @@ -48,6 +199,9 @@ background: #fff; border-radius: 24rpx 24rpx 0 0; padding: 40rpx 0 30rpx 0; + position: relative; + z-index: 9999; + .header { display: flex; justify-content: center; @@ -56,25 +210,30 @@ 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; @@ -84,26 +243,34 @@ } } } + .timer { text-align: center; font-size: 28rpx; color: #888; - // margin-bottom: 30rpx; } + .btns { display: flex; justify-content: space-around; align-items: center; - padding: 40rpx 67rpx 76rpx 67rpx; - // .u-button { - // width: 100rpx; - // height: 100rpx; - // border-radius: 50%; - // display: flex; - // justify-content: center; - // align-items: center; - // margin: 0 10rpx; - // } + padding: 40rpx 67rpx 6rpx 67rpx; } } -</style> \ No newline at end of file + +::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> \ No newline at end of file -- Gitblit v1.7.1