这是一个按钮录音弹窗:你也可你自己换成别的!
点击保存会返回 录音的 路径 通过 v-model 绑定的!(你也可以自己写个emit 返回方法,)
# 要删除的(就这俩)
import {
usualUploadFileOne,
removeFile,
usualGetFileList,
getSpeech
} from '@/common/api/ip'
try{
let res = await getSpeech({ filePath: this.recordFile.fullPath }, { myFile: this.recordFile.fullPath })
this.loading = false
this.$refs.uToast.show({ title: '录音转文字成功,请粘贴内容', type: 'success' })
this.$emit('input', JSON.parse(res.data.data)[0])
this.releaseManger()
}catch(e){
this.loading = false
this.$refs.uToast.show({ title: e, type: 'warning' })
}
uview
注意: 项目没有 uview 组件库的,自己想办法吧!该录音也没用什么,就用了个 进度条和按钮, 自己整的替换了就行
注意: 图片资源自己去 https://www.iconfont.cn/上找 长这样(我不知道怎么传!)
注意: 俩svg 和一个png ;命名和 图片格式别搞错了!导入到对应的 static/img中
文件名 fs-audio
<template>
<view>
<view>
<slot>
<u-button type="default" @click="openRecordDialog">录音转文字</u-button>
</slot>
</view>
<!-- 录音弹窗 -->
<u-mask :show="toggleDialog" :mask-click-able="false">
<view class="recordWrap">
<view class="top_tip">{{topTipText}}</view>
<view class="progress_time_wrap" v-if="toggleDialog">
<view class="record_progress">
<u-circle-progress bg-color="#000" active-color="#2979ff" :percent="record_progress_time">
<image style="width: 70%;height: 70%;" mode="aspectFit" src="/static/img/arecord.png"></image>
</u-circle-progress>
</view>
<view class="record_time">{{record_formate_time}}</view>
</view>
<view class="record_control">
<view class="btn record_reset" @click="resetRecord" v-if="record_status >= 4">
<view class="in_btn reset_btn"></view>
<view class="btn_title">重新录制</view>
</view>
<view class="btn record_start" @click="startRecord">
<view class="in_btn l_btn" :class="{start:record_status == 0 || record_status >=4,pause: record_status == 1 || record_status== 3}"></view>
<view class="in_btn r_btn" :class="{start:record_status == 0 || record_status >=4,pause: record_status == 1 || record_status== 3}"></view>
<template v-if="record_status == 2">
<image style="width: 100%;height: 100%;margin-left: 6rpx;" src="/static/img/play.svg" alt=""></image>
</template>
<view class="btn_title">{{startBtnText}}</view>
</view>
<view class="btn record_reset" @click="playRecord" v-if="record_status >= 4">
<view v-if="record_status == 4" class="in_btn play l_play_btn">
<image style="width: 100%;height: 100%;margin-left: 6rpx;" src="/static/img/play.svg" alt=""></image>
</view>
<template v-if="record_status == 5">
<view class="in_btn pause r_end_btn"></view>
<view class="in_btn pause r_end_btn"></view>
</template>
<view class="btn_title">{{playBtnText}}</view>
</view>
<!-- #ifdef MP-WEIXIN -->
<view class="btn record_start" @click="saveRecord" v-if="record_status == 2">
<view class="in_btn" style="width: 100%; transform: translateX(-4rpx);background-color: #ff000000;">
<image style="width: 100%;height: 100%;margin-left: 6rpx;" src="/static/img/dui.svg" alt=""></image>
</view>
</view>
<!-- #endif -->
</view>
<!-- <view>
{{recordFile.name}}
</view>
<view>
{{recordFile.fullPath}}
</view> -->
<view class="action_btn">
<u-button :ripple="true" :plain="true" class="btn" @click="successClick">确定</u-button>
<u-button :ripple="true" :plain="true" class="btn" @click="cancalClick">取消</u-button>
</view>
<!-- <view class="footer">
<button type="default" @click="toggleDialog = false">关闭</button>
</view> -->
</view>
</u-mask>
<!-- 加载 -->
<u-mask :show="loading" @click="loading = false">
<view class="load_more_m">
<u-loading mode="circle" color="#169ef9" />
<view class="word">录音转文字中...</view>
</view>
</u-mask>
<!-- 提示 -->
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
usualUploadFileOne,
removeFile,
usualGetFileList,
getSpeech
} from '@/common/api/ip'
export default {
name: "fs-audio",
props:{
value: String,
time:{type:Number, default: 600},//录音可录制的总时常
},
data() {
return {
loading: false,
//共
toggleDialog: false, //录音弹窗切换
record_time: 0, //录音时间
record_time_copy: 0, //录音时间
record_progress_time: 0, //录音进度时间
record_formate_time: '00:00:00', //录音格式化时间
record_status: 0,//录音状态 0未开始,1开始,2暂停,3继续,4结束录,5播放,6重新录
record_img: '',
startBtnText:'开始',//录制按钮文字
playBtnText:'播放录音',//录制按钮文字
topTipText: '',
timer: null,//定时器
recordFile: {},//录音文件
//录
recordInstance: null, //录音对象
//播
playInstance: null, //录音对象
tempFilePath:''
};
},
methods: {
//点击取消
cancalClick() {
uni.showModal({
title: "取消录制",
content: "是否取消录制?",
success: (res) => {
if (res.confirm) {
this.releaseManger()
}
}
})
},
//释放管理器
releaseManger() {
this.record_status = 0
this.recordInstance = null
this.playInstance = null
this.toggleDialog = false
},
//点击确定
async successClick() {
if (!this.recordFile.fullPath) {
this.$refs.uToast.show({title: '请录音后再保存',type: 'warning'})
return;
}
//录音转文字
this.loading = true
try{
// await this.getSpeech()
let res = await getSpeech({ filePath: this.recordFile.fullPath }, { myFile: this.recordFile.fullPath })
this.loading = false
this.$refs.uToast.show({ title: '录音转文字成功,请粘贴内容', type: 'success' })
this.$emit('input', JSON.parse(res.data.data)[0])
this.releaseManger()
}catch(e){
this.loading = false
this.$refs.uToast.show({ title: e, type: 'warning' })
//TODO handle the exception
}
},
// 播放录音
playRecord() {
if(this.record_status == 4) {
// #ifdef APP-PLUS
this.playInstance = plus.audio.createPlayer(this.recordFile.fullPath)
this.playInstance.addEventListener('play',()=> {
this.record_time = 0
this.record_status = 5
this.$nextTick(() =>{
this.setTime()
})
})
this.playInstance.play((res) => {
console.log('播放成功完成')
this.record_time = this.record_time_copy
this.record_status = 4
},(err) => {
console.log('播放失败')
})
// #endif
// #ifdef MP-WEIXIN
this.playInstance = uni.createInnerAudioContext()
this.playInstance.src = this.recordFile.fullPath
//音频播放事件
this.playInstance.onPlay(() => {
console.log('开始播放')
this.record_time = 0
this.record_status = 5
this.$nextTick(() =>{
this.setTime()
})
})
// 音频自然播放结束事件/
this.playInstance.onEnded(() => {
console.log('播放结束')
this.record_time = this.record_time_copy
this.record_status = 4
})
this.playInstance.play()
// #endif
}else {
this.playInstance.stop()
this.record_status = 4
this.record_time = this.record_time_copy
}
},
//初始化数据
initData() {
this.record_time = 0, //录音时间
this.record_progress_time = 0, //录音进度时间
this.record_formate_time = '00:00:00', //录音格式化时间
this.clearTime()
},
//初始化对象
init() {
},
// #ifdef MP-WEIXIN
// #endif
// 重置录音
resetRecord() {
this.record_status = 0
},
//录音弹窗切换
openRecordDialog() {
console.log('录音弹窗切换', this.toggleDialog)
this.getRecordSetting()
// this.toggleDialog = !this.toggleDialog
},
//创建录音列表
createAudioList() {
},
//开始录音
startRecord() {
if(this.record_status == 4) {
this.$refs.uToast.show({ title: '请点击重新录制再进行此操作', type: 'warning' })
}
// #ifdef APP-PLUS
this.recordInstance = plus.audio.getRecorder();
if(this.record_status == 0) {
this.recordInstance.record({ filename: '_doc/audio/' }, (recordFile) => {
console.log(recordFile,'保存录音----')
plus.io.resolveLocalFileSystemURL(recordFile, (entry) => {
console.log(entry,'转换后的录音地址')
this.recordFile = entry
// this.getSpeech(entry.fullPath)
}, (e) => {
this.$refs.uToast.show({ title: '读取录音文件错误', type: 'warning' })
});
}, (e) => {
console.log(e,)
this.$refs.uToast.show({ title: '录音失败', type: 'warning' })
});
}else {
this.record_status = 4//结束录
this.record_time_copy = this.record_time
this.recordInstance.stop()
}
if(this.record_status == 0) this.record_status = 1
// #endif
console.log(this.recordInstance,'this.recordInstance')
// #ifdef MP-WEIXIN
this.recordInstance = uni.getRecorderManager()
this.setSetting()
// #endif
},
//小程序录音功能
MPWEIXINstart() {
console.log(this.recordInstance,'this.recordInstance')
//监听开始
this.recordInstance.onStart((res) => {
if(this.record_status == 0) this.record_status = 1
console.log('开始录音')
})
//监听暂停
this.recordInstance.onPause(() => {
console.log('监听暂停')
this.record_status = 2
this.record_time_copy = this.record_time
})
//监听继续
this.recordInstance.onResume(() => {
console.log('监听继续')
this.record_status = 3
this.record_time_copy = this.record_time
})
//监听结束
this.recordInstance.onStop((res) => {
console.log(res.tempFilePath,'监听结束')
this.record_status = 4
this.recordFile.fullPath = res.tempFilePath
this.recordFile.name = res.tempFilePath
})
//监听错误
this.recordInstance.onError((err) => { console.log(err) })
if(this.record_status == 0) {
this.recordInstance.start({duration:600000,format:'wav'});
return;
}else if(this.record_status == 1) {//暂停
this.recordInstance.pause()
return;
}else if(this.record_status == 2) {//继续
this.recordInstance.resume()
return;
}else if(this.record_status == 3) {//暂停
this.recordInstance.pause()
return;
}
},
//录音完成
saveRecord() {
if(this.record_status != 4)
this.recordInstance.stop()
},
//设置定时器
setTime() {
if(this.timer) return;
this.timer = setInterval(() => {
if(this.record_time >= this.time){
return this.record_status = 4
}
this.record_time = this.record_time + 1
},1000)
},
//清除定时器
clearTime() {clearInterval(this.timer);this.timer = null},
//获取录音权限
getRecordSetting() {
// console.log(uni.getSetting,'uni.getSetting')
// #ifdef MP-WEIXIN
this.toggleDialog = !this.toggleDialog
// #endif
// #ifdef APP-PLUS
this.confirmPlatform()
// #endif
},
// #ifdef MP-WEIXIN
setSetting() {
uni.getSetting({
success: (res) => {
console.log(res, JSON.stringify(res, 'getSetting'))
if (res.authSetting['scope.record'] != undefined && res.authSetting['scope.record'] != true) {
uni.showModal({
title: '请求授权位置权限',
content: '需要获取位置权限,请确认授权',
success: (res) => {
if (res.cancel) {
this.$refs.uToast.show({
title: '拒绝授权!',
type: 'warning'
})
} else if (res.confirm) {
uni.openSetting({
success: (dataAu) => {
console.log(dataAu, 'openSetting')
if (dataAu.authSetting[
"scope.record"] == true) {
this.$refs.uToast.show({
title: '授权成功!',
type: 'success'
})
//再次授权,调用wx.getLocation的API
this.MPWEIXINstart()
} else {
this.$refs.uToast.show({
title: '授权失败!',
type: 'warning'
})
}
}
})
}
}
})
} else if (res.authSetting['scope.record'] == undefined) {
//调用wx.getLocation的API
console.log('首次授权')
this.MPWEIXINstart()
} else {
//调用wx.getLocation的API
this.MPWEIXINstart()
}
},
fail(err){
console.log(err,'fail')
},
complete(err) {
console.log(err,'getSetting')
}
})
},
// #endif
// #ifdef APP-PLUS
// 确定运行平台
confirmPlatform() {
switch (uni.getSystemInfoSync().platform) {
case 'android':
console.log('运行Android上');
this.androidGetRecordSetting()
break;
case 'ios':
console.log('运行iOS上');
break;
default:
console.log('运行在开发者工具上');
break;
}
},
//android权限设置
androidGetRecordSetting() {
plus.android.requestPermissions(['android.permission.RECORD_AUDIO'], (e) => {
console.log(e.length > 0, 'e-----android权限设置')
if (e.deniedAlways.length > 0) { //权限被永久拒绝
// plus.runtime.openURL("app-settings://");
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
//可能应该直接进入应用列表的权限设置?=> android.settings.APPLICATION_SETTINGS
var mIntent = new Intent('android.settings.APPLICATION_SETTINGS');
main.startActivity(mIntent);
// 弹出提示框解释为何需要定位权限,引导用户打开设置页面开启
this.$refs.uToast.show({
title: '该功能需要录音权限,请在权限设置中进行授权!'
})
console.log('Always Denied!!! ' + e.deniedAlways.toString());
}
if (e.deniedPresent.length > 0) { //权限被临时拒绝
this.toggleDialog = !this.toggleDialog
// 弹出提示框解释为何需要定位权限,可再次调用plus.android.requestPermissions申请权限
console.log('Present Denied!!! ' + e.deniedPresent.toString());
}
if (e.granted.length > 0) { //权限被允许
//调用依赖获取定位权限的代码
this.toggleDialog = !this.toggleDialog
console.log('Granted!!! ' + e.granted.toString());
}
}, (e) => {
// this.toggleDialog = !this.toggleDialog
// console.log('Request Permissions error:' + JSON.stringify(e));
});
},
// #endif
//数字转时间
secondsFormat(sec){
let hour = Math.floor(sec / 3600)
let minute = Math.floor((sec - hour * 3600) / 60)
let second = sec - hour * 3600 - minute * 60
if (hour < 10) { hour = "0" + hour; }
if (minute < 10) { minute = "0" + minute; }
if (second < 10) { second = "0" + second; }
return hour + ":" + minute + ":" + second;
},
//录音转文字
async getSpeech(tempFilePath) {
await getSpeech({ filePath: this.tempFilePath || tempFilePath }, { myFile: this.tempFilePath || tempFilePath })
.then(res => {
console.log(res, '录音转文字')
this.$emit('input', JSON.parse(res.data.data)[0])
this.$refs.uToast.show({ title: '录音转文字成功,请粘贴内容', type: 'success' })
})
},
},
watch: {
record_time(newValue, oldValue) {
if(newValue == 0) {
this.record_progress_time = 0
this.record_formate_time = '00:00:00'
}else {
this.record_progress_time = (newValue * 100) / this.time
this.record_formate_time = this.secondsFormat(newValue)
}
},
//录音状态0未开始,1开始,2暂停,3继续,4结束录,5播放,6重新录
record_status(newValue, oldValue) {
switch(newValue) {
case 0 : this.initData() ;this.startBtnText = '开始';this.topTipText=""; break;
case 1 : this.setTime() ;this.startBtnText = '暂停' ;this.topTipText="录音中..."; break;
case 2 : this.clearTime() ;this.startBtnText = '继续' ;this.topTipText="录音中..."; break;
case 3 : this.setTime() ;this.startBtnText = '暂停'; this.topTipText="录音中..."; break;
case 4 : this.clearTime() ;this.startBtnText = '录制结束' ; this.playBtnText = '播放录音';this.topTipText=""; break;
case 5 : this.clearTime() ;this.playBtnText = '录音播放中';this.topTipText="播放中..."; break;
}
},
},
mounted() {
this.init() //初始化对象
},
computed:{
//格式化已经录制的时间
formatRecordTime() {
return this.secondsFormat(this.record_time)
}
}
}
</script>
<style lang="scss">
//录音弹窗样式
.recordWrap {
width: 100%;
height: 100vh;
background-color: #000000;
position: relative;
z-index: 999;
box-sizing: border-box;
padding-bottom: 100rpx;
overflow: hidden;
color: white;
.progress_time_wrap{
margin-top: 200rpx;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.top_tip{
position: absolute;
top: 20rpx;
left: 0;
width: 100%;
text-align: center;
height: 60rpx;
line-height: 60rpx;
}
.record_control{
display: flex;
padding: 100rpx;
justify-content: center;
align-items: center;
.btn{
position: relative;
margin: 0 40rpx;
transition: all .5s;
background: #d8d6d6;
box-shadow: 0 0 10px #d8d6d6;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
display: flex;
justify-content: space-around;
align-items: center;
padding: 20rpx;
box-sizing: border-box;
&:active{
transform: scale(0.8);
}
.btn_title{
position: absolute;
top: 100%;
width: 100%;
font-size: 28rpx;
text-align: center;
white-space: nowrap;
}
.in_btn{
background-color: red;
transition: all .5s;
height: 100%;
&.start {
width: 40rpx;
&.start.l_btn{
border-radius: 40rpx 0 0 40rpx;
}
&.start.r_btn{
border-radius: 0 40rpx 40rpx 0;
}
}
&.pause {
width: 20rpx;
border-radius: 10rpx
}
&.reset_btn{
width: 100%;
height: 100%;
border-radius: 20rpx;
}
&.play{
width: 100%;
height: 100%;
border-radius: 10rpx;
&.play.l_play_btn{
background-color: transparent;
// transform: rotate(-45deg);
}
&.play.r_end_btn{
background-color: transparent;
}
}
&.end{
width: 20rpx;
border-radius: 10rpx
}
}
}
}
.action_btn{
position: absolute;
z-index: 1;
bottom: 8rpx;
left: 0;
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
box-sizing: border-box;
.btn{
flex: 1;
margin: 32rpx;
}
}
.footer{
}
}
.load_more_m {
margin: 33vh auto auto;
width: 300rpx;
height: 200rpx;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 20rpx;
flex-direction: column;
.word {
margin-top: 24rpx;
letter-spacing: 0.1em;
}
}
</style>
<fs-audio v-model="CONTENT"></fs-audio>