From 4faf1c3141c33a6bbefecc8baac7972f67080fff Mon Sep 17 00:00:00 2001 From: MatrixSeven Date: Mon, 1 Sep 2025 15:53:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=85=B1=E4=BA=AB=E6=A1=8C=E9=9D=A2?= =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E5=85=A8=E5=B1=8F=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 5 +- chuan-next/src/components/DesktopViewer.tsx | 110 +++++++++++++++--- chuan-next/src/components/WeChatGroup.tsx | 2 +- .../connection/useSharedWebRTCManager.ts | 2 +- chuan-next/src/hooks/webrtc/WebRTCManager.ts | 2 +- chuan-next/src/lib/config.ts | 4 +- cmd/main.go | 1 + 7 files changed, 106 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 691172f..8a00ee5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **安全、快速、简单的点对点文件传输解决方案 - 无需注册,即传即用** -## [在线体验](https://transfer.52python.cn) • [GitHub](https://github.com/MatrixSeven/file-transfer-go) +## [在线体验](https://transfer.52python.cn) • [GitHub](https://github.com/MatrixSeven/file-transfer-go) • [X关注我](https://x.com/_MatrixSeven) ![项目演示](img.png) @@ -31,6 +31,9 @@ ## 🔄 最近更新日志 +### 2025-09--1 +- ✅ **移动端桌面全屏** - 优化移动端下UI,并解决全屏问题 + ### 2025-08-28 - ✅ **完善Docker部署支持** - 优化Docker配置,支持一键部署和多环境配置 - ✅ **优化README文档** - 更新项目说明,完善部署指南和技术栈信息 diff --git a/chuan-next/src/components/DesktopViewer.tsx b/chuan-next/src/components/DesktopViewer.tsx index 04f865c..f3accf0 100644 --- a/chuan-next/src/components/DesktopViewer.tsx +++ b/chuan-next/src/components/DesktopViewer.tsx @@ -144,7 +144,33 @@ export default function DesktopViewer({ // 全屏时自动隐藏控制栏,鼠标移动时显示 setShowControls(false); } else { + // 退出全屏时显示控制栏 setShowControls(true); + + // 延迟检查视频状态,确保全屏切换完成 + setTimeout(() => { + if (videoRef.current && stream) { + console.log('[DesktopViewer] 🔄 退出全屏,检查视频状态'); + + // 确保视频流正确设置 + const currentSrcObject = videoRef.current.srcObject; + if (!currentSrcObject || currentSrcObject !== stream) { + videoRef.current.srcObject = stream; + } + + // 检查视频是否暂停 + if (videoRef.current.paused) { + console.log('[DesktopViewer] ⏸️ 退出全屏后视频已暂停,显示播放按钮'); + setIsPlaying(false); + setNeedsUserInteraction(true); + hasAttemptedAutoplayRef.current = true; // 标记已尝试过自动播放 + } else { + console.log('[DesktopViewer] ▶️ 退出全屏后视频仍在播放'); + setIsPlaying(true); + setNeedsUserInteraction(false); + } + } + }, 200); // 延迟200ms确保全屏切换完成 } }; @@ -153,7 +179,7 @@ export default function DesktopViewer({ return () => { document.removeEventListener('fullscreenchange', handleFullscreenChange); }; - }, []); + }, [stream]); // 鼠标移动处理(全屏时) const handleMouseMove = useCallback(() => { @@ -207,13 +233,43 @@ export default function DesktopViewer({ // 切换全屏 const toggleFullscreen = useCallback(async () => { - if (!containerRef.current) return; + if (!videoRef.current) return; try { if (isFullscreen) { - await document.exitFullscreen(); + // 退出全屏 + if (document.fullscreenElement) { + await document.exitFullscreen(); + } + // 退出iOS全屏模式 + if ((document as any).webkitExitFullscreen) { + await (document as any).webkitExitFullscreen(); + } + // 退出视频全屏模式 + if ((videoRef.current as any).webkitExitFullscreen) { + await (videoRef.current as any).webkitExitFullscreen(); + } + // 退出Android全屏模式 + if ((videoRef.current as any).exitFullscreen) { + await (videoRef.current as any).exitFullscreen(); + } } else { - await containerRef.current.requestFullscreen(); + // 进入标准全屏 + if (videoRef.current.requestFullscreen) { + await videoRef.current.requestFullscreen(); + } + // 进入iOS全屏模式 + else if ((videoRef.current as any).webkitRequestFullscreen) { + await (videoRef.current as any).webkitRequestFullscreen(); + } + // 进入iOS视频全屏模式 + else if ((videoRef.current as any).webkitEnterFullscreen) { + await (videoRef.current as any).webkitEnterFullscreen(); + } + // 进入Android全屏模式 + else if ((videoRef.current as any).requestFullscreen) { + await (videoRef.current as any).requestFullscreen(); + } } } catch (error) { console.error('[DesktopViewer] 全屏切换失败:', error); @@ -223,9 +279,22 @@ export default function DesktopViewer({ // 退出全屏 const exitFullscreen = useCallback(async () => { try { + // 退出标准全屏 if (document.fullscreenElement) { await document.exitFullscreen(); } + // 退出iOS全屏模式 + if ((document as any).webkitExitFullscreen) { + await (document as any).webkitExitFullscreen(); + } + // 退出视频全屏模式 + if (videoRef.current && (videoRef.current as any).webkitExitFullscreen) { + await (videoRef.current as any).webkitExitFullscreen(); + } + // 退出Android全屏模式 + if (videoRef.current && (videoRef.current as any).exitFullscreen) { + await (videoRef.current as any).exitFullscreen(); + } } catch (error) { console.error('[DesktopViewer] 退出全屏失败:', error); } @@ -301,15 +370,15 @@ export default function DesktopViewer({ }} /> - {/* 需要用户交互的播放覆盖层 - 只在自动播放尝试失败后显示 */} - {hasAttemptedAutoplayRef.current && needsUserInteraction && !isPlaying && ( + {/* 需要用户交互的播放覆盖层 - 在视频暂停时显示 */} + {((needsUserInteraction && !isPlaying) || (isConnected && !isPlaying && !needsUserInteraction && videoRef.current?.paused)) && (

点击播放桌面共享

-

浏览器需要用户交互才能开始播放媒体

+

视频已暂停,点击继续播放

)} @@ -331,23 +400,23 @@ export default function DesktopViewer({ showControls || !isFullscreen ? 'opacity-100' : 'opacity-0 pointer-events-none' }`} > -
+
{/* 左侧信息 */}
- {isPlaying ? '桌面共享中' : needsUserInteraction ? '等待播放' : '连接中'} + {isPlaying ? '桌面共享中' : needsUserInteraction ? '等待播放' : isConnected ? '已暂停' : '连接中'}
{videoStats.resolution !== '0x0' && ( <> -
- {videoStats.resolution} +
+ {videoStats.resolution} )} {connectionCode && ( <> -
- {connectionCode} +
+ {connectionCode} )}
@@ -372,7 +441,7 @@ export default function DesktopViewer({ @@ -413,6 +482,19 @@ export default function DesktopViewer({ )}
+ {/* 移动端浮动全屏按钮 - 在控制栏隐藏时显示 */} + {!isFullscreen && ( + + )} + {/* 加载状态 */} {stream && !isConnected && (
diff --git a/chuan-next/src/components/WeChatGroup.tsx b/chuan-next/src/components/WeChatGroup.tsx index 17d873f..cbae69d 100644 --- a/chuan-next/src/components/WeChatGroup.tsx +++ b/chuan-next/src/components/WeChatGroup.tsx @@ -24,7 +24,7 @@ export default function WeChatGroup() { {/* 微信群二维码 - 请将此区域替换为实际的二维码图片 */}
微信群二维码 diff --git a/chuan-next/src/hooks/connection/useSharedWebRTCManager.ts b/chuan-next/src/hooks/connection/useSharedWebRTCManager.ts index c83514e..c864559 100644 --- a/chuan-next/src/hooks/connection/useSharedWebRTCManager.ts +++ b/chuan-next/src/hooks/connection/useSharedWebRTCManager.ts @@ -239,7 +239,7 @@ export function useSharedWebRTCManager(): WebRTCConnection { } // 构建完整的WebSocket URL - const wsUrl = baseWsUrl.replace('/ws/p2p', `/ws/webrtc?code=${roomCode}&role=${role}&channel=shared`); + const wsUrl = `${baseWsUrl}/api/ws/webrtc?code=${roomCode}&role=${role}&channel=shared`; console.log('[SharedWebRTC] 🌐 连接WebSocket:', wsUrl); const ws = new WebSocket(wsUrl); wsRef.current = ws; diff --git a/chuan-next/src/hooks/webrtc/WebRTCManager.ts b/chuan-next/src/hooks/webrtc/WebRTCManager.ts index 8c8437f..ae37e80 100644 --- a/chuan-next/src/hooks/webrtc/WebRTCManager.ts +++ b/chuan-next/src/hooks/webrtc/WebRTCManager.ts @@ -318,7 +318,7 @@ export class WebRTCManager extends EventEmitter { throw new WebRTCError('WS_URL_NOT_CONFIGURED', 'WebSocket URL未配置', false); } - const wsUrl = baseWsUrl.replace('/ws/p2p', `/ws/webrtc?code=${roomCode}&role=${role}&channel=shared`); + const wsUrl = baseWsUrl.replace('/api/ws/webrtc', `/ws/webrtc?code=${roomCode}&role=${role}&channel=shared`); this.wsManager = new WebSocketManager({ url: wsUrl, reconnectAttempts: 5, diff --git a/chuan-next/src/lib/config.ts b/chuan-next/src/lib/config.ts index 2c743fc..10d1fdb 100644 --- a/chuan-next/src/lib/config.ts +++ b/chuan-next/src/lib/config.ts @@ -33,12 +33,12 @@ const getCurrentWsUrl = () => { if (isNextDevServer) { // 开发模式:通过 Next.js 开发服务器访问,连接到后端 WebSocket - return 'ws://localhost:8080/ws/p2p'; + return 'ws://localhost:8080'; } // 生产模式或通过 Go 服务器访问:使用当前域名和端口 const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; - return `${protocol}//${window.location.host}/ws/p2p`; + return `${protocol}//${window.location.host}`; } // 服务器端返回空字符串,强制在客户端计算 return ''; diff --git a/cmd/main.go b/cmd/main.go index 07061a3..3a17bf0 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -58,6 +58,7 @@ func main() { r.Handle("/*", web.CreateFrontendHandler()) // WebRTC信令WebSocket路由 + r.Get("/api/ws/webrtc", h.HandleWebRTCWebSocket) r.Get("/ws/webrtc", h.HandleWebRTCWebSocket) // WebRTC房间API