gongxiangp2/components/upload/StandardModelWhiteBackgroundUpload.tsx
2026-03-06 14:14:50 +08:00

154 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client'
import { useState } from 'react'
import Image from 'next/image'
import {
STANDARD_MODEL_WHITE_BG_VIEWS,
type StandardModelWhiteBgKey,
} from '@/lib/standard-model-white-background'
interface StandardModelWhiteBackgroundUploadProps {
imageUrls: Partial<Record<StandardModelWhiteBgKey, string>>
onSelectImage: (key: StandardModelWhiteBgKey, file: File) => void
onRemoveImage: (key: StandardModelWhiteBgKey) => void
}
export default function StandardModelWhiteBackgroundUpload({
imageUrls,
onSelectImage,
onRemoveImage,
}: StandardModelWhiteBackgroundUploadProps) {
const [draggingKey, setDraggingKey] = useState<StandardModelWhiteBgKey | null>(null)
const handleDragEnter = (event: React.DragEvent, key: StandardModelWhiteBgKey) => {
event.preventDefault()
event.stopPropagation()
setDraggingKey(key)
}
const handleDragLeave = (event: React.DragEvent, key: StandardModelWhiteBgKey) => {
event.preventDefault()
event.stopPropagation()
const rect = (event.currentTarget as HTMLElement).getBoundingClientRect()
const { clientX, clientY } = event
if (clientX <= rect.left || clientX >= rect.right || clientY <= rect.top || clientY >= rect.bottom) {
if (draggingKey === key) {
setDraggingKey(null)
}
}
}
const handleDragOver = (event: React.DragEvent) => {
event.preventDefault()
event.stopPropagation()
event.dataTransfer.dropEffect = 'copy'
}
const handleDrop = (event: React.DragEvent, key: StandardModelWhiteBgKey) => {
event.preventDefault()
event.stopPropagation()
setDraggingKey(null)
const file = event.dataTransfer.files?.[0]
if (!file) {
return
}
onSelectImage(key, file)
}
return (
<div>
<p className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
产品白底图(6张) *
</p>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{STANDARD_MODEL_WHITE_BG_VIEWS.map((view) => {
const inputId = `white-bg-${view.key}`
const imageUrl = imageUrls[view.key]
const isDragging = draggingKey === view.key
return (
<div key={view.key} className="space-y-2">
<p className="text-xs font-medium text-gray-700 dark:text-gray-300">{view.label}</p>
<input
id={inputId}
type="file"
accept="image/*"
className="hidden"
onChange={(event) => {
const file = event.target.files?.[0]
if (file) {
onSelectImage(view.key, file)
}
event.currentTarget.value = ''
}}
/>
{/* biome-ignore lint/a11y/noStaticElementInteractions: 上传槽位需要处理拖拽上传事件 */}
<div
className={`border-2 border-dashed rounded-apple p-3 transition-colors ${
isDragging
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
: 'border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800/50 hover:border-gray-400 dark:hover:border-gray-500'
}`}
onDragEnter={(event) => handleDragEnter(event, view.key)}
onDragLeave={(event) => handleDragLeave(event, view.key)}
onDragOver={handleDragOver}
onDrop={(event) => handleDrop(event, view.key)}
>
{imageUrl ? (
<div className="space-y-2">
<div className="relative w-full h-24 rounded-apple overflow-hidden border-2 border-gray-200 dark:border-gray-600">
<Image
src={imageUrl}
alt={view.label}
fill
unoptimized
className="object-cover"
/>
</div>
<div className="flex gap-2">
<label
htmlFor={inputId}
className="flex-1 text-center text-xs px-2 py-1 rounded-apple bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-600 cursor-pointer transition-colors"
>
更换
</label>
<button
type="button"
className="text-xs px-2 py-1 rounded-apple bg-red-50 dark:bg-red-900/20 text-red-600 dark:text-red-400 hover:bg-red-100 dark:hover:bg-red-900/30 transition-colors"
onClick={() => onRemoveImage(view.key)}
>
删除
</button>
</div>
<p className="text-[11px] text-blue-600 dark:text-blue-400">支持拖拽图片替换</p>
</div>
) : (
<label
htmlFor={inputId}
className="group w-full h-24 rounded-apple bg-gray-100 dark:bg-gray-700 border-2 border-dashed border-gray-300 dark:border-gray-600 flex flex-col items-center justify-center hover:border-gray-400 dark:hover:border-gray-500 transition-colors cursor-pointer"
>
<svg className="w-5 h-5 text-gray-400 group-hover:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<title>上传{view.label}</title>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
</svg>
<span className="mt-1 text-xs text-gray-500 dark:text-gray-400">拖拽或点击上传</span>
</label>
)}
</div>
</div>
)
})}
</div>
<p className="mt-2 text-xs text-gray-500 dark:text-gray-400">
白底图需一次上传完整6张,系统会自动打包为白底图压缩包用于下载。
</p>
<p className="mt-1 text-xs text-blue-600 dark:text-blue-400">
💡 每个角度支持拖拽上传,拖入后会自动替换对应位置图片。
</p>
</div>
)
}