"use client"; import React, { useState, useRef, useEffect, useCallback } from 'react'; import { useSharedWebRTCManager } from '@/hooks/webrtc/useSharedWebRTCManager'; import { useTextTransferBusiness } from '@/hooks/webrtc/useTextTransferBusiness'; import { useFileTransferBusiness } from '@/hooks/webrtc/useFileTransferBusiness'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { useToast } from '@/components/ui/toast-simple'; import { MessageSquare, Image, Download } from 'lucide-react'; import { ConnectionStatus } from '@/components/ConnectionStatus'; interface WebRTCTextReceiverProps { initialCode?: string; onPreviewImage: (imageUrl: string) => void; onRestart?: () => void; onConnectionChange?: (connection: any) => void; } export const WebRTCTextReceiver: React.FC = ({ initialCode = '', onPreviewImage, onRestart, onConnectionChange }) => { const { showToast } = useToast(); // 状态管理 const [pickupCode, setPickupCode] = useState(''); const [inputCode, setInputCode] = useState(initialCode); const [receivedText, setReceivedText] = useState(''); // 实时接收的文本内容 const [receivedImages, setReceivedImages] = useState>([]); const [isTyping, setIsTyping] = useState(false); const [isValidating, setIsValidating] = useState(false); // Ref用于防止重复自动连接 const hasTriedAutoConnect = useRef(false); // 创建共享连接 const connection = useSharedWebRTCManager(); // 使用共享连接创建业务层 const textTransfer = useTextTransferBusiness(connection); const fileTransfer = useFileTransferBusiness(connection); // 连接所有传输通道 const connectAll = useCallback(async (code: string, role: 'sender' | 'receiver') => { console.log('=== 连接所有传输通道 ===', { code, role }); // 只需要连接一次,因为使用的是共享连接 await connection.connect(code, role); }, [connection]); // 是否有任何连接 const hasAnyConnection = textTransfer.isConnected || fileTransfer.isConnected; // 是否正在连接 const isAnyConnecting = textTransfer.isConnecting || fileTransfer.isConnecting; // 通知父组件连接状态变化 useEffect(() => { if (onConnectionChange) { onConnectionChange(connection); } }, [onConnectionChange, connection.isConnected, connection.isConnecting, connection.isPeerConnected]); // 是否有任何错误 const hasAnyError = textTransfer.connectionError || fileTransfer.connectionError; // 重新开始 const restart = () => { setPickupCode(''); setInputCode(''); setReceivedText(''); setIsTyping(false); // 清理接收的图片URL receivedImages.forEach(img => { if (img.content.startsWith('blob:')) { URL.revokeObjectURL(img.content); } }); setReceivedImages([]); // 断开连接(只需要断开一次) connection.disconnect(); if (onRestart) { onRestart(); } }; // 监听实时文本同步 useEffect(() => { const cleanup = textTransfer.onTextSync((text: string) => { setReceivedText(text); }); return cleanup; }, [textTransfer.onTextSync]); // 监听打字状态 useEffect(() => { const cleanup = textTransfer.onTypingStatus((typing: boolean) => { setIsTyping(typing); }); return cleanup; }, [textTransfer.onTypingStatus]); // 监听文件(图片)接收 useEffect(() => { const cleanup = fileTransfer.onFileReceived((fileData) => { if (fileData.file.type.startsWith('image/')) { const imageUrl = URL.createObjectURL(fileData.file); const imageId = Date.now().toString(); setReceivedImages(prev => [...prev, { id: imageId, content: imageUrl, fileName: fileData.file.name }]); showToast(`收到图片: ${fileData.file.name}`, "success"); } }); return cleanup; }, [fileTransfer.onFileReceived]); // 验证并加入房间 const joinRoom = useCallback(async (code: string) => { if (!code || code.length !== 6) return; setIsValidating(true); try { console.log('=== 开始加入房间 ===', code); // 验证房间 const response = await fetch(`/api/room-info?code=${code}`); const roomData = await response.json(); if (!response.ok) { throw new Error(roomData.error || '房间不存在或已过期'); } console.log('=== 房间验证成功 ===', roomData); setPickupCode(code); // 连接到房间 await connectAll(code, 'receiver'); } catch (error: any) { console.error('加入房间失败:', error); showToast(error.message || '加入房间失败', "error"); } finally { setIsValidating(false); } }, [connectAll, showToast]); // 复制文本到剪贴板 const copyToClipboard = async (text: string) => { try { await navigator.clipboard.writeText(text); showToast('已复制到剪贴板', "success"); } catch (error) { console.error('复制失败:', error); showToast('复制失败', "error"); } }; // 处理初始代码连接 useEffect(() => { console.log(`initialCode: ${initialCode}, hasTriedAutoConnect: ${hasTriedAutoConnect.current}`); if (initialCode && initialCode.length === 6 && !hasTriedAutoConnect.current) { console.log('=== 自动连接初始代码 ===', initialCode); hasTriedAutoConnect.current = true setInputCode(initialCode); joinRoom(initialCode); return; } }, [initialCode, joinRoom]); return (
{!hasAnyConnection ? ( // 输入取件码界面

输入取件码

请输入6位取件码来获取实时文字内容

{ e.preventDefault(); joinRoom(inputCode); }} className="space-y-4 sm:space-y-6">
setInputCode(e.target.value.replace(/[^123456789ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijklmnpqrstuvwxyz]/g, ''))} placeholder="请输入取件码" className="text-center text-2xl sm:text-3xl tracking-[0.3em] sm:tracking-[0.5em] font-mono h-12 sm:h-16 border-2 border-slate-200 rounded-xl focus:border-emerald-500 focus:ring-emerald-500 bg-white/80 backdrop-blur-sm pb-2 sm:pb-4" maxLength={6} disabled={isValidating || isAnyConnecting} />

{inputCode.length}/6 位

) : ( // 已连接,显示实时文本

实时文字内容

取件码: {pickupCode}

{/* 文本显示区域 */}

接收到的文字

{receivedText && ( )}
{receivedText ? (
                      {receivedText}
                    
{isTyping && (
对方正在输入...
)}
) : (

{connection.isPeerConnected ? '等待对方发送文字内容...' : '等待连接建立...'}

)}
{/* 图片显示区域 */} {receivedImages.length > 0 && (

接收到的图片 ({receivedImages.length})

{receivedImages.map((image) => (
onPreviewImage(image.content)} > {image.fileName
点击查看
))}
)}
)}
); };