From e27abe1f6b7f1a4b8495f00390351daf60da4a36 Mon Sep 17 00:00:00 2001 From: papapatrick <109422393+Patrickill@users.noreply.github.com> Date: Mon, 29 Jul 2024 18:36:13 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E8=BF=90=E8=A1=8C=E8=AF=A6=E6=83=85?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E4=BC=98=E5=8C=96=20(#2192)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf: 运行详情弹窗优化 * style: 调整样式 * style: 弹窗样式优化&&应用切换圆角添加 * fix: 修复编译错误 --- .../app/public/imgs/modal/wholeRecord.svg | 12 +- .../components/RenderResponseDetail.tsx | 2 +- .../chat/components/WholeResponseModal.tsx | 440 ++++++++++++++---- .../Flow/nodes/render/NodeCard.tsx | 8 +- .../src/pages/chat/components/ChatHeader.tsx | 4 +- .../chat/components/CustomPluginRunBox.tsx | 4 +- 6 files changed, 376 insertions(+), 94 deletions(-) diff --git a/projects/app/public/imgs/modal/wholeRecord.svg b/projects/app/public/imgs/modal/wholeRecord.svg index eb91469b0..c0a4afbc3 100644 --- a/projects/app/public/imgs/modal/wholeRecord.svg +++ b/projects/app/public/imgs/modal/wholeRecord.svg @@ -1 +1,11 @@ - \ No newline at end of file + + + + + + + + + + + diff --git a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderResponseDetail.tsx b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderResponseDetail.tsx index 0e6f1757e..48d572a0c 100644 --- a/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderResponseDetail.tsx +++ b/projects/app/src/components/core/chat/ChatContainer/PluginRunBox/components/RenderResponseDetail.tsx @@ -13,7 +13,7 @@ const RenderResponseDetail = () => { <>{'进行中'} ) : ( - + ); }; diff --git a/projects/app/src/components/core/chat/components/WholeResponseModal.tsx b/projects/app/src/components/core/chat/components/WholeResponseModal.tsx index 431d1251f..46bca0a2e 100644 --- a/projects/app/src/components/core/chat/components/WholeResponseModal.tsx +++ b/projects/app/src/components/core/chat/components/WholeResponseModal.tsx @@ -1,10 +1,8 @@ import React, { useMemo, useState } from 'react'; -import { Box, useTheme, Flex, Image, BoxProps } from '@chakra-ui/react'; +import { Box, Flex, BoxProps, useDisclosure } from '@chakra-ui/react'; import type { ChatHistoryItemResType } from '@fastgpt/global/core/chat/type.d'; import { useTranslation } from 'next-i18next'; import { moduleTemplatesFlat } from '@fastgpt/global/core/workflow/template/constants'; - -import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs'; import MyModal from '@fastgpt/web/components/common/MyModal'; import Markdown from '@/components/Markdown'; import { QuoteList } from '../ChatContainer/ChatBox/components/QuoteModal'; @@ -13,6 +11,17 @@ import { formatNumber } from '@fastgpt/global/common/math/tools'; import { useI18n } from '@/web/context/I18n'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import Avatar from '@fastgpt/web/components/common/Avatar'; +import { useSystem } from '@fastgpt/web/hooks/useSystem'; +import MyIcon from '@fastgpt/web/components/common/Icon'; + +type sideTabItemType = { + moduleLogo?: string; + moduleName: string; + runningTime?: number; + moduleType: string; + nodeId: string; + children: sideTabItemType[]; +}; function RowRender({ children, @@ -40,7 +49,6 @@ function Row({ value?: string | number | boolean | object; rawDom?: React.ReactNode; }) { - const theme = useTheme(); const val = value || rawDom; const isObject = typeof value === 'object'; @@ -66,9 +74,9 @@ function Row({ label={label} mb={isObject ? 0 : 1} {...(isObject - ? { transform: 'translateY(-3px)' } + ? { py: 2, transform: 'translateY(-3px)' } : value - ? { px: 3, py: 2, border: theme.borders.base } + ? { px: 3, py: 2, border: 'base' } : {})} > @@ -93,7 +101,8 @@ const WholeResponseModal = ({ isOpen={true} onClose={onClose} h={['90vh', '80vh']} - minW={['90vw', '600px']} + maxH={['90vh', '700px']} + minW={['90vw', '880px']} iconSrc="/imgs/modal/wholeRecord.svg" title={ @@ -112,59 +121,138 @@ export default WholeResponseModal; export const ResponseBox = React.memo(function ResponseBox({ response, showDetail, - hideTabs = false + hideTabs = false, + useMobile = false }: { response: ChatHistoryItemResType[]; showDetail: boolean; hideTabs?: boolean; + useMobile?: boolean; }) { - const theme = useTheme(); + const { t } = useTranslation(); + const { isPc } = useSystem(); + const flattedResponse = useMemo(() => flattenArray(response), [response]); + const [currentNodeId, setCurrentNodeId] = useState( + flattedResponse[0]?.nodeId ? flattedResponse[0].nodeId : '' + ); + const activeModule = useMemo( + () => flattedResponse.find((item) => item.nodeId === currentNodeId) as ChatHistoryItemResType, + [currentNodeId, flattedResponse] + ); + const sideResponse: sideTabItemType[] = useMemo(() => { + return pretreatmentResponse(response); + }, [response]); + const { + isOpen: isOpenMobileModal, + onOpen: onOpenMobileModal, + onClose: onCloseMobileModal + } = useDisclosure(); + + return ( + <> + {isPc && !useMobile ? ( + + + + + + + + + + + ) : ( + <> + + {!isOpenMobileModal && ( + + { + setCurrentNodeId(item); + onOpenMobileModal(); + }} + isMobile={true} + /> + + )} + {isOpenMobileModal && ( + + + { + e.stopPropagation(); + onCloseMobileModal(); + }} + position={'absolute'} + left={2} + top={'50%'} + transform={'translateY(-50%)'} + /> + + activeModule.moduleType === template.flowNodeType + )?.avatar + } + w={'1.25rem'} + h={'1.25rem'} + borderRadius={'sm'} + /> + + + {t(activeModule.moduleName as any)} + + + + + )} + + + )} + + ); +}); + +const WholeResponseContent = ({ + activeModule, + hideTabs, + showDetail +}: { + activeModule: ChatHistoryItemResType; + hideTabs?: boolean; + showDetail: boolean; +}) => { const { t } = useTranslation(); const { workflowT } = useI18n(); - const list = useMemo( - () => - response.map((item, i) => ({ - label: ( - - item.moduleType === template.flowNodeType) - ?.avatar - } - alt={''} - w={'1.25rem'} - borderRadius={'sm'} - /> - {t(item.moduleName as any)} - - ), - value: `${i}` - })), - [response, t] - ); - - const [currentTab, setCurrentTab] = useState(`0`); - - const activeModule = useMemo(() => response[Number(currentTab)], [currentTab, response]); - return ( - - {!hideTabs && ( - - - - )} + <> {activeModule && ( + {/* common info */} <> - {/* ai chat */} <> + {activeModule.historyPreview?.map((item, i) => ( - {/* dataset search */} <> {activeModule?.searchMode && ( @@ -279,7 +366,6 @@ export const ResponseBox = React.memo(function ResponseBox({ /> )} - {/* classify question */} <> - {/* if-else */} <> - {/* extract */} <> - {/* http */} <> @@ -325,49 +408,236 @@ export const ResponseBox = React.memo(function ResponseBox({ value={activeModule?.httpResult} /> - {/* plugin */} <> - {activeModule?.pluginDetail && activeModule?.pluginDetail.length > 0 && ( - - - - } - /> - )} - {/* text output */} - - {/* tool call */} - {activeModule?.toolDetail && activeModule?.toolDetail.length > 0 && ( - - - - } - /> - )} - {/* code */} )} - + ); -}); +}; + +const WholeResponseSideTab = ({ + response, + value, + onChange, + isMobile = false +}: { + response: sideTabItemType[]; + value: string; + onChange: (index: string) => void; + isMobile?: boolean; +}) => { + return ( + <> + {response.map((item) => ( + + + + ))} + + ); +}; + +const AccordionSideTabItem = ({ + sideBarItem, + onChange, + value, + index +}: { + sideBarItem: sideTabItemType; + onChange: (nodeId: string) => void; + value: string; + index: number; +}) => { + const { isOpen: isShowAccordion, onToggle: onToggleShowAccordion } = useDisclosure({ + defaultIsOpen: false + }); + return ( + <> + + + { + e.stopPropagation(); + onToggleShowAccordion(); + }} + _hover={{ color: 'primary.600', cursor: 'pointer' }} + /> + + + {isShowAccordion && ( + + {sideBarItem.children.map((item) => ( + + ))} + + )} + + ); +}; + +const NormalSideTabItem = ({ + sideBarItem, + onChange, + value, + index, + children +}: { + sideBarItem: sideTabItemType; + onChange: (nodeId: string) => void; + value: string; + index: number; + children?: React.ReactNode; +}) => { + const { t } = useTranslation(); + const leftIndex = index > 3 ? 3 : index; + return ( + { + onChange(sideBarItem.nodeId); + }} + background={value === sideBarItem.nodeId ? 'myGray.100' : ''} + _hover={{ background: 'myGray.100' }} + p={2} + width={'100%'} + cursor={'pointer'} + pl={leftIndex === 0 ? '0.5rem' : `${1.5 * leftIndex + 0.5}rem`} + borderRadius={'md'} + position={'relative'} + > + sideBarItem.moduleType === template.flowNodeType) + ?.avatar + } + alt={''} + w={'1.5rem'} + h={'1.5rem'} + borderRadius={'sm'} + /> + + + {t(sideBarItem.moduleName as any)} + + + {t(sideBarItem.runningTime as any) + 's'} + + + + {children} + + + ); +}; + +const SideTabItem = ({ + sideBarItem, + onChange, + value, + index +}: { + sideBarItem: sideTabItemType; + onChange: (nodeId: string) => void; + value: string; + index: number; +}) => { + if (!sideBarItem) return null; + return sideBarItem.children.length !== 0 ? ( + <> + + + + + ) : ( + + ); +}; + +function pretreatmentResponse(res: ChatHistoryItemResType[]): sideTabItemType[] { + return res.map((item) => { + let children: sideTabItemType[] = []; + if (!!(item?.toolDetail || item?.pluginDetail)) { + if (item?.toolDetail) children.push(...pretreatmentResponse(item?.toolDetail)); + if (item?.pluginDetail) children.push(...pretreatmentResponse(item?.pluginDetail)); + } + + return { + moduleLogo: item.moduleLogo, + moduleName: item.moduleName, + runningTime: item.runningTime, + moduleType: item.moduleType, + nodeId: item.nodeId, + children + }; + }); +} + +function flattenArray(arr: ChatHistoryItemResType[]) { + const result: ChatHistoryItemResType[] = []; + + function helper(currentArray: ChatHistoryItemResType[]) { + currentArray.forEach((item) => { + if (item && typeof item === 'object') { + result.push(item); + + if (Array.isArray(item.toolDetail)) { + helper(item.toolDetail); + } + if (Array.isArray(item.pluginDetail)) { + helper(item.pluginDetail); + } + } + }); + } + + helper(arr); + return result; +} diff --git a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx index 77e74e397..36b5059d0 100644 --- a/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx +++ b/projects/app/src/pages/app/detail/components/WorkflowComponents/Flow/nodes/render/NodeCard.tsx @@ -573,8 +573,8 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({ top={0} zIndex={10} w={'420px'} - maxH={'100%'} minH={'300px'} + maxH={'100%'} border={'base'} > {/* Status header */} @@ -614,7 +614,7 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({ )} {/* Show result */} - + {!debugResult.message && !response && ( )} @@ -623,7 +623,9 @@ const NodeDebugResponse = React.memo(function NodeDebugResponse({ {debugResult.message} )} - {response && } + {response && ( + + )} )} diff --git a/projects/app/src/pages/chat/components/ChatHeader.tsx b/projects/app/src/pages/chat/components/ChatHeader.tsx index ed3bebf55..6e3f18fc0 100644 --- a/projects/app/src/pages/chat/components/ChatHeader.tsx +++ b/projects/app/src/pages/chat/components/ChatHeader.tsx @@ -174,7 +174,7 @@ const MobileDrawer = ({ onClick: () => onclickApp(item._id) })} > - + {item.name} @@ -223,7 +223,7 @@ const MobileHeader = ({ )} - + {name} diff --git a/projects/app/src/pages/chat/components/CustomPluginRunBox.tsx b/projects/app/src/pages/chat/components/CustomPluginRunBox.tsx index 31d115a3d..b83b1d5e3 100644 --- a/projects/app/src/pages/chat/components/CustomPluginRunBox.tsx +++ b/projects/app/src/pages/chat/components/CustomPluginRunBox.tsx @@ -27,7 +27,7 @@ const CustomPluginRunBox = (props: PluginRunBoxProps) => { - + list={[ { label: t('common:common.Output'), value: PluginRunBoxTabEnum.output }, @@ -61,7 +61,7 @@ const CustomPluginRunBox = (props: PluginRunBoxProps) => { py={0} fontSize={'sm'} /> - +