"use client" import { useState, useRef } from "react" import { Card } from "@/components/ui/card" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Textarea } from "@/components/ui/textarea" import { MessageSquare, ImageIcon, Video, FileText, Link2, Users, AppWindowIcon as Window, Plus, X, Upload, Clock, UploadCloud, } from "lucide-react" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { toast } from "@/components/ui/use-toast" interface MessageContent { id: string type: "text" | "image" | "video" | "file" | "miniprogram" | "link" | "group" content: string | { url: string, name: string }[] sendInterval?: number intervalUnit?: "seconds" | "minutes" scheduledTime?: { hour: number minute: number second: number } title?: string description?: string address?: string coverImage?: string groupId?: string linkUrl?: string cover?: string } interface DayPlan { day: number messages: MessageContent[] } interface MessageSettingsProps { formData: any onChange: (data: any) => void onNext: () => void onPrev: () => void } // 消息类型配置 const messageTypes = [ { id: "text", icon: MessageSquare, label: "文本" }, { id: "image", icon: ImageIcon, label: "图片" }, { id: "video", icon: Video, label: "视频" }, { id: "file", icon: FileText, label: "文件" }, { id: "miniprogram", icon: Window, label: "小程序" }, { id: "link", icon: Link2, label: "链接" }, { id: "group", icon: Users, label: "邀请入群" }, ] // 模拟群组数据 const mockGroups = [ { id: "1", name: "产品交流群1", memberCount: 156 }, { id: "2", name: "产品交流群2", memberCount: 234 }, { id: "3", name: "产品交流群3", memberCount: 89 }, ] export function MessageSettings({ formData, onChange, onNext, onPrev }: MessageSettingsProps) { const [dayPlans, setDayPlans] = useState([ { day: 0, messages: [ { id: "1", type: "text", content: "", sendInterval: 5, intervalUnit: "seconds", // 默认改为秒 }, ], }, ]) const [isAddDayPlanOpen, setIsAddDayPlanOpen] = useState(false) const [isGroupSelectOpen, setIsGroupSelectOpen] = useState(false) const [selectedGroupId, setSelectedGroupId] = useState("") const fileInputRef = useRef(null) const [uploading, setUploading] = useState(false) const [uploadTarget, setUploadTarget] = useState<{dayIndex: number, messageIndex: number, type: string} | null>(null) const coverInputRef = useRef(null) const [uploadingCover, setUploadingCover] = useState(false) const [coverTarget, setCoverTarget] = useState<{dayIndex: number, messageIndex: number} | null>(null) // 添加新消息 const handleAddMessage = (dayIndex: number, type = "text") => { const updatedPlans = [...dayPlans] const newMessage: MessageContent = { id: Date.now().toString(), type: type as MessageContent["type"], content: "", } if (dayPlans[dayIndex].day === 0) { // 即时消息使用间隔设置 newMessage.sendInterval = 5 newMessage.intervalUnit = "seconds" // 默认改为秒 } else { // 非即时消息使用具体时间设置 newMessage.scheduledTime = { hour: 9, minute: 0, second: 0, } } updatedPlans[dayIndex].messages.push(newMessage) setDayPlans(updatedPlans) onChange({ ...formData, messagePlans: updatedPlans }) } // 更新消息内容 const handleUpdateMessage = (dayIndex: number, messageIndex: number, updates: Partial) => { const updatedPlans = [...dayPlans] updatedPlans[dayIndex].messages[messageIndex] = { ...updatedPlans[dayIndex].messages[messageIndex], ...updates, } setDayPlans(updatedPlans) onChange({ ...formData, messagePlans: updatedPlans }) } // 删除消息 const handleRemoveMessage = (dayIndex: number, messageIndex: number) => { const updatedPlans = [...dayPlans] updatedPlans[dayIndex].messages.splice(messageIndex, 1) setDayPlans(updatedPlans) onChange({ ...formData, messagePlans: updatedPlans }) } // 切换时间单位 const toggleIntervalUnit = (dayIndex: number, messageIndex: number) => { const message = dayPlans[dayIndex].messages[messageIndex] const newUnit = message.intervalUnit === "minutes" ? "seconds" : "minutes" handleUpdateMessage(dayIndex, messageIndex, { intervalUnit: newUnit }) } // 添加新的天数计划 const handleAddDayPlan = () => { const newDay = dayPlans.length setDayPlans([ ...dayPlans, { day: newDay, messages: [ { id: Date.now().toString(), type: "text", content: "", scheduledTime: { hour: 9, minute: 0, second: 0, }, }, ], }, ]) setIsAddDayPlanOpen(false) toast({ title: "添加成功", description: `已添加第${newDay}天的消息计划`, }) } // 选择群组 const handleSelectGroup = (groupId: string) => { setSelectedGroupId(groupId) setIsGroupSelectOpen(false) toast({ title: "选择成功", description: `已选择群组:${mockGroups.find((g) => g.id === groupId)?.name}`, }) } // 处理文件上传 const handleFileUpload = (dayIndex: number, messageIndex: number, type: "image" | "video" | "file") => { setUploadTarget({ dayIndex, messageIndex, type }) fileInputRef.current?.setAttribute('accept', type === 'image' ? 'image/*' : type === 'video' ? 'video/*' : '*') fileInputRef.current?.click() } const handleFileChange = async (event: React.ChangeEvent) => { const file = event.target.files?.[0] if (!file || !uploadTarget) return setUploading(true) const formData = new FormData() formData.append("file", file) try { const token = localStorage.getItem('token'); const headers: HeadersInit = {} if (token) headers['Authorization'] = `Bearer ${token}` const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/v1/attachment/upload`, { method: 'POST', headers, body: formData, }) const result = await response.json() if (result.code === 200 && result.data?.url) { if (uploadTarget.type === 'file') { // 多文件,存对象 const prevFiles = Array.isArray(dayPlans[uploadTarget.dayIndex].messages[uploadTarget.messageIndex].content) ? dayPlans[uploadTarget.dayIndex].messages[uploadTarget.messageIndex].content : [] handleUpdateMessage(uploadTarget.dayIndex, uploadTarget.messageIndex, { content: [...prevFiles, { url: result.data.url, name: result.data.name || result.data.url.split('/').pop() }] }) } else { handleUpdateMessage(uploadTarget.dayIndex, uploadTarget.messageIndex, { content: result.data.url }) } toast({ title: '上传成功', description: `${uploadTarget.type === 'image' ? '图片' : uploadTarget.type === 'video' ? '视频' : '文件'}上传成功` }) } else { toast({ title: '上传失败', description: result.msg || '请重试', variant: 'destructive' }) } } catch (e: any) { toast({ title: '上传失败', description: e?.message || '请重试', variant: 'destructive' }) } finally { setUploading(false) setUploadTarget(null) if (fileInputRef.current) fileInputRef.current.value = '' } } const handleUploadCover = (dayIndex: number, messageIndex: number) => { setCoverTarget({ dayIndex, messageIndex }) coverInputRef.current?.click() } const handleCoverFileChange = async ( event: React.ChangeEvent, dayIndex?: number, messageIndex?: number ) => { const file = event.target.files?.[0] if (!file || !coverTarget) return setUploadingCover(true) const formData = new FormData() formData.append("file", file) try { const token = localStorage.getItem('token') const headers: HeadersInit = {} if (token) headers['Authorization'] = `Bearer ${token}` const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/v1/attachment/upload`, { method: 'POST', headers, body: formData, }) const result = await response.json() if (result.code === 200 && result.data?.url) { handleUpdateMessage(coverTarget.dayIndex, coverTarget.messageIndex, { cover: result.data.url }) toast({ title: '上传成功', description: '封面已添加' }) } else { toast({ title: '上传失败', description: result.msg || '请重试', variant: 'destructive' }) } } catch (e: any) { toast({ title: '上传失败', description: e?.message || '请重试', variant: 'destructive' }) } finally { setUploadingCover(false) setCoverTarget(null) if (coverInputRef.current) coverInputRef.current.value = '' } } const handleRemoveCover = (dayIndex: number, messageIndex: number) => { handleUpdateMessage(dayIndex, messageIndex, { cover: "" }) } return (

消息设置

{dayPlans.map((plan) => ( {plan.day === 0 ? "即时消息" : `第${plan.day}天`} ))} {dayPlans.map((plan, dayIndex) => (
{plan.messages.map((message, messageIndex) => (
{plan.day === 0 ? ( <> handleUpdateMessage(dayIndex, messageIndex, { sendInterval: Number(e.target.value) }) } className="w-20" /> ) : ( <>
handleUpdateMessage(dayIndex, messageIndex, { scheduledTime: { ...(message.scheduledTime || { hour: 0, minute: 0, second: 0 }), hour: Number(e.target.value), }, }) } className="w-16" /> : handleUpdateMessage(dayIndex, messageIndex, { scheduledTime: { ...(message.scheduledTime || { hour: 0, minute: 0, second: 0 }), minute: Number(e.target.value), }, }) } className="w-16" /> : handleUpdateMessage(dayIndex, messageIndex, { scheduledTime: { ...(message.scheduledTime || { hour: 0, minute: 0, second: 0 }), second: Number(e.target.value), }, }) } className="w-16" />
)}
{messageTypes.map((type) => ( ))}
{message.type === "text" && (