修复:
1. 重复请求 2. 后端接口问题修复 已知bug: 1. 交换信令问题 2. rtc未测试
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { defineStore } from "pinia"
|
||||
import { ref, computed } from "vue"
|
||||
import { ref, computed, watch } from "vue"
|
||||
import { chatDB } from "@/utils/db"
|
||||
import { useWebRTC } from "@/composables/useWebRTC"
|
||||
import { useUserStore } from "@/stores/user"
|
||||
@@ -12,22 +12,82 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const connectionStatus = ref("disconnected")
|
||||
const socket = ref(null)
|
||||
|
||||
// 通话相关状态
|
||||
// 通话相关状态增强
|
||||
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 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 webrtc = useWebRTC()
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 计算属性
|
||||
const isConnected = computed(() => connectionStatus.value === "connected")
|
||||
const isInCall = computed(() => callStatus.value !== "idle")
|
||||
const isInCall = computed(() =>
|
||||
["calling", "ringing", "connecting", "ongoing"].includes(callStatus.value)
|
||||
)
|
||||
const isCalling = computed(() => callStatus.value === "calling")
|
||||
const isRinging = computed(() => callStatus.value === "ringing")
|
||||
const isConnecting = computed(() => callStatus.value === "connecting")
|
||||
const isOngoingCall = computed(() => callStatus.value === "ongoing")
|
||||
const isDisconnected = computed(() => callStatus.value === "disconnected")
|
||||
const isHangup = computed(() => callStatus.value === "hangup")
|
||||
|
||||
// 监听通话状态变化
|
||||
watch(() => callStatus.value, (newStatus) => {
|
||||
console.log("通话状态变化:", newStatus)
|
||||
switch(newStatus) {
|
||||
case "disconnected":
|
||||
handleCallDisconnected()
|
||||
break
|
||||
case "hangup":
|
||||
handleCallHangup()
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
// 重置所有通话状态
|
||||
const resetCallState = () => {
|
||||
clearCallTimeout()
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
currentCall.value = null
|
||||
incomingCall.value = null
|
||||
}
|
||||
|
||||
// 清除通话超时
|
||||
const clearCallTimeout = () => {
|
||||
if (callTimeout.value) {
|
||||
clearTimeout(callTimeout.value)
|
||||
callTimeout.value = null
|
||||
}
|
||||
}
|
||||
|
||||
// 设置通话超时
|
||||
const setCallTimeout = (callback, duration = 30000) => {
|
||||
clearCallTimeout()
|
||||
callTimeout.value = setTimeout(() => {
|
||||
callback()
|
||||
clearCallTimeout()
|
||||
}, duration)
|
||||
}
|
||||
|
||||
// 发送通话信令
|
||||
const sendCallSignal = (signal) => {
|
||||
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
|
||||
const message = {
|
||||
request_type: "call_signal",
|
||||
...signal,
|
||||
sender_user_id: userStore.currentUser?.id
|
||||
}
|
||||
socket.value.send(JSON.stringify(message))
|
||||
} else {
|
||||
console.error("WebSocket未连接,无法发送通话信令")
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化数据库
|
||||
const initDB = async () => {
|
||||
@@ -106,24 +166,25 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const addMessage = async (message, currentUserId) => {
|
||||
messages.value.push(message)
|
||||
|
||||
if (currentFriend.value) {
|
||||
// 更新好友列表中的最后消息
|
||||
const friend = friends.value.find((f) => (f.id === message.senderId || f.id === currentFriend.value?.id))
|
||||
if (friend) {
|
||||
let lastMessage = message.content
|
||||
if (message.type === "image") lastMessage = "[图片]"
|
||||
if (message.type === "video") lastMessage = "[视频]"
|
||||
if (message.type === "audio") lastMessage = "[语音]"
|
||||
if (message.type === "video-call" || message.type === "audio-call") lastMessage = "[通话]"
|
||||
|
||||
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)
|
||||
|
||||
// 更新好友列表中的最后消息
|
||||
const friend = friends.value.find((f) => f.id === currentFriend.value.id)
|
||||
if (friend) {
|
||||
let lastMessage = message.content
|
||||
if (message.type === "image") lastMessage = "[图片]"
|
||||
if (message.type === "video") lastMessage = "[视频]"
|
||||
if (message.type === "audio") lastMessage = "[语音]"
|
||||
|
||||
friend.lastMessage = lastMessage.length > 20 ? lastMessage.substring(0, 20) + "..." : lastMessage
|
||||
|
||||
// 更新数据库中的好友信息
|
||||
await chatDB.updateFriendLastMessage(friend.id, currentUserId, friend.lastMessage, 0)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("保存消息失败:", error)
|
||||
}
|
||||
@@ -172,18 +233,22 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const friend = friends.value.find((f) => f.id == senderId)
|
||||
if (friend) {
|
||||
friend.unreadCount = (friend.unreadCount || 0) + 1
|
||||
|
||||
// 更新最后消息
|
||||
let lastMessage = newMessage.content
|
||||
if (newMessage.type === "image") lastMessage = "[图片]"
|
||||
if (newMessage.type === "video") lastMessage = "[视频]"
|
||||
if (newMessage.type === "audio") lastMessage = "[语音]"
|
||||
friend.lastMessage = lastMessage
|
||||
|
||||
// 更新数据库
|
||||
await chatDB.updateFriendLastMessage(friend.id, currentUserId, lastMessage, friend.unreadCount)
|
||||
}
|
||||
}
|
||||
|
||||
// 更新最后消息
|
||||
const friend = friends.value.find((f) => f.id == senderId)
|
||||
if (friend) {
|
||||
let lastMessage = newMessage.content
|
||||
if (newMessage.type === "image") lastMessage = "[图片]"
|
||||
if (newMessage.type === "video") lastMessage = "[视频]"
|
||||
if (newMessage.type === "audio") lastMessage = "[语音]"
|
||||
if (newMessage.type === "video-call" || newMessage.type === "audio-call") lastMessage = "[通话]"
|
||||
friend.lastMessage = lastMessage
|
||||
|
||||
// 更新数据库
|
||||
await chatDB.updateFriendLastMessage(friend.id, currentUserId, lastMessage, friend.unreadCount)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("处理接收消息失败:", error)
|
||||
}
|
||||
@@ -202,6 +267,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理通话信令
|
||||
const handleCallSignal = (data) => {
|
||||
console.log("处理通话信令:", data)
|
||||
console.log("通话状态:", data.call_status)
|
||||
|
||||
// 根据通话状态处理
|
||||
switch (data.call_status) {
|
||||
@@ -220,22 +286,79 @@ export const useChatStore = defineStore("chat", () => {
|
||||
case "candidate":
|
||||
handleIceCandidate(data)
|
||||
break
|
||||
case "no-answer": // 添加无人接听状态
|
||||
case "no-answer":
|
||||
handleCallNoAnswer(data)
|
||||
break
|
||||
case "connecting": // 新增连接状态
|
||||
callConnectionStatus.value = "正在连接..."
|
||||
case "connecting":
|
||||
handleCallConnecting(data)
|
||||
break
|
||||
case "busy": // 对方忙线中
|
||||
case "busy":
|
||||
handleCallBusy(data)
|
||||
break
|
||||
case "hangup": // 对方主动挂断
|
||||
handleCallHangup(data)
|
||||
break
|
||||
case "disconnected": // 对方掉线
|
||||
handleCallDisconnected(data)
|
||||
break
|
||||
case "terminated": // 对方终止呼叫
|
||||
handleCallTerminated(data)
|
||||
break
|
||||
case "failed":
|
||||
handleCallFailed(data)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 处理连接中状态
|
||||
const handleCallConnecting = (data) => {
|
||||
callConnectionStatus.value = "正在连接..."
|
||||
if (currentCall.value?.callId === data.call_id) {
|
||||
callStatus.value = "connecting"
|
||||
}
|
||||
}
|
||||
|
||||
// 处理通话失败
|
||||
const handleCallFailed = (data) => {
|
||||
if ((currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)) {
|
||||
callError.value = "failed"
|
||||
callConnectionStatus.value = "连接失败"
|
||||
|
||||
// 添加通话记录
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value?.callType === "video" || incomingCall.value?.callType === "video" ?
|
||||
"video-call" : "audio-call",
|
||||
content: "[连接失败]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: peerId,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[连接失败]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[连接失败]", friend.unreadCount)
|
||||
}
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
resetCallState()
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理来电
|
||||
const handleIncomingCall = (data) => {
|
||||
// 如果自己正在通话中,自动拒绝并发送忙线状态
|
||||
// 只有在当前没有通话时才处理来电
|
||||
if (isInCall.value) {
|
||||
// console.log 输出当前状态
|
||||
console.log("当前正在通话中,发送忙线状态")
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: data.sender_user_id,
|
||||
@@ -249,11 +372,26 @@ export const useChatStore = defineStore("chat", () => {
|
||||
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: "[未接来电]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: data.sender_user_id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// 重置所有通话状态
|
||||
resetCallState();
|
||||
|
||||
incomingCall.value = {
|
||||
callId: data.call_id,
|
||||
callerId: data.sender_user_id,
|
||||
@@ -280,16 +418,31 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理通话拒绝
|
||||
const handleCallRejected = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "rejected"
|
||||
resetCallState();
|
||||
callConnectionStatus.value = "对方已拒绝"
|
||||
currentCall.value = null
|
||||
console.log("通话已被拒绝")
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
content: "[对方已拒绝]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[对方已拒绝]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[对方已拒绝]", friend.unreadCount)
|
||||
}
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
@@ -299,16 +452,38 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const handleCallEnded = (data) => {
|
||||
if ((currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = null
|
||||
// 添加通话记录
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
if (friend) {
|
||||
const duration = callStatus.value === "ongoing" ?
|
||||
Math.floor((Date.now() - (currentCall.value?.startTime || incomingCall.value?.startTime)) / 1000) : 0
|
||||
|
||||
const callMessage = {
|
||||
type: currentCall.value?.callType === "video" || incomingCall.value?.callType === "video" ?
|
||||
"video-call" : "audio-call",
|
||||
content: callStatus.value === "ongoing" ?
|
||||
`[${currentCall.value?.callType === "video" ? "视频" : "语音"}通话] ${Math.floor(duration/60)}分${duration%60}秒` :
|
||||
"[通话结束]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: peerId,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: duration
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = callMessage.content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, callMessage.content, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState();
|
||||
callConnectionStatus.value = "通话已结束"
|
||||
currentCall.value = null
|
||||
incomingCall.value = null
|
||||
console.log("通话已结束")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
@@ -316,25 +491,43 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 处理ICE候选
|
||||
const handleIceCandidate = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
console.log("收到ICE候选:", data.content)
|
||||
// 这里可以添加WebRTC处理逻辑
|
||||
if ((currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)) {
|
||||
console.log("收到ICE候选:", data.candidate)
|
||||
|
||||
// 添加到WebRTC连接
|
||||
webrtc.addIceCandidate(data.candidate)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理无人接听
|
||||
const handleCallNoAnswer = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "no-answer"
|
||||
// 添加未接来电记录
|
||||
const friend = friends.value.find(f => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
content: "[未接来电]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[未接来电]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[未接来电]", friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState();
|
||||
callConnectionStatus.value = "对方无人接听"
|
||||
currentCall.value = null
|
||||
console.log("对方无人接听")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
@@ -343,16 +536,152 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理对方忙线
|
||||
const handleCallBusy = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "busy"
|
||||
// 添加忙线记录
|
||||
const friend = friends.value.find(f => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
content: "[对方忙线]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[对方忙线]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[对方忙线]", friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState();
|
||||
callConnectionStatus.value = "对方忙线中"
|
||||
currentCall.value = null
|
||||
console.log("对方忙线中")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对方挂断
|
||||
const handleCallHangup = (data) => {
|
||||
const callId = data.call_id
|
||||
const peerId = data.sender_user_id
|
||||
|
||||
if ((currentCall.value && currentCall.value.callId === callId) ||
|
||||
(incomingCall.value && incomingCall.value.callId === callId)) {
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
if (friend) {
|
||||
const duration = callStatus.value === "ongoing" ?
|
||||
Math.floor((Date.now() - (currentCall.value?.startTime || incomingCall.value?.startTime)) / 1000) : 0
|
||||
|
||||
const callMessage = {
|
||||
type: currentCall.value?.callType || incomingCall.value?.callType === "video" ?
|
||||
"video-call" : "audio-call",
|
||||
content: `[对方已挂断] ${Math.floor(duration/60)}分${duration%60}秒`,
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: peerId,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: duration
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = `[对方已挂断] ${Math.floor(duration/60)}分${duration%60}秒`
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, friend.lastMessage, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "对方已挂断"
|
||||
console.log("对方已挂断通话")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对方掉线
|
||||
const handleCallDisconnected = (data) => {
|
||||
const callId = data?.call_id || currentCall.value?.callId || incomingCall.value?.callId
|
||||
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 = callStatus.value === "ongoing" ?
|
||||
Math.floor((Date.now() - (currentCall.value?.startTime || incomingCall.value?.startTime)) / 1000) : 0
|
||||
|
||||
const callMessage = {
|
||||
type: currentCall.value?.callType || incomingCall.value?.callType === "video" ?
|
||||
"video-call" : "audio-call",
|
||||
content: `[网络中断] ${Math.floor(duration/60)}分${duration%60}秒`,
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: peerId,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: duration
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = `[网络中断] ${Math.floor(duration/60)}分${duration%60}秒`
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, friend.lastMessage, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "网络连接已断开"
|
||||
console.log("网络连接已断开")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理对方终止呼叫
|
||||
const handleCallTerminated = (data) => {
|
||||
const callId = data.call_id
|
||||
const peerId = data.sender_user_id
|
||||
|
||||
if ((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 = {
|
||||
type: currentCall.value?.callType || incomingCall.value?.callType === "video" ?
|
||||
"video-call" : "audio-call",
|
||||
content: "[对方已终止呼叫]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: peerId,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[对方已终止呼叫]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[对方已终止呼叫]", friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "对方已终止呼叫"
|
||||
console.log("对方已终止呼叫")
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
@@ -371,6 +700,8 @@ export const useChatStore = defineStore("chat", () => {
|
||||
return
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
|
||||
const callId = Date.now().toString() + Math.random().toString(36).substr(2, 9)
|
||||
|
||||
currentCall.value = {
|
||||
@@ -382,14 +713,32 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
|
||||
callStatus.value = "calling"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = "等待对方接听..."
|
||||
|
||||
// 创建WebRTC连接
|
||||
webrtc.createPeerConnection(callId, peerId, () => {
|
||||
// WebRTC连接成功回调
|
||||
callStatus.value = "ongoing"
|
||||
callConnectionStatus.value = "通话中"
|
||||
clearCallTimeout()
|
||||
}, (error) => {
|
||||
// WebRTC连接失败回调
|
||||
console.error("WebRTC连接失败:", error)
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
type: type === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: "failed"
|
||||
})
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "连接失败"
|
||||
})
|
||||
|
||||
// 设置30秒超时(无人接听)
|
||||
const timeoutId = setTimeout(() => {
|
||||
setCallTimeout(() => {
|
||||
if (callStatus.value === "calling") {
|
||||
callStatus.value = "ended"
|
||||
callError.value = "no-answer"
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "对方无人接听"
|
||||
console.log("呼叫超时,对方无人接听")
|
||||
|
||||
@@ -406,17 +755,25 @@ export const useChatStore = defineStore("chat", () => {
|
||||
friend.lastMessage = "[未接来电]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[未接来电]", friend.unreadCount)
|
||||
|
||||
// 添加通话记录
|
||||
const callMessage = {
|
||||
type: type === "video" ? "video-call" : "audio-call",
|
||||
content: "[未接来电]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
currentCall.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
}
|
||||
}, 30000)
|
||||
|
||||
currentCall.value.timeoutId = timeoutId
|
||||
|
||||
// 发送通话请求
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
@@ -433,37 +790,67 @@ 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,
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: incomingCall.value.callId,
|
||||
callStatus: "accepted"
|
||||
callStatus: "connecting"
|
||||
})
|
||||
|
||||
currentCall.value = {
|
||||
callId: incomingCall.value.callId,
|
||||
peerId: incomingCall.value.callerId,
|
||||
callType: incomingCall.value.callType,
|
||||
startTime: Date.now(),
|
||||
status: 'ongoing'
|
||||
}
|
||||
callStatus.value = "connecting"
|
||||
callConnectionStatus.value = "正在连接..."
|
||||
|
||||
callStatus.value = "ongoing"
|
||||
callConnectionStatus.value = "通话中"
|
||||
incomingCall.value = null
|
||||
callError.value = null
|
||||
console.log("接听通话")
|
||||
// 创建WebRTC连接
|
||||
webrtc.createPeerConnection(
|
||||
incomingCall.value.callId,
|
||||
incomingCall.value.callerId,
|
||||
() => {
|
||||
// WebRTC连接成功回调
|
||||
callStatus.value = "ongoing"
|
||||
callConnectionStatus.value = "通话中"
|
||||
|
||||
// 发送接受信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: incomingCall.value.callerId,
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: incomingCall.value.callId,
|
||||
callStatus: "accepted"
|
||||
})
|
||||
|
||||
currentCall.value = {
|
||||
callId: incomingCall.value.callId,
|
||||
peerId: incomingCall.value.callerId,
|
||||
callType: incomingCall.value.callType,
|
||||
startTime: Date.now(),
|
||||
status: 'ongoing'
|
||||
}
|
||||
|
||||
incomingCall.value = null
|
||||
console.log("通话已连接")
|
||||
},
|
||||
(error) => {
|
||||
// WebRTC连接失败回调
|
||||
console.error("WebRTC连接失败:", error)
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: incomingCall.value.callerId,
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: incomingCall.value.callId,
|
||||
callStatus: "failed"
|
||||
})
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "连接失败"
|
||||
}
|
||||
)
|
||||
|
||||
console.log("正在连接通话...")
|
||||
}
|
||||
|
||||
// 拒绝来电
|
||||
const rejectCall = () => {
|
||||
const rejectCall = (reason = "rejected") => {
|
||||
if (!incomingCall.value) return
|
||||
|
||||
// 发送拒绝信号
|
||||
@@ -472,26 +859,35 @@ export const useChatStore = defineStore("chat", () => {
|
||||
receiverId: incomingCall.value.callerId,
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: incomingCall.value.callId,
|
||||
callStatus: "rejected"
|
||||
callStatus: reason // 可以是'rejected'或'busy'
|
||||
})
|
||||
|
||||
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)
|
||||
const content = reason === "busy" ? "[对方忙线]" : "[已拒绝]"
|
||||
|
||||
const callMessage = {
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
content: content,
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, content, friend.unreadCount)
|
||||
}
|
||||
|
||||
incomingCall.value = null
|
||||
resetCallState()
|
||||
callConnectionStatus.value = reason === "busy" ? "对方忙线" : "已拒绝"
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
|
||||
@@ -499,41 +895,157 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
|
||||
// 结束通话
|
||||
const endCall = () => {
|
||||
const endCall = (reason = "ended") => {
|
||||
const callId = currentCall.value?.callId || incomingCall.value?.callId
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
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: callTypeVal === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: "ended"
|
||||
callStatus: reason // 可以是'ended'或'no-answer'
|
||||
})
|
||||
|
||||
callStatus.value = "ended"
|
||||
callConnectionStatus.value = "通话结束"
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
if (friend) {
|
||||
const duration = callStatus.value === "ongoing" ?
|
||||
Math.floor((Date.now() - (currentCall.value?.startTime || incomingCall.value?.startTime)) / 1000) : 0
|
||||
|
||||
let content = ""
|
||||
if (reason === "no-answer") {
|
||||
content = "[未接来电]"
|
||||
} else if (duration > 0) {
|
||||
content = `[${callTypeVal === "视频" ? "视频" : "语音"}通话] ${Math.floor(duration/60)}分${duration%60}秒`
|
||||
} else {
|
||||
content = "[通话结束]"
|
||||
}
|
||||
|
||||
const callMessage = {
|
||||
type: callTypeVal === "video" ? "video-call" : "audio-call",
|
||||
content: content,
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: duration
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = content
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, content, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callConnectionStatus.value = reason === "no-answer" ? "对方无人接听" : "通话结束"
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callStatus.value = "idle"
|
||||
currentCall.value = null
|
||||
incomingCall.value = null
|
||||
callError.value = null
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
|
||||
console.log("结束通话")
|
||||
}
|
||||
|
||||
// 主动挂断通话(用户点击挂断按钮)
|
||||
const hangupCall = () => {
|
||||
const callId = currentCall.value?.callId || incomingCall.value?.callId
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
const callTypeVal = currentCall.value?.callType || incomingCall.value?.callType
|
||||
|
||||
if (!callId || !peerId) return
|
||||
|
||||
// 发送挂断信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
type: callTypeVal === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: "hangup"
|
||||
})
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
if (friend) {
|
||||
const duration = callStatus.value === "ongoing" ?
|
||||
Math.floor((Date.now() - (currentCall.value?.startTime || incomingCall.value?.startTime)) / 1000) : 0
|
||||
|
||||
const callMessage = {
|
||||
type: callTypeVal === "video" ? "video-call" : "audio-call",
|
||||
content: `[已挂断] ${Math.floor(duration/60)}分${duration%60}秒`,
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: duration
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = `[已挂断] ${Math.floor(duration/60)}分${duration%60}秒`
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, friend.lastMessage, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "已挂断"
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
|
||||
console.log("主动挂断通话")
|
||||
}
|
||||
|
||||
// 终止呼叫(在对方接听前取消)
|
||||
const terminateCall = () => {
|
||||
if (!currentCall.value) return
|
||||
|
||||
// 发送终止信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: currentCall.value.peerId,
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: currentCall.value.callId,
|
||||
callStatus: "terminated"
|
||||
})
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
content: "[已取消]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = "[已取消]"
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[已取消]", friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "已取消呼叫"
|
||||
|
||||
// 5秒后清除状态
|
||||
setTimeout(() => {
|
||||
callConnectionStatus.value = ""
|
||||
}, 5000)
|
||||
|
||||
console.log("终止呼叫")
|
||||
}
|
||||
|
||||
return {
|
||||
friends,
|
||||
currentFriend,
|
||||
@@ -549,7 +1061,10 @@ export const useChatStore = defineStore("chat", () => {
|
||||
isInCall,
|
||||
isCalling,
|
||||
isRinging,
|
||||
isConnecting,
|
||||
isOngoingCall,
|
||||
isDisconnected,
|
||||
isHangup,
|
||||
initDB,
|
||||
loadFriends,
|
||||
setCurrentFriend,
|
||||
@@ -560,6 +1075,11 @@ export const useChatStore = defineStore("chat", () => {
|
||||
startCall,
|
||||
acceptCall,
|
||||
rejectCall,
|
||||
endCall
|
||||
endCall,
|
||||
hangupCall,
|
||||
terminateCall,
|
||||
resetCallState,
|
||||
sendCallSignal,
|
||||
clearCallTimeout
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user