不废话,直接上代码
<template>
<view>
<u-popup
round="16" :show="recordShow" :close-on-click-overlay="false"
:safe-area-inset-bottom="false"
@close="close"
@open="open"
>
<view class="tag-popup-box">
<view class="title">
<text>{{ tips }}</text>
<image
src=""
@click="close"
/>
</view>
<view class="voice-box" @touchstart="startRecord" @touchend="stopRecord" @touchcancel="stopRecord">
<image
src=""
class="voice-icon"
/>
</view>
</view>
</u-popup>
</view>
</template>
<script setup lang="ts">
import {onMounted, ref, watch} from "vue";
let start = false
const tips = ref<string>('按住开始录音')
const props = defineProps({
show: {
type: Boolean,
default: false
}
})
const manager = ref<any>()
const emits = defineEmits(['update:show','startRecord','textChange','micInput'])
const startRecord = async () => {
if (start) return // 防止还在识别中时又触发录音
console.log('touch started')
tips.value = '准备中...'
try {
await checkPermission()
} catch (e) {
tips.value = '需要授权'
return
}
manager.value.start()
emits("startRecord")
}
const stopRecord = () => {
if (!start) return // 触发极短时间,stop会在还未start的情况下触发
console.log('touch ended or canceled')
manager.value.stop()
}
watch(() => props.show, (value) => {
recordShow.value = value
})
const recordShow = ref<boolean>(props.show)
const open = () => {
manager.value = requirePlugin("WechatSI").getRecordRecognitionManager()
// recordShow.value = true
manager.value.onStart = (e:any) => {
console.log('on-start')
console.log(e)
start = true
tips.value = '正在识别...'
}
manager.value.onStop = (e:any) => {
console.log('on-stop')
console.log(e)
start = false
if (e.result){
tips.value = '按住开始录音'
emits("micInput", e.result)
} else {
tips.value = '识别失败,请重试'
}
}
manager.value.onRecognize = (e:any) => {
console.log('on-recognize')
console.log(e)
}
manager.value.onError = (e:any) => {
console.log('on-error')
console.log(e)
start = false
tips.value = '识别失败,请重试'
}
}
const close = () => {
recordShow.value = false
emits('update:show', recordShow.value)
}
const checkPermission = async () => {
const sRes = await uni.getSetting()
if (sRes.authSetting['scope.record']) return
try {
const aRes = await uni.authorize({
scope: 'scope.record'
})
} catch (e) {
const mRes = await uni.showModal({
title: '授权',
content: '请打开 录音功能 权限以便进行语音识别',
showCancel: true,
})
if (mRes.cancel) throw new Error('授权失败')
const sRes = await uni.openSetting()
if (sRes.authSetting['scope.record']) {
uni.showModal({
title: '授权成功',
content: '请继续点击下方按钮 进行语音输入',
showCancel: false
})
throw new Error('授权成功')
}
throw new Error('授权失败')
}
}
</script>
<style scoped lang="scss">
.tag-popup-box{
height: 524rpx;
background: #FFFFFF;
width: 100%;
padding: 40rpx 40rpx 0 ;
box-sizing: border-box;
border-radius: 32rpx 32rpx 0rpx 0rpx;
.voice-box{
width: 100%;
display: flex;
justify-content: center;
margin-top: 60rpx;
.voice-icon{
width: 180rpx;
height: 180rpx;
}
}
.title{
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 60rpx;
&>text{
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 44rpx;
}
&>image{
width: 44rpx;
height: 44rpx;
}
}
.content{
width: 100%;
height: 96rpx;
background: rgba(153, 153, 153, 0.08);
border-radius: 12rpx;
padding: 0 26rpx;
box-sizing: border-box;
}
.confirm-btn{
margin-top: 138rpx;
width: 100%;
height: 80rpx;
text-align: center;
background: #07B780;
border-radius: 8rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FFFFFF;
line-height: 80rpx;
}
}
</style>