Commit abcf48d5 by papapatrick Committed by GitHub

perf: switch perf (#2131)

* feat:  新增对话框底部复制按钮

* fix: 对话框底部复制按钮定位问题

* perf: 优化应用切换逻辑

* perf: 删除不必要代码

* fix: 修复编译失败bug&&修复冲突错误

* feat:  新增对话框底部复制按钮

* fix: 对话框底部复制按钮定位问题

* feat: 过长引用折叠功能

* merge: 合并主仓库代码

* refactor:  删除不必要代码

* perf: 优化应用切换逻辑

* perf: 删除不必要代码

* fix: 修复编译失败bug&&修复冲突错误

* merge

* merge: 处理冲突

* refactor: 重构代码删除不必要代码

* perf: 删除不必要代码
parent bf5145e6
...@@ -97,6 +97,8 @@ export const iconPaths = { ...@@ -97,6 +97,8 @@ export const iconPaths = {
'core/app/variable/textarea': () => import('./icons/core/app/variable/textarea.svg'), 'core/app/variable/textarea': () => import('./icons/core/app/variable/textarea.svg'),
'core/chat/QGFill': () => import('./icons/core/chat/QGFill.svg'), 'core/chat/QGFill': () => import('./icons/core/chat/QGFill.svg'),
'core/chat/cancelSpeak': () => import('./icons/core/chat/cancelSpeak.svg'), 'core/chat/cancelSpeak': () => import('./icons/core/chat/cancelSpeak.svg'),
'core/chat/chevronSelector': () => import('./icons/core/chat/chevronSelector.svg'),
'core/chat/sideLine': () => import('./icons/core/chat/sideLine.svg'),
'core/chat/chatFill': () => import('./icons/core/chat/chatFill.svg'), 'core/chat/chatFill': () => import('./icons/core/chat/chatFill.svg'),
'core/chat/chatLight': () => import('./icons/core/chat/chatLight.svg'), 'core/chat/chatLight': () => import('./icons/core/chat/chatLight.svg'),
'core/chat/chatModelTag': () => import('./icons/core/chat/chatModelTag.svg'), 'core/chat/chatModelTag': () => import('./icons/core/chat/chatModelTag.svg'),
......
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.28082 5.72828C6.95538 6.05372 6.95538 6.58136 7.28082 6.90679C7.60626 7.23223 8.1339 7.23223 8.45933 6.90679L10.5 4.86615L12.5406 6.90679C12.8661 7.23223 13.3937 7.23223 13.7191 6.90679C14.0446 6.58136 14.0446 6.05372 13.7191 5.72828L11.0892 3.09839C10.7638 2.77295 10.2362 2.77295 9.91072 3.09839L7.28082 5.72828ZM7.28082 13.0893C6.95538 13.4147 6.95538 13.9424 7.28082 14.2678L9.91072 16.8977C9.9514 16.9384 9.99524 16.974 10.0414 17.0045C10.3649 17.2181 10.8045 17.1825 11.0892 16.8977L13.7191 14.2678C14.0446 13.9424 14.0446 13.4147 13.7191 13.0893C13.3937 12.7639 12.8661 12.7639 12.5406 13.0893L10.5 15.1299L8.45933 13.0893C8.1339 12.7639 7.60626 12.7639 7.28082 13.0893Z"/>
</svg>
<svg width="4" height="14" viewBox="0 0 4 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<line x1="2" y1="2" x2="2" y2="12" stroke="#3370FF" stroke-width="4" stroke-linecap="round"/>
</svg>
{ {
"add_new": "Add new", "add_new": "Add new",
"App": "App", "App": "App",
"all_apps": "All Apps",
"click_to_resume": "Resume", "click_to_resume": "Resume",
"code_editor": "Code edit", "code_editor": "Code edit",
"Export": "Export", "Export": "Export",
......
{ {
"add_new": "新增", "add_new": "新增",
"App": "应用", "App": "应用",
"all_apps": "全部应用",
"click_to_resume": "点击恢复", "click_to_resume": "点击恢复",
"code_editor": "代码编辑", "code_editor": "代码编辑",
"Export": "导出", "Export": "导出",
......
import React from 'react'; import React, { useState, useCallback } from 'react';
import { Flex, useTheme, Box } from '@chakra-ui/react'; import { Flex, useTheme, Box, useDisclosure } from '@chakra-ui/react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import Avatar from '@fastgpt/web/components/common/Avatar'; import Avatar from '@fastgpt/web/components/common/Avatar';
import ToolMenu from './ToolMenu'; import ToolMenu from './ToolMenu';
import type { ChatItemType } from '@fastgpt/global/core/chat/type'; import type { ChatItemType } from '@fastgpt/global/core/chat/type';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import MyTag from '@fastgpt/web/components/common/Tag/index'; import MyTag from '@fastgpt/web/components/common/Tag/index';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
import { ChatContext } from '@/web/core/chat/context/chatContext'; import { ChatContext } from '@/web/core/chat/context/chatContext';
...@@ -13,47 +13,273 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; ...@@ -13,47 +13,273 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import { InitChatResponse } from '@/global/core/chat/api'; import { InitChatResponse } from '@/global/core/chat/api';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants'; import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import { useRouter } from 'next/router';
import { AppListItemType } from '@fastgpt/global/core/app/type';
import {
GetResourceFolderListProps,
GetResourceListItemResponse
} from '@fastgpt/global/common/parentFolder/type';
import { getMyApps } from '@/web/core/app/api';
import SelectOneResource from '@/components/common/folder/SelectOneResource';
const ChatHeader = ({ const ChatHeader = ({
chatData, chatData,
history, history,
showHistory, showHistory,
onRoute2AppDetail onRoute2AppDetail,
apps
}: { }: {
chatData: InitChatResponse;
history: ChatItemType[]; history: ChatItemType[];
showHistory?: boolean; showHistory?: boolean;
onRoute2AppDetail?: () => void; onRoute2AppDetail?: () => void;
apps?: AppListItemType[];
chatData: InitChatResponse;
}) => { }) => {
const theme = useTheme();
const { t } = useTranslation();
const { isPc } = useSystem();
const chatModels = chatData.app.chatModels;
const isPlugin = chatData.app.type === AppTypeEnum.plugin; const isPlugin = chatData.app.type === AppTypeEnum.plugin;
const { isPc } = useSystem();
const onOpenSlider = useContextSelector(ChatContext, (v) => v.onOpenSlider); return (
<>
return isPc && isPlugin ? null : ( {isPc && isPlugin ? null : (
<Flex <Flex
alignItems={'center'} alignItems={'center'}
px={[3, 5]} px={[3, 5]}
minH={['46px', '60px']} minH={['46px', '60px']}
borderBottom={theme.borders.sm} borderBottom={'sm'}
color={'myGray.900'} color={'myGray.900'}
fontSize={'sm'} fontSize={'sm'}
> >
{isPc ? ( {isPc ? (
<PcHeader
title={chatData.title}
chatModels={chatData.app.chatModels}
history={history}
/>
) : (
<MobileHeader
apps={apps}
appId={chatData.appId}
go2AppDetail={onRoute2AppDetail}
name={chatData.app.name}
avatar={chatData.app.avatar}
showHistory={showHistory}
/>
)}
{/* control */}
{!isPlugin && <ToolMenu history={history} />}
</Flex>
)}
</>
);
};
const MobileDrawer = ({
onCloseDrawer,
appId,
apps
}: {
onCloseDrawer: () => void;
appId: string;
apps?: AppListItemType[];
}) => {
enum TabEnum {
recently = 'recently',
app = 'app'
}
const { t } = useTranslation();
const { isPc } = useSystem();
const router = useRouter();
const isTeamChat = router.pathname === '/chat/team';
const [currentTab, setCurrentTab] = useState<TabEnum>(TabEnum.recently);
const getAppList = useCallback(async ({ parentId }: GetResourceFolderListProps) => {
return getMyApps({ parentId }).then((res) =>
res.map<GetResourceListItemResponse>((item) => ({
id: item._id,
name: item.name,
avatar: item.avatar,
isFolder: item.type === AppTypeEnum.folder
}))
);
}, []);
const { onChangeAppId } = useContextSelector(ChatContext, (v) => v);
return (
<>
<Box
position={'absolute'}
top={'45px'}
w={'100vw'}
h={'calc(100% - 45px)'}
background={'rgba(0, 0, 0, 0.2)'}
left={0}
zIndex={5}
onClick={() => {
onCloseDrawer();
}}
>
{/* menu */}
<Box
w={'100vw'}
px={[2, 5]}
padding={2}
onClick={(e) => e.stopPropagation()}
background={'white'}
position={'relative'}
>
{!isPc && appId && (
<LightRowTabs<TabEnum>
flex={'1 0 0'}
width={isTeamChat ? '30%' : '60%'}
mr={10}
inlineStyles={{
px: 1
}}
list={[
...(isTeamChat
? [{ label: t('common:all_apps'), value: TabEnum.recently }]
: [
{ label: t('common:core.chat.Recent use'), value: TabEnum.recently },
{ label: t('common:all_apps'), value: TabEnum.app }
])
]}
value={currentTab}
onChange={setCurrentTab}
/>
)}
</Box>
<Box
width={'100vw'}
height={'auto'}
minH={'10vh'}
maxH={'60vh'}
overflow={'auto'}
background={'white'}
zIndex={3}
onClick={(e) => e.stopPropagation()}
borderRadius={'0 0 10px 10px'}
position={'relative'}
padding={3}
pt={0}
pb={4}
>
{/* history */}
{currentTab === TabEnum.recently && (
<>
{Array.isArray(apps) &&
apps.map((item) => (
<Flex justify={'center'} key={item._id}>
<Flex
py={2.5}
px={2}
width={'100%'}
borderRadius={'md'}
alignItems={'center'}
{...(item._id === appId
? {
backgroundColor: 'primary.50 !important',
color: 'primary.600'
}
: {
onClick: () => onChangeAppId(item._id)
})}
>
<Avatar src={item.avatar} w={'24px'} />
<Box ml={2} className={'textEllipsis'}>
{item.name}
</Box>
</Flex>
</Flex>
))}
</>
)}
{currentTab === TabEnum.app && !isPc && (
<>
<SelectOneResource
value={appId}
onSelect={(id) => {
if (!id) return;
onChangeAppId(id);
}}
server={getAppList}
/>
</>
)}
</Box>
</Box>
</>
);
};
const MobileHeader = ({
showHistory,
go2AppDetail,
name,
avatar,
appId,
apps
}: {
showHistory?: boolean;
go2AppDetail?: () => void;
avatar: string;
name: string;
apps?: AppListItemType[];
appId: string;
}) => {
const { isPc } = useSystem();
const router = useRouter();
const onOpenSlider = useContextSelector(ChatContext, (v) => v.onOpenSlider);
const { isOpen: isOpenDrawer, onToggle: toggleDrawer, onClose: onCloseDrawer } = useDisclosure();
const isShareChat = router.pathname === '/chat/share';
return (
<>
{showHistory && (
<MyIcon name={'menu'} w={'20px'} h={'20px'} color={'myGray.900'} onClick={onOpenSlider} />
)}
<Flex px={3} alignItems={'center'} flex={'1 0 0'} w={0} justifyContent={'center'}>
<Avatar src={avatar} w={'16px'} />
<Box ml={1} className="textEllipsis" onClick={go2AppDetail}>
{name}
</Box>
{isShareChat ? null : (
<MyIcon
_active={{ transform: 'scale(0.9)' }}
name={'core/chat/chevronSelector'}
w={'20px'}
h={'20px'}
color={isOpenDrawer ? 'primary.600' : 'myGray.900'}
onClick={toggleDrawer}
/>
)}
</Flex>
{!isPc && isOpenDrawer && !isShareChat && (
<MobileDrawer apps={apps} appId={appId} onCloseDrawer={onCloseDrawer} />
)}
</>
);
};
const PcHeader = ({
title,
chatModels,
history
}: {
title: string;
chatModels?: string[];
history: ChatItemType[];
}) => {
const { t } = useTranslation();
return (
<> <>
<Box mr={3} maxW={'160px'} className="textEllipsis" color={'myGray.1000'}> <Box mr={3} maxW={'160px'} className="textEllipsis" color={'myGray.1000'}>
{chatData.title} {title}
</Box> </Box>
<MyTag> <MyTag>
<MyIcon name={'history'} w={'14px'} /> <MyIcon name={'history'} w={'14px'} />
<Box ml={1}> <Box ml={1}>
{history.length === 0 {history.length === 0
? t('common:core.chat.New Chat') ? t('common:core.chat.New Chat')
: t('core.chat.History Amount', { amount: history.length })} : t('common:core.chat.History Amount', { amount: history.length })}
</Box> </Box>
</MyTag> </MyTag>
{!!chatModels && chatModels.length > 0 && ( {!!chatModels && chatModels.length > 0 && (
...@@ -68,30 +294,6 @@ const ChatHeader = ({ ...@@ -68,30 +294,6 @@ const ChatHeader = ({
)} )}
<Box flex={1} /> <Box flex={1} />
</> </>
) : (
<>
{showHistory && (
<MyIcon
name={'menu'}
w={'20px'}
h={'20px'}
color={'myGray.900'}
onClick={onOpenSlider}
/>
)}
<Flex px={3} alignItems={'center'} flex={'1 0 0'} w={0} justifyContent={'center'}>
<Avatar src={chatData.app.avatar} w={'16px'} />
<Box ml={1} className="textEllipsis" onClick={onRoute2AppDetail}>
{chatData.app.name}
</Box>
</Flex>
</>
)}
{/* control */}
{!isPlugin && <ToolMenu history={history} />}
</Flex>
); );
}; };
......
import React, { useCallback, useMemo, useState } from 'react'; import React, { useMemo } from 'react';
import { Box, Button, Flex, useTheme, IconButton } from '@chakra-ui/react'; import { Box, Button, Flex, useTheme, IconButton } from '@chakra-ui/react';
import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useSystem } from '@fastgpt/web/hooks/useSystem';
import { useEditTitle } from '@/web/common/hooks/useEditTitle'; import { useEditTitle } from '@/web/common/hooks/useEditTitle';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import Avatar from '@fastgpt/web/components/common/Avatar'; import Avatar from '@fastgpt/web/components/common/Avatar';
...@@ -8,22 +8,13 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; ...@@ -8,22 +8,13 @@ import MyTooltip from '@fastgpt/web/components/common/MyTooltip';
import MyIcon from '@fastgpt/web/components/common/Icon'; import MyIcon from '@fastgpt/web/components/common/Icon';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
import { useConfirm } from '@fastgpt/web/hooks/useConfirm'; import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
import LightRowTabs from '@fastgpt/web/components/common/Tabs/LightRowTabs';
import { useUserStore } from '@/web/support/user/useUserStore'; import { useUserStore } from '@/web/support/user/useUserStore';
import { AppListItemType } from '@fastgpt/global/core/app/type'; import { AppListItemType } from '@fastgpt/global/core/app/type';
import { useI18n } from '@/web/context/I18n'; import { useI18n } from '@/web/context/I18n';
import MyMenu from '@fastgpt/web/components/common/MyMenu'; import MyMenu from '@fastgpt/web/components/common/MyMenu';
import SelectOneResource from '@/components/common/folder/SelectOneResource';
import {
GetResourceFolderListProps,
GetResourceListItemResponse
} from '@fastgpt/global/common/parentFolder/type';
import { getMyApps } from '@/web/core/app/api';
import { AppTypeEnum } from '@fastgpt/global/core/app/constants';
import { useContextSelector } from 'use-context-selector'; import { useContextSelector } from 'use-context-selector';
import { ChatContext } from '@/web/core/chat/context/chatContext'; import { ChatContext } from '@/web/core/chat/context/chatContext';
import MyBox from '@fastgpt/web/components/common/MyBox'; import MyBox from '@fastgpt/web/components/common/MyBox';
import { useSystem } from '@fastgpt/web/hooks/useSystem';
type HistoryItemType = { type HistoryItemType = {
id: string; id: string;
...@@ -32,12 +23,6 @@ type HistoryItemType = { ...@@ -32,12 +23,6 @@ type HistoryItemType = {
top?: boolean; top?: boolean;
}; };
enum TabEnum {
recently = 'recently',
'app' = 'app',
'history' = 'history'
}
const ChatHistorySlider = ({ const ChatHistorySlider = ({
appId, appId,
appName, appName,
...@@ -69,12 +54,9 @@ const ChatHistorySlider = ({ ...@@ -69,12 +54,9 @@ const ChatHistorySlider = ({
const { isPc } = useSystem(); const { isPc } = useSystem();
const { userInfo } = useUserStore(); const { userInfo } = useUserStore();
const [currentTab, setCurrentTab] = useState<TabEnum>(TabEnum.history);
const { const {
histories, histories,
onChangeChatId, onChangeChatId,
onChangeAppId,
chatId: activeChatId, chatId: activeChatId,
isLoading isLoading
} = useContextSelector(ChatContext, (v) => v); } = useContextSelector(ChatContext, (v) => v);
...@@ -86,7 +68,10 @@ const ChatHistorySlider = ({ ...@@ -86,7 +68,10 @@ const ChatHistorySlider = ({
customTitle: item.customTitle, customTitle: item.customTitle,
top: item.top top: item.top
})); }));
const newChat: HistoryItemType = { id: activeChatId, title: t('common:core.chat.New Chat') }; const newChat: HistoryItemType = {
id: activeChatId,
title: t('common:core.chat.New Chat')
};
const activeChat = histories.find((item) => item.chatId === activeChatId); const activeChat = histories.find((item) => item.chatId === activeChatId);
return !activeChat ? [newChat].concat(formatHistories) : formatHistories; return !activeChat ? [newChat].concat(formatHistories) : formatHistories;
...@@ -106,17 +91,6 @@ const ChatHistorySlider = ({ ...@@ -106,17 +91,6 @@ const ChatHistorySlider = ({
[appId, userInfo?.team.permission.hasWritePer] [appId, userInfo?.team.permission.hasWritePer]
); );
const getAppList = useCallback(async ({ parentId }: GetResourceFolderListProps) => {
return getMyApps({ parentId }).then((res) =>
res.map<GetResourceListItemResponse>((item) => ({
id: item._id,
name: item.name,
avatar: item.avatar,
isFolder: item.type === AppTypeEnum.folder
}))
);
}, []);
return ( return (
<MyBox <MyBox
isLoading={isLoading} isLoading={isLoading}
...@@ -154,26 +128,21 @@ const ChatHistorySlider = ({ ...@@ -154,26 +128,21 @@ const ChatHistorySlider = ({
)} )}
{/* menu */} {/* menu */}
<Flex w={'100%'} px={[2, 5]} h={'36px'} my={5} alignItems={'center'}> <Flex
w={'100%'}
px={[2, 5]}
h={'36px'}
my={5}
justify={['space-between', '']}
alignItems={'center'}
>
{!isPc && appId && ( {!isPc && appId && (
<LightRowTabs<TabEnum> <Flex height={'100%'} align={'center'} justify={'center'}>
flex={'1 0 0'} <MyIcon ml={2} name="core/chat/sideLine" />
mr={1} <Box ml={2} fontWeight={'bold'}>
inlineStyles={{ {t('common:core.chat.History')}
px: 1 </Box>
}} </Flex>
list={[
...(isTeamChat
? [{ label: t('common:App'), value: TabEnum.recently }]
: [
{ label: t('common:core.chat.Recent use'), value: TabEnum.recently },
{ label: t('common:App'), value: TabEnum.app }
]),
{ label: t('common:core.chat.History'), value: TabEnum.history }
]}
value={currentTab}
onChange={setCurrentTab}
/>
)} )}
<Button <Button
...@@ -210,7 +179,6 @@ const ChatHistorySlider = ({ ...@@ -210,7 +179,6 @@ const ChatHistorySlider = ({
<Box flex={'1 0 0'} h={0} px={[2, 5]} overflow={'overlay'}> <Box flex={'1 0 0'} h={0} px={[2, 5]} overflow={'overlay'}>
{/* chat history */} {/* chat history */}
{(currentTab === TabEnum.history || isPc) && (
<> <>
{concatHistory.map((item, i) => ( {concatHistory.map((item, i) => (
<Flex <Flex
...@@ -271,7 +239,10 @@ const ChatHistorySlider = ({ ...@@ -271,7 +239,10 @@ const ChatHistorySlider = ({
: t('common:core.chat.Pin'), : t('common:core.chat.Pin'),
icon: 'core/chat/setTopLight', icon: 'core/chat/setTopLight',
onClick: () => { onClick: () => {
onSetHistoryTop({ chatId: item.id, top: !item.top }); onSetHistoryTop({
chatId: item.id,
top: !item.top
});
} }
} }
] ]
...@@ -314,47 +285,6 @@ const ChatHistorySlider = ({ ...@@ -314,47 +285,6 @@ const ChatHistorySlider = ({
</Flex> </Flex>
))} ))}
</> </>
)}
{currentTab === TabEnum.recently && !isPc && (
<>
{Array.isArray(apps) &&
apps.map((item) => (
<Flex
key={item._id}
py={2}
px={3}
mb={3}
borderRadius={'md'}
alignItems={'center'}
{...(item._id === appId
? {
backgroundColor: 'primary.50 !important',
color: 'primary.600'
}
: {
onClick: () => onChangeAppId(item._id)
})}
>
<Avatar src={item.avatar} w={'24px'} />
<Box ml={2} className={'textEllipsis'}>
{item.name}
</Box>
</Flex>
))}
</>
)}
{currentTab === TabEnum.app && !isPc && (
<>
<SelectOneResource
value={appId}
onSelect={(id) => {
if (!id) return;
onChangeAppId(id);
}}
server={getAppList}
/>
</>
)}
</Box> </Box>
{/* exec */} {/* exec */}
......
...@@ -226,6 +226,7 @@ const Chat = ({ ...@@ -226,6 +226,7 @@ const Chat = ({
> >
{/* header */} {/* header */}
<ChatHeader <ChatHeader
apps={myApps}
chatData={chatData} chatData={chatData}
history={chatRecords} history={chatRecords}
onRoute2AppDetail={() => router.push(`/app/detail?appId=${appId}`)} onRoute2AppDetail={() => router.push(`/app/detail?appId=${appId}`)}
......
...@@ -230,7 +230,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => { ...@@ -230,7 +230,7 @@ const Chat = ({ myApps }: { myApps: AppListItemType[] }) => {
flexDirection={'column'} flexDirection={'column'}
> >
{/* header */} {/* header */}
<ChatHeader chatData={chatData} history={chatData.history} showHistory /> <ChatHeader apps={myApps} chatData={chatData} history={chatData.history} showHistory />
{/* chat box */} {/* chat box */}
<Box flex={1}> <Box flex={1}>
{chatData.app.type === AppTypeEnum.plugin ? ( {chatData.app.type === AppTypeEnum.plugin ? (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment