mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-28 00:56:26 +00:00
feat: phone slider
This commit is contained in:
@@ -1,13 +1,18 @@
|
||||
{
|
||||
"App": "App",
|
||||
"Cancel": "No",
|
||||
"Confirm": "Yes",
|
||||
"Warning": "Warning",
|
||||
"app": {
|
||||
"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": {
|
||||
"Confirm to clear history": "Confirm to clear history?",
|
||||
"Exit Chat": "Exit",
|
||||
"History": "History",
|
||||
"New Chat": "New Chat",
|
||||
"You need to a chat app": "You need to a chat app"
|
||||
},
|
||||
|
@@ -1,13 +1,18 @@
|
||||
{
|
||||
"App": "应用",
|
||||
"Cancel": "取消",
|
||||
"Confirm": "确认",
|
||||
"Warning": "提示",
|
||||
"app": {
|
||||
"App Detail": "应用详情",
|
||||
"My Apps": "我的应用"
|
||||
"My Apps": "我的应用",
|
||||
"Confirm Save App Tip": "保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。",
|
||||
"Confirm Del App Tip": "确认删除该应用及其所有聊天记录?"
|
||||
},
|
||||
"chat": {
|
||||
"Confirm to clear history": "确认清空该应用的聊天记录?",
|
||||
"Exit Chat": "退出聊天",
|
||||
"History": "记录",
|
||||
"New Chat": "新对话",
|
||||
"You need to a chat app": "你需要创建一个应用"
|
||||
},
|
||||
|
@@ -35,7 +35,7 @@ const map = {
|
||||
apikey: require('./icons/apikey.svg').default,
|
||||
save: require('./icons/save.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,
|
||||
clear: require('./icons/light/clear.svg').default,
|
||||
apiLight: require('./icons/light/appApi.svg').default,
|
||||
|
@@ -26,7 +26,7 @@ const Navbar = ({ unread }: { unread: number }) => {
|
||||
() => [
|
||||
{
|
||||
label: t('navbar.Chat'),
|
||||
icon: 'chatLight',
|
||||
icon: 'chat',
|
||||
activeIcon: 'chatFill',
|
||||
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
|
||||
activeLink: ['/chat']
|
||||
|
@@ -14,7 +14,7 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
|
||||
() => [
|
||||
{
|
||||
label: t('navbar.Chat'),
|
||||
icon: 'chatLight',
|
||||
icon: 'chat',
|
||||
link: `/chat?appId=${lastChatAppId}&chatId=${lastChatId}`,
|
||||
activeLink: ['/chat'],
|
||||
unread: 0
|
||||
|
@@ -1,6 +1,7 @@
|
||||
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 { useTranslation } from 'react-i18next';
|
||||
|
||||
// @ts-ignore
|
||||
interface Props extends GridProps {
|
||||
@@ -11,7 +12,7 @@ interface Props extends GridProps {
|
||||
}
|
||||
|
||||
const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const sizeMap = useMemo(() => {
|
||||
switch (size) {
|
||||
case 'sm':
|
||||
@@ -47,14 +48,14 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
|
||||
<Box
|
||||
key={item.id}
|
||||
py={sizeMap.inlineP}
|
||||
borderRadius={'sm'}
|
||||
textAlign={'center'}
|
||||
borderBottom={'2px solid transparent'}
|
||||
{...(activeId === item.id
|
||||
? {
|
||||
boxShadow: '0px 2px 2px rgba(137, 156, 171, 0.25)',
|
||||
backgroundImage: theme.lgColor.primary2,
|
||||
color: 'white',
|
||||
cursor: 'default'
|
||||
color: 'myBlue.700',
|
||||
cursor: 'default',
|
||||
fontWeight: 'bold',
|
||||
borderBottomColor: 'myBlue.700'
|
||||
}
|
||||
: {
|
||||
cursor: 'pointer'
|
||||
@@ -64,7 +65,7 @@ const Tabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) => {
|
||||
onChange(item.id);
|
||||
}}
|
||||
>
|
||||
{item.label}
|
||||
{t(item.label) || item.label}
|
||||
</Box>
|
||||
))}
|
||||
</Grid>
|
||||
|
@@ -11,8 +11,9 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
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 { title = t('Warning'), content } = props;
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
const cancelRef = useRef(null);
|
||||
@@ -29,13 +30,13 @@ export const useConfirm = ({ title = 'Warning', content }: { title?: string; con
|
||||
},
|
||||
[onOpen]
|
||||
),
|
||||
ConfirmChild: useCallback(
|
||||
ConfirmModal: useCallback(
|
||||
() => (
|
||||
<AlertDialog isOpen={isOpen} leastDestructiveRef={cancelRef} onClose={onClose}>
|
||||
<AlertDialogOverlay>
|
||||
<AlertDialogContent maxW={'min(90vw,400px)'}>
|
||||
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
||||
{t(title)}
|
||||
{title}
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogBody>{content}</AlertDialogBody>
|
||||
|
@@ -39,7 +39,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
{ icon: 'loginoutLight', label: '登出', id: TabEnum.loginout, Component: () => <></> }
|
||||
]);
|
||||
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: '确认退出登录?'
|
||||
});
|
||||
|
||||
@@ -111,7 +111,7 @@ const Account = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
{currentTab === TabEnum.inform && <InformTable />}
|
||||
</Box>
|
||||
</Flex>
|
||||
<ConfirmChild />
|
||||
<ConfirmModal />
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
@@ -347,7 +347,7 @@ const AppEdit = ({ app, fullScreen, onFullScreen }: Props) => {
|
||||
<MyTooltip label={'测试对话'}>
|
||||
<IconButton
|
||||
mr={6}
|
||||
icon={<MyIcon name={'chatLight'} w={['14px', '16px']} />}
|
||||
icon={<MyIcon name={'chat'} w={['14px', '16px']} />}
|
||||
borderRadius={'lg'}
|
||||
aria-label={'save'}
|
||||
variant={'base'}
|
||||
|
@@ -52,6 +52,7 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import ChatBox, { type ComponentRef, type StartChatFnProps } from '@/components/ChatBox';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { getSpecialModule } from '@/components/ChatBox/utils';
|
||||
|
||||
import { addVariable } from '../VariableEditModal';
|
||||
@@ -63,6 +64,7 @@ const InfoModal = dynamic(() => import('../InfoModal'));
|
||||
const Settings = ({ appId }: { appId: string }) => {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { toast } = useToast();
|
||||
const { appDetail, updateAppDetail, loadKbList, myKbList } = useUserStore();
|
||||
const { isPc } = useGlobalStore();
|
||||
@@ -72,9 +74,11 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
title: '警告',
|
||||
content: '保存后将会覆盖高级编排配置,请确保该应用未使用高级编排功能。'
|
||||
const { openConfirm: openConfirmSave, ConfirmModal: ConfirmSaveModal } = useConfirm({
|
||||
content: t('app.Confirm Save App Tip')
|
||||
});
|
||||
const { openConfirm: openConfirmDel, ConfirmModal: ConfirmDelModal } = useConfirm({
|
||||
content: t('app.Confirm Del App Tip')
|
||||
});
|
||||
const { register, setValue, getValues, reset, handleSubmit, control } = useForm<EditFormType>({
|
||||
defaultValues: getDefaultAppForm()
|
||||
@@ -227,7 +231,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
color: 'red.600'
|
||||
}}
|
||||
isLoading={isLoading}
|
||||
onClick={openConfirm(handleDelModel)}
|
||||
onClick={openConfirmDel(handleDelModel)}
|
||||
/>
|
||||
</Flex>
|
||||
<Box
|
||||
@@ -243,7 +247,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
<Button
|
||||
size={['sm', 'md']}
|
||||
variant={'base'}
|
||||
leftIcon={<MyIcon name={'chatLight'} w={'16px'} />}
|
||||
leftIcon={<MyIcon name={'chat'} w={'16px'} />}
|
||||
onClick={() => router.push(`/chat?appId=${appId}`)}
|
||||
>
|
||||
对话
|
||||
@@ -286,7 +290,7 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
isLoading={isSaving}
|
||||
fontSize={'sm'}
|
||||
size={['sm', 'md']}
|
||||
onClick={openConfirm(handleSubmit((data) => onSubmitSave(data)))}
|
||||
onClick={openConfirmSave(handleSubmit((data) => onSubmitSave(data)))}
|
||||
>
|
||||
{isPc ? '保存并预览' : '保存'}
|
||||
</Button>
|
||||
@@ -494,7 +498,8 @@ const Settings = ({ appId }: { appId: string }) => {
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<ConfirmChild />
|
||||
<ConfirmSaveModal />
|
||||
<ConfirmDelModal />
|
||||
{settingAppInfo && (
|
||||
<InfoModal defaultApp={settingAppInfo} onClose={() => setSettingAppInfo(undefined)} />
|
||||
)}
|
||||
|
@@ -59,7 +59,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
|
||||
{ label: '高级编排', id: TabEnum.adEdit, icon: 'settingLight' },
|
||||
{ label: '链接分享', id: TabEnum.share, icon: 'shareLight' },
|
||||
{ label: 'API访问', id: TabEnum.API, icon: 'apiLight' },
|
||||
{ label: '立即对话', id: 'startChat', icon: 'chatLight' }
|
||||
{ label: '立即对话', id: 'startChat', icon: 'chat' }
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
@@ -34,7 +34,7 @@ const MyApps = () => {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { myApps, loadMyApps } = useUserStore();
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
title: '删除提示',
|
||||
content: '确认删除该应用所有信息?'
|
||||
});
|
||||
@@ -53,7 +53,7 @@ const MyApps = () => {
|
||||
title: '删除成功',
|
||||
status: 'success'
|
||||
});
|
||||
loadMyApps();
|
||||
loadMyApps(true);
|
||||
} catch (err: any) {
|
||||
toast({
|
||||
title: err?.message || '删除失败',
|
||||
@@ -65,7 +65,7 @@ const MyApps = () => {
|
||||
);
|
||||
|
||||
/* 加载模型 */
|
||||
useQuery(['loadModels'], loadMyApps, {
|
||||
useQuery(['loadModels'], () => loadMyApps(true), {
|
||||
refetchOnMount: true
|
||||
});
|
||||
|
||||
@@ -147,7 +147,7 @@ const MyApps = () => {
|
||||
size={'sm'}
|
||||
icon={
|
||||
<MyTooltip label={'去聊天'}>
|
||||
<MyIcon name={'chatLight'} w={'14px'} />
|
||||
<MyIcon name={'chat'} w={'14px'} />
|
||||
</MyTooltip>
|
||||
}
|
||||
variant={'base'}
|
||||
@@ -165,8 +165,10 @@ const MyApps = () => {
|
||||
</Card>
|
||||
))}
|
||||
</Grid>
|
||||
<ConfirmChild />
|
||||
{isOpenCreateModal && <CreateModal onClose={onCloseCreateModal} onSuccess={loadMyApps} />}
|
||||
<ConfirmModal />
|
||||
{isOpenCreateModal && (
|
||||
<CreateModal onClose={onCloseCreateModal} onSuccess={() => loadMyApps(true)} />
|
||||
)}
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@@ -18,6 +18,9 @@ import MyTooltip from '@/components/MyTooltip';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useConfirm } from '@/hooks/useConfirm';
|
||||
import Tabs from '@/components/Tabs';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
type HistoryItemType = {
|
||||
id: string;
|
||||
@@ -26,6 +29,11 @@ type HistoryItemType = {
|
||||
top?: boolean;
|
||||
};
|
||||
|
||||
enum TabEnum {
|
||||
'app' = 'app',
|
||||
'history' = 'history'
|
||||
}
|
||||
|
||||
const ChatHistorySlider = ({
|
||||
appId,
|
||||
appName,
|
||||
@@ -36,7 +44,8 @@ const ChatHistorySlider = ({
|
||||
onDelHistory,
|
||||
onClearHistory,
|
||||
onSetHistoryTop,
|
||||
onSetCustomTitle
|
||||
onSetCustomTitle,
|
||||
onClose
|
||||
}: {
|
||||
appId?: string;
|
||||
appName: string;
|
||||
@@ -48,25 +57,41 @@ const ChatHistorySlider = ({
|
||||
onClearHistory: () => void;
|
||||
onSetHistoryTop?: (e: { chatId: string; top: boolean }) => void;
|
||||
onSetCustomTitle?: (e: { chatId: string; title: string }) => void;
|
||||
onClose: () => void;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { isPc } = useGlobalStore();
|
||||
const { myApps, loadMyApps, userInfo } = useUserStore();
|
||||
|
||||
const [currentTab, setCurrentTab] = useState<`${TabEnum}`>(TabEnum.history);
|
||||
|
||||
// custom title edit
|
||||
const { onOpenModal, EditModal: EditTitleModal } = useEditInfo({
|
||||
title: '自定义历史记录标题',
|
||||
placeholder: '如果设置为空,会自动跟随聊天记录。'
|
||||
});
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: t('chat.Confirm to clear history')
|
||||
});
|
||||
|
||||
const concatHistory = useMemo<HistoryItemType[]>(
|
||||
() => (!activeChatId ? [{ id: activeChatId, title: '新对话' }].concat(history) : history),
|
||||
() =>
|
||||
!activeChatId ? [{ id: activeChatId, title: t('chat.New Chat') }].concat(history) : history,
|
||||
[activeChatId, history]
|
||||
);
|
||||
|
||||
const isShare = useMemo(() => !appId || !userInfo, [appId, userInfo]);
|
||||
|
||||
useQuery(['init'], () => {
|
||||
if (isShare) {
|
||||
setCurrentTab(TabEnum.history);
|
||||
return null;
|
||||
}
|
||||
return loadMyApps(false);
|
||||
});
|
||||
|
||||
return (
|
||||
<Flex
|
||||
position={'relative'}
|
||||
@@ -100,130 +125,183 @@ const ChatHistorySlider = ({
|
||||
</Flex>
|
||||
</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
|
||||
variant={'base'}
|
||||
flex={1}
|
||||
h={'100%'}
|
||||
color={'myBlue.700'}
|
||||
borderRadius={'xl'}
|
||||
leftIcon={<MyIcon name={'edit'} w={'16px'} />}
|
||||
leftIcon={<MyIcon name={'chat'} w={'16px'} />}
|
||||
overflow={'hidden'}
|
||||
onClick={() => onChangeChat()}
|
||||
>
|
||||
{t('chat.New Chat')}
|
||||
</Button>
|
||||
|
||||
<IconButton
|
||||
ml={3}
|
||||
h={'100%'}
|
||||
variant={'base'}
|
||||
aria-label={''}
|
||||
borderRadius={'xl'}
|
||||
onClick={openConfirm(onClearHistory)}
|
||||
>
|
||||
<MyIcon name={'clear'} w={'16px'} />
|
||||
</IconButton>
|
||||
{(isPc || isShare) && (
|
||||
<IconButton
|
||||
ml={3}
|
||||
h={'100%'}
|
||||
variant={'base'}
|
||||
aria-label={''}
|
||||
borderRadius={'xl'}
|
||||
onClick={openConfirm(onClearHistory)}
|
||||
>
|
||||
<MyIcon name={'clear'} w={'16px'} />
|
||||
</IconButton>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
{/* chat history */}
|
||||
<Box flex={'1 0 0'} h={0} px={[2, 5]} overflow={'overlay'}>
|
||||
{concatHistory.map((item, i) => (
|
||||
<Flex
|
||||
position={'relative'}
|
||||
key={item.id || `${i}`}
|
||||
alignItems={'center'}
|
||||
py={3}
|
||||
px={4}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
borderRadius={'lg'}
|
||||
mb={2}
|
||||
_hover={{
|
||||
bg: 'myGray.100',
|
||||
'& .more': {
|
||||
display: 'block'
|
||||
}
|
||||
}}
|
||||
bg={item.top ? '#E6F6F6 !important' : ''}
|
||||
{...(item.id === activeChatId
|
||||
? {
|
||||
backgroundColor: 'myBlue.100 !important',
|
||||
color: 'myBlue.700'
|
||||
}
|
||||
: {
|
||||
onClick: () => {
|
||||
onChangeChat(item.id);
|
||||
{/* chat history */}
|
||||
{(currentTab === TabEnum.history || isPc) && (
|
||||
<>
|
||||
{concatHistory.map((item, i) => (
|
||||
<Flex
|
||||
position={'relative'}
|
||||
key={item.id || `${i}`}
|
||||
alignItems={'center'}
|
||||
py={3}
|
||||
px={4}
|
||||
cursor={'pointer'}
|
||||
userSelect={'none'}
|
||||
borderRadius={'lg'}
|
||||
mb={2}
|
||||
_hover={{
|
||||
bg: 'myGray.100',
|
||||
'& .more': {
|
||||
display: 'block'
|
||||
}
|
||||
})}
|
||||
>
|
||||
<MyIcon name={item.id === activeChatId ? 'chatFill' : 'chatLight'} w={'16px'} />
|
||||
<Box flex={'1 0 0'} ml={3} className="textEllipsis">
|
||||
{item.customTitle || item.title}
|
||||
</Box>
|
||||
{!!item.id && (
|
||||
<Box className="more" display={['block', 'none']}>
|
||||
<Menu autoSelect={false} isLazy offset={[0, 5]}>
|
||||
<MenuButton
|
||||
_hover={{ bg: 'white' }}
|
||||
cursor={'pointer'}
|
||||
borderRadius={'md'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<MyIcon name={'more'} w={'14px'} p={1} />
|
||||
</MenuButton>
|
||||
<MenuList color={'myGray.700'} minW={`90px !important`}>
|
||||
{onSetHistoryTop && (
|
||||
<MenuItem
|
||||
}}
|
||||
bg={item.top ? '#E6F6F6 !important' : ''}
|
||||
{...(item.id === activeChatId
|
||||
? {
|
||||
backgroundColor: 'myBlue.100 !important',
|
||||
color: 'myBlue.700'
|
||||
}
|
||||
: {
|
||||
onClick: () => {
|
||||
onChangeChat(item.id);
|
||||
}
|
||||
})}
|
||||
>
|
||||
<MyIcon name={item.id === activeChatId ? 'chatFill' : 'chat'} w={'16px'} />
|
||||
<Box flex={'1 0 0'} ml={3} className="textEllipsis">
|
||||
{item.customTitle || item.title}
|
||||
</Box>
|
||||
{!!item.id && (
|
||||
<Box className="more" display={['block', 'none']}>
|
||||
<Menu autoSelect={false} isLazy offset={[0, 5]}>
|
||||
<MenuButton
|
||||
_hover={{ bg: 'white' }}
|
||||
cursor={'pointer'}
|
||||
borderRadius={'md'}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onSetHistoryTop({ chatId: item.id, top: !item.top });
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'setTop'} w={'16px'}></MyIcon>
|
||||
{item.top ? '取消置顶' : '置顶'}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onSetCustomTitle && (
|
||||
<MenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onOpenModal({
|
||||
defaultVal: item.customTitle || item.title,
|
||||
onSuccess: (e) =>
|
||||
onSetCustomTitle({
|
||||
chatId: item.id,
|
||||
title: e
|
||||
})
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'customTitle'} w={'16px'}></MyIcon>
|
||||
自定义标题
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
_hover={{ color: 'red.500' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDelHistory(item.id);
|
||||
if (item.id === activeChatId) {
|
||||
onChangeChat();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'delete'} w={'16px'}></MyIcon>
|
||||
删除
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Box>
|
||||
)}
|
||||
</Flex>
|
||||
))}
|
||||
<MyIcon name={'more'} w={'14px'} p={1} />
|
||||
</MenuButton>
|
||||
<MenuList color={'myGray.700'} minW={`90px !important`}>
|
||||
{onSetHistoryTop && (
|
||||
<MenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onSetHistoryTop({ chatId: item.id, top: !item.top });
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'setTop'} w={'16px'}></MyIcon>
|
||||
{item.top ? '取消置顶' : '置顶'}
|
||||
</MenuItem>
|
||||
)}
|
||||
{onSetCustomTitle && (
|
||||
<MenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onOpenModal({
|
||||
defaultVal: item.customTitle || item.title,
|
||||
onSuccess: (e) =>
|
||||
onSetCustomTitle({
|
||||
chatId: item.id,
|
||||
title: e
|
||||
})
|
||||
});
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'customTitle'} w={'16px'}></MyIcon>
|
||||
自定义标题
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem
|
||||
_hover={{ color: 'red.500' }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDelHistory(item.id);
|
||||
if (item.id === activeChatId) {
|
||||
onChangeChat();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MyIcon mr={2} name={'delete'} w={'16px'}></MyIcon>
|
||||
删除
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</Box>
|
||||
)}
|
||||
</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>
|
||||
|
||||
{!isPc && appId && (
|
||||
@@ -245,11 +323,11 @@ const ChatHistorySlider = ({
|
||||
borderRadius={'50%'}
|
||||
aria-label={''}
|
||||
/>
|
||||
切换应用
|
||||
{t('chat.Exit Chat')}
|
||||
</Flex>
|
||||
)}
|
||||
<EditTitleModal />
|
||||
<ConfirmChild />
|
||||
<ConfirmModal />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@@ -10,7 +10,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
|
||||
const router = useRouter();
|
||||
const { myApps, loadMyApps } = useUserStore();
|
||||
|
||||
useQuery(['loadModels'], loadMyApps);
|
||||
useQuery(['loadModels'], () => loadMyApps(false));
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@@ -10,7 +10,7 @@ const ToolMenu = ({ history }: { history: ChatItemType[] }) => {
|
||||
const router = useRouter();
|
||||
const menuList = useRef([
|
||||
{
|
||||
icon: 'chatLight',
|
||||
icon: 'chat',
|
||||
label: '新对话',
|
||||
onClick: () => {
|
||||
router.push({
|
||||
|
@@ -258,7 +258,13 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
||||
return isPc || !appId ? (
|
||||
<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)'} />
|
||||
<DrawerContent maxWidth={'250px'}>{children}</DrawerContent>
|
||||
</Drawer>
|
||||
@@ -269,6 +275,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
|
||||
appName={chatData.app.name}
|
||||
appAvatar={chatData.app.avatar}
|
||||
activeChatId={chatId}
|
||||
onClose={onCloseSlider}
|
||||
history={history.map((item, i) => ({
|
||||
id: item.chatId,
|
||||
title: item.title,
|
||||
|
@@ -151,7 +151,13 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
||||
return isPc ? (
|
||||
<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)'} />
|
||||
<DrawerContent maxWidth={'250px'} boxShadow={'2px 0 10px rgba(0,0,0,0.15)'}>
|
||||
{children}
|
||||
@@ -167,6 +173,7 @@ const ShareChat = ({ shareId, chatId }: { shareId: string; chatId: string }) =>
|
||||
id: item.chatId,
|
||||
title: item.title
|
||||
}))}
|
||||
onClose={onCloseSlider}
|
||||
onChangeChat={(chatId) => {
|
||||
console.log(chatId);
|
||||
|
||||
|
@@ -69,7 +69,7 @@ const ChunkImport = ({ kbId }: { kbId: string }) => {
|
||||
return formatPrice(files.reduce((sum, file) => sum + file.tokens, 0) * unitPrice);
|
||||
}, [files, unitPrice]);
|
||||
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: `该任务无法终止,需要一定时间生成索引,请确认导入。如果余额不足,未完成的任务会被暂停,充值后可继续进行。`
|
||||
});
|
||||
|
||||
@@ -455,7 +455,7 @@ const ChunkImport = ({ kbId }: { kbId: string }) => {
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
<ConfirmChild />
|
||||
<ConfirmModal />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -39,7 +39,7 @@ const CsvImport = ({ kbId }: { kbId: string }) => {
|
||||
);
|
||||
const emptyFiles = useMemo(() => files.length === 0, [files]);
|
||||
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: `该任务无法终止,需要一定时间生成索引,请确认导入。如果余额不足,未完成的任务会被暂停,充值后可继续进行。`
|
||||
});
|
||||
|
||||
@@ -234,7 +234,7 @@ const CsvImport = ({ kbId }: { kbId: string }) => {
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
<ConfirmChild />
|
||||
<ConfirmModal />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -71,7 +71,7 @@ const QAImport = ({ kbId }: { kbId: string }) => {
|
||||
return formatPrice(files.reduce((sum, file) => sum + file.tokens, 0) * unitPrice * 1.3);
|
||||
}, [files, unitPrice]);
|
||||
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: `该任务无法终止!导入后会自动调用大模型生成问答对,会有一些细节丢失,请确认!如果余额不足,未完成的任务会被暂停。`
|
||||
});
|
||||
|
||||
@@ -446,7 +446,7 @@ const QAImport = ({ kbId }: { kbId: string }) => {
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
<ConfirmChild />
|
||||
<ConfirmModal />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -40,7 +40,7 @@ const Info = (
|
||||
const [btnLoading, setBtnLoading] = useState(false);
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
content: '确认删除该知识库?数据将无法恢复,请确认!'
|
||||
});
|
||||
|
||||
@@ -251,7 +251,7 @@ const Info = (
|
||||
/>
|
||||
</Flex>
|
||||
<File onSelect={onSelectFile} />
|
||||
<ConfirmChild />
|
||||
<ConfirmModal />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -18,7 +18,7 @@ const Kb = () => {
|
||||
const theme = useTheme();
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
const { openConfirm, ConfirmChild } = useConfirm({
|
||||
const { openConfirm, ConfirmModal } = useConfirm({
|
||||
title: '删除提示',
|
||||
content: '确认删除该知识库?'
|
||||
});
|
||||
@@ -152,7 +152,7 @@ const Kb = () => {
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
<ConfirmChild />
|
||||
<ConfirmModal />
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
@@ -19,7 +19,7 @@ type State = {
|
||||
updateUserInfo: (user: UserUpdateParams) => void;
|
||||
myApps: AppListItemType[];
|
||||
myCollectionApps: AppListItemType[];
|
||||
loadMyApps: () => Promise<AppListItemType[]>;
|
||||
loadMyApps: (init?: boolean) => Promise<AppListItemType[]>;
|
||||
appDetail: AppSchema;
|
||||
loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>;
|
||||
updateAppDetail(appId: string, data: AppUpdateParams): Promise<void>;
|
||||
@@ -63,7 +63,8 @@ export const useUserStore = create<State>()(
|
||||
},
|
||||
myApps: [],
|
||||
myCollectionApps: [],
|
||||
async loadMyApps() {
|
||||
async loadMyApps(init = true) {
|
||||
if (get().myApps.length > 0 && !init) return [];
|
||||
const res = await getMyModels();
|
||||
set((state) => {
|
||||
state.myApps = res;
|
||||
|
11
client/src/types/i18n.d.ts
vendored
11
client/src/types/i18n.d.ts
vendored
@@ -1,13 +1,10 @@
|
||||
import 'i18next';
|
||||
import common from '../../public/locales/en/common.json';
|
||||
|
||||
interface I18nNamespaces {
|
||||
common: typeof common;
|
||||
}
|
||||
|
||||
declare module 'i18next' {
|
||||
interface CustomTypeOptions {
|
||||
defaultNS: 'common';
|
||||
resources: I18nNamespaces;
|
||||
interface Resources {
|
||||
[key: string]: {
|
||||
[key: string]: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user