diff --git a/README.md b/README.md index 7644417..4b04aa5 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,22 @@ ## ✨ 核心功能 - 📁 **文件传输** - 支持多文件同时传输,基于WebRTC的P2P直连 -- 📝 **文字传输** - 快速分享文本内容 -- 🖥️ **桌面共享** - 实时屏幕共享(开发中) +- 📝 **文字传输** - 快速分享文本内容 ✅ +- 🖥️ **桌面共享** - 实时屏幕共享 ✅ +- 🔗 **连接状态同步** - 实时连接状态UI同步 ✅ - 🔒 **端到端加密** - 数据传输安全,服务器不存储文件 - 📱 **响应式设计** - 完美适配手机、平板、电脑 - 🖥️ **多平台支持** - 支持linux/macos/win 单文件部署 + +## 🔄 开发进度 + +- ✅ 文件传输功能 +- ✅ 文字传输功能 +- ✅ 桌面共享功能 +- ✅ 连接状态UI同步 +- 🔄 大文件传输数据安全保证(进行中) +- 🔄 docker镜像发布(进行中) + ## 🚀 技术栈 **前端** - Next.js 15 + React 18 + TypeScript + Tailwind CSS @@ -38,8 +49,11 @@ cd file-transfer-go **发送文件** 1. 选择文件 → 生成取件码 → 分享6位码 -**接收文件** -1. 输入取件码 → 自动连接 → 下载文件 +**文字传输** +1. 输入文字内容 → 生成取件码 → 分享给对方 + +**桌面共享** +1. 点击共享桌面 → 生成取件码 → 对方输入码观看 ## 📊 项目架构 diff --git a/chuan-next/package.json b/chuan-next/package.json index bc30b4b..79388a2 100644 --- a/chuan-next/package.json +++ b/chuan-next/package.json @@ -35,7 +35,8 @@ "react": "19.1.0", "react-dom": "19.1.0", "tailwind-merge": "^3.3.1", - "tailwindcss-animate": "^1.0.7" + "tailwindcss-animate": "^1.0.7", + "zustand": "^5.0.7" }, "devDependencies": { "@eslint/eslintrc": "^3", diff --git a/chuan-next/src/components/ConnectionStatus.tsx b/chuan-next/src/components/ConnectionStatus.tsx new file mode 100644 index 0000000..8f644fb --- /dev/null +++ b/chuan-next/src/components/ConnectionStatus.tsx @@ -0,0 +1,263 @@ +import React, { useEffect, useState, useMemo } from 'react'; +import { cn } from '@/lib/utils'; +import { useWebRTCStore } from '@/hooks/webrtc/webRTCStore'; + +interface ConnectionStatusProps { + // 房间信息 - 只需要这个基本信息 + currentRoom?: { code: string; role: 'sender' | 'receiver' } | null; + // 样式类名 + className?: string; + // 紧凑模式 + compact?: boolean; + // 内联模式 - 只返回状态文本,不包含UI结构 + inline?: boolean; +} + +// 连接状态枚举 +const getConnectionStatus = (connection: any, currentRoom: any) => { + const isWebSocketConnected = connection?.isWebSocketConnected || false; + const isPeerConnected = connection?.isPeerConnected || false; + const isConnecting = connection?.isConnecting || false; + const error = connection?.error || null; + + if (error) { + return { + type: 'error' as const, + message: '连接失败', + detail: error, + }; + } + + if (isConnecting) { + return { + type: 'connecting' as const, + message: '正在连接', + detail: '建立房间连接中...', + }; + } + + if (!currentRoom) { + return { + type: 'disconnected' as const, + message: '未连接', + detail: '尚未创建房间', + }; + } + + // 如果有房间信息但WebSocket未连接,且不是正在连接状态 + // 可能是状态更新的时序问题,显示连接中状态 + if (!isWebSocketConnected && !isConnecting) { + return { + type: 'connecting' as const, + message: '连接中', + detail: '正在建立WebSocket连接...', + }; + } + + if (isWebSocketConnected && !isPeerConnected) { + return { + type: 'room-ready' as const, + message: '房间已创建', + detail: '等待对方加入并建立P2P连接...', + }; + } + + if (isWebSocketConnected && isPeerConnected) { + return { + type: 'connected' as const, + message: 'P2P连接成功', + detail: '可以开始传输', + }; + } + + return { + type: 'unknown' as const, + message: '状态未知', + detail: '', + }; +}; + +// 状态颜色映射 +const getStatusColor = (type: string) => { + switch (type) { + case 'connected': + return 'text-green-600'; + case 'connecting': + case 'room-ready': + return 'text-yellow-600'; + case 'error': + return 'text-red-600'; + case 'disconnected': + case 'unknown': + default: + return 'text-gray-500'; + } +}; + +// 状态图标 +const StatusIcon = ({ type, className = 'w-3 h-3' }: { type: string; className?: string }) => { + const iconClass = cn('inline-block', className); + + switch (type) { + case 'connected': + return
; + case 'connecting': + case 'room-ready': + return ( + + ); + case 'error': + return ; + case 'disconnected': + case 'unknown': + default: + return ; + } +}; + +// 获取连接状态文字描述 +const getConnectionStatusText = (connection: any) => { + const isWebSocketConnected = connection?.isWebSocketConnected || false; + const isPeerConnected = connection?.isPeerConnected || false; + const isConnecting = connection?.isConnecting || false; + const error = connection?.error || null; + + const wsStatus = isWebSocketConnected ? 'WS已连接' : 'WS未连接'; + const rtcStatus = isPeerConnected ? 'RTC已连接' : + isWebSocketConnected ? 'RTC等待连接' : 'RTC未连接'; + + if (error) { + return `${wsStatus} ${rtcStatus} - 连接失败`; + } + + if (isConnecting) { + return `${wsStatus} ${rtcStatus} - 连接中`; + } + + if (isPeerConnected) { + return `${wsStatus} ${rtcStatus} - P2P连接成功`; + } + + return `${wsStatus} ${rtcStatus}`; +}; + +export function ConnectionStatus(props: ConnectionStatusProps) { + const { currentRoom, className, compact = false, inline = false } = props; + + // 使用全局WebRTC状态 + const webrtcState = useWebRTCStore(); + + // 创建connection对象以兼容现有代码 + const connection = { + isWebSocketConnected: webrtcState.isWebSocketConnected, + isPeerConnected: webrtcState.isPeerConnected, + isConnecting: webrtcState.isConnecting, + error: webrtcState.error, + }; + + // 如果是内联模式,只返回状态文字 + if (inline) { + return {getConnectionStatusText(connection)}; + } + + const status = getConnectionStatus(connection, currentRoom); + + if (compact) { + return ( +