"use client"; import { useState, useEffect, useRef } from "react"; import { ChevronDown, ChevronUp, Video, Loader2, Lightbulb, Package, Crown, Clapperboard, Globe, Clock, Trash2, LayoutTemplate, ImagePlay, Sparkles, Settings, MoreHorizontal, } from "lucide-react"; import { Dropdown, Modal, Tooltip, Upload, Popconfirm, Image, Popover, Switch, } from "antd"; import { UploadOutlined } from "@ant-design/icons"; import { StoryTemplateEntity } from "@/app/service/domain/Entities"; import { useImageStoryServiceHook } from "@/app/service/Interaction/ImageStoryService"; import TemplateCard from "./templateCard"; import { AudioRecorder } from "./AudioRecorder"; import { useTemplateStoryServiceHook } from "@/app/service/Interaction/templateStoryService"; import { useRouter } from "next/navigation"; import { createMovieProjectV1 } from "@/api/video_flow"; import { MovieProjectService, MovieProjectMode, } from "@/app/service/Interaction/MovieProjectService"; import { useLoadScriptText, useUploadFile } from "@/app/service/domain/service"; import { ActionButton } from "../common/ActionButton"; import { HighlightEditor } from "../common/HighlightEditor"; import GlobalLoad from "../common/GlobalLoad"; import { useDeviceType } from '@/hooks/useDeviceType'; import { PcTemplateModal } from "./PcTemplateModal"; import { H5TemplateDrawer } from "./H5TemplateDrawer"; import { PcPhotoStoryModal } from "./PcPhotoStoryModal"; import { H5PhotoStoryDrawer } from "./H5PhotoStoryDrawer"; import { AspectRatioSelector, AspectRatioValue } from "./AspectRatioSelector"; const LauguageOptions = [ { value: "english", label: "English", isVip: false, code:'EN' }, { value: "chinese", label: "Chinese", isVip: false, code:'ZH' }, { value: "japanese", label: "Japanese", isVip: false, code:'JA' }, { value: "spanish", label: "Spanish", isVip: false, code:'ES' }, { value: "portuguese", label: "Portuguese", isVip: false, code:'PT' }, { value: "hindi", label: "Hindi", isVip: false, code:'HI' }, { value: "korean", label: "Korean", isVip: false, code:'KO' }, { value: "arabic", label: "Arabic", isVip: false, code:'AR' }, { value: "russian", label: "Russian", isVip: false, code:'RU' }, { value: "thai", label: "Thai", isVip: false, code:'TH' }, { value: "french", label: "French", isVip: false, code:'FR' }, { value: "german", label: "German", isVip: false, code:'DE' }, { value: "vietnamese", label: "Vietnamese", isVip: false, code:'VI' }, { value: "indonesian", label: "Indonesian", isVip: false, code:'ID' } ] const VideoDurationOptions = [ { value: "8s", label: "8s" }, { value: "1min", label: "1min" }, { value: "2min", label: "2min" }, { value: "unlimited", label: "auto" }, ]; // aspect ratio options moved to reusable component /**模板故事模式弹窗组件 */ /** * 防抖函数 * @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); }; }; /** * 视频工具面板组件 * 提供脚本输入和视频克隆两种模式,支持展开/收起功能 */ export function ChatInputBox({ noData }: { noData: boolean }) { const { isMobile, isDesktop } = useDeviceType(); // 控制面板展开/收起状态 const [isExpanded, setIsExpanded] = useState(false); // 模板故事弹窗状态 const [isTemplateModalOpen, setIsTemplateModalOpen] = useState(false); // 图片故事弹窗状态 const [isPhotoStoryModalOpen, setIsPhotoStoryModalOpen] = useState(false); // 共享状态 - 需要在不同渲染函数间共享 const [script, setScript] = useState(""); // 用户输入的脚本内容 const router = useRouter(); const [loadingIdea, setLoadingIdea] = useState(false); // 获取创意建议时的加载状态 // 各种操作的加载状态 const [isCreating, setIsCreating] = useState(false); // 主视频创建按钮的加载状态 const [isTemplateCreating, setIsTemplateCreating] = useState(false); // 模板故事创建按钮的加载状态 const [isPhotoCreating, setIsPhotoCreating] = useState(false); // 图片故事创建按钮的加载状态 const [isRoleGenerating, setIsRoleGenerating] = useState<{[key: string]: boolean}>({}); // 角色AI生成按钮的加载状态 const [isItemGenerating, setIsItemGenerating] = useState<{[key: string]: boolean}>({}); // 道具AI生成按钮的加载状态 // 配置选项状态 - 整合所有配置项到一个对象 type ConfigOptions = { mode: "auto" | "manual"; resolution: "720p" | "1080p" | "4k"; language: string; videoDuration: string; expansion_mode: boolean; aspect_ratio: AspectRatioValue; }; const [configOptions, setConfigOptions] = useState({ mode: "auto", resolution: "720p", language: "english", videoDuration: "unlimited", expansion_mode: true, aspect_ratio: "VIDEO_ASPECT_RATIO_LANDSCAPE", }); // 从 localStorage 初始化配置 useEffect(() => { const savedConfig = localStorage.getItem('videoFlowConfig'); if (savedConfig) { try { const parsed = JSON.parse(savedConfig); setConfigOptions({ mode: parsed.mode || "auto", resolution: parsed.resolution || "720p", language: parsed.language || "english", videoDuration: parsed.videoDuration || "unlimited", expansion_mode: typeof parsed.expansion_mode === 'boolean' ? parsed.expansion_mode : true, aspect_ratio: parsed.aspect_ratio || "VIDEO_ASPECT_RATIO_LANDSCAPE", }); } catch (error) { console.warn('解析保存的配置失败,使用默认配置:', error); } } }, []); const onConfigChange = (key: K, value: ConfigOptions[K]) => { setConfigOptions((prev) => ({ ...prev, [key]: value, })); if (key === 'videoDuration') { // 当选择 8s 时,强制关闭剧本扩展并禁用开关 if (value === '8s') { setConfigOptions((prev) => ({ ...prev, expansion_mode: false, })); } else { setConfigOptions((prev) => ({ ...prev, expansion_mode: true, })); } } }; const handleCreateVideo = async () => { if (isCreating) return; // 如果正在创建中,直接返回 if (!script) { console.warn("请输入剧本内容"); return; } setIsCreating(true); // 设置创建状态为 true,按钮会显示 loading 状态 try { const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); if (!User.id) { console.error("用户未登录"); return; } // 创建剧集数据 let episodeData: any = { user_id: String(User.id), script: script, mode: configOptions.mode, resolution: configOptions.resolution, language: configOptions.language, video_duration: configOptions.videoDuration, expansion_mode: configOptions.expansion_mode, aspect_ratio: configOptions.aspect_ratio, }; // 调用创建剧集API const result = await MovieProjectService.createProject( MovieProjectMode.NORMAL, episodeData ); const episodeId = result.project_id; router.push(`/movies/work-flow?episodeId=${episodeId}`); } catch (error) { console.error("创建剧集失败:", error); } finally { setIsCreating(false); // 无论成功还是失败,都重置创建状态 } }; return (
{/* 视频故事板工具面板 - 毛玻璃效果背景 */}
{/* 展开/收起控制区域 */} {!noData && ( <> {isExpanded ? ( // 展开状态:显示收起按钮和提示
setIsExpanded(false)} > Click to act
) : ( // 收起状态:显示展开按钮
setIsExpanded(true)} >
)} )} {/* 主要内容区域 - 简化层级,垂直居中 */}
{/* 输入框和Action按钮 - 只在展开状态显示 */} {!isExpanded && (
{/* 第一行:输入框 */}
{/* 文本输入框 - 改为textarea */}