mirror of
https://github.com/MatrixSeven/file-transfer-go.git
synced 2026-02-15 17:54:46 +08:00
feat: 添加文件传输速度和剩余时间计算,优化文件传输进度显示
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import React, { useState, useCallback, useRef } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Download, FileText, Image, Video, Music, Archive } from 'lucide-react';
|
||||
import { Download, FileText, Image, Video, Music, Archive, Clock, Zap } from 'lucide-react';
|
||||
import { useToast } from '@/components/ui/toast-simple';
|
||||
import { ConnectionStatus } from '@/components/ConnectionStatus';
|
||||
import { TransferProgressTracker, formatTransferSpeed, formatTime } from '@/lib/transfer-utils';
|
||||
|
||||
interface FileInfo {
|
||||
id: string;
|
||||
@@ -14,6 +15,8 @@ interface FileInfo {
|
||||
type: string;
|
||||
status: 'ready' | 'downloading' | 'completed';
|
||||
progress: number;
|
||||
transferSpeed?: number; // bytes per second
|
||||
startTime?: number; // 传输开始时间
|
||||
}
|
||||
|
||||
const getFileIcon = (mimeType: string) => {
|
||||
@@ -60,6 +63,9 @@ export function WebRTCFileReceive({
|
||||
const [pickupCode, setPickupCode] = useState('');
|
||||
const [isValidating, setIsValidating] = useState(false);
|
||||
const { showToast } = useToast();
|
||||
|
||||
// 用于跟踪传输进度的trackers
|
||||
const transferTrackers = useRef<Map<string, TransferProgressTracker>>(new Map());
|
||||
|
||||
// 使用传入的取件码或本地状态的取件码
|
||||
const displayPickupCode = propPickupCode || pickupCode;
|
||||
@@ -242,16 +248,44 @@ export function WebRTCFileReceive({
|
||||
const isDownloading = file.status === 'downloading';
|
||||
const isCompleted = file.status === 'completed';
|
||||
const hasDownloadedFile = downloadedFiles?.has(file.id);
|
||||
const currentProgress = file.progress;
|
||||
|
||||
console.log('文件状态:', {
|
||||
fileName: file.name,
|
||||
status: file.status,
|
||||
progress: file.progress,
|
||||
isDownloading,
|
||||
currentProgress
|
||||
isDownloading
|
||||
});
|
||||
|
||||
// 计算传输进度信息
|
||||
let transferInfo = null;
|
||||
let currentProgress = 0; // 使用稳定的进度值
|
||||
|
||||
if (isDownloading && file) {
|
||||
const fileKey = `${file.name}-${file.size}`;
|
||||
let tracker = transferTrackers.current.get(fileKey);
|
||||
|
||||
// 如果tracker不存在,创建一个新的
|
||||
if (!tracker) {
|
||||
tracker = new TransferProgressTracker(file.size);
|
||||
transferTrackers.current.set(fileKey, tracker);
|
||||
}
|
||||
|
||||
// 更新传输进度
|
||||
const transferredBytes = (file.progress / 100) * file.size;
|
||||
const progressInfo = tracker.update(transferredBytes);
|
||||
transferInfo = progressInfo;
|
||||
currentProgress = progressInfo.percentage; // 使用稳定的百分比
|
||||
} else {
|
||||
// 如果不在传输中,使用原始进度值
|
||||
currentProgress = file.progress;
|
||||
}
|
||||
|
||||
// 清理已完成的tracker
|
||||
if (file.status === 'completed') {
|
||||
const fileKey = `${file.name}-${file.size}`;
|
||||
transferTrackers.current.delete(fileKey);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={file.id} className="bg-gradient-to-r from-slate-50 to-blue-50 border border-slate-200 rounded-xl p-3 sm:p-4 hover:shadow-md transition-all duration-200">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between mb-3 gap-3">
|
||||
@@ -266,7 +300,27 @@ export function WebRTCFileReceive({
|
||||
<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 className="space-y-1">
|
||||
{/* 传输速度和剩余时间信息 */}
|
||||
{transferInfo && (
|
||||
<div className="flex items-center space-x-3">
|
||||
<div className="flex items-center gap-1 text-xs text-blue-600">
|
||||
<Zap className="w-3 h-3 flex-shrink-0" />
|
||||
<span className="w-3 font-mono text-right">{transferInfo.speed.displaySpeed}</span>
|
||||
<span className='w-2'/>
|
||||
<span className="w-3">{transferInfo.speed.unit}</span>
|
||||
<span className='w-3'/>
|
||||
</div>
|
||||
{transferInfo.remainingTime.seconds < Infinity && (
|
||||
<div className="flex items-center gap-1 text-xs text-slate-600">
|
||||
<Clock className="w-3 h-3 flex-shrink-0" />
|
||||
<span>剩余</span>
|
||||
<span className="w-3 font-mono text-right">{transferInfo.remainingTime.display}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -289,7 +343,9 @@ export function WebRTCFileReceive({
|
||||
{(isDownloading || isCompleted) && currentProgress > 0 && (
|
||||
<div className="mt-3 space-y-2">
|
||||
<div className="flex justify-between text-sm text-slate-600">
|
||||
<span>{hasDownloadedFile ? '传输完成' : '正在传输...'}</span>
|
||||
<span>
|
||||
{hasDownloadedFile ? '传输完成' : '正在传输...'}
|
||||
</span>
|
||||
<span className="font-medium">{currentProgress.toFixed(1)}%</span>
|
||||
</div>
|
||||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useRef, useCallback } from 'react';
|
||||
import React, { useState, useRef, useCallback, useEffect } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Upload, FileText, Image, Video, Music, Archive, X } from 'lucide-react';
|
||||
import { Upload, FileText, Image, Video, Music, Archive, X, Clock, Zap } from 'lucide-react';
|
||||
import RoomInfoDisplay from '@/components/RoomInfoDisplay';
|
||||
import { ConnectionStatus } from '@/components/ConnectionStatus';
|
||||
import { TransferProgressTracker, formatTransferSpeed, formatTime } from '@/lib/transfer-utils';
|
||||
|
||||
|
||||
interface FileInfo {
|
||||
@@ -14,6 +15,8 @@ interface FileInfo {
|
||||
type: string;
|
||||
status: 'ready' | 'downloading' | 'completed';
|
||||
progress: number;
|
||||
transferSpeed?: number; // bytes per second
|
||||
startTime?: number; // 传输开始时间
|
||||
}
|
||||
|
||||
const getFileIcon = (mimeType: string) => {
|
||||
@@ -65,6 +68,9 @@ export function WebRTCFileUpload({
|
||||
}: WebRTCFileUploadProps) {
|
||||
const [isDragOver, setIsDragOver] = useState(false);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
// 用于跟踪传输进度的trackers
|
||||
const transferTrackers = useRef<Map<string, TransferProgressTracker>>(new Map());
|
||||
|
||||
const handleDragOver = useCallback((e: React.DragEvent) => {
|
||||
e.preventDefault();
|
||||
@@ -197,9 +203,38 @@ export function WebRTCFileUpload({
|
||||
// 查找对应的文件信息(包含状态和进度)
|
||||
const fileInfo = fileList.find(f => f.name === file.name && f.size === file.size);
|
||||
const isTransferringThisFile = fileInfo?.status === 'downloading';
|
||||
const currentProgress = fileInfo?.progress || 0;
|
||||
const fileStatus = fileInfo?.status || 'ready';
|
||||
|
||||
// 计算传输进度信息
|
||||
let transferInfo = null;
|
||||
let currentProgress = 0; // 使用稳定的进度值
|
||||
|
||||
if (isTransferringThisFile && fileInfo) {
|
||||
const fileKey = `${file.name}-${file.size}`;
|
||||
let tracker = transferTrackers.current.get(fileKey);
|
||||
|
||||
// 如果tracker不存在,创建一个新的
|
||||
if (!tracker) {
|
||||
tracker = new TransferProgressTracker(file.size);
|
||||
transferTrackers.current.set(fileKey, tracker);
|
||||
}
|
||||
|
||||
// 更新传输进度
|
||||
const transferredBytes = (fileInfo.progress / 100) * file.size;
|
||||
const progressInfo = tracker.update(transferredBytes);
|
||||
transferInfo = progressInfo;
|
||||
currentProgress = progressInfo.percentage; // 使用稳定的百分比
|
||||
} else {
|
||||
// 如果不在传输中,使用原始进度值
|
||||
currentProgress = fileInfo?.progress || 0;
|
||||
}
|
||||
|
||||
// 清理已完成的tracker
|
||||
if (fileStatus === 'completed') {
|
||||
const fileKey = `${file.name}-${file.size}`;
|
||||
transferTrackers.current.delete(fileKey);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={`${file.name}-${file.size}-${index}`}
|
||||
@@ -227,6 +262,26 @@ export function WebRTCFileUpload({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 传输速度和剩余时间信息 */}
|
||||
{transferInfo && (
|
||||
<div className="flex items-center space-x-3 mt-1">
|
||||
<div className="flex items-center gap-1 text-xs text-blue-600">
|
||||
<Zap className="w-3 h-3 flex-shrink-0" />
|
||||
<span className="w-3 font-mono text-right">{transferInfo.speed.displaySpeed}</span>
|
||||
<span className='w-2'/>
|
||||
<span className="w-3">{transferInfo.speed.unit}</span>
|
||||
<span className='w-3'/>
|
||||
</div>
|
||||
{transferInfo.remainingTime.seconds < Infinity && (
|
||||
<div className="flex items-center gap-1 text-xs text-slate-600">
|
||||
<Clock className="w-3 h-3 flex-shrink-0" />
|
||||
<span>剩余</span>
|
||||
<span className="w-3 font-mono text-right">{transferInfo.remainingTime.display}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
@@ -245,7 +300,9 @@ export function WebRTCFileUpload({
|
||||
<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">
|
||||
<span>{fileStatus === 'downloading' ? '正在发送...' : '发送完成'}</span>
|
||||
<span>
|
||||
{fileStatus === 'downloading' ? '正在发送...' : '发送完成'}
|
||||
</span>
|
||||
<span className="font-medium">{currentProgress.toFixed(1)}%</span>
|
||||
</div>
|
||||
<div className="w-full bg-slate-200 rounded-full h-2">
|
||||
|
||||
@@ -7,6 +7,8 @@ interface FileInfo {
|
||||
type: string;
|
||||
status: 'ready' | 'downloading' | 'completed';
|
||||
progress: number;
|
||||
transferSpeed?: number; // bytes per second
|
||||
startTime?: number; // 传输开始时间
|
||||
}
|
||||
|
||||
interface UseFileStateManagerProps {
|
||||
@@ -72,21 +74,33 @@ export const useFileStateManager = ({
|
||||
}, []);
|
||||
|
||||
// 更新文件状态
|
||||
const updateFileStatus = useCallback((fileId: string, status: FileInfo['status'], progress?: number) => {
|
||||
const updateFileStatus = useCallback((fileId: string, status: FileInfo['status'], progress?: number, transferSpeed?: number) => {
|
||||
setFileList(prev => prev.map(item =>
|
||||
item.id === fileId
|
||||
? { ...item, status, progress: progress ?? item.progress }
|
||||
? {
|
||||
...item,
|
||||
status,
|
||||
progress: progress ?? item.progress,
|
||||
transferSpeed: transferSpeed ?? item.transferSpeed,
|
||||
startTime: status === 'downloading' && !item.startTime ? Date.now() : item.startTime
|
||||
}
|
||||
: item
|
||||
));
|
||||
}, []);
|
||||
|
||||
// 更新文件进度
|
||||
const updateFileProgress = useCallback((fileId: string, fileName: string, progress: number) => {
|
||||
const updateFileProgress = useCallback((fileId: string, fileName: string, progress: number, transferSpeed?: number) => {
|
||||
const newStatus = progress >= 100 ? 'completed' as const : 'downloading' as const;
|
||||
setFileList(prev => prev.map(item => {
|
||||
if (item.id === fileId || item.name === fileName) {
|
||||
console.log(`更新文件 ${item.name} 进度: ${item.progress} -> ${progress}`);
|
||||
return { ...item, progress, status: newStatus };
|
||||
console.log(`更新文件 ${item.name} 进度: ${item.progress} -> ${progress}${transferSpeed ? `, 速度: ${transferSpeed} B/s` : ''}`);
|
||||
return {
|
||||
...item,
|
||||
progress,
|
||||
status: newStatus,
|
||||
transferSpeed: transferSpeed ?? item.transferSpeed,
|
||||
startTime: newStatus === 'downloading' && !item.startTime ? Date.now() : item.startTime
|
||||
};
|
||||
}
|
||||
return item;
|
||||
}));
|
||||
|
||||
273
chuan-next/src/lib/transfer-utils.ts
Normal file
273
chuan-next/src/lib/transfer-utils.ts
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* 传输速度和时间计算工具
|
||||
*/
|
||||
|
||||
export interface TransferSpeed {
|
||||
bytesPerSecond: number;
|
||||
displaySpeed: string;
|
||||
unit: string;
|
||||
}
|
||||
|
||||
export interface TransferProgress {
|
||||
totalBytes: number;
|
||||
transferredBytes: number;
|
||||
percentage: number;
|
||||
speed: TransferSpeed;
|
||||
remainingTime: {
|
||||
seconds: number;
|
||||
display: string;
|
||||
};
|
||||
elapsedTime: {
|
||||
seconds: number;
|
||||
display: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化传输速度显示
|
||||
* @param bytesPerSecond 每秒传输的字节数
|
||||
* @returns 格式化的速度显示
|
||||
*/
|
||||
export function formatTransferSpeed(bytesPerSecond: number): TransferSpeed {
|
||||
if (bytesPerSecond < 1024) {
|
||||
return {
|
||||
bytesPerSecond,
|
||||
displaySpeed: `${bytesPerSecond.toFixed(0)}`,
|
||||
unit: 'B/s'
|
||||
};
|
||||
} else if (bytesPerSecond < 1024 * 1024) {
|
||||
const kbps = bytesPerSecond / 1024;
|
||||
return {
|
||||
bytesPerSecond,
|
||||
displaySpeed: `${kbps.toFixed(1)}`,
|
||||
unit: 'KB/s'
|
||||
};
|
||||
} else {
|
||||
const mbps = bytesPerSecond / (1024 * 1024);
|
||||
return {
|
||||
bytesPerSecond,
|
||||
displaySpeed: `${mbps.toFixed(1)}`,
|
||||
unit: 'MB/s'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间显示
|
||||
* @param seconds 秒数
|
||||
* @returns 格式化的时间显示
|
||||
*/
|
||||
export function formatTime(seconds: number): string {
|
||||
if (!isFinite(seconds) || seconds < 0) {
|
||||
return '--:--';
|
||||
}
|
||||
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
const secs = Math.floor(seconds % 60);
|
||||
|
||||
if (hours > 0) {
|
||||
return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
||||
} else {
|
||||
return `${minutes}:${secs.toString().padStart(2, '0')}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 传输进度跟踪器
|
||||
*/
|
||||
export class TransferProgressTracker {
|
||||
private startTime: number;
|
||||
private lastUpdateTime: number;
|
||||
private lastSpeedUpdateTime: number;
|
||||
private lastProgressUpdateTime: number;
|
||||
private lastTransferredBytes: number;
|
||||
private speedHistory: number[] = [];
|
||||
private readonly maxHistorySize = 10; // 保持最近10个速度样本
|
||||
private readonly speedUpdateInterval = 300; // 速度更新间隔:0.3秒
|
||||
private readonly progressUpdateInterval = 50; // 进度更新间隔:0.3秒
|
||||
private cachedProgress: TransferProgress | null = null;
|
||||
private lastDisplayedSpeed: TransferSpeed;
|
||||
private lastDisplayedPercentage: number = 0;
|
||||
|
||||
constructor(
|
||||
private totalBytes: number,
|
||||
private initialTransferredBytes: number = 0
|
||||
) {
|
||||
this.startTime = Date.now();
|
||||
this.lastUpdateTime = this.startTime;
|
||||
this.lastSpeedUpdateTime = this.startTime;
|
||||
this.lastProgressUpdateTime = this.startTime;
|
||||
this.lastTransferredBytes = initialTransferredBytes;
|
||||
this.lastDisplayedSpeed = formatTransferSpeed(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新传输进度
|
||||
* @param transferredBytes 已传输的字节数
|
||||
* @returns 传输进度信息
|
||||
*/
|
||||
update(transferredBytes: number): TransferProgress {
|
||||
const now = Date.now();
|
||||
const elapsedTimeMs = now - this.startTime;
|
||||
const timeSinceLastUpdate = now - this.lastUpdateTime;
|
||||
const timeSinceLastSpeedUpdate = now - this.lastSpeedUpdateTime;
|
||||
const timeSinceLastProgressUpdate = now - this.lastProgressUpdateTime;
|
||||
|
||||
// 计算即时速度(基于最近的更新)
|
||||
let instantSpeed = 0;
|
||||
if (timeSinceLastUpdate > 0) {
|
||||
const bytesDiff = transferredBytes - this.lastTransferredBytes;
|
||||
instantSpeed = (bytesDiff * 1000) / timeSinceLastUpdate; // bytes per second
|
||||
}
|
||||
|
||||
// 只有当距离上次速度更新超过指定间隔时才更新速度显示
|
||||
let shouldUpdateSpeed = timeSinceLastSpeedUpdate >= this.speedUpdateInterval;
|
||||
|
||||
// 只有当距离上次进度更新超过指定间隔时才更新进度显示
|
||||
let shouldUpdateProgress = timeSinceLastProgressUpdate >= this.progressUpdateInterval;
|
||||
|
||||
// 如果是第一次更新或者传输完成,立即更新速度和进度
|
||||
if (this.cachedProgress === null || transferredBytes >= this.totalBytes) {
|
||||
shouldUpdateSpeed = true;
|
||||
shouldUpdateProgress = true;
|
||||
}
|
||||
|
||||
if (shouldUpdateSpeed) {
|
||||
// 更新速度历史
|
||||
if (instantSpeed > 0) {
|
||||
this.speedHistory.push(instantSpeed);
|
||||
if (this.speedHistory.length > this.maxHistorySize) {
|
||||
this.speedHistory.shift();
|
||||
}
|
||||
}
|
||||
|
||||
// 计算平均速度
|
||||
let averageSpeed = 0;
|
||||
if (this.speedHistory.length > 0) {
|
||||
averageSpeed = this.speedHistory.reduce((sum, speed) => sum + speed, 0) / this.speedHistory.length;
|
||||
} else if (elapsedTimeMs > 0) {
|
||||
// 如果没有即时速度历史,使用总体平均速度
|
||||
averageSpeed = (transferredBytes * 1000) / elapsedTimeMs;
|
||||
}
|
||||
|
||||
// 更新显示的速度
|
||||
this.lastDisplayedSpeed = formatTransferSpeed(averageSpeed);
|
||||
this.lastSpeedUpdateTime = now;
|
||||
}
|
||||
|
||||
// 更新显示的进度百分比
|
||||
if (shouldUpdateProgress) {
|
||||
const currentPercentage = this.totalBytes > 0 ? (transferredBytes / this.totalBytes) * 100 : 0;
|
||||
this.lastDisplayedPercentage = Math.min(currentPercentage, 100);
|
||||
this.lastProgressUpdateTime = now;
|
||||
}
|
||||
|
||||
// 计算剩余时间(使用当前显示的速度)
|
||||
const remainingBytes = this.totalBytes - transferredBytes;
|
||||
const remainingTimeSeconds = this.lastDisplayedSpeed.bytesPerSecond > 0
|
||||
? remainingBytes / this.lastDisplayedSpeed.bytesPerSecond
|
||||
: Infinity;
|
||||
|
||||
// 更新跟踪状态
|
||||
this.lastUpdateTime = now;
|
||||
this.lastTransferredBytes = transferredBytes;
|
||||
|
||||
// 创建进度对象(使用稳定的进度值)
|
||||
const progress: TransferProgress = {
|
||||
totalBytes: this.totalBytes,
|
||||
transferredBytes,
|
||||
percentage: this.lastDisplayedPercentage,
|
||||
speed: this.lastDisplayedSpeed,
|
||||
remainingTime: {
|
||||
seconds: remainingTimeSeconds,
|
||||
display: formatTime(remainingTimeSeconds)
|
||||
},
|
||||
elapsedTime: {
|
||||
seconds: elapsedTimeMs / 1000,
|
||||
display: formatTime(elapsedTimeMs / 1000)
|
||||
}
|
||||
};
|
||||
|
||||
// 缓存进度信息
|
||||
this.cachedProgress = progress;
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置跟踪器
|
||||
*/
|
||||
reset(totalBytes?: number, initialTransferredBytes: number = 0) {
|
||||
if (totalBytes !== undefined) {
|
||||
this.totalBytes = totalBytes;
|
||||
}
|
||||
this.startTime = Date.now();
|
||||
this.lastUpdateTime = this.startTime;
|
||||
this.lastSpeedUpdateTime = this.startTime;
|
||||
this.lastProgressUpdateTime = this.startTime;
|
||||
this.lastTransferredBytes = initialTransferredBytes;
|
||||
this.speedHistory = [];
|
||||
this.cachedProgress = null;
|
||||
this.lastDisplayedSpeed = formatTransferSpeed(0);
|
||||
this.lastDisplayedPercentage = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取总字节数
|
||||
*/
|
||||
getTotalBytes(): number {
|
||||
return this.totalBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取平均速度(整个传输过程)
|
||||
*/
|
||||
getOverallAverageSpeed(): number {
|
||||
const elapsedTimeMs = Date.now() - this.startTime;
|
||||
if (elapsedTimeMs > 0) {
|
||||
return (this.lastTransferredBytes * 1000) / elapsedTimeMs;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建传输进度跟踪器
|
||||
* @param totalBytes 总字节数
|
||||
* @param initialTransferredBytes 初始已传输字节数
|
||||
* @returns 传输进度跟踪器实例
|
||||
*/
|
||||
export function createTransferTracker(totalBytes: number, initialTransferredBytes: number = 0): TransferProgressTracker {
|
||||
return new TransferProgressTracker(totalBytes, initialTransferredBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* 简单的传输速度计算(无状态)
|
||||
* @param transferredBytes 已传输字节数
|
||||
* @param elapsedTimeMs 经过的时间(毫秒)
|
||||
* @returns 格式化的速度
|
||||
*/
|
||||
export function calculateSpeed(transferredBytes: number, elapsedTimeMs: number): TransferSpeed {
|
||||
if (elapsedTimeMs <= 0) {
|
||||
return formatTransferSpeed(0);
|
||||
}
|
||||
|
||||
const bytesPerSecond = (transferredBytes * 1000) / elapsedTimeMs;
|
||||
return formatTransferSpeed(bytesPerSecond);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算剩余时间
|
||||
* @param remainingBytes 剩余字节数
|
||||
* @param bytesPerSecond 每秒传输字节数
|
||||
* @returns 格式化的剩余时间
|
||||
*/
|
||||
export function calculateRemainingTime(remainingBytes: number, bytesPerSecond: number): string {
|
||||
if (bytesPerSecond <= 0 || remainingBytes <= 0) {
|
||||
return '--:--';
|
||||
}
|
||||
|
||||
const remainingSeconds = remainingBytes / bytesPerSecond;
|
||||
return formatTime(remainingSeconds);
|
||||
}
|
||||
Reference in New Issue
Block a user