目前对方可以接收到通话申请了(接电话有通话中判断错误导致重复send-to-user路由的问题)
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue</title>
|
||||
<title>奶酪-即时通讯-demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
<span class="status-text">
|
||||
{{ isFriendOnline ? '在线' : '离线' }}
|
||||
</span>
|
||||
<span v-if="callStatus" class="call-status-text">
|
||||
{{ callStatusText }}
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -64,62 +67,49 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 视频通话组件 -->
|
||||
<VideoCallComponent
|
||||
v-if="showVideoCall"
|
||||
:caller-info="callerInfo"
|
||||
:call-type="callType"
|
||||
:is-incoming="isIncoming"
|
||||
@accept-call="handleAcceptCall"
|
||||
@reject-call="handleRejectCall"
|
||||
@end-call="handleEndCall"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { ref, computed } from 'vue';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
import { useThemeStore } from '@/stores/theme';
|
||||
import VideoCallComponent from './VideoCallComponent.vue';
|
||||
|
||||
const chatStore = useChatStore();
|
||||
const themeStore = useThemeStore();
|
||||
|
||||
const isFriendOnline = ref(true);
|
||||
const showMoreActions = ref(false);
|
||||
const showVideoCall = ref(false);
|
||||
const callType = ref('video');
|
||||
const isIncoming = ref(false);
|
||||
const callerInfo = ref(null);
|
||||
|
||||
// 监听通话状态变化
|
||||
watch(() => chatStore.callStatus, (status) => {
|
||||
if (status === 'calling' || status === 'ringing' || status === 'ongoing') {
|
||||
showVideoCall.value = true;
|
||||
} else {
|
||||
showVideoCall.value = false;
|
||||
// 获取当前通话状态
|
||||
const callStatus = computed(() => {
|
||||
if (!chatStore.currentFriend) return null;
|
||||
|
||||
// 检查是否正在与当前好友通话
|
||||
if (chatStore.currentCall && chatStore.currentCall.peerId === chatStore.currentFriend.id) {
|
||||
return chatStore.callConnectionStatus || '通话中';
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
// 监听来电
|
||||
watch(() => chatStore.incomingCall, (call) => {
|
||||
if (call) {
|
||||
isIncoming.value = true;
|
||||
callerInfo.value = chatStore.friends.find(f => f.id === call.callerId);
|
||||
callType.value = call.callType;
|
||||
} else {
|
||||
isIncoming.value = false;
|
||||
}
|
||||
});
|
||||
// 获取通话状态文本
|
||||
const callStatusText = computed(() => {
|
||||
if (!callStatus.value) return '';
|
||||
|
||||
// 监听当前通话
|
||||
watch(() => chatStore.currentCall, (call) => {
|
||||
if (call) {
|
||||
callerInfo.value = chatStore.friends.find(f => f.id === call.peerId);
|
||||
callType.value = call.callType;
|
||||
isIncoming.value = false;
|
||||
switch (callStatus.value) {
|
||||
case '等待对方接听...':
|
||||
return '📞 呼叫中...';
|
||||
case '通话中':
|
||||
return '📞 通话中';
|
||||
case '对方已拒绝':
|
||||
return '❌ 已拒绝';
|
||||
case '对方无人接听':
|
||||
return '🕒 未接听';
|
||||
case '对方忙线中':
|
||||
return '🚫 忙线中';
|
||||
default:
|
||||
return '📞 ' + callStatus.value;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -152,21 +142,6 @@ const startVideoCall = () => {
|
||||
chatStore.startCall(chatStore.currentFriend.id, 'video');
|
||||
};
|
||||
|
||||
// 接听来电
|
||||
const handleAcceptCall = () => {
|
||||
chatStore.acceptCall();
|
||||
};
|
||||
|
||||
// 拒绝来电
|
||||
const handleRejectCall = () => {
|
||||
chatStore.rejectCall();
|
||||
};
|
||||
|
||||
// 结束通话
|
||||
const handleEndCall = () => {
|
||||
chatStore.endCall();
|
||||
};
|
||||
|
||||
// 清空聊天记录
|
||||
const clearChatHistory = () => {
|
||||
if (confirm('确定要清空与该好友的聊天记录吗?')) {
|
||||
@@ -184,7 +159,6 @@ const viewFriendProfile = () => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 保持原有样式不变 */
|
||||
.chat-header {
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #e2e8f0;
|
||||
@@ -278,6 +252,22 @@ const viewFriendProfile = () => {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
/* 添加通话状态样式 */
|
||||
.call-status-text {
|
||||
margin-left: 8px;
|
||||
font-size: 13px;
|
||||
color: #3b82f6;
|
||||
font-weight: 500;
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.chat-header.dark .call-status-text {
|
||||
color: #93c5fd;
|
||||
background: rgba(59, 130, 246, 0.2);
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -427,5 +417,9 @@ const viewFriendProfile = () => {
|
||||
.header-actions {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.call-status-text {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="caller-details">
|
||||
<div class="caller-name">{{ callerInfo.name }}</div>
|
||||
<div class="call-status">{{ callStatus }} {{ formattedDuration }}</div>
|
||||
<div class="call-status">{{ connectionText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -120,12 +120,18 @@
|
||||
<div v-if="!isMinimized" class="call-controls">
|
||||
<!-- 来电控制按钮 -->
|
||||
<div v-if="isIncoming && !isOngoing" class="incoming-call-controls">
|
||||
<div v-if="callStatus === 'busy'" class="busy-status">
|
||||
<i class="fas fa-phone-slash"></i>
|
||||
<span>对方忙线中</span>
|
||||
</div>
|
||||
<template v-else>
|
||||
<button class="accept-btn" @click="acceptCall">
|
||||
<i class="fas fa-phone"></i> 接听
|
||||
</button>
|
||||
<button class="reject-btn" @click="rejectCall">
|
||||
<i class="fas fa-phone-slash"></i> 拒绝
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
@@ -205,7 +211,6 @@ const isCameraOn = ref(props.callType === 'video');
|
||||
const isSpeakerOn = ref(true);
|
||||
const hasLocalVideo = ref(false);
|
||||
const hasRemoteVideo = ref(false);
|
||||
const connectionText = ref('正在连接...');
|
||||
const callDuration = ref(0);
|
||||
const callTimer = ref(null);
|
||||
const isCameraWorking = ref(true);
|
||||
@@ -223,6 +228,35 @@ const localVideo = ref(null);
|
||||
const remoteVideo = ref(null);
|
||||
const remoteVideoPreview = ref(null);
|
||||
|
||||
// 获取当前通话状态
|
||||
const callStatus = computed(() => {
|
||||
return chatStore.callError;
|
||||
});
|
||||
|
||||
// 连接状态文本
|
||||
const connectionText = computed(() => {
|
||||
// 优先使用 chatStore 中的详细状态
|
||||
if (chatStore.callConnectionStatus) {
|
||||
return chatStore.callConnectionStatus;
|
||||
}
|
||||
|
||||
// 处理忙线状态
|
||||
if (chatStore.callError === 'busy') {
|
||||
return '对方忙线中';
|
||||
}
|
||||
|
||||
// 默认状态显示
|
||||
if (props.isIncoming && !isOngoing.value) {
|
||||
return '来电中...';
|
||||
}
|
||||
|
||||
if (isOngoing.value) {
|
||||
return `通话中 ${formattedDuration.value}`;
|
||||
}
|
||||
|
||||
return '正在连接...';
|
||||
});
|
||||
|
||||
// 通话计时器
|
||||
const startCallTimer = () => {
|
||||
if (callTimer.value) clearInterval(callTimer.value);
|
||||
@@ -248,14 +282,6 @@ const containerStyle = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
// 通话状态
|
||||
const callStatus = computed(() => {
|
||||
if (props.isIncoming && !isOngoing.value) {
|
||||
return '来电中...';
|
||||
}
|
||||
return '通话中';
|
||||
});
|
||||
|
||||
// 初始化媒体设备
|
||||
const initializeMedia = async () => {
|
||||
try {
|
||||
@@ -267,13 +293,11 @@ const initializeMedia = async () => {
|
||||
// 获取本地媒体流
|
||||
await webrtc.getLocalMedia(constraints);
|
||||
|
||||
connectionText.value = '已连接';
|
||||
startCallTimer();
|
||||
} catch (error) {
|
||||
console.error('无法访问媒体设备:', error);
|
||||
isCameraOn.value = false;
|
||||
isCameraWorking.value = false;
|
||||
connectionText.value = '连接失败';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -331,7 +355,6 @@ const endCall = () => {
|
||||
|
||||
isVisible.value = false;
|
||||
emit('end-call');
|
||||
chatStore.endCall();
|
||||
};
|
||||
|
||||
// 接听通话
|
||||
@@ -345,7 +368,6 @@ const acceptCall = () => {
|
||||
const rejectCall = () => {
|
||||
isVisible.value = false;
|
||||
emit('reject-call');
|
||||
chatStore.rejectCall();
|
||||
};
|
||||
|
||||
// 拖拽功能
|
||||
@@ -478,7 +500,6 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 保持原有样式不变 */
|
||||
.video-call-container {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
@@ -849,6 +870,22 @@ onUnmounted(() => {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* 添加忙线状态样式 */
|
||||
.busy-status {
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
color: #ff6b6b;
|
||||
padding: 12px 24px;
|
||||
border-radius: 30px;
|
||||
font-size: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.busy-status i {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 600px) {
|
||||
.video-call-container:not(.minimized) {
|
||||
|
||||
@@ -54,13 +54,13 @@ export function useWebSocket() {
|
||||
const data = JSON.parse(event.data)
|
||||
console.log("收到WebSocket消息:", data)
|
||||
|
||||
// 处理通话信令
|
||||
// 优先处理通话信令(无论是否在当前聊天窗口)
|
||||
if (data.call_id && data.call_status) {
|
||||
handleCallSignal(data)
|
||||
return
|
||||
}
|
||||
|
||||
// 处理普通消息
|
||||
// 处理普通消息 - 添加来源判断防止循环
|
||||
if (data.sender_user_id && data.receiver_user_id) {
|
||||
chatStore.handleIncomingMessage(data, userStore.currentUser?.id)
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const currentCall = ref(null)
|
||||
const incomingCall = ref(null)
|
||||
const callStatus = ref("idle") // idle, calling, ringing, ongoing, ended
|
||||
const callError = ref(null) // 错误状态:'rejected', 'no-answer', 'busy'
|
||||
const callConnectionStatus = ref("") // 连接状态:等待接听、正在连接等
|
||||
|
||||
const webrtc = useWebRTC()
|
||||
const userStore = useUserStore()
|
||||
@@ -69,7 +71,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
friend.lastMessage = ""
|
||||
friend.unreadCount = 0
|
||||
})
|
||||
friends.value = friend极
|
||||
friends.value = friendList
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +132,12 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 处理接收到的消息
|
||||
const handleIncomingMessage = async (messageData, currentUserId) => {
|
||||
// 添加来源检查 - 防止循环
|
||||
if (messageData.isFromHttp) {
|
||||
console.log("忽略来自HTTP的消息,避免循环")
|
||||
return
|
||||
}
|
||||
|
||||
const senderId = messageData.sender_user_id
|
||||
const receiverId = messageData.receiver_user_id
|
||||
|
||||
@@ -162,7 +170,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
} else {
|
||||
// 更新未读消息计数
|
||||
const friend = friends.value.find((f) => f.id == senderId)
|
||||
console.log(f.id == senderId, senderId, f)
|
||||
if (friend) {
|
||||
friend.unreadCount = (friend.unreadCount || 0) + 1
|
||||
|
||||
@@ -213,11 +220,40 @@ export const useChatStore = defineStore("chat", () => {
|
||||
case "candidate":
|
||||
handleIceCandidate(data)
|
||||
break
|
||||
case "no-answer": // 添加无人接听状态
|
||||
handleCallNoAnswer(data)
|
||||
break
|
||||
case "connecting": // 新增连接状态
|
||||
callConnectionStatus.value = "正在连接..."
|
||||
break
|
||||
case "busy": // 对方忙线中
|
||||
handleCallBusy(data)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 处理来电
|
||||
const handleIncomingCall = (data) => {
|
||||
// 如果自己正在通话中,自动拒绝并发送忙线状态
|
||||
if (isInCall.value) {
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: data.sender_user_id,
|
||||
type: data.message_type === 6 ? "video-call" : "audio-call",
|
||||
callId: data.call_id,
|
||||
callStatus: "busy"
|
||||
})
|
||||
|
||||
// 添加未接来电消息
|
||||
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)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
incomingCall.value = {
|
||||
callId: data.call_id,
|
||||
callerId: data.sender_user_id,
|
||||
@@ -225,6 +261,8 @@ export const useChatStore = defineStore("chat", () => {
|
||||
content: data.content
|
||||
}
|
||||
callStatus.value = "ringing"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = "收到来电"
|
||||
|
||||
console.log("收到来电:", incomingCall.value)
|
||||
}
|
||||
@@ -233,6 +271,8 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const handleCallAccepted = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ongoing"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = "通话中"
|
||||
console.log("通话已被接受")
|
||||
}
|
||||
}
|
||||
@@ -241,8 +281,17 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const handleCallRejected = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "rejected"
|
||||
callConnectionStatus.value = "对方已拒绝"
|
||||
currentCall.value = null
|
||||
console.log("通话已被拒绝")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,9 +300,17 @@ export const useChatStore = defineStore("chat", () => {
|
||||
if ((currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = "通话已结束"
|
||||
currentCall.value = null
|
||||
incomingCall.value = null
|
||||
console.log("通话已结束")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,21 +322,102 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理无人接听
|
||||
const handleCallNoAnswer = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "no-answer"
|
||||
callConnectionStatus.value = "对方无人接听"
|
||||
currentCall.value = null
|
||||
console.log("对方无人接听")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对方忙线
|
||||
const handleCallBusy = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "busy"
|
||||
callConnectionStatus.value = "对方忙线中"
|
||||
currentCall.value = null
|
||||
console.log("对方忙线中")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
// 发起通话
|
||||
const startCall = (peerId, type) => {
|
||||
if (isInCall.value) return
|
||||
if (isInCall.value) {
|
||||
alert('您正在通话中,请先结束当前通话。')
|
||||
return
|
||||
}
|
||||
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
if (!friend) {
|
||||
alert('好友信息无效')
|
||||
return
|
||||
}
|
||||
|
||||
const callId = Date.now().toString() + Math.random().toString(36).substr(2, 9)
|
||||
|
||||
currentCall.value = {
|
||||
callId: callId,
|
||||
peerId: peerId,
|
||||
callType: type
|
||||
callType: type,
|
||||
startTime: Date.now(),
|
||||
status: 'calling'
|
||||
}
|
||||
|
||||
callStatus.value = "calling"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = "等待对方接听..."
|
||||
|
||||
// 修复参数传递问题
|
||||
// 设置30秒超时(无人接听)
|
||||
const timeoutId = setTimeout(() => {
|
||||
if (callStatus.value === "calling") {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "no-answer"
|
||||
callConnectionStatus.value = "对方无人接听"
|
||||
console.log("呼叫超时,对方无人接听")
|
||||
|
||||
// 发送无人接听信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
type: type === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: "no-answer"
|
||||
})
|
||||
|
||||
// 更新好友最后消息为未接来电
|
||||
friend.lastMessage = "[未接来电]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[未接来电]", friend.unreadCount)
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
currentCall.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}, 30000)
|
||||
|
||||
currentCall.value.timeoutId = timeoutId
|
||||
|
||||
// 发送通话请求
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
@@ -295,7 +433,12 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const acceptCall = () => {
|
||||
if (!incomingCall.value) return
|
||||
|
||||
// 修复参数传递问题
|
||||
// 清除可能存在的超时计时器
|
||||
if (currentCall.value?.timeoutId) {
|
||||
clearTimeout(currentCall.value.timeoutId)
|
||||
}
|
||||
|
||||
// 发送接受信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: incomingCall.value.callerId,
|
||||
@@ -307,11 +450,15 @@ export const useChatStore = defineStore("chat", () => {
|
||||
currentCall.value = {
|
||||
callId: incomingCall.value.callId,
|
||||
peerId: incomingCall.value.callerId,
|
||||
callType: incomingCall.value.callType
|
||||
callType: incomingCall.value.callType,
|
||||
startTime: Date.now(),
|
||||
status: 'ongoing'
|
||||
}
|
||||
|
||||
callStatus.value = "ongoing"
|
||||
callConnectionStatus.value = "通话中"
|
||||
incomingCall.value = null
|
||||
callError.value = null
|
||||
console.log("接听通话")
|
||||
}
|
||||
|
||||
@@ -319,7 +466,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const rejectCall = () => {
|
||||
if (!incomingCall.value) return
|
||||
|
||||
// 修复参数传递问题
|
||||
// 发送拒绝信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: incomingCall.value.callerId,
|
||||
@@ -328,8 +475,26 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callStatus: "rejected"
|
||||
})
|
||||
|
||||
callStatus.value = "idle"
|
||||
callStatus.value = "ended"
|
||||
callConnectionStatus.value = "已拒绝"
|
||||
callError.value = "rejected"
|
||||
|
||||
// 更新好友最后消息为已拒绝
|
||||
const friend = friends.value.find(f => f.id === incomingCall.value.callerId)
|
||||
if (friend) {
|
||||
friend.lastMessage = "[已拒绝]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[已拒绝]", friend.unreadCount)
|
||||
}
|
||||
|
||||
incomingCall.value = null
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
|
||||
console.log("拒绝通话")
|
||||
}
|
||||
|
||||
@@ -337,22 +502,35 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const endCall = () => {
|
||||
const callId = currentCall.value?.callId || incomingCall.value?.callId
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
const callType = currentCall.value?.callType || incomingCall.value?.callType
|
||||
const callTypeVal = currentCall.value?.callType || incomingCall.value?.callType
|
||||
|
||||
if (!callId || !peerId) return
|
||||
|
||||
// 修复参数传递问题
|
||||
// 清除超时计时器
|
||||
if (currentCall.value?.timeoutId) {
|
||||
clearTimeout(currentCall.value.timeoutId)
|
||||
}
|
||||
|
||||
// 发送结束信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
type: callType === "video" ? "video-call" : "audio-call",
|
||||
type: callTypeVal === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: "ended"
|
||||
})
|
||||
|
||||
callStatus.value = "ended"
|
||||
callConnectionStatus.value = "通话结束"
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
currentCall.value = null
|
||||
incomingCall.value = null
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
|
||||
console.log("结束通话")
|
||||
}
|
||||
|
||||
@@ -365,6 +543,8 @@ export const useChatStore = defineStore("chat", () => {
|
||||
currentCall,
|
||||
incomingCall,
|
||||
callStatus,
|
||||
callError,
|
||||
callConnectionStatus,
|
||||
isConnected,
|
||||
isInCall,
|
||||
isCalling,
|
||||
|
||||
@@ -34,7 +34,7 @@ service.interceptors.response.use(
|
||||
localStorage.removeItem("token")
|
||||
localStorage.removeItem("chatUser")
|
||||
window.location.href = "/login"
|
||||
return Promise.reject(new极(msg))
|
||||
return Promise.reject(new Error(msg))
|
||||
}
|
||||
message.error(msg)
|
||||
return Promise.reject(new Error(msg))
|
||||
@@ -129,6 +129,8 @@ export const sendMessage = (data) => {
|
||||
receiver_user_id: data.receiverId,
|
||||
message_type: messageTypeMap[data.type] || 0,
|
||||
message_content: data.content || "",
|
||||
// 添加来源标记
|
||||
isFromHttp: true
|
||||
}
|
||||
|
||||
// 如果包含通话信令,添加call_id和call_status
|
||||
|
||||
@@ -13,6 +13,17 @@
|
||||
<!-- 录音状态指示器 -->
|
||||
<RecordingIndicator />
|
||||
|
||||
<!-- 视频通话组件(移动到此处) -->
|
||||
<VideoCallComponent
|
||||
v-if="showVideoCall"
|
||||
:caller-info="callerInfo"
|
||||
:call-type="callType"
|
||||
:is-incoming="isIncoming"
|
||||
@accept-call="handleAcceptCall"
|
||||
@reject-call="handleRejectCall"
|
||||
@end-call="handleEndCall"
|
||||
/>
|
||||
|
||||
<!-- 主聊天容器 -->
|
||||
<div class="flex-1 max-w-7xl mx-auto bg-white/90 backdrop-blur-sm rounded-2xl shadow-2xl overflow-hidden flex z-10">
|
||||
<!-- 侧边导航 -->
|
||||
@@ -39,7 +50,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onUnmounted, provide } from 'vue';
|
||||
import {onMounted, onUnmounted, ref, watch} from 'vue';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import { useChatStore } from '@/stores/chat';
|
||||
import { useThemeStore } from '@/stores/theme';
|
||||
@@ -55,6 +66,7 @@ import MediaPreview from '@/components/MediaPreview.vue';
|
||||
import FriendsManagement from '@/components/FriendsManagement.vue';
|
||||
import GroupsManagement from '@/components/GroupsManagement.vue';
|
||||
import MomentsView from '@/components/MomentsView.vue';
|
||||
import VideoCallComponent from '@/components/VideoCallComponent.vue';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const chatStore = useChatStore();
|
||||
@@ -62,23 +74,62 @@ const themeStore = useThemeStore();
|
||||
|
||||
const currentNav = ref('chat');
|
||||
|
||||
// 视频通话相关状态
|
||||
const showVideoCall = ref(false);
|
||||
const callType = ref('video');
|
||||
const isIncoming = ref(false);
|
||||
const callerInfo = ref(null);
|
||||
|
||||
// 初始化WebSocket连接
|
||||
const { connectWebSocket, disconnectWebSocket } = useWebSocket();
|
||||
|
||||
// 初始化录音功能
|
||||
const { isRecording } = useRecording();
|
||||
|
||||
// 提供录音状态给子组件
|
||||
provide('isRecording', isRecording);
|
||||
|
||||
// 处理导航切换
|
||||
const handleNavChange = (nav) => {
|
||||
currentNav.value = nav;
|
||||
};
|
||||
|
||||
// 检查用户会话
|
||||
userStore.checkSession();
|
||||
// 监听通话状态变化
|
||||
watch(() => chatStore.callStatus, (status) => {
|
||||
showVideoCall.value = status !== 'idle';
|
||||
});
|
||||
|
||||
// 监听来电
|
||||
watch(() => chatStore.incomingCall, (call) => {
|
||||
if (call) {
|
||||
isIncoming.value = true;
|
||||
callerInfo.value = chatStore.friends.find(f => f.id === call.callerId);
|
||||
callType.value = call.callType;
|
||||
} else {
|
||||
isIncoming.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// 监听当前通话
|
||||
watch(() => chatStore.currentCall, (call) => {
|
||||
if (call) {
|
||||
callerInfo.value = chatStore.friends.find(f => f.id === call.peerId);
|
||||
callType.value = call.callType;
|
||||
isIncoming.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// 处理接听通话
|
||||
const handleAcceptCall = () => {
|
||||
chatStore.acceptCall();
|
||||
};
|
||||
|
||||
// 处理拒绝通话
|
||||
const handleRejectCall = () => {
|
||||
chatStore.rejectCall();
|
||||
};
|
||||
|
||||
// 处理结束通话
|
||||
const handleEndCall = () => {
|
||||
chatStore.endCall();
|
||||
};
|
||||
// 加载主题
|
||||
themeStore.loadTheme();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user