feat: 合并effect,优化逻辑

This commit is contained in:
MatrixSeven
2025-08-29 18:19:59 +08:00
parent 0c33a72c0a
commit 86fd9ec08c
7 changed files with 55 additions and 144 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import React, { useEffect, useState } from 'react';
import React from 'react';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Upload, MessageSquare, Monitor, Users } from 'lucide-react';
import Hero from '@/components/Hero';
@@ -18,8 +18,6 @@ export default function HomePage() {
const {
activeTab,
handleTabChange,
getConnectionInfo,
hasInitialized,
confirmDialogState,
closeConfirmDialog
} = useTabNavigation();
@@ -34,18 +32,6 @@ export default function HomePage() {
showUnsupportedModalManually,
} = useWebRTCSupport();
// 桌面共享功能的占位符函数(保持向后兼容)
const handleStartSharing = async () => {
console.log('开始桌面共享');
};
const handleStopSharing = async () => {
console.log('停止桌面共享');
};
const handleJoinSharing = async (code: string) => {
console.log('加入桌面共享:', code);
};
// 处理Tabs组件的字符串参数
const handleTabChangeWrapper = (value: string) => {

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState, useMemo } from 'react';
import React, { useMemo } from 'react';
import { cn } from '@/lib/utils';
import { useWebRTCStore } from '@/hooks/index';
@@ -14,7 +14,7 @@ interface ConnectionStatusProps {
}
// 连接状态枚举
const getConnectionStatus = (connection: any, currentRoom: any) => {
const getConnectionStatus = (connection: { isWebSocketConnected?: boolean; isPeerConnected?: boolean; isConnecting?: boolean; error?: string | null }, currentRoom: { code: string; role: 'sender' | 'receiver' } | null) => {
const isWebSocketConnected = connection?.isWebSocketConnected || false;
const isPeerConnected = connection?.isPeerConnected || false;
const isConnecting = connection?.isConnecting || false;
@@ -116,7 +116,7 @@ const StatusIcon = ({ type, className = 'w-3 h-3' }: { type: string; className?:
};
// 获取连接状态文字描述
const getConnectionStatusText = (connection: any) => {
const getConnectionStatusText = (connection: { isWebSocketConnected?: boolean; isPeerConnected?: boolean; isConnecting?: boolean; error?: string | null }) => {
const isWebSocketConnected = connection?.isWebSocketConnected || false;
const isPeerConnected = connection?.isPeerConnected || false;
const isConnecting = connection?.isConnecting || false;
@@ -155,12 +155,14 @@ export function ConnectionStatus(props: ConnectionStatusProps) {
error: webrtcState.error,
};
const isConnected = webrtcState.isWebSocketConnected && webrtcState.isPeerConnected;
// 如果是内联模式,只返回状态文字
if (inline) {
return <span className={cn('text-sm text-slate-600', className)}>{getConnectionStatusText(connection)}</span>;
}
const status = getConnectionStatus(connection, currentRoom);
const status = getConnectionStatus(connection, currentRoom ?? null);
if (compact) {
return (
@@ -244,7 +246,7 @@ export function ConnectionStatus(props: ConnectionStatusProps) {
}
// 简化版本的 Hook用于快速集成 - 现在已经不需要了,但保留兼容性
export function useConnectionStatus(webrtcConnection?: any) {
export function useConnectionStatus(webrtcConnection?: { isWebSocketConnected?: boolean; isPeerConnected?: boolean; isConnecting?: boolean; currentRoom?: { code: string; role: 'sender' | 'receiver' } | null; error?: string | null }) {
// 这个hook现在不再需要因为ConnectionStatus组件直接使用底层连接
// 但为了向后兼容,保留这个接口
return useMemo(() => ({

View File

@@ -6,26 +6,18 @@ import { Button } from '@/components/ui/button';
import { Share, Monitor } from 'lucide-react';
import WebRTCDesktopReceiver from '@/components/webrtc/WebRTCDesktopReceiver';
import WebRTCDesktopSender from '@/components/webrtc/WebRTCDesktopSender';
import { useWebRTCStore } from '@/hooks/index';
interface DesktopShareProps {
// 保留向后兼容性的props已废弃但保留接口
onStartSharing?: () => Promise<string>;
onStopSharing?: () => Promise<void>;
onJoinSharing?: (code: string) => Promise<void>;
}
export default function DesktopShare({
onStartSharing,
onStopSharing,
onJoinSharing
}: DesktopShareProps) {
const [mode, setMode] = useState<'share' | 'view'>('share');
// 使用全局WebRTC状态
const webrtcState = useWebRTCStore();
// 使用统一的URL处理器带模式转换
const { updateMode, getCurrentRoomCode } = useURLHandler({
featureType: 'desktop',
@@ -44,9 +36,8 @@ export default function DesktopShare({
return code;
}, [getCurrentRoomCode]);
// 连接状态变化处理 - 现在不需要了,因为使用全局状态
const handleConnectionChange = useCallback((connection: any) => {
// 这个函数现在可能不需要了,但为了兼容现有的子组件接口,保留它
// 连接状态变化处理 - 为了兼容现有的子组件接口,保留它
const handleConnectionChange = useCallback((connection: { isConnected: boolean; isWebSocketConnected: boolean }) => {
console.log('桌面共享连接状态变化:', connection);
}, []);

View File

@@ -83,7 +83,7 @@ export const WebRTCFileTransfer: React.FC = () => {
isPeerConnected: connection.isPeerConnected
});
const { joinRoom: originalJoinRoom, isJoiningRoom } = useRoomConnection({
const { joinRoom: originalJoinRoom } = useRoomConnection({
connect,
isConnecting,
isConnected
@@ -264,28 +264,33 @@ export const WebRTCFileTransfer: React.FC = () => {
return;
}
console.log('当前选中的文件列表:', selectedFiles.map(f => f.name));
// 在发送方的selectedFiles中查找对应文件
const file = selectedFiles.find(f => f.name === fileName);
if (!file) {
console.error('找不到匹配的文件:', fileName);
console.log('可用文件:', selectedFiles.map(f => `${f.name} (${f.size} bytes)`));
showToast(`无法找到文件: ${fileName}`, "error");
return;
}
console.log('找到匹配文件,开始发送:', file.name, 'ID:', fileId, '文件大小:', file.size);
// 更新发送方文件状态为downloading
// 更新发送方文件状态为downloading - 统一使用updateFileStatus
updateFileStatus(fileId, 'downloading', 0);
// 发送文件
try {
sendFile(file, fileId);
// 移除不必要的Toast - 传输开始状态在UI中已经显示
} catch (sendError) {
console.error('发送文件失败:', sendError);
showToast(`发送文件失败: ${fileName}`, "error");
// 重置文件状态
// 重置文件状态 - 统一使用updateFileStatus
updateFileStatus(fileId, 'ready', 0);
}
} else {
@@ -340,86 +345,7 @@ export const WebRTCFileTransfer: React.FC = () => {
}
}, [error, mode, showToast, lastError]);
// 处理文件接收
useEffect(() => {
const cleanup = onFileReceived((fileData: { id: string; file: File }) => {
console.log('=== 接收到文件 ===');
console.log('文件:', fileData.file.name, 'ID:', fileData.id);
// 更新下载的文件
setDownloadedFiles(prev => new Map(prev.set(fileData.id, fileData.file)));
// 更新文件状态
setFileList(prev => prev.map(item =>
item.id === fileData.id
? { ...item, status: 'completed' as const, progress: 100 }
: item
));
// 移除不必要的Toast - 文件完成状态在UI中已经显示
});
return cleanup;
}, [onFileReceived]);
// 处理文件请求(发送方监听)
useEffect(() => {
const cleanup = onFileRequested((fileId: string, fileName: string) => {
console.log('=== 收到文件请求 ===');
console.log('文件:', fileName, 'ID:', fileId, '当前模式:', mode);
if (mode === 'send') {
// 检查连接状态
if (!isConnected || error) {
console.log('连接已断开,无法发送文件');
showToast('连接已断开,无法发送文件', "error");
return;
}
console.log('当前选中的文件列表:', selectedFiles.map(f => f.name));
// 在发送方的selectedFiles中查找对应文件
const file = selectedFiles.find(f => f.name === fileName);
if (!file) {
console.error('找不到匹配的文件:', fileName);
console.log('可用文件:', selectedFiles.map(f => `${f.name} (${f.size} bytes)`));
showToast(`无法找到文件: ${fileName}`, "error");
return;
}
console.log('找到匹配文件,开始发送:', file.name, 'ID:', fileId, '文件大小:', file.size);
// 更新发送方文件状态为downloading
setFileList(prev => prev.map(item =>
item.id === fileId || item.name === fileName
? { ...item, status: 'downloading' as const, progress: 0 }
: item
));
// 发送文件
try {
sendFile(file, fileId);
// 移除不必要的Toast - 传输开始状态在UI中已经显示
} catch (sendError) {
console.error('发送文件失败:', sendError);
showToast(`发送文件失败: ${fileName}`, "error");
// 重置文件状态
setFileList(prev => prev.map(item =>
item.id === fileId || item.name === fileName
? { ...item, status: 'ready' as const, progress: 0 }
: item
));
}
} else {
console.warn('接收模式下收到文件请求,忽略');
}
});
return cleanup;
}, [onFileRequested, mode, selectedFiles, sendFile, isConnected, error]);
// 监听连接状态变化和清理传输状态
useEffect(() => {

View File

@@ -115,40 +115,45 @@ export const useFileStateManager = ({
console.log('=== selectedFiles变化同步文件列表 ===', {
selectedFilesCount: selectedFiles.length,
fileListCount: fileList.length,
selectedFileNames: selectedFiles.map(f => f.name)
});
// 根据selectedFiles创建新的文件信息列表
const newFileInfos: FileInfo[] = selectedFiles.map(file => {
// 尝试找到现有的文件信息,保持已有的状态
const existingFileInfo = fileList.find(info => info.name === file.name && info.size === file.size);
return existingFileInfo || {
id: generateFileId(),
name: file.name,
size: file.size,
type: file.type,
status: 'ready' as const,
progress: 0
};
});
// 检查文件列表是否真正发生变化
const fileListChanged =
newFileInfos.length !== fileList.length ||
newFileInfos.some(newFile =>
!fileList.find(oldFile => oldFile.name === newFile.name && oldFile.size === newFile.size)
);
if (fileListChanged) {
console.log('文件列表发生变化,更新:', {
before: fileList.map(f => f.name),
after: newFileInfos.map(f => f.name)
// 使用函数式更新获取当前fileList避免依赖fileList
setFileList(currentFileList => {
// 根据selectedFiles创建新的文件信息列表
const newFileInfos: FileInfo[] = selectedFiles.map(file => {
// 尝试在当前fileList中找到现有的文件信息保持已有的状态
const existingFileInfo = currentFileList.find(info => info.name === file.name && info.size === file.size);
return existingFileInfo || {
id: generateFileId(),
name: file.name,
size: file.size,
type: file.type,
status: 'ready' as const,
progress: 0
};
});
setFileList(newFileInfos);
}
}, [selectedFiles, mode, pickupCode, fileList, generateFileId]);
// 检查文件列表是否真正发生变化
const fileListChanged =
newFileInfos.length !== currentFileList.length ||
newFileInfos.some(newFile =>
!currentFileList.find(oldFile => oldFile.name === newFile.name && oldFile.size === newFile.size)
);
if (fileListChanged) {
console.log('文件列表发生变化,更新:', {
before: currentFileList.map(f => f.name),
after: newFileInfos.map(f => f.name)
});
return newFileInfos;
}
// 如果没有变化返回当前的fileList
return currentFileList;
});
}, [selectedFiles, mode, pickupCode, generateFileId]); // 移除fileList依赖避免无限循环
return {
selectedFiles,

View File

@@ -1,5 +1,5 @@
import { EventEmitter } from 'events';
import { WebRTCError, WebRTCMessage, ConnectionEvent, EventHandler } from './types';
import { WebRTCError, ConnectionEvent, EventHandler } from './types';
interface WebSocketManagerConfig {
url: string;

View File

@@ -43,6 +43,7 @@ export function detectWebRTCSupport(): WebRTCSupport {
pc.close();
}
} catch (error) {
console.warn(error);
missing.push('DataChannel');
}