feat: phone slider

This commit is contained in:
archer 2023-07-26 11:59:12 +08:00
parent 248be38939
commit ffdef41bf2
No known key found for this signature in database
GPG Key ID: 569A5660D2379E28
24 changed files with 275 additions and 166 deletions

View File

@ -1,13 +1,18 @@
{ {
"App": "App",
"Cancel": "No", "Cancel": "No",
"Confirm": "Yes", "Confirm": "Yes",
"Warning": "Warning", "Warning": "Warning",
"app": { "app": {
"App Detail": "App Detail", "App Detail": "App Detail",
"My Apps": "My Apps" "My Apps": "My Apps",
"Confirm Save App Tip": "After saving, the advanced orchestration configuration will be overwritten. Make sure that the application does not use advanced orchestration.",
"Confirm Del App Tip": "Confirm to delete the app and all its chats"
}, },
"chat": { "chat": {
"Confirm to clear history": "Confirm to clear history?", "Confirm to clear history": "Confirm to clear history?",
"Exit Chat": "Exit",
"History": "History",
"New Chat": "New Chat", "New Chat": "New Chat",
"You need to a chat app": "You need to a chat app" "You need to a chat app": "You need to a chat app"
}, },

View File

@ -1,13 +1,18 @@
{ {
"App": "应用",
"Cancel": "取消", "Cancel": "取消",
"Confirm": "确认", "Confirm": "确认",
"Warning": "提示", "Warning": "提示",
"app": { "app": {
"App Detail": "应用详情", "App Detail": "应用详情",
"My Apps": "我的应用" "My Apps": "我的应用",
"Confirm Save App Tip": "保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。",
"Confirm Del App Tip": "确认删除该应用及其所有聊天记录?"
}, },
"chat": { "chat": {
"Confirm to clear history": "确认清空该应用的聊天记录?", "Confirm to clear history": "确认清空该应用的聊天记录?",
"Exit Chat": "退出聊天",
"History": "记录",
"New Chat": "新对话", "New Chat": "新对话",
"You need to a chat app": "你需要创建一个应用" "You need to a chat app": "你需要创建一个应用"
}, },

View File

@ -35,7 +35,7 @@ const map = {
apikey: require('./icons/apikey.svg').default, apikey: require('./icons/apikey.svg').default,
save: require('./icons/save.svg').default, save: require('./icons/save.svg').default,
minus: require('./icons/minus.svg').default, minus: require('./icons/minus.svg').default,
chatLight: require('./icons/light/chat.svg').default, chat: require('./icons/light/chat.svg').default,
chatFill: require('./icons/fill/chat.svg').default, chatFill: require('./icons/fill/chat.svg').default,
clear: require('./icons/light/clear.svg').default, clear: require('./icons/light/clear.svg').default,
apiLight: require('./icons/light/appApi.svg').default, apiLight: require('./icons/light/appApi.svg').default,

View File

@ -26,7 +26,7 @@ const Navbar = ({ unread }: { unread: number }) => {
() => [ () => [
{ {
label: t('navbar.Chat'), label: t('navbar.Chat'),
icon: 'chatLight', icon: 'chat',
activeIcon: 'chatFill', activeIcon: 'chatFill',
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`, link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
activeLink: ['/chat'] activeLink: ['/chat']

View File

@ -14,7 +14,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
() => [ () => [
{ {
label: t('navbar.Chat'), label: t('navbar.Chat'),
icon: 'chatLight', icon: 'chat',
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`, link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
activeLink: ['/chat'], activeLink: ['/chat'],
unread: 0 unread: 0

View File

@ -1,6 +1,7 @@
import React, { useMemo } from 'react'; import React, { useMemo } from 'react';
import { Box, Grid, useTheme } from '@chakra-ui/react'; import { Box, Grid } from '@chakra-ui/react';
import type { GridProps } from '@chakra-ui/react'; import type { GridProps } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
// @ts-ignore // @ts-ignore
interface Props extends GridProps { interface Props extends GridProps {
@ -11,7 +12,7 @@ interface Props extends GridProps {
} }
const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => { const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
const theme = useTheme(); const { t } = useTranslation();
const sizeMap = useMemo(() => { const sizeMap = useMemo(() => {
switch (size) { switch (size) {
case 'sm': case 'sm':
@ -47,14 +48,14 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
<Box <Box
key={item.id} key={item.id}
py={sizeMap.inlineP} py={sizeMap.inlineP}
borderRadius={'sm'}
textAlign={'center'} textAlign={'center'}
borderBottom={'2px solid transparent'}
{...(activeId === item.id {...(activeId === item.id
? { ? {
boxShadow: '0px 2px 2px rgba(137, 156, 171, 0.25)', color: 'myBlue.700',
backgroundImage: theme.lgColor.primary2, cursor: 'default',
color: 'white', fontWeight: 'bold',
cursor: 'default' borderBottomColor: 'myBlue.700'
} }
: { : {
cursor: 'pointer' cursor: 'pointer'
@ -64,7 +65,7 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
onChange(item.id); onChange(item.id);
}} }}
> >
{item.label} {t(item.label) || item.label}
</Box> </Box>
))} ))}
</Grid> </Grid>

View File

@ -11,8 +11,9 @@ import {
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next'; import { useTranslation } from 'next-i18next';
export const useConfirm = ({ title = 'Warning', content }: { title?: string; content: string }) => { export const useConfirm = (props: { title?: string; content: string }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { title = t('Warning'), content } = props;
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const cancelRef = useRef(null); const cancelRef = useRef(null);
@ -29,13 +30,13 @@ export const useConfirm = ({ title = 'Warning', content }: { title?: string; con
}, },
[onOpen] [onOpen]
), ),
ConfirmChild: useCallback( ConfirmModal: useCallback(
() => ( () => (
<AlertDialog isOpen={isOpen} leastDestructiveRef={cancelRef} onClose={onClose}> <AlertDialog isOpen={isOpen} leastDestructiveRef={cancelRef} onClose={onClose}>
<AlertDialogOverlay> <AlertDialogOverlay>
<AlertDialogContent maxW={'min(90vw,400px)'}> <AlertDialogContent maxW={'min(90vw,400px)'}>
<AlertDialogHeader fontSize="lg" fontWeight="bold"> <AlertDialogHeader fontSize="lg" fontWeight="bold">
{t(title)} {title}
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogBody>{content}</AlertDialogBody> <AlertDialogBody>{content}</AlertDialogBody>

View File

@ -39,7 +39,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
{ icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <></> } { icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <></> }
]); ]);
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
content: '确认退出登录?' content: '确认退出登录?'
}); });
@ -111,7 +111,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
{currentTab === TabEnum.inform && <InformTable />} {currentTab === TabEnum.inform && <InformTable />}
</Box> </Box>
</Flex> </Flex>
<ConfirmChild /> <ConfirmModal />
</PageContainer> </PageContainer>
); );
}; };

View File

@ -347,7 +347,7 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
<MyTooltip label={'测试对话'}> <MyTooltip label={'测试对话'}>
<IconButton <IconButton
mr={6} mr={6}
icon={<MyIcon name={'chatLight'} w={['14px', '16px']} />} icon={<MyIcon name={'chat'} w={['14px', '16px']} />}
borderRadius={'lg'} borderRadius={'lg'}
aria-label={'save'} aria-label={'save'}
variant={'base'} variant={'base'}

View File

@ -52,6 +52,7 @@ import MyTooltip from '@/components/MyTooltip';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox'; import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
import { useTranslation } from 'react-i18next';
import { getSpecialModule } from '@/components/ChatBox/utils'; import { getSpecialModule } from '@/components/ChatBox/utils';
import { addVariable } from '../VariableEditModal'; import { addVariable } from '../VariableEditModal';
@ -63,6 +64,7 @@ const InfoModal = dynamic(() => import('../InfoModal'));
const Settings = ({ appId }: { appId: string }) => { const Settings = ({ appId }: { appId: string }) => {
const theme = useTheme(); const theme = useTheme();
const router = useRouter(); const router = useRouter();
const { t } = useTranslation();
const { toast } = useToast(); const { toast } = useToast();
const { appDetail, updateAppDetail, loadKbList, myKbList } = useUserStore(); const { appDetail, updateAppDetail, loadKbList, myKbList } = useUserStore();
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
@ -72,9 +74,11 @@ const Settings = ({ appId }: { appId: string }) => {
const [refresh, setRefresh] = useState(false); const [refresh, setRefresh] = useState(false);
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
title: '警告', content: t('app.Confirm Save App Tip')
content: '保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。' });
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
content: t('app.Confirm Del App Tip')
}); });
const { register, setValue, getValues, reset, handleSubmit, control } = useForm<EditFormType>({ const { register, setValue, getValues, reset, handleSubmit, control } = useForm<EditFormType>({
defaultValues: getDefaultAppForm() defaultValues: getDefaultAppForm()
@ -227,7 +231,7 @@ const Settings = ({ appId }: { appId: string }) => {
color: 'red.600' color: 'red.600'
}} }}
isLoading={isLoading} isLoading={isLoading}
onClick={openConfirm(handleDelModel)} onClick={openConfirmDel(handleDelModel)}
/> />
</Flex> </Flex>
<Box <Box
@ -243,7 +247,7 @@ const Settings = ({ appId }: { appId: string }) => {
<Button <Button
size={['sm', 'md']} size={['sm', 'md']}
variant={'base'} variant={'base'}
leftIcon={<MyIcon name={'chatLight'} w={'16px'} />} leftIcon={<MyIcon name={'chat'} w={'16px'} />}
onClick={() => router.push(`/chat?appId=${appId}`)} onClick={() => router.push(`/chat?appId=${appId}`)}
> >
@ -286,7 +290,7 @@ const Settings = ({ appId }: { appId: string }) => {
isLoading={isSaving} isLoading={isSaving}
fontSize={'sm'} fontSize={'sm'}
size={['sm', 'md']} size={['sm', 'md']}
onClick={openConfirm(handleSubmit((data) => onSubmitSave(data)))} onClick={openConfirmSave(handleSubmit((data) => onSubmitSave(data)))}
> >
{isPc ? '保存并预览' : '保存'} {isPc ? '保存并预览' : '保存'}
</Button> </Button>
@ -494,7 +498,8 @@ const Settings = ({ appId }: { appId: string }) => {
/> />
</Box> </Box>
<ConfirmChild /> <ConfirmSaveModal />
<ConfirmDelModal />
{settingAppInfo && ( {settingAppInfo && (
<InfoModal defaultApp={settingAppInfo} onClose={() => setSettingAppInfo(undefined)} /> <InfoModal defaultApp={settingAppInfo} onClose={() => setSettingAppInfo(undefined)} />
)} )}

View File

@ -59,7 +59,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
{ label: '高级编排', id: TabEnum.adEdit, icon: 'settingLight' }, { label: '高级编排', id: TabEnum.adEdit, icon: 'settingLight' },
{ label: '链接分享', id: TabEnum.share, icon: 'shareLight' }, { label: '链接分享', id: TabEnum.share, icon: 'shareLight' },
{ label: 'API访问', id: TabEnum.API, icon: 'apiLight' }, { label: 'API访问', id: TabEnum.API, icon: 'apiLight' },
{ label: '立即对话', id: 'startChat', icon: 'chatLight' } { label: '立即对话', id: 'startChat', icon: 'chat' }
], ],
[] []
); );

View File

@ -34,7 +34,7 @@ const MyApps = () => {
const theme = useTheme(); const theme = useTheme();
const router = useRouter(); const router = useRouter();
const { myApps, loadMyApps } = useUserStore(); const { myApps, loadMyApps } = useUserStore();
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
title: '删除提示', title: '删除提示',
content: '确认删除该应用所有信息?' content: '确认删除该应用所有信息?'
}); });
@ -53,7 +53,7 @@ const MyApps = () => {
title: '删除成功', title: '删除成功',
status: 'success' status: 'success'
}); });
loadMyApps(); loadMyApps(true);
} catch (err: any) { } catch (err: any) {
toast({ toast({
title: err?.message || '删除失败', title: err?.message || '删除失败',
@ -65,7 +65,7 @@ const MyApps = () => {
); );
/* 加载模型 */ /* 加载模型 */
useQuery(['loadModels'], loadMyApps, { useQuery(['loadModels'], () => loadMyApps(true), {
refetchOnMount: true refetchOnMount: true
}); });
@ -147,7 +147,7 @@ const MyApps = () => {
size={'sm'} size={'sm'}
icon={ icon={
<MyTooltip label={'去聊天'}> <MyTooltip label={'去聊天'}>
<MyIcon name={'chatLight'} w={'14px'} /> <MyIcon name={'chat'} w={'14px'} />
</MyTooltip> </MyTooltip>
} }
variant={'base'} variant={'base'}
@ -165,8 +165,10 @@ const MyApps = () => {
</Card> </Card>
))} ))}
</Grid> </Grid>
<ConfirmChild /> <ConfirmModal />
{isOpenCreateModal && <CreateModal onClose={onCloseCreateModal} onSuccess={loadMyApps} />} {isOpenCreateModal && (
<CreateModal onClose={onCloseCreateModal} onSuccess={() => loadMyApps(true)} />
)}
</PageContainer> </PageContainer>
); );
}; };

View File

@ -1,4 +1,4 @@
import React, { useMemo } from 'react'; import React, { useMemo, useState } from 'react';
import { import {
Box, Box,
Button, Button,
@ -18,6 +18,9 @@ import MyTooltip from '@/components/MyTooltip';
import MyIcon from '@/components/Icon'; import MyIcon from '@/components/Icon';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useConfirm } from '@/hooks/useConfirm'; import { useConfirm } from '@/hooks/useConfirm';
import Tabs from '@/components/Tabs';
import { useUserStore } from '@/store/user';
import { useQuery } from '@tanstack/react-query';
type HistoryItemType = { type HistoryItemType = {
id: string; id: string;
@ -26,6 +29,11 @@ type HistoryItemType = {
top?: boolean; top?: boolean;
}; };
enum TabEnum {
'app' = 'app',
'history' = 'history'
}
const ChatHistorySlider = ({ const ChatHistorySlider = ({
appId, appId,
appName, appName,
@ -36,7 +44,8 @@ const ChatHistorySlider = ({
onDelHistory, onDelHistory,
onClearHistory, onClearHistory,
onSetHistoryTop, onSetHistoryTop,
onSetCustomTitle onSetCustomTitle,
onClose
}: { }: {
appId?: string; appId?: string;
appName: string; appName: string;
@ -48,25 +57,41 @@ const ChatHistorySlider = ({
onClearHistory: () => void; onClearHistory: () => void;
onSetHistoryTop?: (e: { chatId: string; top: boolean }) => void; onSetHistoryTop?: (e: { chatId: string; top: boolean }) => void;
onSetCustomTitle?: (e: { chatId: string; title: string }) => void; onSetCustomTitle?: (e: { chatId: string; title: string }) => void;
onClose: () => void;
}) => { }) => {
const theme = useTheme(); const theme = useTheme();
const router = useRouter(); const router = useRouter();
const { t } = useTranslation(); const { t } = useTranslation();
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const { myApps, loadMyApps, userInfo } = useUserStore();
const [currentTab, setCurrentTab] = useState<`${TabEnum}`>(TabEnum.history);
// custom title edit // custom title edit
const { onOpenModal, EditModal: EditTitleModal } = useEditInfo({ const { onOpenModal, EditModal: EditTitleModal } = useEditInfo({
title: '自定义历史记录标题', title: '自定义历史记录标题',
placeholder: '如果设置为空,会自动跟随聊天记录。' placeholder: '如果设置为空,会自动跟随聊天记录。'
}); });
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
content: t('chat.Confirm to clear history') content: t('chat.Confirm to clear history')
}); });
const concatHistory = useMemo<HistoryItemType[]>( const concatHistory = useMemo<HistoryItemType[]>(
() => (!activeChatId ? [{ id: activeChatId, title: '新对话' }].concat(history) : history), () =>
!activeChatId ? [{ id: activeChatId, title: t('chat.New Chat') }].concat(history) : history,
[activeChatId, history] [activeChatId, history]
); );
const isShare = useMemo(() => !appId || !userInfo, [appId, userInfo]);
useQuery(['init'], () => {
if (isShare) {
setCurrentTab(TabEnum.history);
return null;
}
return loadMyApps(false);
});
return ( return (
<Flex <Flex
position={'relative'} position={'relative'}
@ -100,21 +125,35 @@ const ChatHistorySlider = ({
</Flex> </Flex>
</MyTooltip> </MyTooltip>
)} )}
{/* btn */}
<Flex w={'100%'} px={[2, 5]} h={'36px'} my={5}> {/* menu */}
<Flex w={'100%'} px={[2, 5]} h={'36px'} my={5} alignItems={'center'}>
{!isPc && !isShare && (
<Tabs
w={'120px'}
mr={2}
list={[
{ label: 'App', id: TabEnum.app },
{ label: 'chat.History', id: TabEnum.history }
]}
activeId={currentTab}
onChange={(e) => setCurrentTab(e as `${TabEnum}`)}
/>
)}
<Button <Button
variant={'base'} variant={'base'}
flex={1} flex={1}
h={'100%'} h={'100%'}
color={'myBlue.700'} color={'myBlue.700'}
borderRadius={'xl'} borderRadius={'xl'}
leftIcon={<MyIcon name={'edit'} w={'16px'} />} leftIcon={<MyIcon name={'chat'} w={'16px'} />}
overflow={'hidden'} overflow={'hidden'}
onClick={() => onChangeChat()} onClick={() => onChangeChat()}
> >
{t('chat.New Chat')} {t('chat.New Chat')}
</Button> </Button>
{(isPc || isShare) && (
<IconButton <IconButton
ml={3} ml={3}
h={'100%'} h={'100%'}
@ -125,10 +164,13 @@ const ChatHistorySlider = ({
> >
<MyIcon name={'clear'} w={'16px'} /> <MyIcon name={'clear'} w={'16px'} />
</IconButton> </IconButton>
)}
</Flex> </Flex>
{/* chat history */}
<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 */}
{(currentTab === TabEnum.history || isPc) && (
<>
{concatHistory.map((item, i) => ( {concatHistory.map((item, i) => (
<Flex <Flex
position={'relative'} position={'relative'}
@ -158,7 +200,7 @@ const ChatHistorySlider = ({
} }
})} })}
> >
<MyIcon name={item.id === activeChatId ? 'chatFill' : 'chatLight'} w={'16px'} /> <MyIcon name={item.id === activeChatId ? 'chatFill' : 'chat'} w={'16px'} />
<Box flex={'1 0 0'} ml={3} className="textEllipsis"> <Box flex={'1 0 0'} ml={3} className="textEllipsis">
{item.customTitle || item.title} {item.customTitle || item.title}
</Box> </Box>
@ -224,6 +266,42 @@ const ChatHistorySlider = ({
)} )}
</Flex> </Flex>
))} ))}
</>
)}
{currentTab === TabEnum.app && !isPc && (
<>
{myApps.map((item) => (
<Flex
key={item._id}
py={2}
px={3}
mb={3}
borderRadius={'lg'}
alignItems={'center'}
{...(item._id === appId
? {
backgroundColor: 'myBlue.100 !important',
color: 'myBlue.700'
}
: {
onClick: () => {
router.replace({
query: {
appId: item._id
}
});
onClose();
}
})}
>
<Avatar src={item.avatar} w={'24px'} />
<Box ml={2} className={'textEllipsis'}>
{item.name}
</Box>
</Flex>
))}
</>
)}
</Box> </Box>
{!isPc && appId && ( {!isPc && appId && (
@ -245,11 +323,11 @@ const ChatHistorySlider = ({
borderRadius={'50%'} borderRadius={'50%'}
aria-label={''} aria-label={''}
/> />
{t('chat.Exit Chat')}
</Flex> </Flex>
)} )}
<EditTitleModal /> <EditTitleModal />
<ConfirmChild /> <ConfirmModal />
</Flex> </Flex>
); );
}; };

View File

@ -10,7 +10,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
const router = useRouter(); const router = useRouter();
const { myApps, loadMyApps } = useUserStore(); const { myApps, loadMyApps } = useUserStore();
useQuery(['loadModels'], loadMyApps); useQuery(['loadModels'], () => loadMyApps(false));
return ( return (
<> <>

View File

@ -10,7 +10,7 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
const router = useRouter(); const router = useRouter();
const menuList = useRef([ const menuList = useRef([
{ {
icon: 'chatLight', icon: 'chat',
label: '新对话', label: '新对话',
onClick: () => { onClick: () => {
router.push({ router.push({

View File

@ -258,7 +258,13 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
return isPc || !appId ? ( return isPc || !appId ? (
<SideBar>{children}</SideBar> <SideBar>{children}</SideBar>
) : ( ) : (
<Drawer isOpen={isOpenSlider} placement="left" size={'xs'} onClose={onCloseSlider}> <Drawer
isOpen={isOpenSlider}
placement="left"
autoFocus={false}
size={'xs'}
onClose={onCloseSlider}
>
<DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} /> <DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} />
<DrawerContent maxWidth={'250px'}>{children}</DrawerContent> <DrawerContent maxWidth={'250px'}>{children}</DrawerContent>
</Drawer> </Drawer>
@ -269,6 +275,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
appName={chatData.app.name} appName={chatData.app.name}
appAvatar={chatData.app.avatar} appAvatar={chatData.app.avatar}
activeChatId={chatId} activeChatId={chatId}
onClose={onCloseSlider}
history={history.map((item, i) => ({ history={history.map((item, i) => ({
id: item.chatId, id: item.chatId,
title: item.title, title: item.title,

View File

@ -151,7 +151,13 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
return isPc ? ( return isPc ? (
<SideBar>{children}</SideBar> <SideBar>{children}</SideBar>
) : ( ) : (
<Drawer isOpen={isOpenSlider} placement="left" size={'xs'} onClose={onCloseSlider}> <Drawer
isOpen={isOpenSlider}
placement="left"
autoFocus={false}
size={'xs'}
onClose={onCloseSlider}
>
<DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} /> <DrawerOverlay backgroundColor={'rgba(255,255,255,0.5)'} />
<DrawerContent maxWidth={'250px'} boxShadow={'2px 0 10px rgba(0,0,0,0.15)'}> <DrawerContent maxWidth={'250px'} boxShadow={'2px 0 10px rgba(0,0,0,0.15)'}>
{children} {children}
@ -167,6 +173,7 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
id: item.chatId, id: item.chatId,
title: item.title title: item.title
}))} }))}
onClose={onCloseSlider}
onChangeChat={(chatId) => { onChangeChat={(chatId) => {
console.log(chatId); console.log(chatId);

View File

@ -69,7 +69,7 @@ const ChunkImport = ({ kbId }: { kbId: string }) => {
return formatPrice(files.reduce((sum, file) => sum + file.tokens, 0) * unitPrice); return formatPrice(files.reduce((sum, file) => sum + file.tokens, 0) * unitPrice);
}, [files, unitPrice]); }, [files, unitPrice]);
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
content: `该任务无法终止,需要一定时间生成索引,请确认导入。如果余额不足,未完成的任务会被暂停,充值后可继续进行。` content: `该任务无法终止,需要一定时间生成索引,请确认导入。如果余额不足,未完成的任务会被暂停,充值后可继续进行。`
}); });
@ -455,7 +455,7 @@ const ChunkImport = ({ kbId }: { kbId: string }) => {
)} )}
</Box> </Box>
)} )}
<ConfirmChild /> <ConfirmModal />
</Box> </Box>
); );
}; };

View File

@ -39,7 +39,7 @@ const CsvImport = ({ kbId }: { kbId: string }) => {
); );
const emptyFiles = useMemo(() => files.length === 0, [files]); const emptyFiles = useMemo(() => files.length === 0, [files]);
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
content: `该任务无法终止,需要一定时间生成索引,请确认导入。如果余额不足,未完成的任务会被暂停,充值后可继续进行。` content: `该任务无法终止,需要一定时间生成索引,请确认导入。如果余额不足,未完成的任务会被暂停,充值后可继续进行。`
}); });
@ -234,7 +234,7 @@ const CsvImport = ({ kbId }: { kbId: string }) => {
</Box> </Box>
</Box> </Box>
)} )}
<ConfirmChild /> <ConfirmModal />
</Box> </Box>
); );
}; };

View File

@ -71,7 +71,7 @@ const QAImport = ({ kbId }: { kbId: string }) => {
return formatPrice(files.reduce((sum, file) => sum + file.tokens, 0) * unitPrice * 1.3); return formatPrice(files.reduce((sum, file) => sum + file.tokens, 0) * unitPrice * 1.3);
}, [files, unitPrice]); }, [files, unitPrice]);
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
content: `该任务无法终止!导入后会自动调用大模型生成问答对,会有一些细节丢失,请确认!如果余额不足,未完成的任务会被暂停。` content: `该任务无法终止!导入后会自动调用大模型生成问答对,会有一些细节丢失,请确认!如果余额不足,未完成的任务会被暂停。`
}); });
@ -446,7 +446,7 @@ const QAImport = ({ kbId }: { kbId: string }) => {
)} )}
</Box> </Box>
)} )}
<ConfirmChild /> <ConfirmModal />
</Box> </Box>
); );
}; };

View File

@ -40,7 +40,7 @@ const Info = (
const [btnLoading, setBtnLoading] = useState(false); const [btnLoading, setBtnLoading] = useState(false);
const [refresh, setRefresh] = useState(false); const [refresh, setRefresh] = useState(false);
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
content: '确认删除该知识库?数据将无法恢复,请确认!' content: '确认删除该知识库?数据将无法恢复,请确认!'
}); });
@ -251,7 +251,7 @@ const Info = (
/> />
</Flex> </Flex>
<File onSelect={onSelectFile} /> <File onSelect={onSelectFile} />
<ConfirmChild /> <ConfirmModal />
</Box> </Box>
); );
}; };

View File

@ -18,7 +18,7 @@ const Kb = () => {
const theme = useTheme(); const theme = useTheme();
const router = useRouter(); const router = useRouter();
const { toast } = useToast(); const { toast } = useToast();
const { openConfirm, ConfirmChild } = useConfirm({ const { openConfirm, ConfirmModal } = useConfirm({
title: '删除提示', title: '删除提示',
content: '确认删除该知识库?' content: '确认删除该知识库?'
}); });
@ -152,7 +152,7 @@ const Kb = () => {
</Box> </Box>
</Flex> </Flex>
)} )}
<ConfirmChild /> <ConfirmModal />
</PageContainer> </PageContainer>
); );
}; };

View File

@ -19,7 +19,7 @@ type State = {
updateUserInfo: (user: UserUpdateParams) => void; updateUserInfo: (user: UserUpdateParams) => void;
myApps: AppListItemType[]; myApps: AppListItemType[];
myCollectionApps: AppListItemType[]; myCollectionApps: AppListItemType[];
loadMyApps: () => Promise<AppListItemType[]>; loadMyApps: (init?: boolean) => Promise<AppListItemType[]>;
appDetail: AppSchema; appDetail: AppSchema;
loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>; loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>;
updateAppDetail(appId: string, data: AppUpdateParams): Promise<void>; updateAppDetail(appId: string, data: AppUpdateParams): Promise<void>;
@ -63,7 +63,8 @@ export const useUserStore = create<State>()(
}, },
myApps: [], myApps: [],
myCollectionApps: [], myCollectionApps: [],
async loadMyApps() { async loadMyApps(init = true) {
if (get().myApps.length > 0 && !init) return [];
const res = await getMyModels(); const res = await getMyModels();
set((state) => { set((state) => {
state.myApps = res; state.myApps = res;

View File

@ -1,13 +1,10 @@
import 'i18next'; import 'i18next';
import common from '../../public/locales/en/common.json'; import common from '../../public/locales/en/common.json';
interface I18nNamespaces {
common: typeof common;
}
declare module 'i18next' { declare module 'i18next' {
interface CustomTypeOptions { interface Resources {
defaultNS: 'common'; [key: string]: {
resources: I18nNamespaces; [key: string]: string;
};
} }
} }