From 260ce49cda0bdef661c0484ad523a196dc93a128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sat, 6 Sep 2025 23:57:13 +0800 Subject: [PATCH] =?UTF-8?q?mock=20=E7=99=BE=E7=A7=91=E5=85=A8=E4=B9=A6?= =?UTF-8?q?=E6=A8=A1=E7=89=88=20=E6=94=AF=E6=8C=81=E8=BE=93=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Interaction/templateStoryService.ts | 11 ++- app/service/domain/Entities.ts | 9 +++ components/ChatInputBox/ChatInputBox.tsx | 68 ++++++++++++++++++- components/pages/work-flow/media-viewer.tsx | 1 + 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/app/service/Interaction/templateStoryService.ts b/app/service/Interaction/templateStoryService.ts index 89dacc4..c946d4b 100644 --- a/app/service/Interaction/templateStoryService.ts +++ b/app/service/Interaction/templateStoryService.ts @@ -68,6 +68,15 @@ export const useTemplateStoryServiceHook = (): UseTemplateStoryService => { setIsLoading(true); const templates = await templateStoryUseCase.getTemplateStoryList(); + templates.forEach(template => { + if (template.template_id === '69') { + template.freeInputItem = { + user_tips: "How is coffee made?", + constraints: "", + free_input_text: "" + }; + } + }); setTemplateStoryList(templates); setSelectedTemplate(templates[0]); @@ -237,7 +246,7 @@ export const useTemplateStoryServiceHook = (): UseTemplateStoryService => { setIsLoading(true); const params: CreateMovieProjectV3Request = { - script: selectedTemplate?.generateText || "", + script: selectedTemplate?.freeInputItem?.free_input_text || selectedTemplate?.generateText || "", category: selectedTemplate?.category || "", user_id, mode, diff --git a/app/service/domain/Entities.ts b/app/service/domain/Entities.ts index da780fd..0f26ff8 100644 --- a/app/service/domain/Entities.ts +++ b/app/service/domain/Entities.ts @@ -172,4 +172,13 @@ export interface StoryTemplateEntity { /** 道具照片URL */ photo_url: string; }[]; + /** 自由输入文字 */ + freeInputItem?: { + /** 用户提示,提示给用户需要输入什么内容 */ + user_tips: string; + /** 约束,可选,用于传给ai,让ai去拦截用户不符合约束的输入内容 */ + constraints: string; + /** 自由输入文字 */ + free_input_text: string; + } } diff --git a/components/ChatInputBox/ChatInputBox.tsx b/components/ChatInputBox/ChatInputBox.tsx index c32b6e0..a0113b7 100644 --- a/components/ChatInputBox/ChatInputBox.tsx +++ b/components/ChatInputBox/ChatInputBox.tsx @@ -46,6 +46,24 @@ import { HighlightEditor } from "../common/HighlightEditor"; 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); + }; +}; + const RenderTemplateStoryMode = ({ isTemplateCreating, setIsTemplateCreating, @@ -93,6 +111,22 @@ const RenderTemplateStoryMode = ({ 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 反馈 @@ -258,6 +292,7 @@ const RenderTemplateStoryMode = ({ + {/* 角色配置区域 */} {selectedTemplate?.storyRole && selectedTemplate.storyRole.length > 0 && ( @@ -755,7 +790,38 @@ const RenderTemplateStoryMode = ({ */} -
+
+ {/** 自由输入文字 */} + {(selectedTemplate?.freeInputItem) && ( +
+ { + const value = e.target.value; + // 限制输入长度为500字符 + if (value.length > 500) { + return; + } + // 立即更新UI显示 + if (!selectedTemplate?.freeInputItem) return; + const updatedTemplate: StoryTemplateEntity = { + ...selectedTemplate, + freeInputItem: { + ...selectedTemplate.freeInputItem, + free_input_text: value + } + }; + setSelectedTemplate(updatedTemplate); + // 使用防抖函数处理实际的状态更新 + debouncedUpdateInput(value); + }} + maxLength={500} + /> +
+ )} 0} handleCreateVideo={handleConfirm} diff --git a/components/pages/work-flow/media-viewer.tsx b/components/pages/work-flow/media-viewer.tsx index 419f9ed..9f0f90f 100644 --- a/components/pages/work-flow/media-viewer.tsx +++ b/components/pages/work-flow/media-viewer.tsx @@ -427,6 +427,7 @@ export const MediaViewer = React.memo(function MediaViewer({ // 渲染视频内容 const renderVideoContent = (onGotoCut: () => void) => { + if (!taskObject.videos.data[currentSketchIndex]) return null; const urls = taskObject.videos.data[currentSketchIndex]?.urls ? taskObject.videos.data[currentSketchIndex]?.urls.join(',') : ''; return (