From 0133cc0798510e1425ccd2e6967b1b244ab726fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=B7=E9=BE=99?= Date: Tue, 26 Aug 2025 15:52:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A8=E8=BF=9B=EF=BC=8C=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ChatInputBox/ChatInputBox.tsx | 129 ++++++++++++++--------- 1 file changed, 82 insertions(+), 47 deletions(-) diff --git a/components/ChatInputBox/ChatInputBox.tsx b/components/ChatInputBox/ChatInputBox.tsx index a69ace9..ee022d7 100644 --- a/components/ChatInputBox/ChatInputBox.tsx +++ b/components/ChatInputBox/ChatInputBox.tsx @@ -83,6 +83,8 @@ const RenderTemplateStoryMode = ({ const { uploadFile, isUploading } = useUploadFile(); // 本地加载状态,用于 UI 反馈 const [localLoading, setLocalLoading] = useState(0); + // 控制输入框显示状态 + const [inputVisible, setInputVisible] = useState<{ [key: string]: boolean }>({}); const router = useRouter(); // 组件挂载时获取模板列表 useEffect(() => { @@ -91,6 +93,23 @@ const RenderTemplateStoryMode = ({ } }, [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); @@ -251,13 +270,13 @@ const RenderTemplateStoryMode = ({ {/* AI生成按钮 */} + handleCreateVideo={() => { handleFieldBlur( field.field_name, field.value || "" - ) - } - + ); + setInputVisible(prev => ({ ...prev, [field.field_name]: false })); + }} icon={} width="w-8" height="h-8" @@ -269,7 +288,9 @@ const RenderTemplateStoryMode = ({ classNames={{ root: "max-w-none", }} - trigger="focus" + open={inputVisible[field.field_name]} + onOpenChange={(visible) => setInputVisible(prev => ({ ...prev, [field.field_name]: visible }))} + trigger="contextMenu" styles={{ root: { zIndex: 1000 } }} > {/* 图片 */} @@ -301,52 +322,66 @@ const RenderTemplateStoryMode = ({ - {/* 上传按钮 - 右上角 */} - { - const isImage = file.type.startsWith("image/"); - if (!isImage) { - console.error("只能上传图片文件"); - return false; - } - const isLt5M = file.size / 1024 / 1024 < 5; - if (!isLt5M) { - console.error("图片大小不能超过5MB"); - return false; - } - return true; - }} - customRequest={async ({ file, onSuccess, onError }) => { - try { - const fileObj = file as File; - const uploadedUrl = await uploadFile( - fileObj, - (progress) => { - console.log(`上传进度: ${progress}%`); - } - ); - await AvatarAndAnalyzeFeatures( - uploadedUrl, - field.field_name - ); - onSuccess?.(uploadedUrl); - } catch (error) { - console.error("字段图片上传失败:", error); - onError?.(error as Error); - } - }} - > - + {/* 按钮组 - 右上角 */} +
+ {/* AI生成按钮 */} + - + + {/* 上传按钮 */} + { + const isImage = file.type.startsWith("image/"); + if (!isImage) { + console.error("只能上传图片文件"); + return false; + } + const isLt5M = file.size / 1024 / 1024 < 5; + if (!isLt5M) { + console.error("图片大小不能超过5MB"); + return false; + } + return true; + }} + customRequest={async ({ file, onSuccess, onError }) => { + try { + const fileObj = file as File; + const uploadedUrl = await uploadFile( + fileObj, + (progress) => { + console.log(`上传进度: ${progress}%`); + } + ); + await AvatarAndAnalyzeFeatures( + uploadedUrl, + field.field_name + ); + onSuccess?.(uploadedUrl); + } catch (error) { + console.error("字段图片上传失败:", error); + onError?.(error as Error); + } + }} + > + + + + +
))}