修复:
1. 连接有问题 现有问题: 1. 视频流有问题
This commit is contained in:
@@ -13,7 +13,6 @@
|
||||
<!-- 拖拽头部 -->
|
||||
<div
|
||||
class="call-header"
|
||||
v-if="!isMinimized"
|
||||
@mousedown="startDrag"
|
||||
>
|
||||
<div class="call-info">
|
||||
@@ -36,6 +35,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 友好提示信息 -->
|
||||
<div v-if="!isMinimized && showFriendlyMessage" class="friendly-message">
|
||||
<div class="message-content">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span>{{ friendlyMessage }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设备状态指示 -->
|
||||
<div v-if="!isMinimized" class="device-status-container">
|
||||
<div v-if="callType === 'video' && !isCameraWorking" class="status-alert">
|
||||
@@ -44,6 +51,9 @@
|
||||
<div v-if="!isMicWorking" class="status-alert">
|
||||
<i class="fas fa-microphone-slash"></i> 麦克风未工作
|
||||
</div>
|
||||
<div v-if="!hasRemoteVideo && callType === 'video' && callStatus === 'ongoing'" class="status-alert remote-camera-off">
|
||||
<i class="fas fa-video-slash"></i> 对方未开启摄像头
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最小化状态 -->
|
||||
@@ -96,7 +106,7 @@
|
||||
<!-- 本地视频 -->
|
||||
<div
|
||||
class="local-video-container"
|
||||
v-if="callType === 'video' && isCameraWorking"
|
||||
v-if="callType === 'video' && showLocalVideo"
|
||||
>
|
||||
<video
|
||||
ref="localVideo"
|
||||
@@ -110,8 +120,8 @@
|
||||
v-else-if="callType === 'video'"
|
||||
class="local-placeholder-container"
|
||||
>
|
||||
<div class="local-avatar" :style="{ background: callerInfo.color }">
|
||||
{{ callerInfo.name.charAt(0) }}
|
||||
<div class="local-avatar" :style="{ background: userStore.currentUser?.color || '#666' }">
|
||||
{{ userStore.currentUser?.name?.charAt(0) || 'U' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -184,14 +194,16 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue';
|
||||
import { ref, reactive, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
|
||||
import { useThemeStore } from '@/stores/theme';
|
||||
import { useWebRTC } from '@/composables/useWebRTC';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
|
||||
const themeStore = useThemeStore();
|
||||
const chatStore = useChatStore();
|
||||
const webrtc = useWebRTC();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const props = defineProps({
|
||||
callerInfo: {
|
||||
@@ -220,10 +232,14 @@ const isSpeakerOn = ref(true);
|
||||
const hasRemoteVideo = ref(false);
|
||||
const callDuration = ref(0);
|
||||
const callTimer = ref(null);
|
||||
const isCameraWorking = ref(true);
|
||||
const isMicWorking = ref(true);
|
||||
const isDragging = ref(false);
|
||||
const isAccepting = ref(false); // 新增:防止重复接听
|
||||
const isAccepting = ref(false);
|
||||
const showLocalVideo = ref(false);
|
||||
|
||||
// 友好提示相关
|
||||
const showFriendlyMessage = ref(false);
|
||||
const friendlyMessage = ref('');
|
||||
const friendlyMessageTimer = ref(null);
|
||||
|
||||
// 拖拽相关状态
|
||||
const position = reactive({ x: 0, y: 0 });
|
||||
@@ -240,19 +256,30 @@ const callStatus = computed(() => {
|
||||
return chatStore.callStatus;
|
||||
});
|
||||
|
||||
// 本地媒体状态
|
||||
const hasLocalVideo = computed(() => webrtc.hasLocalVideo.value);
|
||||
const hasLocalAudio = computed(() => webrtc.hasLocalAudio.value);
|
||||
const isCameraWorking = computed(() => hasLocalVideo.value && isCameraOn.value);
|
||||
const isMicWorking = computed(() => hasLocalAudio.value && isMicOn.value);
|
||||
|
||||
// 连接状态文本
|
||||
const connectionText = computed(() => {
|
||||
// 优先使用 chatStore 中的详细状态
|
||||
if (chatStore.callConnectionStatus) {
|
||||
return chatStore.callConnectionStatus;
|
||||
}
|
||||
|
||||
// 处理忙线状态
|
||||
if (callStatus.value === "busy") {
|
||||
return '对方忙线中';
|
||||
}
|
||||
|
||||
// 默认状态显示
|
||||
if (callStatus.value === "hangup") {
|
||||
return '对方已挂断';
|
||||
}
|
||||
|
||||
if (callStatus.value === "disconnected") {
|
||||
return '网络连接已断开';
|
||||
}
|
||||
|
||||
if (props.isIncoming && callStatus.value !== "ongoing") {
|
||||
return '来电中...';
|
||||
}
|
||||
@@ -261,15 +288,44 @@ const connectionText = computed(() => {
|
||||
return `通话中 ${formattedDuration.value}`;
|
||||
}
|
||||
|
||||
if (callStatus.value === "connecting") {
|
||||
return '正在连接...';
|
||||
}
|
||||
|
||||
return '正在连接...';
|
||||
});
|
||||
|
||||
// 显示友好提示
|
||||
const showFriendlyNotification = (message, duration = 3000) => {
|
||||
friendlyMessage.value = message;
|
||||
showFriendlyMessage.value = true;
|
||||
|
||||
if (friendlyMessageTimer.value) {
|
||||
clearTimeout(friendlyMessageTimer.value);
|
||||
}
|
||||
|
||||
friendlyMessageTimer.value = setTimeout(() => {
|
||||
showFriendlyMessage.value = false;
|
||||
friendlyMessage.value = '';
|
||||
}, duration);
|
||||
};
|
||||
|
||||
// 通话计时器
|
||||
const startCallTimer = () => {
|
||||
if (callTimer.value) clearInterval(callTimer.value);
|
||||
callDuration.value = 0;
|
||||
callTimer.value = setInterval(() => {
|
||||
callDuration.value += 1;
|
||||
}, 1000);
|
||||
console.log("通话计时器已启动");
|
||||
};
|
||||
|
||||
const stopCallTimer = () => {
|
||||
if (callTimer.value) {
|
||||
clearInterval(callTimer.value);
|
||||
callTimer.value = null;
|
||||
console.log("通话计时器已停止");
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化通话时间
|
||||
@@ -289,43 +345,53 @@ const containerStyle = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
// 初始化媒体设备 - 修复:只在需要时获取媒体
|
||||
// 初始化媒体设备
|
||||
const initializeMedia = async () => {
|
||||
try {
|
||||
// 只有在接听来电或通话已接受时才获取媒体
|
||||
if (props.isIncoming && callStatus.value === "ringing") {
|
||||
if (callStatus.value === "calling" || callStatus.value === "connecting" || callStatus.value === "ongoing") {
|
||||
const constraints = {
|
||||
audio: true,
|
||||
video: props.callType === 'video'
|
||||
};
|
||||
|
||||
console.log("初始化媒体设备,约束:", constraints);
|
||||
await webrtc.getLocalMedia(constraints);
|
||||
|
||||
// 立即设置本地视频
|
||||
await nextTick();
|
||||
updateLocalVideo();
|
||||
|
||||
} else if (props.isIncoming && callStatus.value === "ringing") {
|
||||
console.log("来电状态,暂不获取媒体流");
|
||||
return;
|
||||
}
|
||||
|
||||
if (callStatus.value === "calling") {
|
||||
console.log("呼出状态,暂不获取媒体流");
|
||||
return;
|
||||
}
|
||||
|
||||
const constraints = {
|
||||
audio: true,
|
||||
video: props.callType === 'video'
|
||||
};
|
||||
|
||||
console.log("初始化媒体设备,约束:", constraints);
|
||||
// 获取本地媒体流
|
||||
await webrtc.getLocalMedia(constraints);
|
||||
|
||||
if (callStatus.value === "ongoing") {
|
||||
startCallTimer();
|
||||
} else {
|
||||
console.log("当前状态不需要获取媒体:", callStatus.value);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('无法访问媒体设备:', error);
|
||||
isCameraOn.value = false;
|
||||
isCameraWorking.value = false;
|
||||
console.warn('无法访问媒体设备,但继续通话流程:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 更新本地视频显示
|
||||
const updateLocalVideo = async () => {
|
||||
await nextTick();
|
||||
if (webrtc.localStream.value && localVideo.value) {
|
||||
console.log("设置本地视频流到video元素");
|
||||
localVideo.value.srcObject = webrtc.localStream.value;
|
||||
showLocalVideo.value = props.callType === 'video' && webrtc.hasLocalVideo.value;
|
||||
console.log("本地视频显示状态:", showLocalVideo.value);
|
||||
} else {
|
||||
console.log("本地视频流或元素不存在:", {
|
||||
stream: !!webrtc.localStream.value,
|
||||
element: !!localVideo.value
|
||||
});
|
||||
showLocalVideo.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 控制功能
|
||||
const toggleMic = () => {
|
||||
isMicOn.value = !isMicOn.value;
|
||||
isMicWorking.value = isMicOn.value;
|
||||
if (webrtc.localStream.value) {
|
||||
webrtc.localStream.value.getAudioTracks().forEach(track => {
|
||||
track.enabled = isMicOn.value;
|
||||
@@ -333,14 +399,18 @@ const toggleMic = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const toggleCamera = () => {
|
||||
const toggleCamera = async () => {
|
||||
if (props.callType === 'video') {
|
||||
isCameraOn.value = !isCameraOn.value;
|
||||
isCameraWorking.value = isCameraOn.value;
|
||||
if (webrtc.localStream.value) {
|
||||
webrtc.localStream.value.getVideoTracks().forEach(track => {
|
||||
track.enabled = isCameraOn.value;
|
||||
});
|
||||
|
||||
try {
|
||||
await webrtc.toggleVideoStream(isCameraOn.value);
|
||||
await nextTick();
|
||||
updateLocalVideo();
|
||||
console.log("摄像头切换成功:", isCameraOn.value);
|
||||
} catch (error) {
|
||||
console.error("摄像头切换失败:", error);
|
||||
isCameraOn.value = !isCameraOn.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -355,21 +425,18 @@ const toggleSpeaker = () => {
|
||||
const toggleMinimize = () => {
|
||||
isMinimized.value = !isMinimized.value;
|
||||
|
||||
// 最小化时确保在屏幕内
|
||||
if (isMinimized.value) {
|
||||
position.x = Math.max(0, Math.min(position.x, window.innerWidth - 200));
|
||||
position.y = Math.max(0, Math.min(position.y, window.innerHeight - 60));
|
||||
} else {
|
||||
// 最大化时确保在屏幕内
|
||||
position.x = Math.max(0, Math.min(position.x, window.innerWidth - 500));
|
||||
position.y = Math.max(0, Math.min(position.y, window.innerHeight - 380));
|
||||
}
|
||||
};
|
||||
|
||||
const endCall = () => {
|
||||
if (callTimer.value) clearInterval(callTimer.value);
|
||||
stopCallTimer();
|
||||
|
||||
// 清除所有视频源
|
||||
if (localVideo.value) localVideo.value.srcObject = null;
|
||||
if (remoteVideo.value) remoteVideo.value.srcObject = null;
|
||||
if (remoteVideoPreview.value) remoteVideoPreview.value.srcObject = null;
|
||||
@@ -381,7 +448,6 @@ const endCall = () => {
|
||||
|
||||
// 接听通话
|
||||
const acceptCall = () => {
|
||||
// 防止重复点击
|
||||
if (isAccepting.value || chatStore.callStatus === "connecting" || chatStore.callStatus === "ongoing") {
|
||||
console.log("已在处理接听或通话中,忽略重复点击")
|
||||
return;
|
||||
@@ -390,13 +456,12 @@ const acceptCall = () => {
|
||||
console.log("用户点击接听按钮")
|
||||
isAccepting.value = true;
|
||||
|
||||
// 调用store的acceptCall方法
|
||||
chatStore.acceptCall().then(() => {
|
||||
console.log("接听请求已发送")
|
||||
showFriendlyNotification("正在接听通话...", 2000);
|
||||
}).catch((error) => {
|
||||
console.error("接听失败:", error)
|
||||
}).finally(() => {
|
||||
// 延迟重置状态,避免快速重复点击
|
||||
setTimeout(() => {
|
||||
isAccepting.value = false;
|
||||
}, 3000);
|
||||
@@ -407,7 +472,6 @@ const acceptCall = () => {
|
||||
|
||||
// 拒绝通话
|
||||
const rejectCall = () => {
|
||||
// 确保只拒绝一次
|
||||
if (chatStore.callStatus === "idle" || isAccepting.value) {
|
||||
console.log("通话已结束或正在接听,忽略拒绝操作")
|
||||
return;
|
||||
@@ -427,7 +491,6 @@ const startDrag = (event) => {
|
||||
|
||||
isDragging.value = true;
|
||||
|
||||
// 记录初始位置(鼠标位置和元素位置)
|
||||
startPosition.x = event.clientX;
|
||||
startPosition.y = event.clientY;
|
||||
|
||||
@@ -438,19 +501,15 @@ const startDrag = (event) => {
|
||||
const handleDrag = (event) => {
|
||||
if (!isDragging.value) return;
|
||||
|
||||
// 计算鼠标移动的偏移量
|
||||
const deltaX = event.clientX - startPosition.x;
|
||||
const deltaY = event.clientY - startPosition.y;
|
||||
|
||||
// 更新元素位置
|
||||
position.x += deltaX;
|
||||
position.y += deltaY;
|
||||
|
||||
// 更新初始位置为当前位置
|
||||
startPosition.x = event.clientX;
|
||||
startPosition.y = event.clientY;
|
||||
|
||||
// 确保不超出屏幕边界
|
||||
const width = isMinimized.value ? 200 : 500;
|
||||
const height = isMinimized.value ? 60 : 380;
|
||||
|
||||
@@ -474,16 +533,15 @@ const handleWindowResize = () => {
|
||||
};
|
||||
|
||||
// 监听本地流变化
|
||||
watch(() => webrtc.localStream.value, (newStream) => {
|
||||
if (newStream && localVideo.value) {
|
||||
localVideo.value.srcObject = newStream;
|
||||
} else if (localVideo.value) {
|
||||
localVideo.value.srcObject = null;
|
||||
}
|
||||
watch(() => webrtc.localStream.value, async (newStream) => {
|
||||
console.log("本地流变化:", !!newStream);
|
||||
await nextTick();
|
||||
updateLocalVideo();
|
||||
});
|
||||
|
||||
// 监听远程流变化
|
||||
watch(() => webrtc.remoteStream.value, (newStream) => {
|
||||
console.log("远程流变化:", !!newStream);
|
||||
if (newStream) {
|
||||
if (remoteVideo.value) {
|
||||
remoteVideo.value.srcObject = newStream;
|
||||
@@ -503,46 +561,76 @@ watch(() => webrtc.remoteStream.value, (newStream) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 监听通话状态 - 修复:避免过早关闭连接
|
||||
// 监听通话状态
|
||||
watch(() => chatStore.callStatus, (status, oldStatus) => {
|
||||
console.log("VideoCallComponent 监听到通话状态变化:", oldStatus, "->", status);
|
||||
|
||||
if (status === "ongoing") {
|
||||
// 开始计时
|
||||
if (status === "calling") {
|
||||
console.log("发起通话,初始化媒体设备")
|
||||
initializeMedia();
|
||||
} else if (status === "ongoing") {
|
||||
if (!callTimer.value) {
|
||||
console.log("开始通话计时")
|
||||
startCallTimer();
|
||||
}
|
||||
showFriendlyNotification("通话已连接", 2000);
|
||||
} else if (status === "ended" || status === "idle") {
|
||||
// 只有在真正结束时才关闭
|
||||
console.log("通话结束,准备关闭组件");
|
||||
stopCallTimer();
|
||||
setTimeout(() => {
|
||||
endCall();
|
||||
}, 100); // 延迟一点确保状态同步
|
||||
}, 100);
|
||||
} else if (status === "connecting") {
|
||||
// 连接中时初始化媒体
|
||||
console.log("通话连接中,初始化媒体设备")
|
||||
initializeMedia();
|
||||
console.log("通话连接中,确保媒体设备已初始化")
|
||||
if (!webrtc.localStream.value) {
|
||||
initializeMedia();
|
||||
}
|
||||
showFriendlyNotification("正在建立连接...", 2000);
|
||||
} else if (status === "failed") {
|
||||
console.log("通话失败")
|
||||
showFriendlyNotification("连接失败", 3000);
|
||||
setTimeout(() => {
|
||||
endCall();
|
||||
}, 3000); // 3秒后关闭
|
||||
}, 3000);
|
||||
} else if (status === "hangup") {
|
||||
console.log("对方已挂断,3秒后关闭组件")
|
||||
showFriendlyNotification("对方已挂断", 3000);
|
||||
setTimeout(() => {
|
||||
endCall();
|
||||
}, 3000);
|
||||
} else if (status === "disconnected") {
|
||||
console.log("网络连接已断开,3秒后关闭组件")
|
||||
showFriendlyNotification("网络连接已断开", 3000);
|
||||
setTimeout(() => {
|
||||
endCall();
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听连接状态变化以显示友好提示
|
||||
watch(() => chatStore.callConnectionStatus, (newStatus, oldStatus) => {
|
||||
if (newStatus && newStatus !== oldStatus) {
|
||||
if (newStatus.includes("对方已接听")) {
|
||||
showFriendlyNotification("对方已接听", 2000);
|
||||
} else if (newStatus.includes("对方已拒绝")) {
|
||||
showFriendlyNotification("对方已拒绝", 3000);
|
||||
} else if (newStatus.includes("对方已挂断")) {
|
||||
showFriendlyNotification("对方已挂断", 3000);
|
||||
} else if (newStatus.includes("通话已连接")) {
|
||||
showFriendlyNotification("通话已连接", 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
// 设置初始居中位置
|
||||
position.x = Math.max(0, (window.innerWidth - 500) / 2);
|
||||
position.y = Math.max(0, (window.innerHeight - 380) / 2);
|
||||
|
||||
window.addEventListener('resize', handleWindowResize);
|
||||
|
||||
// 修复:根据通话状态决定是否初始化媒体
|
||||
console.log("VideoCallComponent mounted, callStatus:", callStatus.value, "isIncoming:", props.isIncoming);
|
||||
console.log("VideoCallComponent mounted, callStatus:", chatStore.callStatus, "isIncoming:", props.isIncoming);
|
||||
|
||||
// 只有在特定状态下才初始化媒体
|
||||
if (callStatus.value === 'ongoing' || callStatus.value === 'connecting') {
|
||||
if (['calling', 'connecting', 'ongoing'].includes(chatStore.callStatus)) {
|
||||
initializeMedia();
|
||||
}
|
||||
});
|
||||
@@ -550,12 +638,15 @@ onMounted(() => {
|
||||
onUnmounted(() => {
|
||||
console.log("VideoCallComponent unmounted");
|
||||
|
||||
if (callTimer.value) clearInterval(callTimer.value);
|
||||
stopCallTimer();
|
||||
if (friendlyMessageTimer.value) {
|
||||
clearTimeout(friendlyMessageTimer.value);
|
||||
}
|
||||
|
||||
document.removeEventListener('mousemove', handleDrag);
|
||||
document.removeEventListener('mouseup', stopDrag);
|
||||
window.removeEventListener('resize', handleWindowResize);
|
||||
|
||||
// 清除所有视频源
|
||||
if (localVideo.value) {
|
||||
localVideo.value.srcObject = null;
|
||||
}
|
||||
@@ -566,7 +657,6 @@ onUnmounted(() => {
|
||||
remoteVideoPreview.value.srcObject = null;
|
||||
}
|
||||
|
||||
// 关闭WebRTC连接
|
||||
webrtc.closeConnection();
|
||||
});
|
||||
</script>
|
||||
@@ -670,13 +760,47 @@ onUnmounted(() => {
|
||||
background: #ff6b6b;
|
||||
}
|
||||
|
||||
.device-status-container {
|
||||
.friendly-message {
|
||||
position: absolute;
|
||||
top: 65px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
z-index: 15;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.message-content {
|
||||
background: rgba(76, 175, 80, 0.9);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
animation: slideInDown 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideInDown {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.device-status-container {
|
||||
position: absolute;
|
||||
top: 90px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 15px;
|
||||
z-index: 10;
|
||||
padding: 5px;
|
||||
@@ -691,6 +815,10 @@ onUnmounted(() => {
|
||||
animation: blink 1.5s infinite;
|
||||
}
|
||||
|
||||
.status-alert.remote-camera-off {
|
||||
background: rgba(255, 152, 0, 0.8);
|
||||
}
|
||||
|
||||
@keyframes blink {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.6; }
|
||||
@@ -738,6 +866,7 @@ onUnmounted(() => {
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mini-info {
|
||||
@@ -799,6 +928,7 @@ onUnmounted(() => {
|
||||
justify-content: center;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
@@ -852,6 +982,12 @@ onUnmounted(() => {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.local-video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.call-controls {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
@@ -898,7 +1034,6 @@ onUnmounted(() => {
|
||||
background: #ff5252;
|
||||
}
|
||||
|
||||
/* 新增来电控制按钮样式 */
|
||||
.incoming-call-controls {
|
||||
position: absolute;
|
||||
bottom: 100px;
|
||||
@@ -942,7 +1077,6 @@ onUnmounted(() => {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 添加忙线状态样式 */
|
||||
.busy-status {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
color: #ff6b6b;
|
||||
@@ -958,7 +1092,6 @@ onUnmounted(() => {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 600px) {
|
||||
.video-call-container:not(.minimized) {
|
||||
width: 95vw !important;
|
||||
|
||||
@@ -9,9 +9,11 @@ export function useWebRTC() {
|
||||
const peerConnection = ref(null)
|
||||
const isConnected = ref(false)
|
||||
const isConnecting = ref(false)
|
||||
const hasLocalVideo = ref(false)
|
||||
const hasLocalAudio = ref(false)
|
||||
|
||||
const userStore = useUserStore()
|
||||
const chatStore = useChatStore() // Moved to top-level
|
||||
const chatStore = useChatStore()
|
||||
|
||||
const configuration = {
|
||||
iceServers: [
|
||||
@@ -36,29 +38,27 @@ export function useWebRTC() {
|
||||
if (event.candidate) {
|
||||
console.log("发送ICE候选:", event.candidate)
|
||||
|
||||
// 只有在连接建立过程中才发送 ICE 候选
|
||||
if (chatStore.callStatus === "connecting" || chatStore.callStatus === "ongoing") {
|
||||
try {
|
||||
await callAPI.sendCandidate(
|
||||
userStore.currentUser?.id,
|
||||
peerId,
|
||||
callId,
|
||||
event.candidate,
|
||||
6, // 默认视频通话类型
|
||||
)
|
||||
await callAPI.sendCandidate(userStore.currentUser?.id, peerId, callId, event.candidate, 6)
|
||||
} catch (error) {
|
||||
console.error("发送ICE候选失败:", error)
|
||||
}
|
||||
} else {
|
||||
console.log("通话状态不正确,跳过发送ICE候选:", chatStore.callStatus)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peerConnection.value.ontrack = (event) => {
|
||||
if (event.streams && event.streams[0]) {
|
||||
console.log("接收到远程流:", event.streams[0])
|
||||
remoteStream.value = event.streams[0]
|
||||
console.log("接收到远程流:", remoteStream.value)
|
||||
|
||||
const videoTracks = event.streams[0].getVideoTracks()
|
||||
const audioTracks = event.streams[0].getAudioTracks()
|
||||
console.log("远程流包含:", {
|
||||
video: videoTracks.length,
|
||||
audio: audioTracks.length,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,19 +66,12 @@ export function useWebRTC() {
|
||||
const state = peerConnection.value?.connectionState
|
||||
console.log("WebRTC连接状态变化:", state)
|
||||
|
||||
// 只有在有效的通话状态下才处理连接状态变化
|
||||
if (!chatStore.isInCall) {
|
||||
console.log("不在通话中,忽略连接状态变化")
|
||||
return
|
||||
}
|
||||
|
||||
if (state === "connected") {
|
||||
isConnected.value = true
|
||||
isConnecting.value = false
|
||||
// 只有在 connecting 状态时才切换到 ongoing
|
||||
if (chatStore.callStatus === "connecting") {
|
||||
chatStore.callStatus = "ongoing"
|
||||
chatStore.callConnectionStatus = "通话中"
|
||||
chatStore.callConnectionStatus = "通话已连接"
|
||||
console.log("WebRTC连接已建立,通话开始")
|
||||
}
|
||||
} else if (state === "connecting") {
|
||||
@@ -90,7 +83,6 @@ export function useWebRTC() {
|
||||
console.log("WebRTC连接断开")
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
// 只有在通话中才处理断开
|
||||
if (chatStore.callStatus === "ongoing") {
|
||||
chatStore.callStatus = "disconnected"
|
||||
chatStore.callConnectionStatus = "连接已断开"
|
||||
@@ -110,13 +102,14 @@ export function useWebRTC() {
|
||||
const state = peerConnection.value?.iceConnectionState
|
||||
console.log("ICE连接状态变化:", state)
|
||||
|
||||
// 只有在有效的通话状态下才处理ICE状态变化
|
||||
if (!chatStore.isInCall) {
|
||||
console.log("不在通话中,忽略ICE状态变化")
|
||||
return
|
||||
}
|
||||
|
||||
if (state === "failed") {
|
||||
if (state === "connected" || state === "completed") {
|
||||
console.log("ICE连接成功")
|
||||
isConnected.value = true
|
||||
if (chatStore.callStatus === "connecting") {
|
||||
chatStore.callStatus = "ongoing"
|
||||
chatStore.callConnectionStatus = "通话中"
|
||||
}
|
||||
} else if (state === "failed") {
|
||||
console.log("ICE连接失败")
|
||||
if (chatStore.callStatus === "ongoing" || chatStore.callStatus === "connecting") {
|
||||
chatStore.callStatus = "failed"
|
||||
@@ -139,15 +132,140 @@ export function useWebRTC() {
|
||||
// 如果已有本地流,先停止
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach((track) => track.stop())
|
||||
localStream.value = null
|
||||
hasLocalVideo.value = false
|
||||
hasLocalAudio.value = false
|
||||
}
|
||||
|
||||
console.log("获取本地媒体,约束:", constraints)
|
||||
localStream.value = await navigator.mediaDevices.getUserMedia(constraints)
|
||||
console.log("获取本地媒体成功:", localStream.value)
|
||||
return localStream.value
|
||||
|
||||
try {
|
||||
localStream.value = await navigator.mediaDevices.getUserMedia(constraints)
|
||||
console.log("获取本地媒体成功:", localStream.value)
|
||||
|
||||
// 检查实际获取到的轨道
|
||||
const videoTracks = localStream.value.getVideoTracks()
|
||||
const audioTracks = localStream.value.getAudioTracks()
|
||||
|
||||
hasLocalVideo.value = videoTracks.length > 0 && videoTracks[0].enabled
|
||||
hasLocalAudio.value = audioTracks.length > 0 && audioTracks[0].enabled
|
||||
|
||||
console.log("本地媒体状态:", {
|
||||
hasVideo: hasLocalVideo.value,
|
||||
hasAudio: hasLocalAudio.value,
|
||||
videoTracks: videoTracks.length,
|
||||
audioTracks: audioTracks.length,
|
||||
})
|
||||
|
||||
return localStream.value
|
||||
} catch (mediaError) {
|
||||
console.warn("获取完整媒体失败,尝试仅获取音频:", mediaError)
|
||||
|
||||
if (constraints.video) {
|
||||
try {
|
||||
localStream.value = await navigator.mediaDevices.getUserMedia({ audio: constraints.audio, video: false })
|
||||
console.log("仅获取音频成功:", localStream.value)
|
||||
|
||||
const audioTracks = localStream.value.getAudioTracks()
|
||||
hasLocalVideo.value = false
|
||||
hasLocalAudio.value = audioTracks.length > 0 && audioTracks[0].enabled
|
||||
|
||||
console.log("本地媒体状态(仅音频):", { hasVideo: hasLocalVideo.value, hasAudio: hasLocalAudio.value })
|
||||
|
||||
return localStream.value
|
||||
} catch (audioError) {
|
||||
console.warn("获取音频也失败:", audioError)
|
||||
hasLocalVideo.value = false
|
||||
hasLocalAudio.value = false
|
||||
return null
|
||||
}
|
||||
} else {
|
||||
hasLocalVideo.value = false
|
||||
hasLocalAudio.value = false
|
||||
return null
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("获取本地媒体失败:", error)
|
||||
throw error
|
||||
console.error("获取本地媒体完全失败:", error)
|
||||
hasLocalVideo.value = false
|
||||
hasLocalAudio.value = false
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// 重新获取视频流(用于摄像头开关)
|
||||
const toggleVideoStream = async (enable) => {
|
||||
try {
|
||||
if (enable) {
|
||||
console.log("重新获取视频流")
|
||||
const newStream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: true,
|
||||
video: true,
|
||||
})
|
||||
|
||||
// 停止旧的流
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach((track) => track.stop())
|
||||
}
|
||||
|
||||
localStream.value = newStream
|
||||
hasLocalVideo.value = true
|
||||
hasLocalAudio.value = true
|
||||
|
||||
// 如果有PeerConnection,替换轨道
|
||||
if (peerConnection.value) {
|
||||
const videoTrack = newStream.getVideoTracks()[0]
|
||||
const audioTrack = newStream.getAudioTracks()[0]
|
||||
|
||||
const senders = peerConnection.value.getSenders()
|
||||
|
||||
// 替换视频轨道
|
||||
const videoSender = senders.find((sender) => sender.track && sender.track.kind === "video")
|
||||
if (videoSender && videoTrack) {
|
||||
await videoSender.replaceTrack(videoTrack)
|
||||
console.log("替换视频轨道成功")
|
||||
} else if (videoTrack) {
|
||||
peerConnection.value.addTrack(videoTrack, newStream)
|
||||
console.log("添加新视频轨道")
|
||||
}
|
||||
|
||||
// 替换音频轨道
|
||||
const audioSender = senders.find((sender) => sender.track && sender.track.kind === "audio")
|
||||
if (audioSender && audioTrack) {
|
||||
await audioSender.replaceTrack(audioTrack)
|
||||
console.log("替换音频轨道成功")
|
||||
} else if (audioTrack) {
|
||||
peerConnection.value.addTrack(audioTrack, newStream)
|
||||
console.log("添加新音频轨道")
|
||||
}
|
||||
}
|
||||
|
||||
return newStream
|
||||
} else {
|
||||
// 关闭摄像头:只保留音频
|
||||
if (localStream.value) {
|
||||
const videoTracks = localStream.value.getVideoTracks()
|
||||
videoTracks.forEach((track) => {
|
||||
track.stop()
|
||||
localStream.value.removeTrack(track)
|
||||
})
|
||||
hasLocalVideo.value = false
|
||||
|
||||
// 如果有PeerConnection,移除视频轨道
|
||||
if (peerConnection.value) {
|
||||
const senders = peerConnection.value.getSenders()
|
||||
const videoSender = senders.find((sender) => sender.track && sender.track.kind === "video")
|
||||
if (videoSender) {
|
||||
await videoSender.replaceTrack(null)
|
||||
console.log("移除视频轨道")
|
||||
}
|
||||
}
|
||||
}
|
||||
return localStream.value
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("切换视频流失败:", error)
|
||||
return localStream.value
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,19 +274,33 @@ export function useWebRTC() {
|
||||
createPeerConnection(callId, peerId)
|
||||
}
|
||||
|
||||
// 添加本地流到连接
|
||||
// 确保本地流已添加到连接
|
||||
if (localStream.value) {
|
||||
console.log("添加本地流到PeerConnection")
|
||||
const existingSenders = peerConnection.value.getSenders()
|
||||
|
||||
localStream.value.getTracks().forEach((track) => {
|
||||
peerConnection.value.addTrack(track, localStream.value)
|
||||
// 检查是否已经添加了这个轨道
|
||||
const existingSender = existingSenders.find((sender) => sender.track === track)
|
||||
if (!existingSender) {
|
||||
console.log("添加轨道到PeerConnection:", track.kind, track.enabled)
|
||||
peerConnection.value.addTrack(track, localStream.value)
|
||||
} else {
|
||||
console.log("轨道已存在,跳过添加:", track.kind)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.warn("本地流不存在,无法添加到PeerConnection")
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("开始创建Offer")
|
||||
const offer = await peerConnection.value.createOffer({
|
||||
offerToReceiveAudio: true,
|
||||
offerToReceiveVideo: true,
|
||||
})
|
||||
|
||||
console.log("设置本地描述")
|
||||
await peerConnection.value.setLocalDescription(offer)
|
||||
console.log("创建Offer成功:", offer)
|
||||
|
||||
@@ -184,19 +316,35 @@ export function useWebRTC() {
|
||||
createPeerConnection(callId, peerId)
|
||||
}
|
||||
|
||||
// 添加本地流到连接
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach((track) => {
|
||||
peerConnection.value.addTrack(track, localStream.value)
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("设置远程Offer描述")
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(offer))
|
||||
const answer = await peerConnection.value.createAnswer()
|
||||
await peerConnection.value.setLocalDescription(answer)
|
||||
|
||||
// 确保本地流已添加到连接
|
||||
if (localStream.value) {
|
||||
console.log("添加本地流到PeerConnection")
|
||||
const existingSenders = peerConnection.value.getSenders()
|
||||
|
||||
localStream.value.getTracks().forEach((track) => {
|
||||
const existingSender = existingSenders.find((sender) => sender.track === track)
|
||||
if (!existingSender) {
|
||||
console.log("添加轨道到PeerConnection:", track.kind, track.enabled)
|
||||
peerConnection.value.addTrack(track, localStream.value)
|
||||
} else {
|
||||
console.log("轨道已存在,跳过添加:", track.kind)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
console.warn("本地流不存在,无法添加到PeerConnection")
|
||||
}
|
||||
|
||||
console.log("开始创建Answer")
|
||||
const answer = await peerConnection.value.createAnswer()
|
||||
|
||||
console.log("设置本地Answer描述")
|
||||
await peerConnection.value.setLocalDescription(answer)
|
||||
console.log("创建Answer成功:", answer)
|
||||
|
||||
return answer
|
||||
} catch (error) {
|
||||
console.error("创建Answer失败:", error)
|
||||
@@ -206,6 +354,10 @@ export function useWebRTC() {
|
||||
|
||||
const setRemoteAnswer = async (answer) => {
|
||||
try {
|
||||
if (!peerConnection.value) {
|
||||
throw new Error("PeerConnection 未初始化")
|
||||
}
|
||||
console.log("设置远程Answer描述")
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(answer))
|
||||
console.log("设置远程Answer成功")
|
||||
} catch (error) {
|
||||
@@ -216,6 +368,10 @@ export function useWebRTC() {
|
||||
|
||||
const setRemoteOffer = async (offer) => {
|
||||
try {
|
||||
if (!peerConnection.value) {
|
||||
throw new Error("PeerConnection 未初始化")
|
||||
}
|
||||
console.log("设置远程Offer描述")
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(offer))
|
||||
console.log("设置远程Offer成功")
|
||||
} catch (error) {
|
||||
@@ -227,6 +383,7 @@ export function useWebRTC() {
|
||||
const addIceCandidate = async (candidate) => {
|
||||
if (peerConnection.value && peerConnection.value.remoteDescription) {
|
||||
try {
|
||||
console.log("添加ICE候选:", candidate)
|
||||
await peerConnection.value.addIceCandidate(new RTCIceCandidate(candidate))
|
||||
console.log("添加ICE候选成功")
|
||||
} catch (error) {
|
||||
@@ -259,6 +416,8 @@ export function useWebRTC() {
|
||||
remoteStream.value = null
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
hasLocalVideo.value = false
|
||||
hasLocalAudio.value = false
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -267,8 +426,11 @@ export function useWebRTC() {
|
||||
peerConnection,
|
||||
isConnected,
|
||||
isConnecting,
|
||||
hasLocalVideo,
|
||||
hasLocalAudio,
|
||||
createPeerConnection,
|
||||
getLocalMedia,
|
||||
toggleVideoStream,
|
||||
createOffer,
|
||||
createAnswer,
|
||||
setRemoteAnswer,
|
||||
|
||||
@@ -16,9 +16,9 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const currentCall = ref(null)
|
||||
const incomingCall = ref(null)
|
||||
const callStatus = ref("idle") // idle, calling, ringing, connecting, ongoing, ended, disconnected, hangup
|
||||
const callError = ref(null) // 错误状态:'rejected', 'no-answer', 'busy', 'failed'
|
||||
const callConnectionStatus = ref("") // 连接状态描述
|
||||
const callTimeout = ref(null) // 通话超时计时器
|
||||
const callError = ref(null)
|
||||
const callConnectionStatus = ref("")
|
||||
const callTimeout = ref(null)
|
||||
|
||||
const webrtc = useWebRTC()
|
||||
const userStore = useUserStore()
|
||||
@@ -38,14 +38,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
() => callStatus.value,
|
||||
(newStatus) => {
|
||||
console.log("通话状态变化:", newStatus)
|
||||
switch (newStatus) {
|
||||
case "disconnected":
|
||||
handleCallDisconnected()
|
||||
break
|
||||
case "hangup":
|
||||
handleCallHangup()
|
||||
break
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@@ -57,7 +49,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = ""
|
||||
currentCall.value = null
|
||||
incomingCall.value = null
|
||||
// 注意:这里不要立即关闭WebRTC连接,让组件自己处理
|
||||
}
|
||||
|
||||
// 清除通话超时
|
||||
@@ -77,12 +68,11 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}, duration)
|
||||
}
|
||||
|
||||
// 发送通话信令 - 使用新的专用方法
|
||||
// 发送通话信令
|
||||
const sendCallSignalInternal = async (signal) => {
|
||||
try {
|
||||
console.log("发送通话信令:", signal)
|
||||
|
||||
// 确保必要参数存在
|
||||
if (!userStore.currentUser?.id) {
|
||||
throw new Error("用户未登录")
|
||||
}
|
||||
@@ -99,11 +89,10 @@ export const useChatStore = defineStore("chat", () => {
|
||||
throw new Error("缺少通话状态")
|
||||
}
|
||||
|
||||
// 构建请求数据
|
||||
const requestData = {
|
||||
sender_user_id: userStore.currentUser.id,
|
||||
receiver_user_id: signal.receiver_user_id,
|
||||
message_type: signal.call_type || (signal.call_status === "invite" ? 6 : 7), // 6=视频, 7=语音
|
||||
message_type: signal.call_type || (signal.call_status === "invite" ? 6 : 7),
|
||||
message_content: JSON.stringify(signal.data || {}),
|
||||
call_id: signal.call_id,
|
||||
call_status: signal.call_status,
|
||||
@@ -133,14 +122,11 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 加载好友列表
|
||||
const loadFriends = async (presetUsers, currentUserId) => {
|
||||
try {
|
||||
// 从数据库获取好友列表
|
||||
let friendList = await chatDB.getFriends(currentUserId)
|
||||
|
||||
// 如果数据库中没有好友,使用预设用户初始化
|
||||
if (friendList.length === 0) {
|
||||
friendList = presetUsers.filter((user) => user.id !== currentUserId)
|
||||
|
||||
// 保存到数据库
|
||||
for (const friend of friendList) {
|
||||
await chatDB.saveFriend(
|
||||
{
|
||||
@@ -156,7 +142,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
friends.value = friendList
|
||||
} catch (error) {
|
||||
console.error("加载好友列表失败:", error)
|
||||
// 降级到预设用户
|
||||
const friendList = presetUsers.filter((user) => user.id !== currentUserId)
|
||||
friendList.forEach((friend) => {
|
||||
friend.lastMessage = ""
|
||||
@@ -169,7 +154,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 设置当前好友
|
||||
const setCurrentFriend = (friend) => {
|
||||
currentFriend.value = friend
|
||||
// 清除未读消息计数
|
||||
if (friend) {
|
||||
friend.unreadCount = 0
|
||||
}
|
||||
@@ -179,11 +163,9 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const switchFriend = async (friend, currentUserId) => {
|
||||
currentFriend.value = friend
|
||||
|
||||
// 清空未读消息计数
|
||||
friend.unreadCount = 0
|
||||
await chatDB.clearUnreadCount(friend.id)
|
||||
|
||||
// 加载聊天记录
|
||||
try {
|
||||
const chatHistory = await chatDB.getChatHistory(currentUserId, friend.id)
|
||||
messages.value = chatHistory.sort((a, b) => a.timestamp - b.timestamp)
|
||||
@@ -197,7 +179,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const addMessage = async (message, currentUserId) => {
|
||||
messages.value.push(message)
|
||||
|
||||
// 更新好友列表中的最后消息
|
||||
const friend = friends.value.find((f) => f.id === message.senderId || f.id === currentFriend.value?.id)
|
||||
if (friend) {
|
||||
let lastMessage = message.content
|
||||
@@ -208,13 +189,11 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
friend.lastMessage = lastMessage.length > 20 ? lastMessage.substring(0, 20) + "..." : lastMessage
|
||||
|
||||
// 更新数据库中的好友信息
|
||||
await chatDB.updateFriendLastMessage(friend.id, currentUserId, friend.lastMessage, 0)
|
||||
}
|
||||
|
||||
if (currentFriend.value && friend && friend.id === currentFriend.value.id) {
|
||||
try {
|
||||
// 保存到数据库
|
||||
await chatDB.saveMessage(message, currentUserId, currentFriend.value.id)
|
||||
} catch (error) {
|
||||
console.error("保存消息失败:", error)
|
||||
@@ -224,7 +203,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 处理接收到的消息
|
||||
const handleIncomingMessage = async (messageData, currentUserId) => {
|
||||
// 添加来源检查 - 防止循环
|
||||
if (messageData.isFromHttp) {
|
||||
console.log("忽略来自HTTP的消息,避免循环")
|
||||
return
|
||||
@@ -235,7 +213,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
if (receiverId !== currentUserId) return
|
||||
|
||||
// 如果是通话信令,直接处理
|
||||
if (messageData.call_id || messageData.call_status) {
|
||||
handleCallSignal(messageData)
|
||||
return
|
||||
@@ -252,22 +229,18 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
|
||||
try {
|
||||
// 保存消息到数据库
|
||||
await chatDB.saveMessage(newMessage, currentUserId, senderId)
|
||||
|
||||
// 如果消息来自当前聊天用户,直接显示
|
||||
if (currentFriend.value && senderId == currentFriend.value.id) {
|
||||
newMessage.read = true
|
||||
messages.value.push(newMessage)
|
||||
} else {
|
||||
// 更新未读消息计数
|
||||
const friend = friends.value.find((f) => f.id == senderId)
|
||||
if (friend) {
|
||||
friend.unreadCount = (friend.unreadCount || 0) + 1
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后消息
|
||||
const friend = friends.value.find((f) => f.id == senderId)
|
||||
if (friend) {
|
||||
let lastMessage = newMessage.content
|
||||
@@ -277,7 +250,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
if (newMessage.type === "video-call" || newMessage.type === "audio-call") lastMessage = "[通话]"
|
||||
friend.lastMessage = lastMessage
|
||||
|
||||
// 更新数据库
|
||||
await chatDB.updateFriendLastMessage(friend.id, currentUserId, lastMessage, friend.unreadCount)
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -306,7 +278,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
console.log("处理通话信令:", data)
|
||||
console.log("通话状态:", data.call_status)
|
||||
|
||||
// 根据通话状态处理
|
||||
switch (data.call_status) {
|
||||
case "invite":
|
||||
handleIncomingCall(data)
|
||||
@@ -338,13 +309,13 @@ export const useChatStore = defineStore("chat", () => {
|
||||
case "busy":
|
||||
handleCallBusy(data)
|
||||
break
|
||||
case "hangup": // 对方主动挂断
|
||||
case "hangup":
|
||||
handleCallHangup(data)
|
||||
break
|
||||
case "disconnected": // 对方掉线
|
||||
case "disconnected":
|
||||
handleCallDisconnected(data)
|
||||
break
|
||||
case "terminated": // 对方终止呼叫
|
||||
case "terminated":
|
||||
handleCallTerminated(data)
|
||||
break
|
||||
case "failed":
|
||||
@@ -356,7 +327,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理Offer信令
|
||||
const handleOffer = async (data) => {
|
||||
if (incomingCall.value && incomingCall.value.callId === data.call_id) {
|
||||
// 确保只处理一次 Offer
|
||||
if (callStatus.value === "ongoing") {
|
||||
console.log("通话已建立,忽略重复的 Offer")
|
||||
return
|
||||
@@ -366,11 +336,13 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const offer = JSON.parse(data.content || data.message_content || "{}")
|
||||
console.log("收到Offer:", offer)
|
||||
|
||||
// 设置远程Offer并创建Answer
|
||||
await webrtc.setRemoteOffer(offer)
|
||||
if (!webrtc.peerConnection.value) {
|
||||
console.log("创建 WebRTC 连接以处理 Offer")
|
||||
webrtc.createPeerConnection(data.call_id, data.sender_user_id)
|
||||
}
|
||||
|
||||
const answer = await webrtc.createAnswer(offer, data.call_id, data.sender_user_id)
|
||||
|
||||
// 发送Answer - 使用便捷方法
|
||||
await callAPI.sendAnswer(userStore.currentUser.id, data.sender_user_id, data.call_id, answer, data.message_type)
|
||||
|
||||
console.log("发送Answer成功")
|
||||
@@ -384,7 +356,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理Answer信令
|
||||
const handleAnswer = async (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
// 确保只处理一次 Answer
|
||||
if (callStatus.value === "ongoing") {
|
||||
console.log("通话已建立,忽略重复的 Answer")
|
||||
return
|
||||
@@ -394,7 +365,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const answer = JSON.parse(data.content || data.message_content || "{}")
|
||||
console.log("收到Answer:", answer)
|
||||
|
||||
// 设置远程Answer
|
||||
await webrtc.setRemoteAnswer(answer)
|
||||
|
||||
callStatus.value = "connecting"
|
||||
@@ -423,7 +393,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callError.value = "failed"
|
||||
callConnectionStatus.value = "连接失败"
|
||||
|
||||
// 添加通话记录
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
const friend = friends.value.find((f) => f.id === peerId)
|
||||
if (friend) {
|
||||
@@ -441,12 +410,10 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[连接失败]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[连接失败]", friend.unreadCount)
|
||||
}
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
resetCallState()
|
||||
}, 5000)
|
||||
@@ -455,18 +422,15 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 处理来电
|
||||
const handleIncomingCall = (data) => {
|
||||
// 只有在当前没有通话时才处理来电
|
||||
if (isInCall.value) {
|
||||
console.log("当前正在通话中,发送忙线状态")
|
||||
callAPI.sendBusy(userStore.currentUser.id, data.sender_user_id, data.call_id, data.message_type)
|
||||
|
||||
// 添加未接来电消息
|
||||
const friend = friends.value.find((f) => f.id === data.sender_user_id)
|
||||
if (friend) {
|
||||
friend.lastMessage = "[未接来电]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[未接来电]", friend.unreadCount)
|
||||
|
||||
// 添加通话记录
|
||||
const callMessage = {
|
||||
type: data.message_type === 6 ? "video-call" : "audio-call",
|
||||
content: "[未接来电]",
|
||||
@@ -482,7 +446,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 重置所有通话状态
|
||||
resetCallState()
|
||||
|
||||
incomingCall.value = {
|
||||
@@ -497,7 +460,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
console.log("收到来电:", incomingCall.value)
|
||||
|
||||
// 设置来电超时(30秒后自动拒绝)
|
||||
setCallTimeout(() => {
|
||||
if (callStatus.value === "ringing" && incomingCall.value) {
|
||||
console.log("来电超时,自动拒绝")
|
||||
@@ -509,7 +471,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理通话接受
|
||||
const handleCallAccepted = async (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
// 防止重复处理 accepted 状态
|
||||
if (callStatus.value === "connecting" || callStatus.value === "ongoing") {
|
||||
console.log("通话已在连接中,忽略重复的 accepted 信令")
|
||||
return
|
||||
@@ -520,11 +481,17 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = "对方已接听,正在连接..."
|
||||
console.log("通话已被接受,开始交换信令")
|
||||
|
||||
// 接受通话后开始创建Offer
|
||||
try {
|
||||
if (!webrtc.localStream.value) {
|
||||
console.log("获取本地媒体用于创建Offer")
|
||||
await webrtc.getLocalMedia({
|
||||
audio: true,
|
||||
video: currentCall.value.callType === "video",
|
||||
})
|
||||
}
|
||||
|
||||
const offer = await webrtc.createOffer(currentCall.value.callId, currentCall.value.peerId)
|
||||
|
||||
// 发送Offer给对方 - 使用便捷方法
|
||||
await callAPI.sendOffer(
|
||||
userStore.currentUser.id,
|
||||
currentCall.value.peerId,
|
||||
@@ -548,7 +515,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = "对方已拒绝"
|
||||
console.log("通话已被拒绝")
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find((f) => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
@@ -562,12 +528,10 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[对方已拒绝]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[对方已拒绝]", friend.unreadCount)
|
||||
}
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
@@ -580,7 +544,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
(currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)
|
||||
) {
|
||||
// 添加通话记录
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
const friend = friends.value.find((f) => f.id === peerId)
|
||||
if (friend) {
|
||||
@@ -606,7 +569,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = callMessage.content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, callMessage.content, friend.unreadCount)
|
||||
}
|
||||
@@ -615,7 +577,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = "通话已结束"
|
||||
console.log("通话已结束")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
@@ -632,7 +593,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const candidate = JSON.parse(data.content || data.message_content || "{}")
|
||||
console.log("收到ICE候选:", candidate)
|
||||
|
||||
// 添加到WebRTC连接
|
||||
webrtc.addIceCandidate(candidate)
|
||||
} catch (error) {
|
||||
console.error("处理ICE候选失败:", error)
|
||||
@@ -643,7 +603,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理无人接听
|
||||
const handleCallNoAnswer = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
// 添加未接来电记录
|
||||
const friend = friends.value.find((f) => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
@@ -657,7 +616,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[未接来电]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[未接来电]", friend.unreadCount)
|
||||
}
|
||||
@@ -666,7 +624,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = "对方无人接听"
|
||||
console.log("对方无人接听")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
@@ -676,7 +633,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理对方忙线
|
||||
const handleCallBusy = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
// 添加忙线记录
|
||||
const friend = friends.value.find((f) => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
@@ -690,7 +646,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[对方忙线]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[对方忙线]", friend.unreadCount)
|
||||
}
|
||||
@@ -699,7 +654,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = "对方忙线中"
|
||||
console.log("对方忙线中")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
@@ -712,7 +666,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const peerId = data?.sender_user_id || currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
|
||||
if (callId && peerId) {
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find((f) => f.id === peerId)
|
||||
if (friend) {
|
||||
const duration =
|
||||
@@ -722,7 +675,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
const callMessage = {
|
||||
type: currentCall.value?.callType || incomingCall.value?.callType === "video" ? "video-call" : "audio-call",
|
||||
content: `[对方已挂断] ${Math.floor(duration / 60)}分${duration % 60}秒`,
|
||||
content: duration > 0 ? `[对方已挂断] ${Math.floor(duration / 60)}分${duration % 60}秒` : "[对方已挂断]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: peerId,
|
||||
read: true,
|
||||
@@ -731,19 +684,17 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = `[对方已挂断] ${Math.floor(duration / 60)}分${duration % 60}秒`
|
||||
friend.lastMessage = callMessage.content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, friend.lastMessage, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callStatus.value = "hangup"
|
||||
callConnectionStatus.value = "对方已挂断"
|
||||
console.log("对方已挂断通话")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
resetCallState()
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,7 +704,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const peerId = data?.sender_user_id || currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
|
||||
if (callId && peerId) {
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find((f) => f.id === peerId)
|
||||
if (friend) {
|
||||
const duration =
|
||||
@@ -763,7 +713,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
const callMessage = {
|
||||
type: currentCall.value?.callType || incomingCall.value?.callType === "video" ? "video-call" : "audio-call",
|
||||
content: `[网络中断] ${Math.floor(duration / 60)}分${duration % 60}秒`,
|
||||
content: duration > 0 ? `[网络中断] ${Math.floor(duration / 60)}分${duration % 60}秒` : "[网络中断]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: peerId,
|
||||
read: true,
|
||||
@@ -772,19 +722,17 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = `[网络中断] ${Math.floor(duration / 60)}分${duration % 60}秒`
|
||||
friend.lastMessage = callMessage.content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, friend.lastMessage, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callStatus.value = "disconnected"
|
||||
callConnectionStatus.value = "网络连接已断开"
|
||||
console.log("网络连接已断开")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
resetCallState()
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +745,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
(currentCall.value && currentCall.value.callId === callId) ||
|
||||
(incomingCall.value && incomingCall.value.callId === callId)
|
||||
) {
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find((f) => f.id === peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
@@ -811,7 +758,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[对方已终止呼叫]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[对方已终止呼叫]", friend.unreadCount)
|
||||
}
|
||||
@@ -820,7 +766,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = "对方已终止呼叫"
|
||||
console.log("对方已终止呼叫")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
@@ -840,7 +785,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 验证用户登录状态
|
||||
if (!userStore.currentUser?.id) {
|
||||
alert("用户未登录,无法发起通话")
|
||||
return
|
||||
@@ -861,24 +805,30 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callStatus.value = "calling"
|
||||
callConnectionStatus.value = "等待对方接听..."
|
||||
|
||||
// 先不获取本地媒体,等对方接听后再获取
|
||||
console.log("发起通话,等待对方接听...")
|
||||
// 立即获取本地媒体并显示
|
||||
try {
|
||||
console.log("发起通话,立即获取本地媒体...")
|
||||
await webrtc.getLocalMedia({
|
||||
audio: true,
|
||||
video: type === "video",
|
||||
})
|
||||
console.log("本地媒体获取成功,可以显示自己的摄像头")
|
||||
} catch (error) {
|
||||
console.warn("获取本地媒体失败,但继续通话流程:", error)
|
||||
}
|
||||
|
||||
// 设置30秒超时(无人接听)
|
||||
// 设置30秒超时
|
||||
setCallTimeout(() => {
|
||||
if (callStatus.value === "calling") {
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "对方无人接听"
|
||||
console.log("呼叫超时,对方无人接听")
|
||||
|
||||
// 发送无人接听信号 - 使用便捷方法
|
||||
callAPI.sendNoAnswer(userStore.currentUser.id, peerId, callId, type === "video" ? 6 : 7)
|
||||
|
||||
// 更新好友最后消息为未接来电
|
||||
friend.lastMessage = "[未接来电]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[未接来电]", friend.unreadCount)
|
||||
|
||||
// 添加通话记录
|
||||
const callMessage = {
|
||||
type: type === "video" ? "video-call" : "audio-call",
|
||||
content: "[未接来电]",
|
||||
@@ -890,14 +840,13 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}, 30000)
|
||||
|
||||
// 发送通话请求 - 使用便捷方法
|
||||
// 发送通话请求
|
||||
try {
|
||||
console.log("准备发送通话邀请:", {
|
||||
senderUserId: userStore.currentUser.id,
|
||||
@@ -913,7 +862,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
console.error("发起通话失败:", error)
|
||||
resetCallState()
|
||||
|
||||
// 提供更友好的错误提示
|
||||
let errorMessage = "发起通话失败"
|
||||
if (error.response?.status === 400) {
|
||||
errorMessage = "请求参数错误,请检查网络连接"
|
||||
@@ -934,13 +882,11 @@ export const useChatStore = defineStore("chat", () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 防止重复接听
|
||||
if (callStatus.value === "connecting" || callStatus.value === "ongoing") {
|
||||
console.log("通话已在进行中,忽略重复接听")
|
||||
return
|
||||
}
|
||||
|
||||
// 清除任何可能的超时定时器
|
||||
clearCallTimeout()
|
||||
|
||||
console.log("开始接听通话:", incomingCall.value)
|
||||
@@ -950,12 +896,17 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
try {
|
||||
// 获取本地媒体
|
||||
await webrtc.getLocalMedia({
|
||||
audio: true,
|
||||
video: incomingCall.value.callType === "video",
|
||||
})
|
||||
try {
|
||||
await webrtc.getLocalMedia({
|
||||
audio: true,
|
||||
video: incomingCall.value.callType === "video",
|
||||
})
|
||||
console.log("接听时获取本地媒体成功")
|
||||
} catch (mediaError) {
|
||||
console.warn("接听时获取本地媒体失败,但继续通话流程:", mediaError)
|
||||
}
|
||||
|
||||
// 发送接受信号 - 使用便捷方法
|
||||
// 发送接受信号
|
||||
await callAPI.accept(
|
||||
userStore.currentUser.id,
|
||||
incomingCall.value.callerId,
|
||||
@@ -985,7 +936,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果已经在连接中,不允许拒绝
|
||||
if (callStatus.value === "connecting" || callStatus.value === "ongoing") {
|
||||
console.log("通话已在进行中,无法拒绝")
|
||||
return
|
||||
@@ -994,7 +944,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
console.log("开始拒绝通话:", reason)
|
||||
|
||||
try {
|
||||
// 发送拒绝信号 - 使用便捷方法
|
||||
if (reason === "rejected") {
|
||||
await callAPI.reject(
|
||||
userStore.currentUser.id,
|
||||
@@ -1011,7 +960,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
)
|
||||
}
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find((f) => f.id === incomingCall.value.callerId)
|
||||
if (friend) {
|
||||
const content = reason === "busy" ? "[对方忙线]" : reason === "no-answer" ? "[未接来电]" : "[已拒绝]"
|
||||
@@ -1027,7 +975,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, content, friend.unreadCount)
|
||||
}
|
||||
@@ -1035,7 +982,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
resetCallState()
|
||||
callConnectionStatus.value = reason === "busy" ? "对方忙线" : reason === "no-answer" ? "无人接听" : "已拒绝"
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
@@ -1058,10 +1004,8 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
|
||||
try {
|
||||
// 发送结束信号 - 使用便捷方法
|
||||
await callAPI.end(userStore.currentUser.id, peerId, callId, callTypeVal === "video" ? 6 : 7)
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find((f) => f.id === peerId)
|
||||
if (friend) {
|
||||
const duration =
|
||||
@@ -1089,7 +1033,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, content, friend.unreadCount)
|
||||
}
|
||||
@@ -1097,7 +1040,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
resetCallState()
|
||||
callConnectionStatus.value = reason === "no-answer" ? "对方无人接听" : "通话结束"
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
|
||||
Reference in New Issue
Block a user