import { PlusOutlined } from '@ant-design/icons'; import type { GetProp, UploadFile, UploadProps } from 'antd'; import { Image, message, Spin, Upload } from 'antd'; import React, { useCallback, useEffect, useState } from 'react'; import { uploadImage } from '@/services/infra/media'; type FileType = Parameters>[0]; const getBase64 = (file: FileType): Promise => new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => resolve(reader.result as string); reader.onerror = (error) => reject(error); }); // accept: .doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document image/*,.pdf const UploadImages: React.FC<{ value?: string; onChange?: (value: string | string[]) => void; multiple?: boolean; accept?: string; maxCount?: number; }> = (props) => { const { value, multiple = false, maxCount = 1, accept = 'image/png,image/jpeg', onChange, } = props; const [previewOpen, setPreviewOpen] = useState(false); const [previewImage, setPreviewImage] = useState(''); const [fileList, setFileList] = useState([]); const [uploading, setUploading] = useState(false); useEffect(() => { if (value) { console.log(value.split(',')); const list = value.split(',').map((item, index) => ({ uid: index.toString(), url: item, thumbUrl: item, status: 'done', name: item, })); setFileList(list as UploadFile[]); } else { setFileList([]); } }, [value]); const beforeUpload = (file: FileType) => { const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'; if (!isJpgOrPng) { message.error('仅支持.jpg .png 格式!'); } // const isLt2M = file.size / 1024 / 1024 < 2; // if (!isLt2M) { // message.error('Image must smaller than 2MB!'); // } return isJpgOrPng; }; const handlePreview = async (file: UploadFile) => { if (!file.url && !file.preview) { file.preview = await getBase64(file.originFileObj as FileType); } setPreviewImage(file.url || (file.preview as string)); setPreviewOpen(true); }; const handleRemove = (file: UploadFile): boolean => { const newFileList = fileList.filter((item) => item.uid !== file.uid); const newUrl = newFileList.map((item) => item.url) as string[]; onChange?.(newUrl.join(',')); return true; }; const uploadButton = ( ); const uploadFile = useCallback(async (file: File): Promise => { return new Promise((resolve, reject) => { const formData = new FormData(); formData.append('file', file); try { uploadImage(formData).then((res) => { if (res) { resolve(res); } else { reject(new Error('上传失败:未返回有效的URL')); } }); } catch (error) { reject(error); } }); }, []); const handleLoadImage: UploadProps['customRequest'] = async (option) => { const { file, onSuccess, onError, onProgress } = option; try { setUploading(true); // 模拟进度更新 onProgress?.({ percent: 10 }); // 调用后端接口 const url = await uploadFile(file as File); onProgress?.({ percent: 100 }); if (url) { if (maxCount === 1) { onChange?.(url); onSuccess?.({ url }); } else { const res = value?.split(',') || []; console.log([...res, url].join(',')); onChange?.([...res, url].join(',')); } message.success('上传成功'); } else { throw new Error('上传失败'); } } catch (error) { console.error('Upload error:', error); onError?.(error as Error); message.error(`上传失败: ${(error as Error).message}`); } finally { setUploading(false); } }; return ( {fileList.length >= maxCount ? null : uploadButton} {previewImage && ( setPreviewOpen(visible), afterOpenChange: (visible) => !visible && setPreviewImage(''), }} src={previewImage} /> )} ); }; export default UploadImages;