mirror of
https://github.com/MatrixSeven/file-transfer-go.git
synced 2026-03-19 23:22:16 +08:00
feat:添加链接QR支持,删除无用文件
This commit is contained in:
@@ -50,19 +50,21 @@ export default function HomePage() {
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="text"
|
||||
className="flex items-center justify-center space-x-2 px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200 hover:bg-slate-50 data-[state=active]:bg-emerald-500 data-[state=active]:text-white data-[state=active]:shadow-md data-[state=active]:hover:bg-emerald-600"
|
||||
className="flex items-center justify-center space-x-2 px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200 hover:bg-slate-50 data-[state=active]:bg-emerald-500 data-[state=active]:text-white data-[state=active]:shadow-md data-[state=active]:hover:bg-emerald-600 relative"
|
||||
>
|
||||
<MessageSquare className="w-4 h-4" />
|
||||
<span className="hidden sm:inline">文本传输</span>
|
||||
<span className="sm:hidden">文本</span>
|
||||
<span className="text-xs bg-orange-100 text-orange-600 px-1.5 py-0.5 rounded ml-1 absolute -top-1 -right-1">开发中</span>
|
||||
</TabsTrigger>
|
||||
<TabsTrigger
|
||||
value="desktop"
|
||||
className="flex items-center justify-center space-x-2 px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200 hover:bg-slate-50 data-[state=active]:bg-purple-500 data-[state=active]:text-white data-[state=active]:shadow-md data-[state=active]:hover:bg-purple-600"
|
||||
className="flex items-center justify-center space-x-2 px-4 py-3 text-sm font-medium rounded-lg transition-all duration-200 hover:bg-slate-50 data-[state=active]:bg-purple-500 data-[state=active]:text-white data-[state=active]:shadow-md data-[state=active]:hover:bg-purple-600 relative"
|
||||
>
|
||||
<Monitor className="w-4 h-4" />
|
||||
<span className="hidden sm:inline">共享桌面</span>
|
||||
<span className="sm:hidden">桌面</span>
|
||||
<span className="text-xs bg-orange-100 text-orange-600 px-1.5 py-0.5 rounded ml-1 absolute -top-1 -right-1">开发中</span>
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
</div>
|
||||
@@ -74,49 +76,43 @@ export default function HomePage() {
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="text" className="mt-0 animate-fade-in-up">
|
||||
<TextTransfer
|
||||
onSendText={async (text: string) => {
|
||||
try {
|
||||
const response = await fetch('/api/create-text-room', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ text }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || '创建文本房间失败');
|
||||
}
|
||||
|
||||
return data.code;
|
||||
} catch (error) {
|
||||
console.error('创建文本房间失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}}
|
||||
onReceiveText={async (code: string) => {
|
||||
try {
|
||||
const response = await fetch(`/api/get-text-content?code=${code}`);
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.error || '获取文本内容失败');
|
||||
}
|
||||
|
||||
return data.text;
|
||||
} catch (error) {
|
||||
console.error('获取文本内容失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<div className="max-w-md mx-auto p-8 bg-white/90 backdrop-blur-sm rounded-2xl shadow-lg border border-slate-200">
|
||||
<div className="text-center">
|
||||
<div className="w-16 h-16 mx-auto mb-4 bg-gradient-to-br from-emerald-100 to-emerald-200 rounded-full flex items-center justify-center">
|
||||
<MessageSquare className="w-8 h-8 text-emerald-600" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-slate-800 mb-2">文字传输</h3>
|
||||
<p className="text-slate-600 mb-4">此功能正在开发中...</p>
|
||||
<div className="bg-emerald-50 border border-emerald-200 rounded-lg p-4">
|
||||
<p className="text-sm text-emerald-700">
|
||||
🚧 敬请期待!我们正在为您开发更便捷的文字传输功能
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-4">
|
||||
目前请使用文件传输功能
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="desktop" className="mt-0 animate-fade-in-up">
|
||||
<DesktopShare />
|
||||
<div className="max-w-md mx-auto p-8 bg-white/90 backdrop-blur-sm rounded-2xl shadow-lg border border-slate-200">
|
||||
<div className="text-center">
|
||||
<div className="w-16 h-16 mx-auto mb-4 bg-gradient-to-br from-purple-100 to-purple-200 rounded-full flex items-center justify-center">
|
||||
<Monitor className="w-8 h-8 text-purple-600" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-slate-800 mb-2">桌面共享</h3>
|
||||
<p className="text-slate-600 mb-4">此功能正在开发中...</p>
|
||||
<div className="bg-purple-50 border border-purple-200 rounded-lg p-4">
|
||||
<p className="text-sm text-purple-700">
|
||||
🚧 敬请期待!我们正在为您开发实时桌面共享功能
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-4">
|
||||
目前请使用文件传输功能
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</div>
|
||||
</Tabs>
|
||||
|
||||
@@ -7,6 +7,13 @@ export async function GET(request: NextRequest) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const code = searchParams.get('code');
|
||||
|
||||
if (!code) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Missing code parameter' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
console.log('API Route: Getting room info, proxying to:', `${GO_BACKEND_URL}/api/room-info?code=${code}`);
|
||||
|
||||
const response = await fetch(`${GO_BACKEND_URL}/api/room-info?code=${code}`, {
|
||||
|
||||
68
chuan-next/src/components/QRCodeDisplay.tsx
Normal file
68
chuan-next/src/components/QRCodeDisplay.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import QRCode from 'qrcode';
|
||||
|
||||
interface QRCodeDisplayProps {
|
||||
value: string;
|
||||
size?: number;
|
||||
className?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export default function QRCodeDisplay({
|
||||
value,
|
||||
size = 200,
|
||||
className = "",
|
||||
title = "扫码传输"
|
||||
}: QRCodeDisplayProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [error, setError] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
const generateQR = async () => {
|
||||
try {
|
||||
if (canvasRef.current && value) {
|
||||
await QRCode.toCanvas(canvasRef.current, value, {
|
||||
width: size,
|
||||
margin: 2,
|
||||
color: {
|
||||
dark: '#1e293b', // slate-800
|
||||
light: '#ffffff'
|
||||
}
|
||||
});
|
||||
setError('');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('生成二维码失败:', err);
|
||||
setError('生成二维码失败');
|
||||
}
|
||||
};
|
||||
|
||||
generateQR();
|
||||
}, [value, size]);
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<div className={`flex items-center justify-center bg-slate-100 rounded-lg ${className}`}
|
||||
style={{ width: size, height: size }}>
|
||||
<p className="text-sm text-slate-500">{error}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{title && (
|
||||
<h3 className="text-sm font-medium text-slate-700 text-center mb-3">{title}</h3>
|
||||
)}
|
||||
<div className="flex justify-center">
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
className="rounded-lg"
|
||||
style={{ maxWidth: '100%', height: 'auto' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import React, { useState, useRef, useCallback } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { useToast } from '@/components/ui/toast-simple';
|
||||
import { Upload, FileText, Image, Video, Music, Archive, X } from 'lucide-react';
|
||||
import QRCodeDisplay from '@/components/QRCodeDisplay';
|
||||
|
||||
interface FileInfo {
|
||||
id: string;
|
||||
@@ -398,62 +399,77 @@ export function WebRTCFileUpload({
|
||||
{/* 取件码展示 */}
|
||||
{pickupCode && (
|
||||
<div className="border-t border-slate-200 pt-6">
|
||||
<div className="text-center mb-4 sm:mb-6">
|
||||
<div className="w-12 h-12 sm:w-16 sm:h-16 mx-auto mb-4 bg-gradient-to-br from-emerald-500 to-teal-500 rounded-2xl flex items-center justify-center animate-float">
|
||||
<FileText className="w-6 h-6 sm:w-8 sm:h-8 text-white" />
|
||||
</div>
|
||||
<h3 className="text-xl sm:text-2xl font-bold bg-gradient-to-r from-emerald-600 to-teal-600 bg-clip-text text-transparent mb-2">
|
||||
取件码生成成功!
|
||||
</h3>
|
||||
<p className="text-sm sm:text-base text-slate-600">分享以下信息给接收方</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4 sm:space-y-6">
|
||||
{/* 取件码 */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-3">取件码</label>
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
<div className="flex-1 code-display rounded-xl p-4 sm:p-6 text-center">
|
||||
<div className="text-2xl sm:text-3xl font-bold font-mono bg-gradient-to-r from-emerald-600 to-teal-600 bg-clip-text text-transparent tracking-wider">
|
||||
{pickupCode}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={onCopyCode}
|
||||
className="px-4 sm:px-6 py-3 bg-emerald-500 hover:bg-emerald-600 text-white rounded-xl font-medium shadow-lg transition-all duration-200 hover:shadow-xl w-full sm:w-auto"
|
||||
>
|
||||
复制
|
||||
</Button>
|
||||
{/* 左上角状态提示 - 类似已选择文件的风格 */}
|
||||
<div className="flex items-center mb-6">
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="w-10 h-10 bg-gradient-to-br from-emerald-500 to-teal-500 rounded-xl flex items-center justify-center">
|
||||
<FileText className="w-5 h-5 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-slate-800">取件码生成成功!</h3>
|
||||
<p className="text-sm text-slate-600">分享以下信息给接收方</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 取件链接 */}
|
||||
{/* 中间区域:取件码 + 分隔线 + 二维码 */}
|
||||
<div className="flex flex-col lg:flex-row lg:items-start gap-6 lg:gap-8 mb-8">
|
||||
{/* 左侧:取件码 */}
|
||||
<div className="flex-1">
|
||||
<label className="block text-sm font-medium text-slate-700 mb-3">取件码</label>
|
||||
<div className="flex flex-col items-center rounded-xl border border-slate-200 p-6 h-40 justify-center bg-slate-50">
|
||||
<div className="text-2xl font-bold font-mono bg-gradient-to-r from-emerald-600 to-teal-600 bg-clip-text text-transparent tracking-wider">
|
||||
{pickupCode}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={onCopyCode}
|
||||
className="w-full px-4 py-2.5 bg-emerald-500 hover:bg-emerald-600 text-white rounded-lg font-medium shadow transition-all duration-200 mt-3"
|
||||
>
|
||||
复制取件码
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 分隔线 - 大屏幕显示竖线,移动端隐藏 */}
|
||||
<div className="hidden lg:block w-px bg-slate-200 h-64 mt-6"></div>
|
||||
|
||||
{/* 右侧:二维码 */}
|
||||
{pickupLink && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-3">取件链接</label>
|
||||
<div className="flex flex-col sm:flex-row gap-3">
|
||||
<div className="flex-1 code-display rounded-xl p-3 sm:p-4">
|
||||
<div className="text-xs sm:text-sm text-slate-700 break-all font-mono">
|
||||
{pickupLink}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={onCopyLink}
|
||||
className="px-4 sm:px-6 py-3 bg-blue-500 hover:bg-blue-600 text-white rounded-xl font-medium shadow-lg transition-all duration-200 hover:shadow-xl w-full sm:w-auto"
|
||||
>
|
||||
复制
|
||||
</Button>
|
||||
<div className="flex-1">
|
||||
<label className="block text-sm font-medium text-slate-700 mb-3">扫码传输</label>
|
||||
<div className="flex flex-col items-center rounded-xl border border-slate-200 p-6 h-40 justify-center bg-slate-50">
|
||||
<QRCodeDisplay
|
||||
value={pickupLink}
|
||||
size={120}
|
||||
title=""
|
||||
className="w-auto"
|
||||
/>
|
||||
</div>
|
||||
<div className="w-full px-4 py-2.5 bg-blue-500 text-white rounded-lg font-medium shadow transition-all duration-200 mt-3 text-center">
|
||||
使用手机扫码快速访问
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 使用提示 */}
|
||||
<div className="mt-4 sm:mt-6 p-3 sm:p-4 bg-gradient-to-r from-blue-50 to-indigo-50 rounded-xl border border-blue-200">
|
||||
<p className="text-xs sm:text-sm text-slate-600 text-center">
|
||||
💡 <span className="font-medium">使用提示:</span>接收方输入取件码或访问取件链接即可下载文件
|
||||
</p>
|
||||
</div>
|
||||
{/* 底部:取件链接 */}
|
||||
{pickupLink && (
|
||||
<div className="space-y-3">
|
||||
<div className="flex gap-3">
|
||||
<div className="flex-1 code-display rounded-lg p-3 bg-slate-50 border border-slate-200">
|
||||
<div className="text-sm text-slate-700 break-all font-mono leading-relaxed">
|
||||
{pickupLink}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
onClick={onCopyLink}
|
||||
className="px-4 py-2.5 bg-blue-500 hover:bg-blue-600 text-white rounded-lg font-medium shadow transition-all duration-200 shrink-0"
|
||||
>
|
||||
复制链接
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -75,10 +75,10 @@ export const useTabManager = (isConnected: boolean, pickupCode: string, isConnec
|
||||
currentMode = '文件传输';
|
||||
break;
|
||||
case 'text':
|
||||
currentMode = '文字传输';
|
||||
currentMode = '文字传输(开发中)';
|
||||
break;
|
||||
case 'desktop':
|
||||
currentMode = '桌面共享';
|
||||
currentMode = '桌面共享(开发中)';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -87,10 +87,10 @@ export const useTabManager = (isConnected: boolean, pickupCode: string, isConnec
|
||||
targetMode = '文件传输';
|
||||
break;
|
||||
case 'text':
|
||||
targetMode = '文字传输';
|
||||
targetMode = '文字传输(开发中)';
|
||||
break;
|
||||
case 'desktop':
|
||||
targetMode = '桌面共享';
|
||||
targetMode = '桌面共享(开发中)';
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user