feat: 更新文件传输功能,添加速度和ETA计算,优化进度回调,增强用户体验

This commit is contained in:
MatrixSeven
2026-03-05 12:51:50 +08:00
parent 2ba026809f
commit da3e4f1067
8 changed files with 297 additions and 257 deletions

View File

@@ -181,7 +181,7 @@ export const WebRTCFileTransfer: React.FC = () => {
fileName: progressInfo.fileName,
progress: progressInfo.progress
});
updateFileProgress(progressInfo.fileId, progressInfo.fileName, progressInfo.progress);
updateFileProgress(progressInfo.fileId, progressInfo.fileName, progressInfo.progress, progressInfo.speed, progressInfo.eta);
if (progressInfo.progress >= 100 && mode === 'send') {
setCurrentTransferFile(null);
}

View File

@@ -25,6 +25,28 @@ const formatFileSize = (bytes: number): string => {
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
const formatSpeed = (bytesPerSecond: number): string => {
if (bytesPerSecond <= 0) return '--';
const k = 1024;
if (bytesPerSecond < k) return `${bytesPerSecond.toFixed(0)} B/s`;
if (bytesPerSecond < k * k) return `${(bytesPerSecond / k).toFixed(1)} KB/s`;
if (bytesPerSecond < k * k * k) return `${(bytesPerSecond / (k * k)).toFixed(2)} MB/s`;
return `${(bytesPerSecond / (k * k * k)).toFixed(2)} GB/s`;
};
const formatETA = (seconds: number): string => {
if (seconds <= 0 || !isFinite(seconds)) return '--';
if (seconds < 60) return `${Math.ceil(seconds)}`;
if (seconds < 3600) {
const m = Math.floor(seconds / 60);
const s = Math.ceil(seconds % 60);
return `${m}${s > 0 ? s + '秒' : ''}`;
}
const h = Math.floor(seconds / 3600);
const m = Math.ceil((seconds % 3600) / 60);
return `${h}${m > 0 ? m + '分' : ''}`;
};
interface WebRTCFileReceiveProps {
onJoinRoom: (code: string) => void;
files: FileInfo[];
@@ -204,6 +226,8 @@ export function WebRTCFileReceive({
const isCompleted = file.status === 'completed';
const hasDownloadedFile = downloadedFiles?.has(file.id);
const currentProgress = file.progress;
const currentSpeed = file.speed;
const currentEta = file.eta;
console.log('文件状态:', {
fileName: file.name,
@@ -226,9 +250,6 @@ export function WebRTCFileReceive({
{hasDownloadedFile && (
<p className="text-xs text-emerald-600 font-medium"> </p>
)}
{isDownloading && (
<p className="text-xs text-blue-600 font-medium"> ...{currentProgress.toFixed(1)}%</p>
)}
</div>
</div>
<Button
@@ -249,9 +270,17 @@ export function WebRTCFileReceive({
{(isDownloading || isCompleted) && currentProgress > 0 && (
<div className="mt-3 space-y-2">
<div className="flex justify-between text-sm text-slate-600">
<div className="flex justify-between items-center text-sm text-slate-600">
<span>{hasDownloadedFile ? '传输完成' : '正在传输...'}</span>
<span className="font-medium">{currentProgress.toFixed(1)}%</span>
<div className="flex items-center space-x-3">
{isDownloading && currentSpeed != null && currentSpeed > 0 && (
<span className="text-xs text-blue-600 font-medium">{formatSpeed(currentSpeed)}</span>
)}
{isDownloading && currentEta != null && currentEta > 0 && (
<span className="text-xs text-slate-500"> {formatETA(currentEta)}</span>
)}
<span className="font-medium">{currentProgress.toFixed(1)}%</span>
</div>
</div>
<div className="w-full bg-slate-200 rounded-full h-2">
<div

View File

@@ -23,6 +23,28 @@ const formatFileSize = (bytes: number): string => {
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
const formatSpeed = (bytesPerSecond: number): string => {
if (bytesPerSecond <= 0) return '--';
const k = 1024;
if (bytesPerSecond < k) return `${bytesPerSecond.toFixed(0)} B/s`;
if (bytesPerSecond < k * k) return `${(bytesPerSecond / k).toFixed(1)} KB/s`;
if (bytesPerSecond < k * k * k) return `${(bytesPerSecond / (k * k)).toFixed(2)} MB/s`;
return `${(bytesPerSecond / (k * k * k)).toFixed(2)} GB/s`;
};
const formatETA = (seconds: number): string => {
if (seconds <= 0 || !isFinite(seconds)) return '--';
if (seconds < 60) return `${Math.ceil(seconds)}`;
if (seconds < 3600) {
const m = Math.floor(seconds / 60);
const s = Math.ceil(seconds % 60);
return `${m}${s > 0 ? s + '秒' : ''}`;
}
const h = Math.floor(seconds / 3600);
const m = Math.ceil((seconds % 3600) / 60);
return `${h}${m > 0 ? m + '分' : ''}`;
};
interface WebRTCFileUploadProps {
selectedFiles: File[];
fileList?: FileInfo[]; // 添加文件列表信息(包含状态和进度)
@@ -190,6 +212,8 @@ export function WebRTCFileUpload({
const isTransferringThisFile = fileInfo?.status === 'downloading';
const currentProgress = fileInfo?.progress || 0;
const fileStatus = fileInfo?.status || 'ready';
const currentSpeed = fileInfo?.speed;
const currentEta = fileInfo?.eta;
return (
<div
@@ -235,9 +259,17 @@ export function WebRTCFileUpload({
{(fileStatus === 'downloading' || fileStatus === 'completed') && currentProgress > 0 && (
<div className="px-3 sm:px-4 pb-3 sm:pb-4">
<div className="space-y-2">
<div className="flex justify-between text-xs text-slate-600">
<div className="flex justify-between items-center text-xs text-slate-600">
<span>{fileStatus === 'downloading' ? '正在发送...' : '发送完成'}</span>
<span className="font-medium">{currentProgress.toFixed(1)}%</span>
<div className="flex items-center space-x-3">
{fileStatus === 'downloading' && currentSpeed != null && currentSpeed > 0 && (
<span className="text-orange-600 font-medium">{formatSpeed(currentSpeed)}</span>
)}
{fileStatus === 'downloading' && currentEta != null && currentEta > 0 && (
<span className="text-slate-500"> {formatETA(currentEta)}</span>
)}
<span className="font-medium">{currentProgress.toFixed(1)}%</span>
</div>
</div>
<div className="w-full bg-slate-200 rounded-full h-2">
<div