From 0de25a0544b9b3ef3a25b11a4caab74d0c6e99ee Mon Sep 17 00:00:00 2001 From: kura Date: Thu, 7 May 2026 21:21:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/file/item/desptopView.vue | 803 +++++++++++++++++++++++----- 1 file changed, 670 insertions(+), 133 deletions(-) diff --git a/src/pages/file/item/desptopView.vue b/src/pages/file/item/desptopView.vue index c402737..752c14f 100644 --- a/src/pages/file/item/desptopView.vue +++ b/src/pages/file/item/desptopView.vue @@ -1,53 +1,293 @@ @@ -55,7 +295,6 @@ import { computed, nextTick, ref, onMounted, onUnmounted } from "vue"; import { peer } from "../utils/peer"; import { message } from "ant-design-vue"; -import { UpOutlined, DownOutlined, PhoneOutlined } from "@ant-design/icons-vue"; const props = defineProps<{ peerId: string; @@ -76,67 +315,101 @@ interface MediaEndedEvent extends CustomEvent { }; } +interface MediaStartedEvent extends CustomEvent { + detail: { + peerId: string; + }; +} + const videoRef = ref(null); const audioRef = ref(null); const videoContainer = ref(null); const desktopStream = ref(null); const callStream = ref(null); +const isDesktopActive = ref(false); +const isCallActive = ref(false); const isFullscreen = ref(false); -const isCollapsed = ref(false); const isCallMuted = ref(false); +const callDuration = ref(0); +let durationTimer: number | null = null; -const hasMedia = computed(() => !!desktopStream.value || !!callStream.value); -const headerTitle = computed(() => { - if (desktopStream.value && callStream.value) return "远程桌面与通话"; - if (desktopStream.value) return "远程桌面"; - return "语音通话"; +const callDurationStr = computed(() => { + const mins = Math.floor(callDuration.value / 60); + const secs = callDuration.value % 60; + return `${String(mins).padStart(2, "0")}:${String(secs).padStart(2, "0")}`; }); -// 切换收起/展开状态 -const toggleCollapse = () => { - isCollapsed.value = !isCollapsed.value; +const startDurationTimer = () => { + callDuration.value = 0; + durationTimer = window.setInterval(() => { + callDuration.value++; + }, 1000); +}; + +const stopDurationTimer = () => { + if (durationTimer !== null) { + clearInterval(durationTimer); + durationTimer = null; + } + callDuration.value = 0; }; -// 处理远程流 const handleStream = async (event: StreamEvent) => { const { stream: remoteStream, type } = event.detail; if (props.peerId !== event.detail.peerId) return; if (type === "desktop") { + isDesktopActive.value = true; desktopStream.value = remoteStream; - isCollapsed.value = false; // 收到流时自动展开 await nextTick(); if (videoRef.value) { videoRef.value.srcObject = remoteStream; + videoRef.value.muted = true; + videoRef.value.play().catch(() => { + message.warning("浏览器阻止了自动播放,请点击桌面画面恢复播放"); + }); } } else if (type === "call") { + isCallActive.value = true; callStream.value = remoteStream; - isCollapsed.value = false; + startDurationTimer(); await nextTick(); if (audioRef.value) { audioRef.value.srcObject = remoteStream; - audioRef.value.muted = isCallMuted.value; - audioRef.value.play().catch(() => { - message.warning("浏览器阻止了自动播放,请点击通话区域恢复声音"); - }); } } }; -// 处理媒体结束 +const handleDesktopStarted = (event: MediaStartedEvent) => { + if (props.peerId !== event.detail.peerId) return; + isDesktopActive.value = true; +}; + +const handleCallStarted = (event: MediaStartedEvent) => { + if (props.peerId !== event.detail.peerId) return; + isCallActive.value = true; + startDurationTimer(); +}; + const handleMediaEnded = (event: MediaEndedEvent) => { const { type } = event.detail; if (props.peerId !== event.detail.peerId) return; if (type === "desktop") { + isDesktopActive.value = false; desktopStream.value = null; if (videoRef.value) { videoRef.value.srcObject = null; } message.info("远程桌面共享已结束"); + if (!isCallActive.value) { + stopDurationTimer(); + } } else if (type === "call") { + isCallActive.value = false; callStream.value = null; if (audioRef.value) { audioRef.value.srcObject = null; } + stopDurationTimer(); message.info("语音通话已结束"); } }; @@ -147,6 +420,7 @@ const endDesktop = () => { const endCall = () => { peer.endMedia(props.peerId, "call"); + stopDurationTimer(); }; const toggleCallMuted = () => { @@ -156,10 +430,8 @@ const toggleCallMuted = () => { } }; -// 切换全屏 const toggleFullscreen = async () => { if (!videoContainer.value) return; - try { if (!isFullscreen.value) { if (videoContainer.value.requestFullscreen) { @@ -170,12 +442,11 @@ const toggleFullscreen = async () => { await document.exitFullscreen(); } } - } catch (err) { + } catch { message.error("切换全屏失败"); } }; -// 监听全屏变化 const handleFullscreenChange = () => { isFullscreen.value = !!document.fullscreenElement; }; @@ -186,132 +457,398 @@ const streamListener: EventListener = (event) => { const mediaEndedListener: EventListener = (event) => { handleMediaEnded(event as MediaEndedEvent); }; +const desktopStartedListener: EventListener = (event) => { + handleDesktopStarted(event as MediaStartedEvent); +}; +const callStartedListener: EventListener = (event) => { + handleCallStarted(event as MediaStartedEvent); +}; onMounted(() => { peer.on("stream", streamListener); + peer.on("desktop-started", desktopStartedListener); + peer.on("call-started", callStartedListener); peer.on("media-ended", mediaEndedListener); document.addEventListener("fullscreenchange", handleFullscreenChange); }); onUnmounted(() => { peer.off("stream", streamListener); + peer.off("desktop-started", desktopStartedListener); + peer.off("call-started", callStartedListener); peer.off("media-ended", mediaEndedListener); document.removeEventListener("fullscreenchange", handleFullscreenChange); - - // 清理视频流 + stopDurationTimer(); desktopStream.value?.getTracks().forEach((track) => track.stop()); callStream.value?.getTracks().forEach((track) => track.stop()); });