'use client' import Image from 'next/image' import type { BatchFileItem } from './upload-types' import { PREVIEW_OPTIONAL_TYPES } from './upload-constants' import { requiresCategoryAndScene, requiresProductCategoryName, requiresRenderer } from '@/lib/material-validation' import { formatBytes } from './upload-utils' interface BatchFileListProps { batchFiles: BatchFileItem[] materialType: string categories: Array<{ id: string; name: string }> scenes: Array<{ id: string; name: string }> platforms: Array<{ id: string; name: string }> productCategories: Array<{ id: string; name: string }> renderer: string batchPreviewDragging: Record onToggleExpand: (index: number) => void onDelete: (index: number) => void onUpdateProductModel: (index: number, value: string) => void onUpdatePreviewImage: (index: number, file: File) => void onRemovePreviewImage: (index: number) => void onUpdateCategory: (index: number, value: string) => void onUpdateScene: (index: number, value: string) => void onUpdatePlatform: (index: number, value: string) => void onUpdateProductCategory: (index: number, value: string) => void onUpdateRenderer: (index: number, value: string) => void onExitBatchMode: () => void onPreviewDragEnter: (itemId: string) => void onPreviewDragLeave: (itemId: string) => void } export default function BatchFileList({ batchFiles, materialType, categories, scenes, platforms, productCategories, renderer, batchPreviewDragging, onToggleExpand, onDelete, onUpdateProductModel, onUpdatePreviewImage, onRemovePreviewImage, onUpdateCategory, onUpdateScene, onUpdatePlatform, onUpdateProductCategory, onUpdateRenderer, onExitBatchMode, onPreviewDragEnter, onPreviewDragLeave, }: BatchFileListProps) { const handlePreviewDrop = (e: React.DragEvent, itemId: string, index: number) => { e.preventDefault() e.stopPropagation() const files = Array.from(e.dataTransfer.files) const imageFile = files.find(f => f.type.startsWith('image/')) if (imageFile) { onUpdatePreviewImage(index, imageFile) } } const handlePreviewFileSelect = (e: React.ChangeEvent, index: number) => { const file = e.target.files?.[0] if (file) { onUpdatePreviewImage(index, file) } } return (

批量上传模式({batchFiles.length} 个文件)

{batchFiles.map((item, index) => (
{/* 文件行(可点击展开/收起) */}
onToggleExpand(index)} >

{item.file.name}

{formatBytes(item.file.size)} {item.productModel && `· SPU: ${item.productModel}`}

{/* 展开的配置区域 */} {item.expanded && (
{/* SPU型号 */}
onUpdateProductModel(index, e.target.value)} className="w-full px-4 py-2 rounded-apple border border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:border-gray-900 dark:focus:border-gray-400 focus:ring-2 focus:ring-gray-200 dark:focus:ring-gray-600 outline-none" placeholder="例如:XY-2024-001" onClick={(e) => e.stopPropagation()} />
{/* 预览图片(如果需要) */} {!PREVIEW_OPTIONAL_TYPES.includes(materialType) && materialType !== '详情模板' && (
{item.previewImageUrl ? (
Preview
) : (
{ e.preventDefault() e.stopPropagation() onPreviewDragEnter(item.id) }} onDragLeave={(e) => { e.preventDefault() e.stopPropagation() const rect = (e.currentTarget as HTMLElement).getBoundingClientRect() const x = e.clientX const y = e.clientY if (x <= rect.left || x >= rect.right || y <= rect.top || y >= rect.bottom) { onPreviewDragLeave(item.id) } }} onDragOver={(e) => { e.preventDefault() e.stopPropagation() }} onDrop={(e) => { handlePreviewDrop(e, item.id, index) onPreviewDragLeave(item.id) }} onClick={(e) => { e.stopPropagation() document.getElementById(`batch-preview-${item.id}`)?.click() }} > handlePreviewFileSelect(e, index)} className="hidden" id={`batch-preview-${item.id}`} onClick={(e) => e.stopPropagation()} /> 拖拽或点击选择图片
)}
)} {/* 使用店铺和场景类别(如果不是自动通用类型) */} {requiresCategoryAndScene(materialType) && ( <>
)} {/* 平台分类(可选,仅在后台配置了平台时显示,标准模型不显示) */} {platforms.length > 0 && materialType !== '标准模型' && (
)} {/* 品类分类(标准模型必填,其他类型可选) */} {productCategories.length > 0 && (
)} {/* 渲染器(仅3D场景显示) */} {materialType === '3D场景' && (
)}
)}
))}
) }