feat: phone slider
This commit is contained in:
parent
248be38939
commit
ffdef41bf2
@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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": "你需要创建一个应用"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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']
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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'}
|
||||||
|
|||||||
@ -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)} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -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' }
|
||||||
],
|
],
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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 (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -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({
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
11
client/src/types/i18n.d.ts
vendored
11
client/src/types/i18n.d.ts
vendored
@ -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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user