mirror of
https://github.com/MatrixSeven/file-transfer-go.git
synced 2026-06-12 22:03:10 +08:00
feat: 调整UI/RTC逻辑
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Upload, MessageSquare, Monitor, Github, ExternalLink } from 'lucide-react';
|
||||
import Hero from '@/components/Hero';
|
||||
@@ -10,6 +11,21 @@ import { WebRTCFileTransfer } from '@/components/WebRTCFileTransfer';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
export default function HomePage() {
|
||||
const searchParams = useSearchParams();
|
||||
const [activeTab, setActiveTab] = useState('webrtc');
|
||||
const [hasInitialized, setHasInitialized] = useState(false);
|
||||
|
||||
// 根据URL参数设置初始标签(仅首次加载时)
|
||||
useEffect(() => {
|
||||
if (!hasInitialized) {
|
||||
const urlType = searchParams.get('type');
|
||||
if (urlType && ['webrtc', 'text', 'desktop'].includes(urlType)) {
|
||||
setActiveTab(urlType);
|
||||
}
|
||||
setHasInitialized(true);
|
||||
}
|
||||
}, [searchParams, hasInitialized]);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-blue-50">
|
||||
<div className="container mx-auto px-4 py-4 sm:py-6 md:py-8">
|
||||
@@ -20,7 +36,7 @@ export default function HomePage() {
|
||||
|
||||
{/* Main Content */}
|
||||
<div className="max-w-4xl mx-auto">
|
||||
<Tabs defaultValue="webrtc" className="w-full">
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
|
||||
{/* Tabs Navigation - 横向布局 */}
|
||||
<div className="mb-6">
|
||||
<TabsList className="grid w-full grid-cols-3 max-w-lg mx-auto h-auto bg-white/90 backdrop-blur-sm shadow-lg rounded-xl p-2 border border-slate-200">
|
||||
|
||||
38
chuan-next/src/app/api/webrtc-room-status/route.ts
Normal file
38
chuan-next/src/app/api/webrtc-room-status/route.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
const GO_BACKEND_URL = process.env.GO_BACKEND_URL || 'http://localhost:8080';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const code = searchParams.get('code');
|
||||
|
||||
if (!code) {
|
||||
return NextResponse.json(
|
||||
{ success: false, message: '取件码不能为空' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log('API Route: Getting WebRTC room status, proxying to:', `${GO_BACKEND_URL}/api/webrtc-room-status?code=${code}`);
|
||||
|
||||
const response = await fetch(`${GO_BACKEND_URL}/api/webrtc-room-status?code=${code}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
console.log('Backend response:', response.status, data);
|
||||
|
||||
return NextResponse.json(data, { status: response.status });
|
||||
} catch (error) {
|
||||
console.error('API Route Error:', error);
|
||||
return NextResponse.json(
|
||||
{ success: false, message: '获取房间状态失败', details: error instanceof Error ? error.message : 'Unknown error' },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,7 @@ export const WebRTCFileTransfer: React.FC = () => {
|
||||
// 房间状态
|
||||
const [pickupCode, setPickupCode] = useState('');
|
||||
const [mode, setMode] = useState<'send' | 'receive'>('send');
|
||||
const [hasProcessedInitialUrl, setHasProcessedInitialUrl] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const {
|
||||
@@ -54,27 +55,43 @@ export const WebRTCFileTransfer: React.FC = () => {
|
||||
onFileProgress
|
||||
} = useWebRTCTransfer();
|
||||
|
||||
// 从URL参数中获取初始模式
|
||||
// 从URL参数中获取初始模式(仅在首次加载时处理)
|
||||
useEffect(() => {
|
||||
const urlMode = searchParams.get('mode') as 'send' | 'receive';
|
||||
const type = searchParams.get('type');
|
||||
const code = searchParams.get('code');
|
||||
|
||||
if (type === 'webrtc' && urlMode && ['send', 'receive'].includes(urlMode)) {
|
||||
// 只在首次加载且URL中有webrtc类型时处理
|
||||
if (!hasProcessedInitialUrl && type === 'webrtc' && urlMode && ['send', 'receive'].includes(urlMode)) {
|
||||
console.log('=== 处理初始URL参数 ===');
|
||||
console.log('URL模式:', urlMode, '类型:', type, '取件码:', code);
|
||||
|
||||
setMode(urlMode);
|
||||
setHasProcessedInitialUrl(true);
|
||||
|
||||
if (code && urlMode === 'receive') {
|
||||
// 自动加入房间
|
||||
// 自动加入房间,使用房间状态检查
|
||||
console.log('URL中有取件码,自动加入房间');
|
||||
joinRoom(code);
|
||||
}
|
||||
}
|
||||
}, [searchParams]);
|
||||
}, [searchParams, hasProcessedInitialUrl]);
|
||||
|
||||
// 更新URL参数
|
||||
const updateMode = useCallback((newMode: 'send' | 'receive') => {
|
||||
console.log('=== 手动切换模式 ===');
|
||||
console.log('新模式:', newMode);
|
||||
|
||||
setMode(newMode);
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
params.set('type', 'webrtc');
|
||||
params.set('mode', newMode);
|
||||
|
||||
// 如果切换到发送模式,移除code参数
|
||||
if (newMode === 'send') {
|
||||
params.delete('code');
|
||||
}
|
||||
|
||||
router.push(`?${params.toString()}`, { scroll: false });
|
||||
}, [searchParams, router]);
|
||||
|
||||
@@ -164,14 +181,46 @@ export const WebRTCFileTransfer: React.FC = () => {
|
||||
};
|
||||
|
||||
// 加入房间 (接收模式)
|
||||
const joinRoom = (code: string) => {
|
||||
const joinRoom = async (code: string) => {
|
||||
console.log('=== 加入房间 ===');
|
||||
console.log('取件码:', code);
|
||||
|
||||
setPickupCode(code.trim());
|
||||
connect(code.trim(), 'receiver');
|
||||
const trimmedCode = code.trim();
|
||||
|
||||
showToast(`正在连接到房间: ${code}`, "info");
|
||||
// 检查取件码格式
|
||||
if (!trimmedCode || trimmedCode.length !== 6) {
|
||||
showToast('请输入正确的6位取件码', "error");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 先检查房间状态
|
||||
console.log('检查房间状态...');
|
||||
showToast('正在检查房间状态...', "info");
|
||||
|
||||
const response = await fetch(`/api/webrtc-room-status?code=${trimmedCode}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
showToast(result.message || '房间不存在或已过期', "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查发送方是否在线
|
||||
if (!result.sender_online) {
|
||||
showToast('发送方不在线,请确认取件码是否正确', "error");
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('房间状态检查通过,开始连接...');
|
||||
setPickupCode(trimmedCode);
|
||||
connect(trimmedCode, 'receiver');
|
||||
|
||||
showToast(`正在连接到房间: ${trimmedCode}`, "info");
|
||||
} catch (error) {
|
||||
console.error('检查房间状态失败:', error);
|
||||
showToast('检查房间状态失败,请重试', "error");
|
||||
}
|
||||
};
|
||||
|
||||
// 重置连接状态 (用于连接失败后重新输入)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useState, useCallback, useRef } from 'react';
|
||||
import { FileInfo, TransferProgress } from '@/types';
|
||||
import { useState, useCallback } from 'react';
|
||||
import { TransferProgress } from '@/types';
|
||||
import { useToast } from '@/components/ui/toast-simple';
|
||||
|
||||
interface FileTransferData {
|
||||
|
||||
@@ -20,9 +20,9 @@ export function useWebRTCTransfer() {
|
||||
|
||||
// 设置数据通道消息处理
|
||||
useEffect(() => {
|
||||
const dataChannel = connection.getDataChannel();
|
||||
const dataChannel = connection.localDataChannel || connection.remoteDataChannel;
|
||||
if (dataChannel && dataChannel.readyState === 'open') {
|
||||
console.log('设置数据通道消息处理器');
|
||||
console.log('设置数据通道消息处理器, 通道类型:', connection.localDataChannel ? '本地' : '远程');
|
||||
|
||||
// 扩展消息处理以包含文件列表
|
||||
const originalHandler = fileTransfer.handleMessage;
|
||||
@@ -50,7 +50,7 @@ export function useWebRTCTransfer() {
|
||||
originalHandler(event);
|
||||
};
|
||||
}
|
||||
}, [connection.isConnected, connection.getDataChannel, fileTransfer.handleMessage]);
|
||||
}, [connection.localDataChannel, connection.remoteDataChannel, fileTransfer.handleMessage]);
|
||||
|
||||
// 发送文件
|
||||
const sendFile = useCallback((file: File, fileId?: string) => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
* 用于在静态导出模式下直接与 Go 后端通信
|
||||
*/
|
||||
|
||||
import { config, getApiUrl, getDirectBackendUrl } from './config';
|
||||
import { config } from './config';
|
||||
|
||||
interface ApiResponse {
|
||||
success: boolean;
|
||||
|
||||
@@ -27,11 +27,16 @@ const getCurrentBaseUrl = () => {
|
||||
// 动态获取 WebSocket URL
|
||||
const getCurrentWsUrl = () => {
|
||||
if (typeof window !== 'undefined') {
|
||||
// 在开发模式下,始终使用后端的WebSocket地址
|
||||
if (window.location.hostname === 'localhost' && (window.location.port === '3000' || window.location.port === '3001')) {
|
||||
// 检查是否是 Next.js 开发服务器(端口 3000 或 3001)
|
||||
const isNextDevServer = window.location.hostname === 'localhost' &&
|
||||
(window.location.port === '3000' || window.location.port === '3001');
|
||||
|
||||
if (isNextDevServer) {
|
||||
// 开发模式:通过 Next.js 开发服务器访问,连接到后端 WebSocket
|
||||
return 'ws://localhost:8080/ws/p2p';
|
||||
}
|
||||
// 在生产模式下,使用当前域名
|
||||
|
||||
// 生产模式或通过 Go 服务器访问:使用当前域名和端口
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
return `${protocol}//${window.location.host}/ws/p2p`;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ export const apiRoutes = [
|
||||
|
||||
// 客户端API配置(用于静态导出时的客户端请求)
|
||||
export const clientApiConfig = {
|
||||
// 直接连接到 Go 后端
|
||||
baseUrl: 'http://localhost:8080', // 构建时可通过环境变量替换
|
||||
wsUrl: 'ws://localhost:8080/ws', // 构建时可通过环境变量替换
|
||||
// 直接连接到 Go 后端 - 动态获取当前域名
|
||||
baseUrl: typeof window !== 'undefined' ? window.location.origin : '',
|
||||
wsUrl: typeof window !== 'undefined'
|
||||
? `${window.location.protocol === 'https:' ? 'wss:' : 'ws:'}//${window.location.host}/ws`
|
||||
: '',
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user