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

277 lines
5.7 KiB
Vue
Raw Normal View History

2024-12-18 15:46:27 +08:00
<!-- 语音 -->
<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: 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)
}
})
emit('send', message)
} 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>