"use client" import type React from "react" import { useState, useRef } from "react" import { useRouter } from "next/navigation" import { ChevronLeft, Plus, X, Image as ImageIcon, UploadCloud, Link, Video, FileText, Layers, CalendarDays, ChevronDown } from "lucide-react" import { Card } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" import { Label } from "@/components/ui/label" import { toast } from "@/components/ui/use-toast" import Image from "next/image" import { Input } from "@/components/ui/input" import { cn } from "@/lib/utils" import { api } from "@/lib/api" import { showToast } from "@/lib/toast" interface ApiResponse { code: number msg: string data: T } // 素材类型枚举 const MATERIAL_TYPES = [ { id: 1, name: "图片", icon: ImageIcon }, { id: 2, name: "链接", icon: Link }, { id: 3, name: "视频", icon: Video }, { id: 4, name: "文本", icon: FileText }, { id: 5, name: "小程序", icon: Layers } ] export default function NewMaterialPage({ params }: { params: { id: string } }) { const router = useRouter() const [content, setContent] = useState("") const [images, setImages] = useState([]) const [previewUrls, setPreviewUrls] = useState([]) const [materialType, setMaterialType] = useState(1) const [url, setUrl] = useState("") const [desc, setDesc] = useState("") const [image, setImage] = useState("") const [videoUrl, setVideoUrl] = useState("") const [publishTime, setPublishTime] = useState("") const [comment, setComment] = useState("") const [loading, setLoading] = useState(false) const fileInputRef = useRef(null) // 图片上传 const handleUploadImage = () => { fileInputRef.current?.click() } const handleFileChange = async (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (!file) return if (!file.type.startsWith('image/')) { showToast("请选择图片文件", "error") return } const loadingToast = showToast("正在上传图片...", "loading", true) setLoading(true) const formData = new FormData() formData.append("file", file) try { const token = localStorage.getItem('token'); const headers: HeadersInit = { // 浏览器会自动为 FormData 设置 Content-Type 为 multipart/form-data,无需手动设置 }; if (token) { headers['Authorization'] = `Bearer ${token}`; } const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/v1/attachment/upload`, { method: 'POST', headers: headers, body: formData, }); const result: ApiResponse = await response.json(); if (result.code === 200 && result.data?.url) { setImages((prev) => [...prev, result.data.url]); setPreviewUrls((prev) => [...prev, result.data.url]); showToast("图片上传成功", "success"); } else { showToast(result.msg || "图片上传失败", "error"); } } catch (error: any) { showToast(error?.message || "图片上传失败", "error") } finally { loadingToast.remove && loadingToast.remove() setLoading(false) // 清空文件输入框,以便再次上传同一文件 if (fileInputRef.current) { fileInputRef.current.value = ''; } } } const handleRemoveImage = (indexToRemove: number) => { setImages(images.filter((_, index) => index !== indexToRemove)) setPreviewUrls(previewUrls.filter((_, index) => index !== indexToRemove)) } // 创建素材 const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() // 校验 if (!content) { showToast("请输入内容", "error") return } if (!comment) { showToast("请输入评论内容", "error") return } if (materialType === 1 && images.length === 0) { showToast("请上传图片", "error") return } else if (materialType === 2 && (!url || !desc)) { showToast("请输入描述和链接地址", "error") return } else if (materialType === 3 && (!url && !videoUrl)) { showToast("请填写视频链接或上传视频", "error") return } setLoading(true) const loadingToast = showToast("正在创建素材...", "loading", true) try { const payload: any = { libraryId: params.id, type: materialType, content: content, comment: comment, sendTime: publishTime, } if (materialType === 1) { payload.resUrls = images } else if (materialType === 2) { payload.urls = [{ desc, image, url }] } else if (materialType === 3) { payload.urls = videoUrl ? [videoUrl] : [] } const response = await api.post('/v1/content/library/create-item', payload) if (response.code === 200) { showToast("创建成功", "success") router.push(`/content/${params.id}/materials`) } else { showToast(response.msg || "创建失败", "error") } } catch (error: any) { showToast(error?.message || "创建素材失败", "error") } finally { loadingToast.remove && loadingToast.remove() setLoading(false) } } return (

新建素材

{/* 基础信息分组 */}
基础信息
setPublishTime(e.target.value)} className="w-full h-12 rounded-2xl border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-100 px-4 text-base placeholder:text-gray-300" placeholder="请选择发布时间" style={{ width: 'auto' }} />
{/* 内容信息分组(所有类型都展示内容和评论) */}
内容信息