This commit is contained in:
Your Name
2026-03-19 12:19:00 +08:00
parent 7832514f28
commit 7147c8e148
243 changed files with 1662 additions and 437 deletions
+98 -9
View File
@@ -1,5 +1,9 @@
<template>
<view class="chat-container">
<view
class="chat-container"
@touchend.capture="onRecordingTouchEnd"
@touchcancel.capture="onRecordingTouchCancel"
>
<!-- 顶部导航栏 -->
<!-- 消息列表 -->
<scroll-view
@@ -126,8 +130,20 @@
</view>
<!-- 录音浮层 - 微信风格 -->
<view v-if="isRecording" class="recording-overlay">
<view class="recording-popup" :class="{ 'recording-cancel': willCancel }">
<view
v-if="isRecording"
class="recording-overlay"
@click="forceCancelRecording"
@touchend="onVoiceTouchEnd"
@touchcancel="onVoiceTouchCancel"
>
<view
class="recording-popup"
:class="{ 'recording-cancel': willCancel }"
@click.stop
@touchend.stop="onVoiceTouchEnd"
@touchcancel.stop="onVoiceTouchCancel"
>
<view class="recording-icon">
<view v-if="!willCancel" class="recording-waves">
<view class="wave"></view>
@@ -183,6 +199,9 @@
const isRecording = ref(false);
const recordingDuration = ref(0);
const willCancel = ref(false); // 上滑取消
let voiceModeSwitchTime = 0; // 切换语音模式的时间戳,用于防误触
let voiceHoldTimer = null; // 按住计时器,必须按住超过此时间才真正开始录音
let isVoiceTouchDown = false; // 手指是否仍在按下
const playingAudioId = ref('');
let innerAudioContext = null;
let chat = null;
@@ -210,7 +229,27 @@
// 切换输入模式(文字/语音)
function toggleInputMode() {
inputMode.value = inputMode.value === 'text' ? 'voice' : 'text';
const isSwitchToVoice = inputMode.value === 'text';
inputMode.value = isSwitchToVoice ? 'voice' : 'text';
// 切换到语音时:重置录音状态,防止卡住;记录时间用于防误触
if (isSwitchToVoice) {
isVoiceTouchDown = false;
if (voiceHoldTimer) {
clearTimeout(voiceHoldTimer);
voiceHoldTimer = null;
}
isRecording.value = false;
willCancel.value = false;
recordingDuration.value = 0;
if (recordingTimer) {
clearInterval(recordingTimer);
recordingTimer = null;
}
if (recorderManager) {
try { recorderManager.stop(); } catch (_) {}
}
voiceModeSwitchTime = Date.now();
}
}
// 初始化录音管理器
@@ -239,14 +278,23 @@
// #endif
}
// 按住说话 - 开始
// 按住说话 - 开始(必须按住超过 300ms 才真正开始录音,点击一下不会触发)
function onVoiceTouchStart(e) {
// #ifdef MP-WEIXIN
// 防误触:刚切换语音模式 400ms 内忽略触摸
if (Date.now() - voiceModeSwitchTime < 400) return;
e.preventDefault();
isVoiceTouchDown = true;
willCancel.value = false;
touchStartY = e.touches[0]?.clientY || 0;
if (!recorderManager) initRecorderManager();
startRecord();
// 必须按住 300ms 才真正开始录音,点击一下不会触发
voiceHoldTimer = setTimeout(() => {
voiceHoldTimer = null;
if (isVoiceTouchDown) {
startRecord();
}
}, 300);
// #endif
// #ifndef MP-WEIXIN
uni.showToast({ title: '当前平台暂不支持语音', icon: 'none' });
@@ -257,6 +305,13 @@
function onVoiceTouchEnd(e) {
// #ifdef MP-WEIXIN
e.preventDefault();
isVoiceTouchDown = false;
if (voiceHoldTimer) {
clearTimeout(voiceHoldTimer);
voiceHoldTimer = null;
// 未按住满 300ms 就松开了,不开始录音
return;
}
if (isRecording.value && recorderManager) {
recorderManager.stop();
}
@@ -268,6 +323,40 @@
onVoiceTouchEnd(e);
}
// 捕获阶段监听:录音时任意位置松开都能结束(解决浮层遮挡导致 touchend 收不到的问题)
function onRecordingTouchEnd(e) {
if (isRecording.value) {
e.stopPropagation();
onVoiceTouchEnd(e);
}
}
function onRecordingTouchCancel(e) {
if (isRecording.value) {
e.stopPropagation();
onVoiceTouchCancel(e);
}
}
// 强制取消录音(点击蒙层逃生,防止卡住)
function forceCancelRecording() {
isVoiceTouchDown = false;
if (voiceHoldTimer) {
clearTimeout(voiceHoldTimer);
voiceHoldTimer = null;
}
if (!isRecording.value) return;
willCancel.value = true;
if (recorderManager) {
try { recorderManager.stop(); } catch (_) {}
}
isRecording.value = false;
recordingDuration.value = 0;
if (recordingTimer) {
clearInterval(recordingTimer);
recordingTimer = null;
}
}
let touchStartY = 0;
// 监听上滑取消
function onVoiceTouchMove(e) {
@@ -964,16 +1053,16 @@
justify-content: center;
flex-shrink: 0;
font-weight: 500;
background: #e0e0e0;
}
.avatar-in {
background: #e0e0e0;
margin-right: 20rpx;
}
.avatar-out {
background: #95ec69;
margin-left: 20rpx;
}