"use client"; import { useState, useEffect } from "react"; import { Clapperboard, Sparkles, LayoutTemplate, } from "lucide-react"; import { Modal, Tooltip, Upload, Image, } from "antd"; import { UploadOutlined } from "@ant-design/icons"; import { StoryTemplateEntity } from "@/app/service/domain/Entities"; import { useTemplateStoryServiceHook } from "@/app/service/Interaction/templateStoryService"; import TemplateCard from "./templateCard"; import { useRouter } from "next/navigation"; import { useUploadFile } from "@/app/service/domain/service"; import { ActionButton } from "../common/ActionButton"; import GlobalLoad from "../common/GlobalLoad"; /** * 防抖函数 * @param {Function} func - 需要防抖的函数 * @param {number} wait - 等待时间(ms) * @returns {Function} - 防抖后的函数 */ const debounce = (func: Function, wait: number) => { let timeout: NodeJS.Timeout; return function executedFunction(...args: any[]) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; }; interface PcTemplateModalProps { isTemplateCreating: boolean; setIsTemplateCreating: (value: boolean) => void; isRoleGenerating: { [key: string]: boolean }; setIsRoleGenerating: (value: { [key: string]: boolean } | ((prev: { [key: string]: boolean }) => { [key: string]: boolean })) => void; isItemGenerating: { [key: string]: boolean }; setIsItemGenerating: (value: { [key: string]: boolean } | ((prev: { [key: string]: boolean }) => { [key: string]: boolean })) => void; isOpen: boolean; onClose: () => void; configOptions: { mode: "auto" | "manual"; resolution: "720p" | "1080p" | "4k"; language: string; videoDuration: string; }; } /** * PC端模板故事模式弹窗组件 */ export const PcTemplateModal = ({ isTemplateCreating, setIsTemplateCreating, isRoleGenerating, setIsRoleGenerating, isItemGenerating, setIsItemGenerating, isOpen, onClose, configOptions = { mode: "auto" as "auto" | "manual", resolution: "720p" as "720p" | "1080p" | "4k", language: "english", videoDuration: "1min", }, }: PcTemplateModalProps) => { // 使用 hook 管理状态 const { templateStoryList, selectedTemplate, isLoading, getTemplateStoryList, actionStory, setSelectedTemplate, AvatarAndAnalyzeFeatures, updateRoleImage, updateItemImage, handleRoleFieldBlur, handleItemFieldBlur, clearData, } = useTemplateStoryServiceHook(); // 防抖处理的输入更新函数 const debouncedUpdateInput = debounce((value: string) => { // 过滤特殊字符 const sanitizedValue = value.replace(/[<>]/g, ''); // 更新输入值 if (!selectedTemplate?.freeInputItem) return; const updatedTemplate: StoryTemplateEntity = { ...selectedTemplate, freeInputItem: { ...selectedTemplate.freeInputItem, free_input_text: sanitizedValue } }; setSelectedTemplate(updatedTemplate); }, 300); // 300ms 的防抖延迟 // 使用上传文件hook const { uploadFile, isUploading } = useUploadFile(); // 本地加载状态,用于 UI 反馈 const [localLoading, setLocalLoading] = useState(0); // 控制输入框显示状态 const [inputVisible, setInputVisible] = useState<{ [key: string]: boolean }>( {} ); const router = useRouter(); // 组件挂载时获取模板列表 useEffect(() => { if (isOpen) { getTemplateStoryList(); } }, [isOpen, getTemplateStoryList]); // 监听点击外部区域关闭输入框 useEffect(() => { const handleClickOutside = (event: MouseEvent) => { const target = event.target as Element; // 检查是否点击了输入框相关的元素 if ( !target.closest(".ant-tooltip") && !target.closest('[data-alt*="field-ai-button"]') ) { // 关闭所有打开的输入框 setInputVisible({}); } }; document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, []); // 处理模板选择 const handleTemplateSelect = (template: StoryTemplateEntity) => { setSelectedTemplate(template); }; // 处理确认操作 const handleConfirm = async () => { if (!selectedTemplate) return; if (isTemplateCreating) return; setIsTemplateCreating(true); let timer: NodeJS.Timeout | null = null; try { // 获取当前用户信息 const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); if (!User.id) { console.error("用户未登录"); return; } // 启动进度条动画 timer = setInterval(() => { setLocalLoading((prev) => { if (prev >= 95) { return 95; } return prev + 0.1; }); }, 100); setLocalLoading(1); const projectId = await actionStory( String(User.id), configOptions.mode, configOptions.resolution, configOptions.language ); if (projectId) { // 跳转到电影详情页 router.push(`/movies/work-flow?episodeId=${projectId}`); onClose(); // 重置状态 setSelectedTemplate(null); } console.log("Story action created:", projectId); } catch (error) { console.error("Failed to create story action:", error); setIsTemplateCreating(false); setLocalLoading(0); // 这里可以添加 toast 提示 // 重置状态 setSelectedTemplate(null); } finally { setLocalLoading(0); if (timer) { clearInterval(timer); } } }; // 模板列表渲染 const templateListRender = () => { return (
{selectedTemplate.generateText}
No templates available
Please try again later