这是一个按钮录音弹窗:你也可你自己换成别的! 点击保存会返回 录音的 路径 通过 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' })
}
用到 scss、 组件库、图片位置
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,
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{
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' })
}
},
playRecord() {
if(this.record_status == 4) {
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('播放失败')
})
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()
}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() {
},
resetRecord() {
this.record_status = 0
},
openRecordDialog() {
console.log('录音弹窗切换', this.toggleDialog)
this.getRecordSetting()
},
createAudioList() {
},
startRecord() {
if(this.record_status == 4) {
this.$refs.uToast.show({ title: '请点击重新录制再进行此操作', type: 'warning' })
}
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
}, (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
console.log(this.recordInstance,'this.recordInstance')
this.recordInstance = uni.getRecorderManager()
this.setSetting()
},
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() {
this.toggleDialog = !this.toggleDialog
this.confirmPlatform()
},
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'
})
this.MPWEIXINstart()
} else {
this.$refs.uToast.show({
title: '授权失败!',
type: 'warning'
})
}
}
})
}
}
})
} else if (res.authSetting['scope.record'] == undefined) {
console.log('首次授权')
this.MPWEIXINstart()
} else {
this.MPWEIXINstart()
}
},
fail(err){
console.log(err,'fail')
},
complete(err) {
console.log(err,'getSetting')
}
})
},
confirmPlatform() {
switch (uni.getSystemInfoSync().platform) {
case 'android':
console.log('运行Android上');
this.androidGetRecordSetting()
break;
case 'ios':
console.log('运行iOS上');
break;
default:
console.log('运行在开发者工具上');
break;
}
},
androidGetRecordSetting() {
plus.android.requestPermissions(['android.permission.RECORD_AUDIO'], (e) => {
console.log(e.length > 0, 'e-----android权限设置')
if (e.deniedAlways.length > 0) {
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass("android.content.Intent");
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
console.log('Present Denied!!! ' + e.deniedPresent.toString());
}
if (e.granted.length > 0) {
this.toggleDialog = !this.toggleDialog
console.log('Granted!!! ' + e.granted.toString());
}
}, (e) => {
});
},
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)
}
},
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;
}
&.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>
ok 完事了, 有问题就问,我还会完善的!
|