gongxiangp2/components/upload/UploadProgress.tsx

145 lines
5.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import type { BatchUploadStatus } from './upload-types'
import { formatSpeed, calculateRemainingTime } from './upload-utils'
interface UploadProgressProps {
uploading: boolean
isBatchMode: boolean
batchUploadStatus: BatchUploadStatus | null
uploadProgress: number
uploadSpeed: number
isProcessing: boolean
onCancel: () => void
}
export default function UploadProgress({
uploading,
isBatchMode,
batchUploadStatus,
uploadProgress,
uploadSpeed,
isProcessing,
onCancel,
}: UploadProgressProps) {
if (!uploading) return null
if (isBatchMode && batchUploadStatus) {
const { currentFileIndex, totalFiles, currentFileName, currentFileProgress, currentFileSpeed, fileStatuses } = batchUploadStatus
const completedFiles = fileStatuses.filter(s => s.status === 'done').length
const failedFiles = fileStatuses.filter(s => s.status === 'failed').length
const remainingBytes = fileStatuses
.slice(currentFileIndex)
.reduce((sum, status, idx) => {
const file = batchUploadStatus.fileStatuses[currentFileIndex + idx]
if (!file) return sum
const fileSize = 100 // 假设每个文件100单位,实际应该从batchFiles获取
return sum + (fileSize * (100 - status.progress) / 100)
}, 0)
return (
<div className="space-y-4">
{/* 整体进度 */}
<div className="space-y-2">
<div className="flex items-center justify-between text-sm">
<span className="text-gray-700 dark:text-gray-300">
整体进度: {completedFiles}/{totalFiles} 完成
{failedFiles > 0 && <span className="text-red-600 ml-2">({failedFiles} 失败)</span>}
</span>
<span className="text-gray-600 dark:text-gray-400">{uploadProgress}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-blue-600 h-2 rounded-full transition-all duration-300"
style={{ width: `${uploadProgress}%` }}
/>
</div>
</div>
{/* 当前文件进度 */}
<div className="border border-gray-200 dark:border-gray-700 rounded-apple p-3 space-y-2">
<div className="flex items-center justify-between text-sm">
<span className="text-gray-700 dark:text-gray-300 font-medium">
当前文件 ({currentFileIndex + 1}/{totalFiles}): {currentFileName}
</span>
<span className="text-gray-600 dark:text-gray-400">{currentFileProgress}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-green-600 h-2 rounded-full transition-all duration-300"
style={{ width: `${currentFileProgress}%` }}
/>
</div>
{currentFileSpeed > 0 && (
<div className="flex items-center justify-between text-xs text-gray-500 dark:text-gray-400">
<span>速度: {formatSpeed(currentFileSpeed)}</span>
<span>剩余时间: {calculateRemainingTime(remainingBytes, currentFileSpeed)}</span>
</div>
)}
</div>
{/* 文件状态列表 */}
<div className="max-h-60 overflow-y-auto space-y-2">
{fileStatuses.map((status, idx) => (
<div key={idx} className="flex items-center justify-between text-sm p-2 bg-gray-50 dark:bg-gray-800 rounded">
<div className="flex items-center space-x-2 flex-1 min-w-0">
{status.status === 'done' && <span className="text-green-600">✓</span>}
{status.status === 'failed' && <span className="text-red-600">✗</span>}
{status.status === 'uploading' && <span className="text-blue-600 animate-spin">⟳</span>}
{status.status === 'processing' && <span className="text-yellow-600">⏳</span>}
{status.status === 'pending' && <span className="text-gray-400">○</span>}
<span className="text-gray-700 dark:text-gray-300 truncate">{status.fileName}</span>
</div>
<div className="flex items-center space-x-2">
<span className="text-gray-600 dark:text-gray-400 text-xs">{status.progress}%</span>
{status.error && (
<span className="text-red-600 text-xs" title={status.error}>错误</span>
)}
</div>
</div>
))}
</div>
<button
type="button"
onClick={onCancel}
className="w-full btn-secondary"
>
取消上传
</button>
</div>
)
}
// 单文件上传进度
return (
<div className="space-y-2">
<div className="flex items-center justify-between text-sm">
<span className="text-gray-700 dark:text-gray-300">
{isProcessing ? '处理中...' : '上传中...'}
</span>
<span className="text-gray-600 dark:text-gray-400">{uploadProgress}%</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2">
<div
className="bg-blue-600 h-2 rounded-full transition-all duration-300"
style={{ width: `${uploadProgress}%` }}
/>
</div>
{uploadSpeed > 0 && !isProcessing && (
<div className="text-xs text-gray-500 dark:text-gray-400">
速度: {formatSpeed(uploadSpeed)}
</div>
)}
<button
type="button"
onClick={onCancel}
className="w-full btn-secondary"
>
取消上传
</button>
</div>
)
}