feat: error track, app scroll

This commit is contained in:
archer 2023-09-03 17:37:14 +08:00
parent 7c16d08ec0
commit e0b23a26f2
No known key found for this signature in database
GPG Key ID: 569A5660D2379E28
9 changed files with 101 additions and 40 deletions

View File

@ -37,7 +37,7 @@
"chat": { "chat": {
"Admin Mark Content": "纠正后的回复", "Admin Mark Content": "纠正后的回复",
"Complete Response": "完整响应", "Complete Response": "完整响应",
"Confirm to clear history": "确认清空该应用的聊天记录?", "Confirm to clear history": "确认清空该应用的在线聊天记录?分享和 API 调用的记录不会被清空。",
"Exit Chat": "退出聊天", "Exit Chat": "退出聊天",
"Feedback Close": "关闭反馈", "Feedback Close": "关闭反馈",
"Feedback Failed": "提交反馈异常", "Feedback Failed": "提交反馈异常",

View File

@ -439,13 +439,20 @@ const ChatBox = (
border: theme.borders.base, border: theme.borders.base,
mr: 3 mr: 3
}; };
const controlContainerStyle = { const controlContainerStyle = useCallback((status: ChatSiteItemType['status']) => {
className: 'control', return {
color: 'myGray.400', className: 'control',
display: feedbackType === FeedbackTypeEnum.admin ? 'flex' : ['flex', 'none'], color: 'myGray.400',
pl: 1, display:
mt: 2 status === 'finish'
}; ? feedbackType === FeedbackTypeEnum.admin
? 'flex'
: ['flex', 'none']
: 'none',
pl: 1,
mt: 2
};
}, []);
const MessageCardStyle: BoxProps = { const MessageCardStyle: BoxProps = {
px: 4, px: 4,
py: 3, py: 3,
@ -604,7 +611,11 @@ const ChatBox = (
{item.obj === 'Human' && ( {item.obj === 'Human' && (
<> <>
<Flex w={'100%'} alignItems={'center'} justifyContent={'flex-end'}> <Flex w={'100%'} alignItems={'center'} justifyContent={'flex-end'}>
<Flex {...controlContainerStyle} justifyContent={'flex-end'} mr={3}> <Flex
{...controlContainerStyle(item.status)}
justifyContent={'flex-end'}
mr={3}
>
<MyTooltip label={'复制'}> <MyTooltip label={'复制'}>
<MyIcon <MyIcon
{...controlIconStyle} {...controlIconStyle}
@ -652,7 +663,7 @@ const ChatBox = (
<> <>
<Flex w={'100%'} alignItems={'flex-end'}> <Flex w={'100%'} alignItems={'flex-end'}>
<ChatAvatar src={appAvatar} type={'AI'} /> <ChatAvatar src={appAvatar} type={'AI'} />
<Flex {...controlContainerStyle} ml={3}> <Flex {...controlContainerStyle(item.status)} ml={3}>
<MyTooltip label={'复制'}> <MyTooltip label={'复制'}>
<MyIcon <MyIcon
{...controlIconStyle} {...controlIconStyle}

View File

@ -13,6 +13,11 @@ export const fileImgs = [
{ suffix: 'md', src: '/imgs/files/markdown.svg' } { suffix: 'md', src: '/imgs/files/markdown.svg' }
]; ];
export enum TrackEventName {
windowError = 'windowError',
pageError = 'pageError'
}
export const htmlTemplate = `<!DOCTYPE html> export const htmlTemplate = `<!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>

View File

@ -42,6 +42,7 @@ function App({ Component, pageProps }: AppProps) {
const [googleClientVerKey, setGoogleVerKey] = useState<string>(); const [googleClientVerKey, setGoogleVerKey] = useState<string>();
useEffect(() => { useEffect(() => {
// get init data
(async () => { (async () => {
const { const {
feConfigs: { scripts, googleClientVerKey } feConfigs: { scripts, googleClientVerKey }
@ -49,6 +50,21 @@ function App({ Component, pageProps }: AppProps) {
setScripts(scripts || []); setScripts(scripts || []);
setGoogleVerKey(googleClientVerKey); setGoogleVerKey(googleClientVerKey);
})(); })();
// add window error track
window.onerror = function (msg, url) {
window.umami?.track('windowError', {
device: {
userAgent: navigator.userAgent,
platform: navigator.platform,
appName: navigator.appName
},
msg,
url
});
};
return () => {
window.onerror = null;
};
}, []); }, []);
useEffect(() => { useEffect(() => {

View File

@ -1,10 +1,19 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { serviceSideProps } from '@/utils/i18n';
function Error() { function Error() {
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
setTimeout(() => { setTimeout(() => {
router.replace('/app/list'); window.umami?.track('pageError', {
userAgent: navigator.userAgent,
platform: navigator.platform,
appName: navigator.appName
});
}, 1000);
setTimeout(() => {
router.back();
}, 2000); }, 2000);
}, []); }, []);
@ -16,4 +25,12 @@ function Error() {
); );
} }
export async function getServerSideProps(context: any) {
console.log(context);
return {
props: { ...(await serviceSideProps(context)) }
};
}
export default Error; export default Error;

View File

@ -2,6 +2,7 @@ import type { NextApiRequest, NextApiResponse } from 'next';
import { jsonRes } from '@/service/response'; import { jsonRes } from '@/service/response';
import { connectToDatabase, Chat, ChatItem } from '@/service/mongo'; import { connectToDatabase, Chat, ChatItem } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { ChatSourceEnum } from '@/constants/chat';
type Props = { type Props = {
chatId?: string; chatId?: string;
@ -29,14 +30,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
]); ]);
} }
if (appId) { if (appId) {
const chats = await Chat.find({
appId,
userId,
source: ChatSourceEnum.online
}).select('_id');
const chatIds = chats.map((chat) => chat._id);
await Promise.all([ await Promise.all([
Chat.deleteMany({ Chat.deleteMany({
appId, _id: { $in: chatIds }
userId
}), }),
ChatItem.deleteMany({ ChatItem.deleteMany({
userId, chatId: { $in: chatIds }
appId
}) })
]); ]);
} }

View File

@ -15,29 +15,31 @@ const SliderApps = ({ appId }: { appId: string }) => {
useQuery(['loadModels'], () => loadMyApps(false)); useQuery(['loadModels'], () => loadMyApps(false));
return ( return (
<> <Flex flexDirection={'column'} h={'100%'}>
<Flex <Box px={5} py={4}>
alignItems={'center'} <Flex
cursor={'pointer'} alignItems={'center'}
py={2} cursor={'pointer'}
px={3} py={2}
borderRadius={'md'} px={3}
_hover={{ bg: 'myGray.200' }} borderRadius={'md'}
onClick={() => router.push('/app/list')} _hover={{ bg: 'myGray.200' }}
> onClick={() => router.push('/app/list')}
<IconButton >
mr={3} <IconButton
icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />} mr={3}
bg={'white'} icon={<MyIcon name={'backFill'} w={'18px'} color={'myBlue.600'} />}
boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'} bg={'white'}
h={'28px'} boxShadow={'1px 1px 9px rgba(0,0,0,0.15)'}
size={'sm'} h={'28px'}
borderRadius={'50%'} size={'sm'}
aria-label={''} borderRadius={'50%'}
/> aria-label={''}
{t('chat.Exit Chat')} />
</Flex> {t('chat.Exit Chat')}
<Box mt={5}> </Flex>
</Box>
<Box flex={'1 0 0'} h={0} px={5} overflow={'overlay'}>
{myApps.map((item) => ( {myApps.map((item) => (
<Flex <Flex
key={item._id} key={item._id}
@ -72,7 +74,7 @@ const SliderApps = ({ appId }: { appId: string }) => {
</Flex> </Flex>
))} ))}
</Box> </Box>
</> </Flex>
); );
}; };

View File

@ -252,7 +252,7 @@ const Chat = ({ appId, chatId }: { appId: string; chatId: string }) => {
</Head> </Head>
{/* pc show myself apps */} {/* pc show myself apps */}
{isPc && ( {isPc && (
<Box p={5} borderRight={theme.borders.base} w={'220px'} flexShrink={0}> <Box borderRight={theme.borders.base} w={'220px'} flexShrink={0}>
<SliderApps appId={appId} /> <SliderApps appId={appId} />
</Box> </Box>
)} )}

View File

@ -4,6 +4,7 @@ import type { Pool } from 'pg';
import type { Tiktoken } from '@dqbd/tiktoken'; import type { Tiktoken } from '@dqbd/tiktoken';
import type { Logger } from 'winston'; import type { Logger } from 'winston';
import { ChatModelItemType, QAModelItemType, VectorModelItemType } from './model'; import { ChatModelItemType, QAModelItemType, VectorModelItemType } from './model';
import { TrackEventName } from '@/constants/common';
export type PagingData<T> = { export type PagingData<T> = {
pageNum: number; pageNum: number;
@ -60,5 +61,8 @@ declare global {
particlesJS: any; particlesJS: any;
grecaptcha: any; grecaptcha: any;
QRCode: any; QRCode: any;
umami?: {
track: (event: `${TrackEventName}`, data: any) => void;
};
} }
} }