"use client"; import { useState, useRef, useEffect } from "react"; import { ChevronDown, ChevronUp, Video, Loader2, Lightbulb, Package, Crown, Clapperboard, Globe, AudioLines, Clock, Trash2, Plus, LayoutTemplate, ImagePlay, Sparkles, RotateCcw, Settings, } from "lucide-react"; import { Dropdown, Modal, Tooltip, Upload, Image, Spin } from "antd"; import { PlusOutlined, UploadOutlined, EyeOutlined } 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 { createScriptEpisodeNew } from "@/api/script_episode"; import { useRouter } from "next/navigation"; import { EditorContent, useEditor } from "@tiptap/react"; import StarterKit from "@tiptap/starter-kit"; import { HighlightTextExtension } from "@/components/ui/main-editor/HighlightText"; import Placeholder from "@tiptap/extension-placeholder"; import { createMovieProjectV1 } from "@/api/video_flow"; import { useLoadScriptText, useUploadFile } from "@/app/service/domain/service"; // 自定义音频播放器样式 const customAudioPlayerStyles = ` .custom-audio-player { background: rgba(255, 255, 255, 0.05) !important; border-radius: 8px !important; border: 1px solid rgba(255, 255, 255, 0.1) !important; } .custom-audio-player .rhap_main-controls-button { color: white !important; } .custom-audio-player .rhap_progress-filled { background-color: #3b82f6 !important; } .custom-audio-player .rhap_progress-indicator { background-color: #3b82f6 !important; } .custom-audio-player .rhap_time { color: rgba(255, 255, 255, 0.7) !important; } .custom-audio-player .rhap_volume-controls { color: white !important; } /* 模式选择下拉菜单样式 */ .mode-dropdown .ant-dropdown-menu { background: rgba(255, 255, 255, 0.08) !important; backdrop-filter: blur(20px) !important; border: 1px solid rgba(255, 255, 255, 0.12) !important; border-radius: 10px !important; padding: 6px !important; min-width: 160px !important; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important; } .mode-dropdown .ant-dropdown-menu-item { padding: 6px 10px !important; border-radius: 6px !important; color: rgba(255, 255, 255, 0.9) !important; transition: all 0.2s ease !important; margin-bottom: 3px !important; } .mode-dropdown .ant-dropdown-menu-item:hover { background: rgba(255, 255, 255, 0.15) !important; transform: translateX(4px) !important; } .mode-dropdown .ant-dropdown-menu-item:last-child { margin-bottom: 0 !important; } /* 模式提示tooltip样式 */ .mode-tooltip .ant-tooltip-inner { background: rgba(0, 0, 0, 0.8) !important; backdrop-filter: blur(10px) !important; border: 1px solid rgba(255, 255, 255, 0.1) !important; border-radius: 8px !important; color: white !important; font-size: 12px !important; line-height: 1.4 !important; max-width: 200px !important; } .mode-tooltip .ant-tooltip-arrow::before { background: rgba(0, 0, 0, 0.8) !important; border: 1px solid rgba(255, 255, 255, 0.1) !important; } /* 模板卡片样式 */ .line-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; } /* 自定义滚动条 */ .template-list-scroll::-webkit-scrollbar { width: 4px; } .template-list-scroll::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.05); border-radius: 2px; } .template-list-scroll::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.2); border-radius: 2px; } .template-list-scroll::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.3); } /* 自定义缩放类 */ .scale-102 { transform: scale(1.02); } /* 文本截断类 */ .line-clamp-3 { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; } `; /**模板故事模式弹窗组件 */ const RenderTemplateStoryMode = ({ isOpen, onClose, }: { isOpen: boolean; onClose: () => void; }) => { // 使用 hook 管理状态 const { templateStoryList, selectedTemplate, activeRoleIndex, activeRole, isLoading, getTemplateStoryList, actionStory, setSelectedTemplate, setActiveRoleIndex, setActiveRoleImage, setActiveRoleAudio, } = useTemplateStoryServiceHook(); // 本地加载状态,用于 UI 反馈 const [localLoading, setLocalLoading] = useState(false); // 组件挂载时获取模板列表 useEffect(() => { if (isOpen) { getTemplateStoryList(); } }, [isOpen, getTemplateStoryList]); // 处理模板选择 const handleTemplateSelect = (template: StoryTemplateEntity) => { setSelectedTemplate(template); setActiveRoleIndex(0); // 重置角色选择 }; // 处理确认操作 const handleConfirm = async () => { if (!selectedTemplate) return; try { setLocalLoading(true); const projectId = await actionStory(); console.log("Story action created:", projectId); onClose(); // 重置状态 setSelectedTemplate(null); setActiveRoleIndex(0); } catch (error) { console.error("Failed to create story action:", error); // 这里可以添加 toast 提示 } finally { setLocalLoading(false); } }; // 处理角色图片上传 const handleRoleImageUpload = (roleIndex: number, file: any) => { if (file && selectedTemplate) { // 模拟上传成功,设置图片URL const imageUrl = URL.createObjectURL(file); setActiveRoleImage(imageUrl); } }; // 删除角色图片 const handleDeleteRoleImage = (roleIndex: number) => { if (selectedTemplate) { setActiveRoleImage(""); } }; // 模板列表渲染 const templateListRender = () => { return (

Story Templates

{templateStoryList.map((template, index) => (
handleTemplateSelect(template)} >
))}
); }; // 故事编辑器渲染 const storyEditorRender = () => { return isLoading ? (
) : selectedTemplate ? (
{/* 模板信息头部 - 增加顶部空间 */}
{/* 左侧图片 */}
{selectedTemplate.name}
{/* 右侧信息 - 增加文本渲染空间 */}

{selectedTemplate.name}

{selectedTemplate.generateText}

{/* 角色自定义部分 - 精简布局 */}

Character Customization

{/* 紧凑布局 */}
{/* 左侧:当前选中角色的音频与照片更改 - 精简版本 */}
{/* 图片上传部分 - 精简 */}
false} onChange={(info) => { if (info.file.status === "done") { handleRoleImageUpload( activeRoleIndex, info.file.originFileObj ); } }} > {activeRole?.photo_url ? (
Character Portrait
Change Photo
) : (
Upload Photo
)}
{/* 音频部分 - 精简版本 */}
{/* 音频操作区域 - 使用新的 AudioRecorder 组件 */}
{ setActiveRoleAudio(audioUrl); }} onAudioDeleted={() => { setActiveRoleAudio(""); }} />
{/* 右侧:角色图片缩略图列表 - 精简 */}

Characters

{selectedTemplate.storyRole.map((role, index: number) => ( ))}
{/* 弹窗底部操作 - 只保留 Action 按钮 */}
) : (

No templates available

Please try again later

); }; return ( <> { // 清空所有选中的内容数据 setSelectedTemplate(null); setActiveRoleIndex(0); onClose(); }} footer={null} width="60%" style={{ maxWidth: "800px", marginTop: "10vh" }} className="template-modal" closeIcon={
×
} >
{/* 弹窗头部 */}

Template Story Selection

{templateListRender()}
{storyEditorRender()}
); }; /** * 视频工具面板组件 * 提供脚本输入和视频克隆两种模式,支持展开/收起功能 */ export function ChatInputBox() { // 控制面板展开/收起状态 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 [configOptions, setConfigOptions] = useState<{ mode: "auto" | "manual"; resolution: "720p" | "1080p" | "4k"; language: string; videoDuration: string; }>({ mode: "auto", resolution: "720p", language: "english", videoDuration: "1min", }); // 配置项显示控制状态 const [showConfigOptions, setShowConfigOptions] = useState(false); const handleGetIdea = () => { if (loadingIdea) return; setLoadingIdea(true); const ideaText = "a cute capybara with an orange on its head, staring into the distance and walking forward"; setTimeout(() => { setScript(ideaText); setLoadingIdea(false); }, 3000); }; // Handle creating video const handleCreateVideo = async () => { setIsCreating(true); if (!script) { setIsCreating(false); return; } const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); // 创建剧集数据 let episodeData: any = { user_id: String(User.id), script: script, mode: configOptions.mode, resolution: configOptions.resolution, language: configOptions.language, video_duration: configOptions.videoDuration, }; // 调用创建剧集API const episodeResponse = await createMovieProjectV1(episodeData); console.log("episodeResponse", episodeResponse); if (episodeResponse.code !== 0) { console.error(`创建剧集失败: ${episodeResponse.message}`); alert(`创建剧集失败: ${episodeResponse.message}`); return; } let episodeId = episodeResponse.data.project_id; // let episodeId = '9c34fcc4-c8d8-44fc-879e-9bd56f608c76'; router.push(`/create/work-flow?episodeId=${episodeId}`); setIsCreating(false); }; return (
{/* 视频故事板工具面板 - 毛玻璃效果背景 */}
{/* 展开/收起控制区域 */} {isExpanded ? ( // 展开状态:显示收起按钮和提示
setIsExpanded(false)} > Click to action
) : ( // 收起状态:显示展开按钮
setIsExpanded(true)} >
)} {/* 主要内容区域 - 简化层级,垂直居中 */}
{/* 右上角齿轮图标和配置项 */} {!isExpanded && (
{/* 使用 Dropdown 替代手动控制显示/隐藏 */} (
setConfigOptions((prev) => ({ ...prev, [key]: value })) } />
)} placement={"left" as any} trigger={["click"]} > {/* 配置项显示控制按钮 - 齿轮图标 */}
)} {/* 输入框和Action按钮 - 只在展开状态显示 */} {!isExpanded && (
{/* 第一行:输入框 */}
{/* 文本输入框 - 改为textarea */}