jiuyiUniapp/jiuyi2/pages/news/chat/jy-voice.vue

289 lines
5.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 语音 -->
<template>
<view class="voice_box" @touchstart="sv.touchstartVoice" @touchmove.stop.prevent="sv.touchmoveVoice"
@touchend="sv.touchendVoice" @touchcancel="sv.touchcancelVoice">
<text class="voice_text c000">{{ voiceText }}</text>
</view>
<!-- 语音状态显示 -->
<template v-if="voiceFlg">
<!-- 录音UI效果 -->
<view class="record" :class="voiceFlg ? '' : 'hidden'">
<uni-icons :class="[voiceStop ? 'cancel' : 'ing']" :type="voiceStop ? 'micoff' : 'mic'" size="100" />
<view class="tis" :class="voiceStop ? 'change' : ''">{{ voiceTis }}</view>
</view>
</template>
</template>
<script setup>
import {
ref,
defineEmits
} from 'vue'
// 腾讯云聊天
import TencentCloudChat from '@tencentcloud/chat';
const props = defineProps({
msg: {
type: Object
},
})
const emit = defineEmits(['send'])
//录音
// #ifdef APP-PLUS
const recorderManager = uni.getRecorderManager();
// #endif
// 录音时长
const voiceLength = ref(0);
// 录音定时器
const voiceTimer = ref(null);
// 录音文本
const voiceText = ref('按住 说话');
// 录音提示
const voiceTis = ref('手指上滑 取消发送');
// 录音图标显示
const voiceFlg = ref(false);
// 录音开始Y坐标
const voicePageY = ref(0);
// 录音结束
const voiceStop = ref(false);
const str = '';
// 录音相关
const sv = {
// 按下触发
touchstartVoice: (e) => {
voicePageY.value = (e.changedTouches[0].pageY).toFixed(2);
recorderManager.start({
duration: 60000, // 录音的时长,单位 ms最大值 60000010 分钟)
sampleRate: 44100, // 采样率
numberOfChannels: 1, // 录音通道数
encodeBitRate: 192000, // 编码码率
format: "mp3"
});
voiceLength.value = 0;
voiceFlg.value = true
console.log('recorder start success');
//录音开始,
voiceTimer.value = setInterval(() => {
voiceLength.value += 0.1;
}, 100);
console.log('touchstartVoice', voicePageY.value);
},
// 滑动触发
touchmoveVoice: (e) => {
// 没有展示UI不触发
if (!voiceFlg.value) {
return;
}
let numTemp = voicePageY.value - ((e.changedTouches[0].pageY).toFixed(2));
if (numTemp >= 60) {
console.log('取消发送');
voiceStop.value = true
voiceTis.value = '松开手指 取消发送'
} else {
console.log('继续发送');
voiceStop.value = false
voiceTis.value = '手指上滑 取消发送'
}
},
// 松开触发
touchendVoice: () => {
// 没有展示UI不触发
if (!voiceFlg.value) {
return;
}
clearInterval(voiceTimer.value);
voiceText.value = '按住 说话'
voiceTis.value = "手指上滑 取消发送"
console.log('touchendVoice');
sv.stop();
},
// 打断触发
touchcancelVoice: () => {
clearInterval(voiceTimer.value);
// 关闭UI
voiceText.value = '按住 说话'
voiceTis.value = "手指上滑 取消发送"
// 不发送语音
voiceStop.value = true
console.log('touchcancelVoice');
sv.stop();
},
stop: () => {
voiceTimer.value = null;
voiceFlg.value = false
recorderManager.stop(); // 录音结束
console.log('录音结束');
}
};
// #ifdef APP-PLUS
// 监听录音停止事件
recorderManager.onStop((res) => {
// 被打断等情况不发送
if (voiceStop.value) {
return
}
// 正常情况
if (voiceStop.value) {
uni.showToast({
icon: "none",
title: "取消发送",
duration: 2000
})
return
}
if (voiceLength.value < 1) {
uni.showToast({
icon: "none",
title: "语音时长过短",
duration: 2000
})
return
}
if (voiceLength.value > 60) {
uni.showToast({
icon: "none",
title: "语音时长过长",
duration: 2000
})
return
}
console.log('file', res)
try {
let message = uni.$chat.createAudioMessage({
to: props.msg.id,
conversationType: props.msg.type,
payload: {
file: res
},
// 音频上传进度回调
onProgress: function (event) {
console.log('file uploading:', event)
}
})
let obj = {
query: {
toUserId: message.to,
formId: message.from,
msgType: message.type,
},
data: message
}
emit('send', obj)
} catch (e) {
console.log('message catch', e)
}
//
})
// #endif
</script>
<style scoped lang="scss">
.voice_box {
padding: 20rpx 0;
margin: 0 20rpx;
border-radius: 50rpx;
background: #fff;
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.hidden {
display: none !important;
}
.record {
width: 40vw;
height: 40vw;
position: fixed;
top: 55%;
left: 30%;
background-color: rgba(0, 0, 0, .6);
border-radius: 20rpx;
.ing {
width: 100%;
height: 30vw;
display: flex;
justify-content: center;
align-items: center;
// 模拟录音音效动画
@keyframes volatility {
0% {
background-position: 0% 130%;
}
20% {
background-position: 0% 150%;
}
30% {
background-position: 0% 155%;
}
40% {
background-position: 0% 150%;
}
50% {
background-position: 0% 145%;
}
70% {
background-position: 0% 150%;
}
80% {
background-position: 0% 155%;
}
90% {
background-position: 0% 140%;
}
100% {
background-position: 0% 135%;
}
}
background-image: linear-gradient(to bottom, #f09b37, #fff 50%);
background-size: 100% 200%;
animation: volatility 1.5s ease-in-out -1.5s infinite alternate;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-size: 150rpx;
color: #f09b37;
}
.cancel {
width: 100%;
height: 30vw;
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 150rpx;
}
.tis {
width: 100%;
height: 10vw;
display: flex;
justify-content: center;
font-size: 28rpx;
color: #fff;
&.change {
color: #f09b37;
}
}
}
</style>