'use client' import { useState, useRef, useEffect } from 'react' import Image from 'next/image' interface EditMaterialModalProps { material: { id: string previewUrl: string productModel: string categoryName: string sceneName: string materialType: string renderer: string authorName: string } onClose: () => void onSuccess: () => void } export default function EditMaterialModal({ material, onClose, onSuccess }: EditMaterialModalProps) { const [previewImage, setPreviewImage] = useState(null) const [previewUrl, setPreviewUrl] = useState(material.previewUrl) const [productModel, setProductModel] = useState(material.productModel) const [categoryName, setCategoryName] = useState(material.categoryName) const [sceneName, setSceneName] = useState(material.sceneName) const [materialType, setMaterialType] = useState(material.materialType || '3DMAX') const [renderer, setRenderer] = useState(material.renderer || 'CR') const [authorName, setAuthorName] = useState(material.authorName) const [categories, setCategories] = useState>([]) const [scenes, setScenes] = useState>([]) const [showNewCategoryInput, setShowNewCategoryInput] = useState(false) const [newCategoryName, setNewCategoryName] = useState('') const [showNewSceneInput, setShowNewSceneInput] = useState(false) const [newSceneName, setNewSceneName] = useState('') const [updating, setUpdating] = useState(false) const [error, setError] = useState('') const previewInputRef = useRef(null) // 加载分类和场景列表 useEffect(() => { fetchCategories() fetchScenes() }, []) const fetchCategories = async () => { try { const response = await fetch('/api/categories') if (response.ok) { const data = await response.json() setCategories(data) } } catch (error) { console.error('Error fetching categories:', error) } } const fetchScenes = async () => { try { const response = await fetch('/api/scenes') if (response.ok) { const data = await response.json() setScenes(data) } } catch (error) { console.error('Error fetching scenes:', error) } } const handleAddNewCategory = async () => { if (!newCategoryName.trim()) { setError('请输入一级分类名称') return } try { const response = await fetch('/api/categories', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newCategoryName.trim() }), }) if (response.ok) { const newCategory = await response.json() await fetchCategories() setCategoryName(newCategory.name) setNewCategoryName('') setShowNewCategoryInput(false) setError('') } else { const data = await response.json() setError(data.error || '添加一级分类失败') } } catch (error) { console.error('Error adding category:', error) setError('添加一级分类失败') } } const handleAddNewScene = async () => { if (!newSceneName.trim()) { setError('请输入场景名称') return } try { const response = await fetch('/api/scenes', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name: newSceneName.trim() }), }) if (response.ok) { const newScene = await response.json() await fetchScenes() setSceneName(newScene.name) setNewSceneName('') setShowNewSceneInput(false) setError('') } else { const data = await response.json() setError(data.error || '添加场景失败') } } catch (error) { console.error('Error adding scene:', error) setError('添加场景失败') } } const handlePreviewChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (file) { if (!file.type.startsWith('image/')) { setError('请选择图片文件') return } setPreviewImage(file) setPreviewUrl(URL.createObjectURL(file)) setError('') } } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setError('') if (!productModel || !categoryName || !sceneName || !renderer || !authorName) { setError('请填写所有字段') return } setUpdating(true) try { const formData = new FormData() formData.append('id', material.id) formData.append('productModel', productModel) formData.append('categoryName', categoryName) formData.append('sceneName', sceneName) formData.append('materialType', materialType) formData.append('renderer', renderer) formData.append('authorName', authorName) if (previewImage) { formData.append('previewImage', previewImage) } const response = await fetch('/api/materials/update', { method: 'PUT', body: formData, }) if (response.ok) { onSuccess() } else { const data = await response.json() setError(data.error || '更新失败') } } catch (error) { console.error('Update error:', error) setError('更新失败,请稍后再试') } finally { setUpdating(false) } } return (

编辑素材

{error && (
{error}
)} {/* Preview Image */}
previewInputRef.current?.click()} className="border-2 border-dashed border-gray-300 rounded-apple p-4 text-center cursor-pointer hover:border-primary-500 transition-colors" >
预览

点击更换预览图(可选)

{/* Product Model */}
{ // 只允许英文、数字和常见符号(- _ .),过滤中文,自动转大写 const value = e.target.value.replace(/[^a-zA-Z0-9\-_.]/g, '').toUpperCase() setProductModel(value) }} className="input-apple" placeholder="例如:XY-2024-001" required />
{/* Category Name (一级分类) */}
{!showNewCategoryInput ? (
) : (
setNewCategoryName(e.target.value)} className="input-apple flex-1" placeholder="输入新的一级分类名称" autoFocus />
)}
{/* Scene Name (二级分类) */}
{!showNewSceneInput ? (
) : (
setNewSceneName(e.target.value)} className="input-apple" placeholder="输入新场景名称" autoFocus />

添加后将自动加入到场景列表中

)}
{/* Material Type */}
{/* Renderer (仅3DMAX显示) */} {materialType === '3DMAX' && (
)} {/* Author Name */}
setAuthorName(e.target.value)} className="input-apple" placeholder="作者花名" required />
{/* Actions */}
) }