312 lines
10 KiB
Vue
312 lines
10 KiB
Vue
<template>
|
|
<view class="send--voice">
|
|
<view class="voice" hover-class="chat-hover" @touchstart="startRecord" @touchend="stopRecord"
|
|
@touchmove="touchmove">
|
|
<text class="button">按住 说话</text>
|
|
</view>
|
|
<!-- 录音层 -->
|
|
<view class="lay" v-if="showRecordTip">
|
|
<view class="lay-header">
|
|
<view class="modal">
|
|
<image class="icon" src="@/static/icon/record-icon.png" mode="widthFix"></image>
|
|
<text class="text">录音中 {{recordTime}} s</text>
|
|
</view>
|
|
</view>
|
|
<view class="lay-toast">上滑取消</view>
|
|
<view class="lay-footer">
|
|
<image class="lay-footer-icon videoFlicker" src="@/static/icon/audio_green.png" mode="widthFix"></image>
|
|
<view class="lay-footer-text">松开发送</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import im from '@/utils/im/index.js'
|
|
import permision from '@/utils/permission.js'
|
|
import imBase from '../../mixins/imBase.js'
|
|
|
|
export default {
|
|
mixins: [
|
|
imBase
|
|
],
|
|
props: {
|
|
conversationType: {
|
|
type: Number,
|
|
default: 0
|
|
},
|
|
targetId: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
showRecordTip: false,
|
|
recordTime: 60,
|
|
interval: 0,
|
|
maxRecordTime: 60,
|
|
recorderManager: null,
|
|
mp3AudioSrc: null,
|
|
isMoveCancel: false,
|
|
isBetaPlay: false, // 暂时无用
|
|
startOffsetTop: 0
|
|
}
|
|
},
|
|
computed: {
|
|
sender() {
|
|
return this.$store.getters.sender
|
|
}
|
|
},
|
|
created() {
|
|
this.recorderManager = uni.getRecorderManager()
|
|
},
|
|
methods: {
|
|
// 检查安卓录制权限
|
|
async getAndroidPermission() {
|
|
return await permision.requestAndroidPermission('android.permission.RECORD_AUDIO')
|
|
},
|
|
// 录制语音消息
|
|
startRecord(e) {
|
|
this.getAndroidPermission().then(code => {
|
|
switch (code) {
|
|
case 1:
|
|
this.startOffsetTop = e.target.offsetTop
|
|
this.showRecordTip = true
|
|
this.recorderManager.start()
|
|
this.interval = setInterval(() => {
|
|
this.recordTime -= 1
|
|
if (this.recordTime === 0) {
|
|
this.stopRecord()
|
|
}
|
|
}, 1000)
|
|
break;
|
|
case 0:
|
|
uni.showToast({
|
|
title: '暂无麦克风权限,请前往应用设置开启麦克风',
|
|
icon: 'none'
|
|
})
|
|
break;
|
|
case -1:
|
|
uni.showToast({
|
|
title: '应用权限错误',
|
|
icon: 'none'
|
|
})
|
|
break;
|
|
}
|
|
})
|
|
},
|
|
// 结束录音
|
|
stopRecord(e) {
|
|
if (!this.showRecordTip) return
|
|
// 延迟500毫秒结束录音
|
|
setTimeout(() => {
|
|
this.recorderManager.stop()
|
|
clearInterval(this.interval)
|
|
// 监听录音结束
|
|
this.recorderManager.onStop(res => {
|
|
if (this.isMoveCancel) {
|
|
this.isMoveCancel = false
|
|
return
|
|
}
|
|
if ((this.maxRecordTime - this.recordTime) <= 0) {
|
|
uni.showToast({
|
|
title: '说话时间太短',
|
|
icon: 'none',
|
|
})
|
|
this.showRecordTip = false
|
|
return
|
|
}
|
|
this.mp3AudioSrc = res.tempFilePath
|
|
this.showRecordTip = false
|
|
this.senVoice()
|
|
})
|
|
}, 500)
|
|
},
|
|
// 发送语音消息
|
|
senVoice() {
|
|
if (this.mp3AudioSrc === null) {
|
|
uni.showToast({
|
|
title: '发送失败, 暂无音频信息',
|
|
icon: 'none'
|
|
})
|
|
return
|
|
}
|
|
im.sentVoice(this.conversationType, this.targetId, this.mp3AudioSrc, (this.maxRecordTime -
|
|
this.recordTime)).then(() => {
|
|
this.recordTime = this.maxRecordTime
|
|
this.mp3AudioSrc = null
|
|
setTimeout(() => {
|
|
this.$emit('success')
|
|
this.toastAudiMp3()
|
|
}, 500)
|
|
})
|
|
},
|
|
// 移动按钮
|
|
touchmove(e) {
|
|
if (this.startOffsetTop - e.changedTouches[0].pageY > 100) {
|
|
if (this.showRecordTip) {
|
|
this.isMoveCancel = true
|
|
this.showRecordTip = false
|
|
this.recorderManager.stop()
|
|
clearInterval(this.interval)
|
|
this.recordTime = this.maxRecordTime
|
|
this.mp3AudioSrc = null
|
|
return
|
|
}
|
|
}
|
|
},
|
|
// 试听语音
|
|
startPlay() {
|
|
let betaAudio = uni.createInnerAudioContext()
|
|
betaAudio.src = this.mp3AudioSrc;
|
|
// 在播放中
|
|
if (this.isBetaPlay) {
|
|
betaAudio.stop()
|
|
betaAudio.onStop(() => {
|
|
this.isBetaPlay = false;
|
|
betaAudio.destroy()
|
|
})
|
|
return
|
|
}
|
|
// 监听音频播放中
|
|
betaAudio.play()
|
|
betaAudio.onPlay(() => {
|
|
this.isBetaPlay = true;
|
|
})
|
|
// 监听音频结束
|
|
betaAudio.onEnded(() => {
|
|
this.isBetaPlay = false;
|
|
betaAudio.destroy()
|
|
})
|
|
},
|
|
// 播放提示音乐
|
|
toastAudiMp3() {
|
|
let toastAudio = uni.createInnerAudioContext()
|
|
toastAudio.src = require('@/static/im/toast/sentVoice.mp3')
|
|
toastAudio.autoplay = true
|
|
toastAudio.volume = .1
|
|
toastAudio.onEnded(() => {
|
|
toastAudio.destroy()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
@keyframes playFlicker {
|
|
0% {
|
|
opacity: 1;
|
|
}
|
|
|
|
50% {
|
|
opacity: .5;
|
|
}
|
|
|
|
100% {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.videoFlicker {
|
|
animation: playFlicker 1s infinite;
|
|
}
|
|
</style>
|
|
|
|
<style scoped lang="scss">
|
|
.send--voice {
|
|
.voice {
|
|
display: flex;
|
|
background: $window-color;
|
|
height: 70rpx;
|
|
line-height: 70rpx;
|
|
justify-content: center;
|
|
align-items: center;
|
|
width: 400rpx;
|
|
border-radius: 10rpx;
|
|
margin-right: 15rpx;
|
|
padding: 0 20rpx;
|
|
font-weight: bold;
|
|
|
|
.button {
|
|
font-size: 30rpx;
|
|
color: #333;
|
|
}
|
|
}
|
|
|
|
.lay {
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: 9;
|
|
background: rgba($color: #000000, $alpha: .5);
|
|
height: 100vh;
|
|
width: 100vw;
|
|
box-sizing: border-box;
|
|
|
|
.lay-header {
|
|
height: calc(100vh - 140px);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
.modal {
|
|
display: flex;
|
|
background: rgba(0, 0, 0, .6);
|
|
position: fixed;
|
|
height: 200rpx;
|
|
width: 300rpx;
|
|
border-radius: 10rpx;
|
|
z-index: 99;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
|
|
.icon {
|
|
width: 88rpx;
|
|
height: 88rpx;
|
|
}
|
|
|
|
.text {
|
|
font-size: 28rpx;
|
|
color: #FFFFFF;
|
|
}
|
|
}
|
|
}
|
|
|
|
.lay-toast {
|
|
text-align: center;
|
|
color: rgba($color: #fff, $alpha: .8);
|
|
font-size: 28rpx;
|
|
}
|
|
|
|
.lay-footer {
|
|
background-color: white;
|
|
height: 100px;
|
|
border-radius: 50% 50% 0 0;
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
text-align: center;
|
|
display: flex;
|
|
justify-content: center;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
|
|
.lay-footer-icon {
|
|
width: 58rpx;
|
|
height: 58rpx;
|
|
}
|
|
|
|
.lay-footer-text {
|
|
line-height: 40rpx;
|
|
color: gray;
|
|
font-size: 28rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|