'use client' import { useMemo, useState } from 'react' import Image from 'next/image' import { STANDARD_MODEL_WHITE_BG_VIEWS, type StandardModelWhiteBgKey, } from '@/lib/standard-model-white-background' import { hasDragLeftDropZone, prepareFileDrag } from './drag-drop-utils' interface OtherImagePreview { id: string url: string name: string } interface StandardModelWhiteBackgroundUploadProps { imageUrls: Partial> otherImages: OtherImagePreview[] uploading?: boolean error?: string onSelectImage: (key: StandardModelWhiteBgKey, file: File) => void onRemoveImage: (key: StandardModelWhiteBgKey) => void onSelectOtherImages: (files: FileList | File[]) => void onRemoveOtherImage: (id: string) => void } export default function StandardModelWhiteBackgroundUpload({ imageUrls, otherImages, uploading = false, error, onSelectImage, onRemoveImage, onSelectOtherImages, onRemoveOtherImage, }: StandardModelWhiteBackgroundUploadProps) { const [draggingKey, setDraggingKey] = useState(null) const [isOtherDragging, setIsOtherDragging] = useState(false) const uploadedRequiredCount = useMemo( () => STANDARD_MODEL_WHITE_BG_VIEWS.filter((view) => !!imageUrls[view.key]).length, [imageUrls], ) const missingLabels = useMemo( () => STANDARD_MODEL_WHITE_BG_VIEWS .filter((view) => !imageUrls[view.key]) .map((view) => view.label), [imageUrls], ) const handleDragEnter = (event: React.DragEvent, key: StandardModelWhiteBgKey) => { prepareFileDrag(event, uploading) if (uploading) return setDraggingKey(key) } const handleDragLeave = (event: React.DragEvent, key: StandardModelWhiteBgKey) => { event.preventDefault() event.stopPropagation() if (hasDragLeftDropZone(event)) { if (draggingKey === key) { setDraggingKey(null) } } } const handleDragOver = (event: React.DragEvent) => { prepareFileDrag(event, uploading) } const handleDrop = (event: React.DragEvent, key: StandardModelWhiteBgKey) => { prepareFileDrag(event, uploading) setDraggingKey(null) if (uploading) return const file = event.dataTransfer.files?.[0] if (!file) { return } onSelectImage(key, file) } const handleOtherDrop = (event: React.DragEvent) => { prepareFileDrag(event, uploading) setIsOtherDragging(false) if (uploading) return const files = event.dataTransfer.files if (!files || files.length === 0) { return } onSelectOtherImages(files) } return (
固定角度 {uploadedRequiredCount} / {STANDARD_MODEL_WHITE_BG_VIEWS.length} 可分次补传 {otherImages.length > 0 && ( 其他图片 {otherImages.length} 张 )} {uploading && ( 上传处理中 )}
{missingLabels.length > 0 ? `未上传:${missingLabels.join('、')}(可先保存,后续再补)` : '8 张固定角度已齐,可直接保存。'}
{error && (
{error}
)}

固定角度

可选,建议补齐 8 张
{STANDARD_MODEL_WHITE_BG_VIEWS.map((view) => { const inputId = `white-bg-${view.key}` const imageUrl = imageUrls[view.key] const isDragging = draggingKey === view.key return (

{view.label}

可选
{ const file = event.target.files?.[0] if (file) { onSelectImage(view.key, file) } event.currentTarget.value = '' }} /> {/* biome-ignore lint/a11y/noStaticElementInteractions: 上传槽位需要拖拽和点击交互 */}
) })}

其他图片

可选,多张
{ if (event.target.files && event.target.files.length > 0) { onSelectOtherImages(event.target.files) } event.currentTarget.value = '' }} /> {/* biome-ignore lint/a11y/noStaticElementInteractions: 其他图片区需要拖拽上传 */}
) }