From d98e540037606e4324fa8e8727671379efcfcdb6 Mon Sep 17 00:00:00 2001 From: gaoziman <2942894660@qq.com> Date: Sat, 20 Dec 2025 12:13:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E7=BB=84=E4=BB=B6):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E9=A2=84=E8=A7=88=E5=88=97=E8=A1=A8=E7=BB=84?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现 FilePreviewItem 展示单个文件信息 - 根据文件类型显示对应图标和颜色 - 图片文件显示缩略图预览 - 显示文件名、大小和上传状态 - 支持上传进度条展示 - 提供悬浮删除按钮 --- src/components/features/FilePreviewList.tsx | 147 ++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/components/features/FilePreviewList.tsx diff --git a/src/components/features/FilePreviewList.tsx b/src/components/features/FilePreviewList.tsx new file mode 100644 index 0000000..59d55ab --- /dev/null +++ b/src/components/features/FilePreviewList.tsx @@ -0,0 +1,147 @@ +'use client'; + +import { X, File, FileImage, FileText, FileSpreadsheet, FileCode, FileArchive, Loader2 } from 'lucide-react'; +import { cn } from '@/lib/utils'; +import { UploadFile, FileType, formatFileSize } from '@/types/file-upload'; +import Image from 'next/image'; + +interface FilePreviewListProps { + files: UploadFile[]; + onRemove: (fileId: string) => void; + className?: string; +} + +// 根据文件类型获取图标 +function getFileIcon(fileType: FileType) { + switch (fileType) { + case 'image': + return FileImage; + case 'pdf': + case 'document': + return FileText; + case 'spreadsheet': + return FileSpreadsheet; + case 'code': + case 'markdown': + return FileCode; + case 'archive': + return FileArchive; + default: + return File; + } +} + +// 根据文件类型获取颜色 +function getFileColor(fileType: FileType): string { + switch (fileType) { + case 'image': + return 'text-blue-500'; + case 'pdf': + return 'text-red-500'; + case 'document': + return 'text-blue-600'; + case 'spreadsheet': + return 'text-green-500'; + case 'code': + case 'markdown': + return 'text-purple-500'; + case 'archive': + return 'text-orange-500'; + default: + return 'text-gray-500'; + } +} + +interface FilePreviewItemProps { + file: UploadFile; + onRemove: (fileId: string) => void; +} + +function FilePreviewItem({ file, onRemove }: FilePreviewItemProps) { + const Icon = getFileIcon(file.type); + const colorClass = getFileColor(file.type); + + return ( +
+ {file.name} +
++ {formatFileSize(file.size)} + {file.status === 'error' && file.error && ( + {file.error} + )} +
+