import { Box, Button, Flex, Grid, useDisclosure, Text } from '@chakra-ui/react'; import React, { useMemo, useState, useCallback, useEffect, useRef } from 'react'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { useTranslation } from 'next-i18next'; import { SmallAddIcon } from '@chakra-ui/icons'; import type { AppSimpleEditFormType } from '@fastgpt/global/core/app/type'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { theme } from '@fastgpt/web/styles/theme'; import { FlowNodeInputTypeEnum, FlowNodeTypeEnum } from '@fastgpt/global/core/workflow/node/constant'; import Avatar from '@fastgpt/web/components/common/Avatar'; import { keyframes } from '@emotion/react'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import { getWebLLMModel } from '@/web/common/system/utils'; import ToolSelectModal, { childAppSystemKey } from '@/pageComponents/app/detail/Gate/components/ToolSelectModal'; import ConfigToolModal from '@/pageComponents/app/detail/Gate/components/ConfigToolModal'; // 定义粉碎动画关键帧 const shatterKeyframes = keyframes` 0% { opacity: 1; transform: scale(1); filter: blur(0); } 50% { opacity: 0.5; transform: scale(0.7) rotate(5deg) translateY(10px); filter: blur(2px); } 100% { opacity: 0; transform: scale(0.2) rotate(-5deg) translateY(15px); filter: blur(4px); } `; // 定义淡入动画关键帧 const fadeInKeyframes = keyframes` 0% { opacity: 0; } 100% { opacity: 1; } `; // 样式常量 const spacing = { xs: 2 }; const formStyles = { fontWeight: 500, fontSize: '14px', lineHeight: '20px', letterSpacing: '0.1px' }; const ToolSelect = ({ appForm, setAppForm }: { appForm: AppSimpleEditFormType; setAppForm: (newAppForm: AppSimpleEditFormType) => void; }) => { const { t } = useTranslation(); const [configTool, setConfigTool] = useState< AppSimpleEditFormType['selectedTools'][number] | null >(null); // 添加删除状态管理 const [deletingToolIds, setDeletingToolIds] = useState>(new Set()); const { isOpen: isOpenToolsSelect, onOpen: onOpenToolsSelect, onClose: onCloseToolsSelect } = useDisclosure(); const selectedModel = getWebLLMModel(appForm.aiSettings.model); // 使用 useCallback 缓存删除函数 const handleDeleteTool = useCallback( (toolId: string) => { // 先设置删除标记,触发动画 setDeletingToolIds((prev) => new Set([...prev, toolId])); // 设置延时,等待动画完成后再从数组中移除 setTimeout(() => { const newAppForm = { ...appForm, selectedTools: appForm.selectedTools.filter((tool) => tool.id !== toolId) }; setAppForm(newAppForm); // 清除删除标记 setDeletingToolIds((prev) => { const newSet = new Set(prev); newSet.delete(toolId); return newSet; }); }, 150); // 动画持续时间缩短到150ms }, [appForm, setAppForm] ); return ( <> {/* 标题区域 */} {t('common:core.app.Tool call')} {/* 已有工具时显示新增按钮 */} {appForm.selectedTools.length > 0 && ( )} {/* 工具容器 */} {appForm.selectedTools.length > 0 ? ( {appForm.selectedTools.map((item) => { const isDeleting = deletingToolIds.has(item.id); return ( { if ( item.inputs .filter((input) => !childAppSystemKey.includes(input.key)) .every( (input) => input.toolDescription || input.renderTypeList.includes(FlowNodeInputTypeEnum.selectLLMModel) || input.renderTypeList.includes(FlowNodeInputTypeEnum.fileSelect) ) || item.flowNodeType === FlowNodeTypeEnum.tool || item.flowNodeType === FlowNodeTypeEnum.toolSet ) { return; } setConfigTool(item); }} > {item.name} { e.stopPropagation(); handleDeleteTool(item.id); }} opacity="0" _groupHover={{ opacity: 1, animation: `${fadeInKeyframes} 0.2s ease` }} > ); })} ) : ( {t('common:Choose')} )} {isOpenToolsSelect && ( { const newAppForm = { ...appForm, selectedTools: [...appForm.selectedTools, e] }; setAppForm(newAppForm); }} onRemoveTool={(e) => { const newAppForm = { ...appForm, selectedTools: appForm.selectedTools.filter((item) => item.pluginId !== e.id) }; setAppForm(newAppForm); }} onClose={onCloseToolsSelect} /> )} {configTool && ( setConfigTool(null)} onAddTool={(e) => { const newAppForm = { ...appForm, selectedTools: appForm.selectedTools.map((item) => item.pluginId === configTool.pluginId ? e : item ) }; setAppForm(newAppForm); }} /> )} ); }; export default React.memo(ToolSelect);