import { useRef, useState } from 'react'; import { Button, Image, Space, Typography, Upload, message } from 'antd'; import { UploadOutlined, DeleteOutlined } from '@ant-design/icons'; import type { UploadProps } from 'antd'; import { uploadFileToOss, type OssMediaType } from '../lib/upload'; type Props = { value?: string[]; onChange?: (urls: string[]) => void; bizType: string; mediaType?: OssMediaType; /** 最多张数;不传则不限制 */ maxCount?: number; tip?: string; accept?: string; }; function normalizeUrls(value?: string[]) { return (value ?? []).map((u) => String(u || '').trim()).filter(Boolean); } /** * 多图批量上传(一次可选多张),用于套餐图 / 环境照 / 商品详情图等。 * Form.Item 直接绑定 string[]。 */ export default function MultiImageUpload({ value, onChange, bizType, mediaType = 'IMAGE', maxCount, tip, accept = 'image/*', }: Props) { const urls = normalizeUrls(value); const [uploading, setUploading] = useState(false); const batchBuf = useRef([]); const remaining = maxCount != null ? Math.max(0, maxCount - urls.length) : Number.POSITIVE_INFINITY; const canAdd = remaining > 0; async function uploadBatch(files: File[]) { const room = maxCount != null ? Math.max(0, maxCount - urls.length) : files.length; const picked = files.slice(0, room); if (!picked.length) { message.warning(maxCount != null ? `最多 ${maxCount} 张` : '无法上传'); return; } if (files.length > picked.length) { message.warning(`已达上限,仅上传前 ${picked.length} 张`); } setUploading(true); const appended: string[] = []; let fail = 0; try { for (const file of picked) { try { const result = await uploadFileToOss(file, { bizType, mediaType }); appended.push(result.url); } catch { fail += 1; } } if (appended.length) { onChange?.([...urls, ...appended]); message.success(`成功上传 ${appended.length} 张${fail ? `,失败 ${fail} 张` : ''}`); } else if (fail) { message.error('上传失败'); } } finally { setUploading(false); } } const beforeUpload: UploadProps['beforeUpload'] = (file, fileList) => { batchBuf.current.push(file as File); if (batchBuf.current.length >= fileList.length) { const files = [...batchBuf.current]; batchBuf.current = []; void uploadBatch(files); } return false; }; function removeAt(index: number) { onChange?.(urls.filter((_, i) => i !== index)); } return ( {tip ?? (maxCount != null ? `最多 ${maxCount} 张,支持一次选择多张批量上传` : '支持一次选择多张批量上传')} {maxCount != null ? `(已选 ${urls.length}/${maxCount})` : urls.length ? `(已选 ${urls.length})` : ''} {urls.length > 0 ? ( {urls.map((url, index) => (
))}
) : null}
); }