235 lines
6.8 KiB
TypeScript
235 lines
6.8 KiB
TypeScript
import React, { useState } from 'react';
|
||
import { useFileDownload } from '../hooks/useFileDownload';
|
||
import { useTusUpload } from '../hooks/useTusUpload';
|
||
|
||
export function AdvancedFileDownload() {
|
||
const { getFileInfo } = useTusUpload();
|
||
const {
|
||
downloadProgress,
|
||
isDownloading,
|
||
downloadError,
|
||
downloadFile,
|
||
downloadFileWithProgress,
|
||
previewFile,
|
||
copyFileLink,
|
||
canPreview,
|
||
getFileIcon,
|
||
} = useFileDownload();
|
||
|
||
const [fileId, setFileId] = useState('');
|
||
const [fileInfo, setFileInfo] = useState<any>(null);
|
||
const [loading, setLoading] = useState(false);
|
||
const [error, setError] = useState<string | null>(null);
|
||
|
||
// 获取文件信息
|
||
const handleGetFileInfo = async () => {
|
||
if (!fileId.trim()) {
|
||
setError('请输入文件ID');
|
||
return;
|
||
}
|
||
|
||
setLoading(true);
|
||
setError(null);
|
||
|
||
try {
|
||
const info = await getFileInfo(fileId);
|
||
if (info) {
|
||
setFileInfo(info);
|
||
} else {
|
||
setError('文件不存在或未准备好');
|
||
}
|
||
} catch (err) {
|
||
setError('获取文件信息失败');
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
// 简单下载
|
||
const handleSimpleDownload = () => {
|
||
downloadFile(fileId, fileInfo?.title);
|
||
};
|
||
|
||
// 带进度的下载
|
||
const handleProgressDownload = async () => {
|
||
try {
|
||
await downloadFileWithProgress(fileId, fileInfo?.title);
|
||
} catch (error) {
|
||
console.error('Download with progress failed:', error);
|
||
}
|
||
};
|
||
|
||
// 预览文件
|
||
const handlePreview = () => {
|
||
previewFile(fileId);
|
||
};
|
||
|
||
// 复制链接
|
||
const handleCopyLink = async () => {
|
||
try {
|
||
await copyFileLink(fileId);
|
||
alert('链接已复制到剪贴板!');
|
||
} catch (error) {
|
||
alert('复制失败');
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="p-6 bg-white rounded-lg shadow-md">
|
||
<h3 className="text-lg font-semibold mb-4">高级文件下载</h3>
|
||
|
||
{/* 文件ID输入 */}
|
||
<div className="mb-4">
|
||
<label className="block text-sm font-medium text-gray-700 mb-2">文件ID</label>
|
||
<div className="flex gap-2">
|
||
<input
|
||
type="text"
|
||
value={fileId}
|
||
onChange={(e) => setFileId(e.target.value)}
|
||
placeholder="输入文件ID"
|
||
className="flex-1 px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||
/>
|
||
<button
|
||
onClick={handleGetFileInfo}
|
||
disabled={loading}
|
||
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
|
||
>
|
||
{loading ? '查询中...' : '查询'}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 错误信息 */}
|
||
{(error || downloadError) && (
|
||
<div className="mb-4 p-3 bg-red-100 border border-red-300 text-red-700 rounded-md">
|
||
{error || downloadError}
|
||
</div>
|
||
)}
|
||
|
||
{/* 下载进度 */}
|
||
{isDownloading && downloadProgress && (
|
||
<div className="mb-4 p-4 bg-blue-50 rounded-md">
|
||
<div className="flex items-center justify-between mb-2">
|
||
<span className="text-sm font-medium text-blue-900">下载进度</span>
|
||
<span className="text-sm text-blue-600">{downloadProgress.percentage}%</span>
|
||
</div>
|
||
<div className="w-full bg-blue-200 rounded-full h-2">
|
||
<div
|
||
className="bg-blue-600 h-2 rounded-full transition-all duration-300"
|
||
style={{ width: `${downloadProgress.percentage}%` }}
|
||
/>
|
||
</div>
|
||
<div className="mt-1 text-xs text-blue-600">
|
||
{formatFileSize(downloadProgress.loaded)} / {formatFileSize(downloadProgress.total)}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* 文件信息 */}
|
||
{fileInfo && (
|
||
<div className="mb-6 p-4 bg-gray-50 rounded-md">
|
||
<div className="flex items-center gap-3 mb-3">
|
||
<span className="text-2xl">{getFileIcon(fileInfo.type || '')}</span>
|
||
<div>
|
||
<h4 className="font-medium">{fileInfo.title || '未知文件'}</h4>
|
||
<p className="text-sm text-gray-600">{fileInfo.type || '未知类型'}</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||
<div>
|
||
<span className="font-medium">状态:</span>
|
||
<span
|
||
className={`ml-2 px-2 py-1 rounded text-xs ${
|
||
fileInfo.status === 'UPLOADED' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800'
|
||
}`}
|
||
>
|
||
{fileInfo.status || '未知'}
|
||
</span>
|
||
</div>
|
||
{fileInfo.meta?.size && (
|
||
<div>
|
||
<span className="font-medium">大小:</span> {formatFileSize(fileInfo.meta.size)}
|
||
</div>
|
||
)}
|
||
<div>
|
||
<span className="font-medium">创建时间:</span> {new Date(fileInfo.createdAt).toLocaleString()}
|
||
</div>
|
||
<div>
|
||
<span className="font-medium">存储类型:</span> {fileInfo.storageType || '未知'}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* 操作按钮 */}
|
||
{fileInfo && (
|
||
<div className="space-y-3">
|
||
<div className="flex gap-2 flex-wrap">
|
||
<button
|
||
onClick={handleSimpleDownload}
|
||
disabled={isDownloading}
|
||
className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700 disabled:opacity-50"
|
||
>
|
||
快速下载
|
||
</button>
|
||
<button
|
||
onClick={handleProgressDownload}
|
||
disabled={isDownloading}
|
||
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
|
||
>
|
||
进度下载
|
||
</button>
|
||
{canPreview(fileInfo.type || '') && (
|
||
<button
|
||
onClick={handlePreview}
|
||
className="px-4 py-2 bg-purple-600 text-white rounded-md hover:bg-purple-700"
|
||
>
|
||
预览文件
|
||
</button>
|
||
)}
|
||
<button onClick={handleCopyLink} className="px-4 py-2 bg-gray-600 text-white rounded-md hover:bg-gray-700">
|
||
复制链接
|
||
</button>
|
||
</div>
|
||
|
||
{/* 文件预览提示 */}
|
||
{canPreview(fileInfo.type || '') && (
|
||
<div className="p-3 bg-purple-50 border border-purple-200 rounded-md">
|
||
<p className="text-sm text-purple-700">💡 此文件支持在线预览,点击"预览文件"可以在浏览器中直接查看</p>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* 使用说明 */}
|
||
<div className="mt-6 p-4 bg-gray-50 rounded-md">
|
||
<h4 className="text-sm font-medium text-gray-900 mb-2">功能说明:</h4>
|
||
<ul className="text-xs text-gray-600 space-y-1">
|
||
<li>
|
||
• <strong>快速下载</strong>:直接通过浏览器下载文件
|
||
</li>
|
||
<li>
|
||
• <strong>进度下载</strong>:显示下载进度,适合大文件
|
||
</li>
|
||
<li>
|
||
• <strong>预览文件</strong>:图片、PDF、视频等可在线预览
|
||
</li>
|
||
<li>
|
||
• <strong>复制链接</strong>:复制文件访问链接到剪贴板
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
// 格式化文件大小
|
||
function formatFileSize(bytes: number): string {
|
||
if (bytes === 0) return '0 Bytes';
|
||
const k = 1024;
|
||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||
}
|