|
@@ -1,46 +1,123 @@
|
|
|
<template>
|
|
|
- <div v-if="visible" class="weixin-call-modal">
|
|
|
+ <div v-if="rtcStore.imSate.videoCallModal" class="weixin-call-modal">
|
|
|
<div class="caller-info">
|
|
|
- <img class="avatar" :src="callAvatar || defaultAvatar" alt="头像" />
|
|
|
- <div class="name">{{ callName || '未知用户' }}</div>
|
|
|
+ <img
|
|
|
+ class="avatar"
|
|
|
+ :src="rtcStore.imSate.callAvatar || defaultAvatar"
|
|
|
+ alt="头像"
|
|
|
+ />
|
|
|
+ <div class="name">{{ rtcStore.imSate.callName || "未知用户" }}</div>
|
|
|
<div class="status">{{ statusText }}</div>
|
|
|
</div>
|
|
|
<div class="btn-group">
|
|
|
- <!-- 来电状态显示接听/拒绝按钮 -->
|
|
|
- <template v-if="!inCall">
|
|
|
- <button class="btn reject" @click="$emit('reject')">拒绝</button>
|
|
|
- <button class="btn accept" @click="$emit('accept')">接听</button>
|
|
|
+ <!-- 拨打方,只显示挂断按钮 -->
|
|
|
+ <template v-if="rtcStore.isCaller">
|
|
|
+ <button class="btn hangup" @click="hangupCall">挂断</button>
|
|
|
</template>
|
|
|
|
|
|
- <!-- 通话中状态显示挂断按钮 -->
|
|
|
+ <!-- 来电方,显示接听和拒绝按钮(未通话中) -->
|
|
|
+ <template v-else-if="!inCall">
|
|
|
+ <button class="btn reject" @click="rejectCall">拒绝</button>
|
|
|
+ <button class="btn accept" @click="acceptCall">接听</button>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 通话中显示挂断按钮 -->
|
|
|
<template v-else>
|
|
|
- <button class="btn hangup" @click="$emit('hangup')">挂断</button>
|
|
|
+ <button class="btn hangup" @click="hangupCall">挂断</button>
|
|
|
</template>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
- <script setup>
|
|
|
|
|
|
- const props = defineProps({
|
|
|
- visible: Boolean, // 是否显示弹窗
|
|
|
- inCall: Boolean, // 是否通话中
|
|
|
- callName: String, // 来电人姓名
|
|
|
- callAvatar: String, // 来电人头像
|
|
|
- });
|
|
|
+ <script setup>
|
|
|
+ import { ref, computed, onMounted, onBeforeUnmount } from "vue";
|
|
|
+ import { useWebSocketStore } from "@/stores/modules/webSocketStore";
|
|
|
+ import { useWebRTCStore } from "@/stores/modules/webrtcStore";
|
|
|
+ import * as Constant from "@/common/constant/Constant";
|
|
|
|
|
|
+ const wsStore = useWebSocketStore();
|
|
|
+ const rtcStore = useWebRTCStore();
|
|
|
+
|
|
|
+ const inCall = ref(false);
|
|
|
const defaultAvatar = "https://example.com/default-avatar.png";
|
|
|
|
|
|
const statusText = computed(() => {
|
|
|
- if (!props.inCall) {
|
|
|
- return "正在语音通话请求...";
|
|
|
- } else {
|
|
|
- return "通话中...";
|
|
|
+ return inCall.value ? "通话中..." : "正在语音通话请求...";
|
|
|
+ });
|
|
|
+
|
|
|
+ function onMessage(message) {
|
|
|
+ if (message.type !== Constant.MESSAGE_TRANS_TYPE) return;
|
|
|
+
|
|
|
+ switch (message.contentType) {
|
|
|
+ case Constant.DIAL_AUDIO_ONLINE:
|
|
|
+ rtcStore.imSate.videoCallModal = true;
|
|
|
+ rtcStore.imSate.callName = message.fromUserName || "未知用户";
|
|
|
+ rtcStore.imSate.callAvatar = message.fromUserAvatar || "";
|
|
|
+ inCall.value = false; // 有来电,未接听
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Constant.ACCEPT_AUDIO_ONLINE:
|
|
|
+ inCall.value = true; // 对方已接听,通话中
|
|
|
+ break;
|
|
|
+
|
|
|
+ case Constant.REJECT_AUDIO_ONLINE:
|
|
|
+ case Constant.CANCELL_AUDIO_ONLINE:
|
|
|
+ case Constant.DIAL_MEDIA_END:
|
|
|
+ rtcStore.imSate.videoCallModal = false;
|
|
|
+ inCall.value = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ async function acceptCall() {
|
|
|
+ try {
|
|
|
+ inCall.value = true;
|
|
|
+ wsStore.sendMessage({
|
|
|
+ messageType: Constant.MESSAGE_TYPE_USER,
|
|
|
+ contentType: Constant.ACCEPT_AUDIO_ONLINE,
|
|
|
+ type: Constant.MESSAGE_TRANS_TYPE,
|
|
|
+ });
|
|
|
+ // 可以调用 rtcStore 初始化本地流、连接等逻辑
|
|
|
+ } catch (err) {
|
|
|
+ console.error("接听失败", err);
|
|
|
+ inCall.value = false;
|
|
|
}
|
|
|
+ }
|
|
|
+
|
|
|
+ function rejectCall() {
|
|
|
+ wsStore.sendMessage({
|
|
|
+ messageType: Constant.MESSAGE_TYPE_USER,
|
|
|
+ contentType: Constant.REJECT_AUDIO_ONLINE,
|
|
|
+ type: Constant.MESSAGE_TRANS_TYPE,
|
|
|
+ });
|
|
|
+ rtcStore.imSate.videoCallModal = false;
|
|
|
+ inCall.value = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ function hangupCall() {
|
|
|
+ rtcStore.cleanup();
|
|
|
+ wsStore.sendMessage({
|
|
|
+ messageType: Constant.MESSAGE_TYPE_USER,
|
|
|
+ contentType: Constant.CANCELL_AUDIO_ONLINE,
|
|
|
+ type: Constant.MESSAGE_TRANS_TYPE,
|
|
|
+ });
|
|
|
+ rtcStore.imSate.videoCallModal = false;
|
|
|
+ inCall.value = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ wsStore.onMessageCallbacks.push(onMessage);
|
|
|
+ });
|
|
|
+
|
|
|
+ onBeforeUnmount(() => {
|
|
|
+ wsStore.onMessageCallbacks = wsStore.onMessageCallbacks.filter(
|
|
|
+ (cb) => cb !== onMessage
|
|
|
+ );
|
|
|
});
|
|
|
</script>
|
|
|
|
|
|
- <style scoped>
|
|
|
+ <style scoped lang="less">
|
|
|
.weixin-call-modal {
|
|
|
position: fixed;
|
|
|
inset: 0;
|
|
@@ -101,7 +178,7 @@
|
|
|
}
|
|
|
|
|
|
.btn.accept {
|
|
|
- background-color: #4cd964; /* 绿色接听 */
|
|
|
+ background-color: #4cd964;
|
|
|
}
|
|
|
|
|
|
.btn.accept:hover {
|
|
@@ -109,7 +186,7 @@
|
|
|
}
|
|
|
|
|
|
.btn.reject {
|
|
|
- background-color: #ff3b30; /* 红色拒绝 */
|
|
|
+ background-color: #ff3b30;
|
|
|
}
|
|
|
|
|
|
.btn.reject:hover {
|