import React from 'react'; import { Image, Spin, Empty } from 'antd'; import { EyeOutlined, FileImageOutlined } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import { fileClient } from '@/client/api'; import type { InferResponseType } from 'hono/client'; // 定义文件类型 type FileItem = InferResponseType; interface FilePreviewProps { fileIds?: number[]; files?: any[]; maxCount?: number; size?: 'small' | 'medium' | 'large'; showCount?: boolean; onFileClick?: (file: FileItem) => void; } interface FilePreviewItemProps { file: FileItem; size: 'small' | 'medium' | 'large'; index?: number; total?: number; } const FilePreviewItem: React.FC = ({ file, size, index, total }) => { const getSize = () => { switch (size) { case 'small': return { width: 45, height: 45 }; case 'medium': return { width: 80, height: 80 }; case 'large': return { width: 120, height: 120 }; default: return { width: 80, height: 80 }; } }; const { width, height } = getSize(); const isImage = file.type?.startsWith('image/'); const previewText = isImage ? '预览' : '查看'; return (
{isImage ? ( {file.name} {previewText}
), }} /> ) : (
{file.name.length > 8 ? `${file.name.substring(0, 6)}...` : file.name}
)} {/* 序号标记 */} {index !== undefined && total !== undefined && total > 1 && (
{index + 1}
)} ); }; const FilePreview: React.FC = ({ fileIds = [], files = [], maxCount = 6, size = 'medium', showCount = true, onFileClick, }) => { // 合并文件ID和文件对象 const allFileIds = [...fileIds, ...(files?.map(f => f.id) || [])]; const uniqueFileIds = [...new Set(allFileIds)].filter(Boolean); // 使用 React Query 查询文件详情 const { data: fileDetails, isLoading, error } = useQuery({ queryKey: ['files', uniqueFileIds], queryFn: async () => { if (uniqueFileIds.length === 0) return []; const promises = uniqueFileIds.map(async (id) => { try { const response = await fileClient[':id']['$get']({ param: { id: id.toString() } }); if (response.ok) { return response.json(); } return null; } catch (error) { console.error(`获取文件 ${id} 详情失败:`, error); return null; } }); const results = await Promise.all(promises); return results.filter(Boolean) as FileItem[]; }, enabled: uniqueFileIds.length > 0, staleTime: 5 * 60 * 1000, // 5分钟 gcTime: 10 * 60 * 1000, // 10分钟 }); if (isLoading) { return (
); } if (error) { return (
); } const displayFiles = fileDetails?.slice(0, maxCount) || []; const remainingCount = Math.max(0, (fileDetails?.length || 0) - maxCount); if (displayFiles.length === 0) { return (
); } return (
{displayFiles.map((file, index) => ( ))}
{showCount && remainingCount > 0 && (
还有 {remainingCount} 张图片未显示
)}
); }; export default FilePreview;