优化交互
This commit is contained in:
@@ -96,7 +96,7 @@
|
||||
<!-- 本地视频 -->
|
||||
<div
|
||||
class="local-video-container"
|
||||
v-if="hasLocalVideo && callType === 'video' && isCameraWorking"
|
||||
v-if="callType === 'video' && isCameraWorking"
|
||||
>
|
||||
<video
|
||||
ref="localVideo"
|
||||
@@ -292,7 +292,9 @@ const initializeMedia = async () => {
|
||||
// 获取本地媒体流
|
||||
await webrtc.getLocalMedia(constraints);
|
||||
|
||||
startCallTimer();
|
||||
if (callStatus.value === "ongoing") {
|
||||
startCallTimer();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('无法访问媒体设备:', error);
|
||||
isCameraOn.value = false;
|
||||
@@ -362,7 +364,6 @@ const acceptCall = () => {
|
||||
// 确保只接听一次
|
||||
if (chatStore.callStatus === "ongoing") return;
|
||||
|
||||
initializeMedia();
|
||||
chatStore.acceptCall();
|
||||
emit('accept-call');
|
||||
};
|
||||
@@ -466,9 +467,9 @@ watch(() => webrtc.remoteStream.value, (newStream) => {
|
||||
// 监听通话状态
|
||||
watch(() => chatStore.callStatus, (status) => {
|
||||
if (status === "ongoing") {
|
||||
// 只在状态变化时初始化媒体
|
||||
if (!hasLocalVideo.value) {
|
||||
initializeMedia();
|
||||
// 开始计时
|
||||
if (!callTimer.value) {
|
||||
startCallTimer();
|
||||
}
|
||||
} else if (status === "ended" || status === "idle") {
|
||||
endCall();
|
||||
@@ -928,4 +929,4 @@ onUnmounted(() => {
|
||||
height: 95vh !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -19,41 +19,26 @@ export function useWebRTC() {
|
||||
{ urls: "stun:stun2.l.google.com:19302" },
|
||||
{ urls: "stun:stun3.l.google.com:19302" },
|
||||
{ urls: "stun:stun4.l.google.com:19302" },
|
||||
// {urls:'stun:stun01.sipphone.com'},
|
||||
// {urls:'stun:stun.ekiga.net'},
|
||||
// {urls:'stun:stun.fwdnet.net'},
|
||||
// {urls:'stun:stun.ideasip.com'},
|
||||
// {urls:'stun:stun.iptel.org'},
|
||||
// {urls:'stun:stun.rixtelecom.se'},
|
||||
// {urls:'stun:stun.schlund.de'},
|
||||
// {urls:'stun:stun.l.google.com:19302'},
|
||||
// {urls:'stun:stun1.l.google.com:19302'},
|
||||
// {urls:'stun:stun2.l.google.com:19302'},
|
||||
// {urls:'stun:stun3.l.google.com:19302'},
|
||||
// {urls:'stun:stun4.l.google.com:19302'},
|
||||
// {urls:'stun:stunserver.org'},
|
||||
// {urls:'stun:stun.softjoys.com'},
|
||||
// {urls:'stun:stun.voiparound.com'},
|
||||
// {urls:'stun:stun.voipbuster.com'},
|
||||
// {urls:'stun:stun.voipstunt.com'},
|
||||
// {urls:'stun:stun.voxgratia.org'},
|
||||
// {urls:'stun:stun.xten.com'},
|
||||
]
|
||||
],
|
||||
}
|
||||
|
||||
const createPeerConnection = (callId, peerId) => {
|
||||
if (peerConnection.value) {
|
||||
closeConnection()
|
||||
}
|
||||
|
||||
peerConnection.value = new RTCPeerConnection(configuration)
|
||||
|
||||
peerConnection.value.onicecandidate = (event) => {
|
||||
if (event.candidate) {
|
||||
console.log("ICE候选:", event.candidate)
|
||||
console.log("发送ICE候选:", event.candidate)
|
||||
|
||||
// 发送ICE候选给对方
|
||||
chatStore.sendCallSignal({
|
||||
call_id: callId,
|
||||
call_status: "candidate",
|
||||
candidate: event.candidate,
|
||||
receiver_user_id: peerId
|
||||
receiver_user_id: peerId,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -72,10 +57,30 @@ export function useWebRTC() {
|
||||
if (state === "connected") {
|
||||
isConnected.value = true
|
||||
isConnecting.value = false
|
||||
chatStore.callStatus = "ongoing"
|
||||
chatStore.callConnectionStatus = "通话中"
|
||||
} else if (state === "connecting") {
|
||||
isConnecting.value = true
|
||||
chatStore.callConnectionStatus = "正在连接..."
|
||||
} else if (state === "disconnected" || state === "failed") {
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
closeConnection();
|
||||
if (chatStore.callStatus === "ongoing") {
|
||||
chatStore.callStatus = "disconnected"
|
||||
chatStore.callConnectionStatus = "连接已断开"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
peerConnection.value.oniceconnectionstatechange = () => {
|
||||
const state = peerConnection.value.iceConnectionState
|
||||
console.log("ICE连接状态变化:", state)
|
||||
|
||||
if (state === "failed" || state === "disconnected") {
|
||||
if (chatStore.callStatus === "ongoing") {
|
||||
chatStore.callStatus = "disconnected"
|
||||
chatStore.callConnectionStatus = "网络连接已断开"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +89,12 @@ export function useWebRTC() {
|
||||
|
||||
const getLocalMedia = async (constraints = { audio: true, video: true }) => {
|
||||
try {
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach((track) => track.stop())
|
||||
}
|
||||
|
||||
localStream.value = await navigator.mediaDevices.getUserMedia(constraints)
|
||||
console.log("获取本地媒体成功:", localStream.value)
|
||||
return localStream.value
|
||||
} catch (error) {
|
||||
console.error("获取本地媒体失败:", error)
|
||||
@@ -104,14 +114,28 @@ export function useWebRTC() {
|
||||
})
|
||||
}
|
||||
|
||||
const offer = await peerConnection.value.createOffer({
|
||||
offerToReceiveAudio: true,
|
||||
offerToReceiveVideo: true
|
||||
})
|
||||
try {
|
||||
const offer = await peerConnection.value.createOffer({
|
||||
offerToReceiveAudio: true,
|
||||
offerToReceiveVideo: true,
|
||||
})
|
||||
|
||||
await peerConnection.value.setLocalDescription(offer)
|
||||
await peerConnection.value.setLocalDescription(offer)
|
||||
console.log("创建Offer成功:", offer)
|
||||
|
||||
return offer
|
||||
// 发送offer给对方
|
||||
chatStore.sendCallSignal({
|
||||
call_id: callId,
|
||||
call_status: "offer",
|
||||
offer: offer,
|
||||
receiver_user_id: peerId,
|
||||
})
|
||||
|
||||
return offer
|
||||
} catch (error) {
|
||||
console.error("创建Offer失败:", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const createAnswer = async (offer, callId, peerId) => {
|
||||
@@ -126,49 +150,83 @@ export function useWebRTC() {
|
||||
})
|
||||
}
|
||||
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(offer))
|
||||
const answer = await peerConnection.value.createAnswer()
|
||||
await peerConnection.value.setLocalDescription(answer)
|
||||
try {
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(offer))
|
||||
const answer = await peerConnection.value.createAnswer()
|
||||
await peerConnection.value.setLocalDescription(answer)
|
||||
|
||||
return answer
|
||||
console.log("创建Answer成功:", answer)
|
||||
|
||||
// 发送answer给对方
|
||||
chatStore.sendCallSignal({
|
||||
call_id: callId,
|
||||
call_status: "answer",
|
||||
answer: answer,
|
||||
receiver_user_id: peerId,
|
||||
})
|
||||
|
||||
return answer
|
||||
} catch (error) {
|
||||
console.error("创建Answer失败:", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const setRemoteAnswer = async (answer) => {
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(answer))
|
||||
try {
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(answer))
|
||||
console.log("设置远程Answer成功")
|
||||
} catch (error) {
|
||||
console.error("设置远程Answer失败:", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const setRemoteOffer = async (offer) => {
|
||||
try {
|
||||
await peerConnection.value.setRemoteDescription(new RTCSessionDescription(offer))
|
||||
console.log("设置远程Offer成功")
|
||||
} catch (error) {
|
||||
console.error("设置远程Offer失败:", error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
const addIceCandidate = async (candidate) => {
|
||||
if (peerConnection.value && peerConnection.value.remoteDescription) {
|
||||
try {
|
||||
await peerConnection.value.addIceCandidate(new RTCIceCandidate(candidate))
|
||||
console.log("添加ICE候选成功")
|
||||
} catch (error) {
|
||||
console.error("添加ICE候选失败:", error)
|
||||
}
|
||||
} else {
|
||||
console.warn("无法添加ICE候选,连接未准备好")
|
||||
}
|
||||
}
|
||||
|
||||
const closeConnection = () => {
|
||||
console.log("关闭WebRTC连接")
|
||||
|
||||
if (localStream.value) {
|
||||
localStream.value.getTracks().forEach((track) => {
|
||||
track.stop();
|
||||
if (localStream.value) {
|
||||
localStream.value.removeTrack(track);
|
||||
}
|
||||
});
|
||||
localStream.value = null;
|
||||
track.stop()
|
||||
})
|
||||
localStream.value = null
|
||||
}
|
||||
|
||||
if (peerConnection.value) {
|
||||
peerConnection.value.onicecandidate = null;
|
||||
peerConnection.value.ontrack = null;
|
||||
peerConnection.value.onconnectionstatechange = null;
|
||||
peerConnection.value.close();
|
||||
peerConnection.value = null;
|
||||
peerConnection.value.onicecandidate = null
|
||||
peerConnection.value.ontrack = null
|
||||
peerConnection.value.onconnectionstatechange = null
|
||||
peerConnection.value.oniceconnectionstatechange = null
|
||||
peerConnection.value.close()
|
||||
peerConnection.value = null
|
||||
}
|
||||
|
||||
remoteStream.value = null;
|
||||
isConnected.value = false;
|
||||
isConnecting.value = false;
|
||||
remoteStream.value = null
|
||||
isConnected.value = false
|
||||
isConnecting.value = false
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -182,7 +240,8 @@ export function useWebRTC() {
|
||||
createOffer,
|
||||
createAnswer,
|
||||
setRemoteAnswer,
|
||||
setRemoteOffer,
|
||||
addIceCandidate,
|
||||
closeConnection,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ export function useWebSocket() {
|
||||
return send({
|
||||
request_type: "call_signal",
|
||||
...signal,
|
||||
sender_user_id: userStore.currentUser?.id
|
||||
sender_user_id: userStore.currentUser?.id,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -181,4 +181,4 @@ export function useWebSocket() {
|
||||
bindUser,
|
||||
generateCallId,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { ref, computed, watch } from "vue"
|
||||
import { chatDB } from "@/utils/db"
|
||||
import { useWebRTC } from "@/composables/useWebRTC"
|
||||
import { useUserStore } from "@/stores/user"
|
||||
import { sendMessage } from "@/utils/request.js"
|
||||
|
||||
export const useChatStore = defineStore("chat", () => {
|
||||
const friends = ref([])
|
||||
@@ -25,9 +24,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 计算属性
|
||||
const isConnected = computed(() => connectionStatus.value === "connected")
|
||||
const isInCall = computed(() =>
|
||||
["calling", "ringing", "connecting", "ongoing"].includes(callStatus.value)
|
||||
)
|
||||
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")
|
||||
@@ -36,17 +33,20 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const isHangup = computed(() => callStatus.value === "hangup")
|
||||
|
||||
// 监听通话状态变化
|
||||
watch(() => callStatus.value, (newStatus) => {
|
||||
console.log("通话状态变化:", newStatus)
|
||||
switch(newStatus) {
|
||||
case "disconnected":
|
||||
handleCallDisconnected()
|
||||
break
|
||||
case "hangup":
|
||||
handleCallHangup()
|
||||
break
|
||||
}
|
||||
})
|
||||
watch(
|
||||
() => callStatus.value,
|
||||
(newStatus) => {
|
||||
console.log("通话状态变化:", newStatus)
|
||||
switch (newStatus) {
|
||||
case "disconnected":
|
||||
handleCallDisconnected()
|
||||
break
|
||||
case "hangup":
|
||||
handleCallHangup()
|
||||
break
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// 重置所有通话状态
|
||||
const resetCallState = () => {
|
||||
@@ -56,6 +56,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
callConnectionStatus.value = ""
|
||||
currentCall.value = null
|
||||
incomingCall.value = null
|
||||
webrtc.closeConnection()
|
||||
}
|
||||
|
||||
// 清除通话超时
|
||||
@@ -79,11 +80,15 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const sendCallSignal = (signal) => {
|
||||
if (socket.value && socket.value.readyState === WebSocket.OPEN) {
|
||||
const message = {
|
||||
request_type: "call_signal",
|
||||
...signal,
|
||||
sender_user_id: userStore.currentUser?.id
|
||||
call_status: signal.call_status,
|
||||
call_type: signal.call_type || (signal.receiver_user_id ? 6 : 7), // 默认视频通话
|
||||
call_id: signal.call_id,
|
||||
caller_id: userStore.currentUser.id,
|
||||
callee_id: signal.receiver_user_id,
|
||||
data: JSON.stringify(signal.offer || signal.answer || signal.candidate || {}),
|
||||
}
|
||||
socket.value.send(JSON.stringify(message))
|
||||
console.log("发送通话信令:", message)
|
||||
} else {
|
||||
console.error("WebSocket未连接,无法发送通话信令")
|
||||
}
|
||||
@@ -117,7 +122,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
lastMessage: "",
|
||||
unreadCount: 0,
|
||||
},
|
||||
currentUserId
|
||||
currentUserId,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -167,7 +172,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
messages.value.push(message)
|
||||
|
||||
// 更新好友列表中的最后消息
|
||||
const friend = friends.value.find((f) => (f.id === message.senderId || f.id === currentFriend.value?.id))
|
||||
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 = "[图片]"
|
||||
@@ -257,9 +262,15 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 根据消息类型编号获取类型字符串
|
||||
const getMessageType = (type) => {
|
||||
const types = [
|
||||
"text", "image", "audio", "video",
|
||||
"prescription", "medical-record",
|
||||
"video-call", "audio-call", "file"
|
||||
"text",
|
||||
"image",
|
||||
"audio",
|
||||
"video",
|
||||
"prescription",
|
||||
"medical-record",
|
||||
"video-call",
|
||||
"audio-call",
|
||||
"file",
|
||||
]
|
||||
return types[type] || "text"
|
||||
}
|
||||
@@ -283,6 +294,12 @@ export const useChatStore = defineStore("chat", () => {
|
||||
case "ended":
|
||||
handleCallEnded(data)
|
||||
break
|
||||
case "offer":
|
||||
handleOffer(data)
|
||||
break
|
||||
case "answer":
|
||||
handleAnswer(data)
|
||||
break
|
||||
case "candidate":
|
||||
handleIceCandidate(data)
|
||||
break
|
||||
@@ -310,6 +327,44 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 处理Offer信令
|
||||
const handleOffer = async (data) => {
|
||||
if (incomingCall.value && incomingCall.value.callId === data.call_id) {
|
||||
try {
|
||||
const offer = JSON.parse(data.data)
|
||||
console.log("收到Offer:", offer)
|
||||
|
||||
// 设置远程Offer并创建Answer
|
||||
await webrtc.setRemoteOffer(offer)
|
||||
const answer = await webrtc.createAnswer(offer, data.call_id, data.caller_id)
|
||||
|
||||
console.log("发送Answer:", answer)
|
||||
} catch (error) {
|
||||
console.error("处理Offer失败:", error)
|
||||
rejectCall("failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理Answer信令
|
||||
const handleAnswer = async (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
try {
|
||||
const answer = JSON.parse(data.data)
|
||||
console.log("收到Answer:", answer)
|
||||
|
||||
// 设置远程Answer
|
||||
await webrtc.setRemoteAnswer(answer)
|
||||
|
||||
callStatus.value = "connecting"
|
||||
callConnectionStatus.value = "正在建立连接..."
|
||||
} catch (error) {
|
||||
console.error("处理Answer失败:", error)
|
||||
endCall("failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理连接中状态
|
||||
const handleCallConnecting = (data) => {
|
||||
callConnectionStatus.value = "正在连接..."
|
||||
@@ -320,24 +375,28 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 处理通话失败
|
||||
const handleCallFailed = (data) => {
|
||||
if ((currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)) {
|
||||
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)
|
||||
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",
|
||||
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
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -357,31 +416,28 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const handleIncomingCall = (data) => {
|
||||
// 只有在当前没有通话时才处理来电
|
||||
if (isInCall.value) {
|
||||
// console.log 输出当前状态
|
||||
console.log("当前正在通话中,发送忙线状态")
|
||||
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"
|
||||
sendCallSignal({
|
||||
call_status: "busy",
|
||||
call_id: data.call_id,
|
||||
receiver_user_id: data.caller_id,
|
||||
})
|
||||
|
||||
// 添加未接来电消息
|
||||
const friend = friends.value.find(f => f.id === data.sender_user_id)
|
||||
const friend = friends.value.find((f) => f.id === data.caller_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",
|
||||
type: data.call_type === 6 ? "video-call" : "audio-call",
|
||||
content: "[未接来电]",
|
||||
time: new Date().toLocaleTimeString().slice(0, 5),
|
||||
senderId: data.sender_user_id,
|
||||
senderId: data.caller_id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
}
|
||||
@@ -390,13 +446,13 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
|
||||
// 重置所有通话状态
|
||||
resetCallState();
|
||||
resetCallState()
|
||||
|
||||
incomingCall.value = {
|
||||
callId: data.call_id,
|
||||
callerId: data.sender_user_id,
|
||||
callType: data.message_type === 6 ? "video" : "audio",
|
||||
content: data.content
|
||||
callerId: data.caller_id,
|
||||
callType: data.call_type === 6 ? "video" : "audio",
|
||||
content: data.data,
|
||||
}
|
||||
callStatus.value = "ringing"
|
||||
callError.value = null
|
||||
@@ -408,22 +464,36 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理通话接受
|
||||
const handleCallAccepted = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
callStatus.value = "ongoing"
|
||||
callStatus.value = "connecting"
|
||||
callError.value = null
|
||||
callConnectionStatus.value = "通话中"
|
||||
console.log("通话已被接受")
|
||||
callConnectionStatus.value = "对方已接听,正在连接..."
|
||||
console.log("通话已被接受,开始交换信令")
|
||||
|
||||
// 开始创建Offer
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await webrtc.getLocalMedia({
|
||||
audio: true,
|
||||
video: currentCall.value.callType === "video",
|
||||
})
|
||||
await webrtc.createOffer(currentCall.value.callId, currentCall.value.peerId)
|
||||
} catch (error) {
|
||||
console.error("创建Offer失败:", error)
|
||||
endCall("failed")
|
||||
}
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
// 处理通话拒绝
|
||||
const handleCallRejected = (data) => {
|
||||
if (currentCall.value && currentCall.value.callId === data.call_id) {
|
||||
resetCallState();
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "对方已拒绝"
|
||||
console.log("通话已被拒绝")
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === currentCall.value.peerId)
|
||||
const friend = friends.value.find((f) => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
@@ -432,7 +502,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -450,26 +520,33 @@ 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)) {
|
||||
if (
|
||||
(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)
|
||||
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 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}秒` :
|
||||
"[通话结束]",
|
||||
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
|
||||
duration: duration,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -478,7 +555,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, callMessage.content, friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState();
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "通话已结束"
|
||||
console.log("通话已结束")
|
||||
|
||||
@@ -491,12 +568,19 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 处理ICE候选
|
||||
const handleIceCandidate = (data) => {
|
||||
if ((currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)) {
|
||||
console.log("收到ICE候选:", data.candidate)
|
||||
if (
|
||||
(currentCall.value && currentCall.value.callId === data.call_id) ||
|
||||
(incomingCall.value && incomingCall.value.callId === data.call_id)
|
||||
) {
|
||||
try {
|
||||
const candidate = JSON.parse(data.data)
|
||||
console.log("收到ICE候选:", candidate)
|
||||
|
||||
// 添加到WebRTC连接
|
||||
webrtc.addIceCandidate(data.candidate)
|
||||
// 添加到WebRTC连接
|
||||
webrtc.addIceCandidate(candidate)
|
||||
} catch (error) {
|
||||
console.error("处理ICE候选失败:", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,7 +588,7 @@ 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)
|
||||
const friend = friends.value.find((f) => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
@@ -513,7 +597,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -522,7 +606,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[未接来电]", friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState();
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "对方无人接听"
|
||||
console.log("对方无人接听")
|
||||
|
||||
@@ -537,7 +621,7 @@ 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)
|
||||
const friend = friends.value.find((f) => f.id === currentCall.value.peerId)
|
||||
if (friend) {
|
||||
const callMessage = {
|
||||
type: currentCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
@@ -546,7 +630,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -555,7 +639,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, "[对方忙线]", friend.unreadCount)
|
||||
}
|
||||
|
||||
resetCallState();
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "对方忙线中"
|
||||
console.log("对方忙线中")
|
||||
|
||||
@@ -568,32 +652,31 @@ export const useChatStore = defineStore("chat", () => {
|
||||
|
||||
// 处理对方挂断
|
||||
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 callId = data?.call_id || currentCall.value?.callId || incomingCall.value?.callId
|
||||
const peerId = data?.caller_id || data?.callee_id || currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
|
||||
if (callId && peerId) {
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === 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 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}秒`,
|
||||
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
|
||||
duration: duration,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = `[对方已挂断] ${Math.floor(duration/60)}分${duration%60}秒`
|
||||
friend.lastMessage = `[对方已挂断] ${Math.floor(duration / 60)}分${duration % 60}秒`
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, friend.lastMessage, friend.unreadCount)
|
||||
}
|
||||
|
||||
@@ -611,29 +694,30 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理对方掉线
|
||||
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
|
||||
const peerId = data?.caller_id || data?.callee_id || currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
|
||||
if (callId && peerId) {
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === 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 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}秒`,
|
||||
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
|
||||
duration: duration,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
// 更新最后消息
|
||||
friend.lastMessage = `[网络中断] ${Math.floor(duration/60)}分${duration%60}秒`
|
||||
friend.lastMessage = `[网络中断] ${Math.floor(duration / 60)}分${duration % 60}秒`
|
||||
chatDB.updateFriendLastMessage(friend.id, userStore.currentUser.id, friend.lastMessage, friend.unreadCount)
|
||||
}
|
||||
|
||||
@@ -651,23 +735,23 @@ export const useChatStore = defineStore("chat", () => {
|
||||
// 处理对方终止呼叫
|
||||
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 peerId = data.caller_id || data.callee_id
|
||||
|
||||
if (
|
||||
(currentCall.value && currentCall.value.callId === callId) ||
|
||||
(incomingCall.value && incomingCall.value.callId === callId)
|
||||
) {
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
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",
|
||||
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
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -688,15 +772,15 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
|
||||
// 发起通话
|
||||
const startCall = (peerId, type) => {
|
||||
const startCall = async (peerId, type) => {
|
||||
if (isInCall.value) {
|
||||
alert('您正在通话中,请先结束当前通话。')
|
||||
alert("您正在通话中,请先结束当前通话。")
|
||||
return
|
||||
}
|
||||
|
||||
const friend = friends.value.find(f => f.id === peerId)
|
||||
const friend = friends.value.find((f) => f.id === peerId)
|
||||
if (!friend) {
|
||||
alert('好友信息无效')
|
||||
alert("好友信息无效")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -709,31 +793,24 @@ export const useChatStore = defineStore("chat", () => {
|
||||
peerId: peerId,
|
||||
callType: type,
|
||||
startTime: Date.now(),
|
||||
status: 'calling'
|
||||
status: "calling",
|
||||
}
|
||||
|
||||
callStatus.value = "calling"
|
||||
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"
|
||||
// 获取本地媒体
|
||||
try {
|
||||
await webrtc.getLocalMedia({
|
||||
audio: true,
|
||||
video: type === "video",
|
||||
})
|
||||
} catch (error) {
|
||||
console.error("获取本地媒体失败:", error)
|
||||
resetCallState()
|
||||
callConnectionStatus.value = "连接失败"
|
||||
})
|
||||
alert("无法访问摄像头或麦克风")
|
||||
return
|
||||
}
|
||||
|
||||
// 设置30秒超时(无人接听)
|
||||
setCallTimeout(() => {
|
||||
@@ -743,12 +820,10 @@ export const useChatStore = defineStore("chat", () => {
|
||||
console.log("呼叫超时,对方无人接听")
|
||||
|
||||
// 发送无人接听信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
type: type === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: "no-answer"
|
||||
sendCallSignal({
|
||||
call_status: "no-answer",
|
||||
call_id: callId,
|
||||
receiver_user_id: peerId,
|
||||
})
|
||||
|
||||
// 更新好友最后消息为未接来电
|
||||
@@ -763,7 +838,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -775,78 +850,50 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}, 30000)
|
||||
|
||||
// 发送通话请求
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
type: type === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: "invite"
|
||||
sendCallSignal({
|
||||
call_status: "invite",
|
||||
call_id: callId,
|
||||
call_type: type === "video" ? 6 : 7,
|
||||
receiver_user_id: peerId,
|
||||
})
|
||||
|
||||
console.log("发起通话:", currentCall.value)
|
||||
}
|
||||
|
||||
// 接听来电
|
||||
const acceptCall = () => {
|
||||
const acceptCall = async () => {
|
||||
if (!incomingCall.value) return
|
||||
|
||||
// 发送连接中信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: incomingCall.value.callerId,
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: incomingCall.value.callId,
|
||||
callStatus: "connecting"
|
||||
})
|
||||
|
||||
callStatus.value = "connecting"
|
||||
callConnectionStatus.value = "正在连接..."
|
||||
|
||||
// 创建WebRTC连接
|
||||
webrtc.createPeerConnection(
|
||||
incomingCall.value.callId,
|
||||
incomingCall.value.callerId,
|
||||
() => {
|
||||
// WebRTC连接成功回调
|
||||
callStatus.value = "ongoing"
|
||||
callConnectionStatus.value = "通话中"
|
||||
try {
|
||||
// 获取本地媒体
|
||||
await webrtc.getLocalMedia({
|
||||
audio: true,
|
||||
video: incomingCall.value.callType === "video",
|
||||
})
|
||||
|
||||
// 发送接受信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: incomingCall.value.callerId,
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: incomingCall.value.callId,
|
||||
callStatus: "accepted"
|
||||
})
|
||||
// 发送接受信号
|
||||
sendCallSignal({
|
||||
call_status: "accepted",
|
||||
call_id: incomingCall.value.callId,
|
||||
receiver_user_id: incomingCall.value.callerId,
|
||||
})
|
||||
|
||||
currentCall.value = {
|
||||
callId: incomingCall.value.callId,
|
||||
peerId: incomingCall.value.callerId,
|
||||
callType: incomingCall.value.callType,
|
||||
startTime: Date.now(),
|
||||
status: 'ongoing'
|
||||
}
|
||||
currentCall.value = {
|
||||
callId: incomingCall.value.callId,
|
||||
peerId: incomingCall.value.callerId,
|
||||
callType: incomingCall.value.callType,
|
||||
startTime: Date.now(),
|
||||
status: "connecting",
|
||||
}
|
||||
|
||||
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("正在连接通话...")
|
||||
console.log("接听通话,等待Offer...")
|
||||
} catch (error) {
|
||||
console.error("接听通话失败:", error)
|
||||
rejectCall("failed")
|
||||
}
|
||||
}
|
||||
|
||||
// 拒绝来电
|
||||
@@ -854,16 +901,14 @@ export const useChatStore = defineStore("chat", () => {
|
||||
if (!incomingCall.value) return
|
||||
|
||||
// 发送拒绝信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: incomingCall.value.callerId,
|
||||
type: incomingCall.value.callType === "video" ? "video-call" : "audio-call",
|
||||
callId: incomingCall.value.callId,
|
||||
callStatus: reason // 可以是'rejected'或'busy'
|
||||
sendCallSignal({
|
||||
call_status: reason,
|
||||
call_id: incomingCall.value.callId,
|
||||
receiver_user_id: incomingCall.value.callerId,
|
||||
})
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === incomingCall.value.callerId)
|
||||
const friend = friends.value.find((f) => f.id === incomingCall.value.callerId)
|
||||
if (friend) {
|
||||
const content = reason === "busy" ? "[对方忙线]" : "[已拒绝]"
|
||||
|
||||
@@ -874,7 +919,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: 0
|
||||
duration: 0,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -900,28 +945,31 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const peerId = currentCall.value?.peerId || incomingCall.value?.callerId
|
||||
const callTypeVal = currentCall.value?.callType || incomingCall.value?.callType
|
||||
|
||||
if (!callId || !peerId) return
|
||||
if (!callId || !peerId) {
|
||||
resetCallState()
|
||||
return
|
||||
}
|
||||
|
||||
// 发送结束信号
|
||||
sendMessage({
|
||||
senderId: userStore.currentUser?.id,
|
||||
receiverId: peerId,
|
||||
type: callTypeVal === "video" ? "video-call" : "audio-call",
|
||||
callId: callId,
|
||||
callStatus: reason // 可以是'ended'或'no-answer'
|
||||
sendCallSignal({
|
||||
call_status: reason,
|
||||
call_id: callId,
|
||||
receiver_user_id: peerId,
|
||||
})
|
||||
|
||||
// 添加通话记录
|
||||
const friend = friends.value.find(f => f.id === 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 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}秒`
|
||||
content = `[${callTypeVal === "video" ? "视频" : "语音"}通话] ${Math.floor(duration / 60)}分${duration % 60}秒`
|
||||
} else {
|
||||
content = "[通话结束]"
|
||||
}
|
||||
@@ -933,7 +981,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
senderId: userStore.currentUser?.id,
|
||||
read: true,
|
||||
timestamp: Date.now(),
|
||||
duration: duration
|
||||
duration: duration,
|
||||
}
|
||||
chatDB.saveMessage(callMessage, userStore.currentUser.id, friend.id)
|
||||
|
||||
@@ -953,99 +1001,6 @@ export const useChatStore = defineStore("chat", () => {
|
||||
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,
|
||||
@@ -1076,10 +1031,8 @@ export const useChatStore = defineStore("chat", () => {
|
||||
acceptCall,
|
||||
rejectCall,
|
||||
endCall,
|
||||
hangupCall,
|
||||
terminateCall,
|
||||
resetCallState,
|
||||
sendCallSignal,
|
||||
clearCallTimeout
|
||||
clearCallTimeout,
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -7,16 +7,16 @@ export const useUserStore = defineStore("user", () => {
|
||||
|
||||
// 预设用户数据
|
||||
const presetUsers = ref([
|
||||
{ id: "1", name: "张三", avatar: "avatar1", color: "#4cc9f0" },
|
||||
{ id: "2", name: "李四", avatar: "avatar2", color: "#ff6b6b" },
|
||||
{ id: "3", name: "王五", avatar: "avatar3", color: "#6a0dad" },
|
||||
{ id: "4", name: "赵六", avatar: "avatar4", color: "#20b2aa" },
|
||||
{ id: "5", name: "钱七", avatar: "avatar5", color: "#ffa500" },
|
||||
{ id: "6", name: "孙八", avatar: "avatar6", color: "#9acd32" },
|
||||
{ id: "7", name: "周九", avatar: "avatar7", color: "#ff1493" },
|
||||
{ id: "8", name: "吴十", avatar: "avatar8", color: "#4682b4" },
|
||||
{ id: "9", name: "郑十一", avatar: "avatar9", color: "#c71585" },
|
||||
{ id: "10", name: "王十二", avatar: "avatar10", color: "#2e8b57" },
|
||||
{ id: "1", room_id: "10001", name: "张三", avatar: "avatar1", color: "#4cc9f0" },
|
||||
{ id: "2", room_id: "10002", name: "李四", avatar: "avatar2", color: "#ff6b6b" },
|
||||
{ id: "3", room_id: "10003", name: "王五", avatar: "avatar3", color: "#6a0dad" },
|
||||
{ id: "4", room_id: "10004", name: "赵六", avatar: "avatar4", color: "#20b2aa" },
|
||||
{ id: "5", room_id: "10005", name: "钱七", avatar: "avatar5", color: "#ffa500" },
|
||||
{ id: "6", room_id: "10006", name: "孙八", avatar: "avatar6", color: "#9acd32" },
|
||||
{ id: "7", room_id: "10007", name: "周九", avatar: "avatar7", color: "#ff1493" },
|
||||
{ id: "8", room_id: "10008", name: "吴十", avatar: "avatar8", color: "#4682b4" },
|
||||
{ id: "9", room_id: "10009", name: "郑十一", avatar: "avatar9", color: "#c71585" },
|
||||
{ id: "10", room_id: "100010", name: "王十二", avatar: "avatar10", color: "#2e8b57" },
|
||||
])
|
||||
|
||||
const login = (user) => {
|
||||
|
||||
@@ -101,6 +101,7 @@ watch(() => chatStore.callStatus, (status) => {
|
||||
watch(() => chatStore.incomingCall, (call) => {
|
||||
if (call) {
|
||||
isIncoming.value = true;
|
||||
console.log(call, 'ssssssssssssssss')
|
||||
callerInfo.value = chatStore.friends.find(f => f.id === call.callerId);
|
||||
callType.value = call.callType;
|
||||
} else {
|
||||
@@ -185,4 +186,4 @@ onUnmounted(() => {
|
||||
.animate-float-slow {
|
||||
animation: float-slow 18s infinite ease-in-out;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user