This commit is contained in:
archer
2023-07-05 23:29:28 +08:00
parent 8e9816d648
commit 46f20c7dc3
18 changed files with 352 additions and 92 deletions

View File

@@ -1,8 +1,9 @@
import { GET, POST, DELETE, PUT } from './request'; import { GET, POST, DELETE, PUT } from './request';
import type { AppSchema } from '@/types/mongoSchema'; import type { AppSchema } from '@/types/mongoSchema';
import type { AppUpdateParams } from '@/types/app'; import type { AppModuleItemType, AppUpdateParams } from '@/types/app';
import { RequestPaging } from '../types/index'; import { RequestPaging } from '../types/index';
import type { AppListResponse } from './response/app'; import type { AppListResponse } from './response/app';
import type { Props as CreateAppProps } from '@/pages/api/app/create';
/** /**
* 获取模型列表 * 获取模型列表
@@ -12,7 +13,7 @@ export const getMyModels = () => GET<AppListResponse>('/app/list');
/** /**
* 创建一个模型 * 创建一个模型
*/ */
export const postCreateModel = (data: { name: string }) => POST<string>('/app/create', data); export const postCreateApp = (data: CreateAppProps) => POST<string>('/app/create', data);
/** /**
* 根据 ID 删除模型 * 根据 ID 删除模型

View File

@@ -20,8 +20,8 @@ const NavbarPhone = ({ unread }: { unread: number }) => {
{ {
label: '应用', label: '应用',
icon: 'tabbarModel', icon: 'tabbarModel',
link: `/model`, link: `/app/list`,
activeLink: ['/model'], activeLink: ['/app/list'],
unread: 0 unread: 0
}, },
{ {

View File

@@ -0,0 +1,22 @@
import React from 'react';
import { Box, useTheme, type BoxProps } from '@chakra-ui/react';
const PageContainer = ({ children, ...props }: BoxProps) => {
const theme = useTheme();
return (
<Box bg={'myGray.100'} h={'100%'} p={[0, 5]} {...props}>
<Box
flex={1}
h={'100%'}
bg={'white'}
borderRadius={['', '2xl']}
border={['', theme.borders.lg]}
overflowY={'auto'}
>
{children}
</Box>
</Box>
);
};
export default PageContainer;

View File

@@ -42,20 +42,19 @@ const SlideTabs = ({ list, size = 'md', activeId, onChange, ...props }: Props) =
px={3} px={3}
mb={2} mb={2}
alignItems={'center'} alignItems={'center'}
_hover={{
bg: 'myWhite.600'
}}
{...(activeId === item.id {...(activeId === item.id
? { ? {
// backgroundImage: 'linear-gradient(to right, #85b1ff 0%, #EBF7FD 100%)', bg: ' myBlue.300 !important',
bg: ' myBlue.300',
fontWeight: 'bold', fontWeight: 'bold',
color: 'myBlue.700', color: 'myBlue.700 ',
cursor: 'default' cursor: 'default'
} }
: { : {
cursor: 'pointer' cursor: 'pointer'
})} })}
_hover={{
bg: 'myWhite.600'
}}
onClick={() => { onClick={() => {
if (activeId === item.id) return; if (activeId === item.id) return;
onChange(item.id); onChange(item.id);

View File

@@ -4,7 +4,7 @@ import { useRouter } from 'next/router';
const NonePage = () => { const NonePage = () => {
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
router.push('/model'); router.push('/app/list');
}, [router]); }, [router]);
return <div></div>; return <div></div>;

View File

@@ -50,10 +50,10 @@ function App({ Component, pageProps }: AppProps) {
<link rel="icon" href="/favicon.ico" /> <link rel="icon" href="/favicon.ico" />
</Head> </Head>
<Script src="/js/particles.js"></Script> <Script src="/js/particles.js"></Script>
<Script src="/js/qrcode.min.js" strategy="afterInteractive"></Script> <Script src="/js/qrcode.min.js" strategy="lazyOnload"></Script>
<Script src="/js/pdf.js" strategy="afterInteractive"></Script> <Script src="/js/pdf.js" strategy="lazyOnload"></Script>
<Script src="/js/html2pdf.bundle.min.js" strategy="afterInteractive"></Script> <Script src="/js/html2pdf.bundle.min.js" strategy="lazyOnload"></Script>
{baiduTongji && <Script src="/js/baidutongji.js" strategy="afterInteractive"></Script>} {baiduTongji && <Script src="/js/baidutongji.js" strategy="lazyOnload"></Script>}
{googleVerKey && ( {googleVerKey && (
<> <>
<Script <Script

View File

@@ -4,14 +4,19 @@ import { jsonRes } from '@/service/response';
import { connectToDatabase } from '@/service/mongo'; import { connectToDatabase } from '@/service/mongo';
import { authUser } from '@/service/utils/auth'; import { authUser } from '@/service/utils/auth';
import { App } from '@/service/models/app'; import { App } from '@/service/models/app';
import { AppModuleItemType } from '@/types/app';
export type Props = {
name: string;
avatar?: string;
modules: AppModuleItemType[];
};
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) { export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
try { try {
const { name } = req.body as { const { name, avatar, modules } = req.body as Props;
name: string;
};
if (!name) { if (!name || !Array.isArray(modules)) {
throw new Error('缺少参数'); throw new Error('缺少参数');
} }
@@ -30,8 +35,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
// 创建模型 // 创建模型
const response = await App.create({ const response = await App.create({
avatar,
name, name,
userId userId,
modules
}); });
jsonRes(res, { jsonRes(res, {

View File

@@ -20,8 +20,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
const { toast } = useToast(); const { toast } = useToast();
const router = useRouter(); const router = useRouter();
const { Loading, setIsLoading } = useLoading(); const { Loading, setIsLoading } = useLoading();
const { userInfo, appDetail, myApps, loadAppDetail, refreshModel, setLastModelId } = const { userInfo, appDetail, myApps, loadAppDetail, setLastModelId } = useUserStore();
useUserStore();
const { File, onOpen: onOpenSelectFile } = useSelectFile({ const { File, onOpen: onOpenSelectFile } = useSelectFile({
fileType: '.jpg,.png', fileType: '.jpg,.png',
multiple: false multiple: false
@@ -61,8 +60,6 @@ const Settings = ({ modelId }: { modelId: string }) => {
chat: data.chat, chat: data.chat,
share: data.share share: data.share
}); });
refreshModel.updateModelDetail(data);
} catch (err: any) { } catch (err: any) {
toast({ toast({
title: err?.message || '更新失败', title: err?.message || '更新失败',
@@ -71,7 +68,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
} }
setBtnLoading(false); setBtnLoading(false);
}, },
[refreshModel, toast] [toast]
); );
// 提交保存表单失败 // 提交保存表单失败
const saveSubmitError = useCallback(() => { const saveSubmitError = useCallback(() => {
@@ -106,8 +103,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
title: '删除成功', title: '删除成功',
status: 'success' status: 'success'
}); });
refreshModel.removeModelDetail(appDetail._id); router.replace(`/app/list`);
router.replace(`/model?modelId=${myApps[1]?._id}`);
} catch (err: any) { } catch (err: any) {
toast({ toast({
title: err?.message || '删除失败', title: err?.message || '删除失败',
@@ -115,7 +111,7 @@ const Settings = ({ modelId }: { modelId: string }) => {
}); });
} }
setIsLoading(false); setIsLoading(false);
}, [appDetail, setIsLoading, toast, refreshModel, router, myApps]); }, [appDetail, setIsLoading, toast, router]);
const onSelectFile = useCallback( const onSelectFile = useCallback(
async (e: File[]) => { async (e: File[]) => {
@@ -152,7 +148,6 @@ const Settings = ({ modelId }: { modelId: string }) => {
status: 'error' status: 'error'
}); });
setLastModelId(''); setLastModelId('');
refreshModel.freshMyModels();
router.replace('/model'); router.replace('/model');
} }
}); });

View File

@@ -9,6 +9,7 @@ import SlideTabs from '@/components/SlideTabs';
import Settings from './components/Settings'; import Settings from './components/Settings';
import { defaultApp } from '@/constants/model'; import { defaultApp } from '@/constants/model';
import Avatar from '@/components/Avatar'; import Avatar from '@/components/Avatar';
import PageContainer from '@/components/PageContainer';
const EditApp = dynamic(() => import('./components/edit'), { const EditApp = dynamic(() => import('./components/edit'), {
ssr: false ssr: false
@@ -78,14 +79,8 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
}, [appId, loadAppDetail]); }, [appId, loadAppDetail]);
return ( return (
<Flex flexDirection={'column'} bg={'myGray.100'} h={'100%'} p={[0, 5]}> <PageContainer>
<Box <Box display={['block', 'flex']} h={'100%'}>
display={['block', 'flex']}
flex={1}
bg={'white'}
borderRadius={['', '2xl']}
border={['', theme.borders.lg]}
>
{/* pc tab */} {/* pc tab */}
<Box display={['none', 'block']} p={4} w={'200px'} borderRight={theme.borders.base}> <Box display={['none', 'block']} p={4} w={'200px'} borderRight={theme.borders.base}>
<Flex mb={4}> <Flex mb={4}>
@@ -141,7 +136,7 @@ const AppDetail = ({ currentTab }: { currentTab: `${TabEnum}` }) => {
{currentTab === TabEnum.share && <Share modelId={appId} />} {currentTab === TabEnum.share && <Share modelId={appId} />}
</Box> </Box>
</Box> </Box>
</Flex> </PageContainer>
); );
}; };

View File

@@ -0,0 +1,217 @@
import React, { useCallback, useState } from 'react';
import {
Box,
Flex,
Button,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
Input,
Grid,
useTheme,
Card
} from '@chakra-ui/react';
import { useSelectFile } from '@/hooks/useSelectFile';
import { useForm } from 'react-hook-form';
import { compressImg } from '@/utils/file';
import { getErrText } from '@/utils/tools';
import { useToast } from '@/hooks/useToast';
import { postCreateApp } from '@/api/app';
import { useRouter } from 'next/router';
import { chatAppDemo } from '@/constants/app';
import Avatar from '@/components/Avatar';
import MyIcon from '@/components/Icon';
type FormType = {
avatar: string;
name: string;
templateId: number;
};
const templates = [
{
id: 0,
icon: 'settings',
name: '简单的对话',
intro: '一个极其简单的 AI 对话应用',
modules: chatAppDemo.modules
},
{
id: 1,
icon: 'settings',
name: '基础知识库',
intro: '每次提问时进行一次知识库搜索,将搜索结果注入 LLM 模型进行参考回答',
modules: chatAppDemo.modules
},
{
id: 2,
icon: 'settings',
name: '问答前引导',
intro: '可以在每次对话开始前提示用户填写一些内容,作为本次对话的永久内容',
modules: chatAppDemo.modules
},
{
id: 3,
icon: 'settings',
name: '意图识别 + 知识库',
intro: '先对用户的问题进行分类,再根据不同类型问题,执行不同的操作',
modules: chatAppDemo.modules
}
];
const CreateModal = ({ onClose, onSuccess }: { onClose: () => void; onSuccess: () => void }) => {
const [refresh, setRefresh] = useState(false);
const [creating, setCreating] = useState(false);
const { toast } = useToast();
const router = useRouter();
const theme = useTheme();
const { register, setValue, getValues, handleSubmit } = useForm<FormType>({
defaultValues: {
avatar: '/icon/logo.png',
name: '',
templateId: 0
}
});
const { File, onOpen: onOpenSelectFile } = useSelectFile({
fileType: '.jpg,.png',
multiple: false
});
const onSelectFile = useCallback(
async (e: File[]) => {
const file = e[0];
if (!file) return;
try {
const src = await compressImg({
file,
maxW: 100,
maxH: 100
});
setValue('avatar', src);
setRefresh((state) => !state);
} catch (err: any) {
toast({
title: getErrText(err, '头像选择异常'),
status: 'warning'
});
}
},
[setValue, toast]
);
const onclickCreate = useCallback(
async (data: FormType) => {
setCreating(true);
try {
const id = await postCreateApp({
avatar: data.avatar,
name: data.name,
modules: templates.find((item) => item.id === data.templateId)?.modules || []
});
toast({
title: '创建成功',
status: 'success'
});
router.push(`/app/detail?appId=${id}`);
onClose();
onSuccess();
} catch (error) {
toast({
title: getErrText(error, '创建应用异常'),
status: 'error'
});
}
setCreating(false);
},
[onClose, onSuccess, router, toast]
);
return (
<Modal isOpen onClose={onClose}>
<ModalOverlay />
<ModalContent w={'700px'} maxW={'90vw'}>
<ModalHeader fontSize={'2xl'}> AI </ModalHeader>
<ModalBody>
<Box color={'myGray.800'}></Box>
<Flex mt={3} alignItems={'center'}>
<Avatar
src={getValues('avatar')}
w={['32px', '36px']}
h={['32px', '36px']}
cursor={'pointer'}
title={'点击选择头像'}
borderRadius={'md'}
onClick={onOpenSelectFile}
/>
<Input
ml={4}
bg={'myWhite.600'}
{...register('name', {
required: '应用名不能为空~'
})}
/>
</Flex>
<Box mt={7} mb={3} color={'myGray.800'}>
</Box>
<Grid
userSelect={'none'}
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2,1fr)']}
gridGap={4}
>
{templates.map((item) => (
<Card
key={item.id}
border={theme.borders.base}
p={3}
borderRadius={'md'}
cursor={'pointer'}
boxShadow={'sm'}
{...(getValues('templateId') === item.id
? {
bg: 'myBlue.300'
}
: {
_hover: {
boxShadow: 'md'
}
})}
onClick={() => {
setValue('templateId', item.id);
setRefresh((state) => !state);
}}
>
<Flex alignItems={'center'}>
<MyIcon name={'apikey'} w={'16px'} />
<Box ml={3} fontWeight={'bold'}>
{item.name}
</Box>
</Flex>
<Box fontSize={'sm'} mt={4}>
{item.intro}
</Box>
</Card>
))}
</Grid>
</ModalBody>
<ModalFooter>
<Button variant={'base'} mr={3} onClick={onClose}>
</Button>
<Button isLoading={creating} onClick={handleSubmit(onclickCreate)}>
</Button>
</ModalFooter>
</ModalContent>
<File onSelect={onSelectFile} />
</Modal>
);
};
export default CreateModal;

View File

@@ -1,29 +1,76 @@
import React from 'react'; import React, { useCallback } from 'react';
import { Box, Grid, Card, useTheme, Flex, IconButton, Button } from '@chakra-ui/react'; import {
Box,
Grid,
Card,
useTheme,
Flex,
IconButton,
Button,
useDisclosure
} from '@chakra-ui/react';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { useUserStore } from '@/store/user'; import { useUserStore } from '@/store/user';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import Avatar from '@/components/Avatar';
import styles from './index.module.scss';
import MyIcon from '@/components/Icon';
import { AddIcon } from '@chakra-ui/icons'; import { AddIcon } from '@chakra-ui/icons';
import { delModelById } from '@/api/app';
import { useToast } from '@/hooks/useToast';
import { useConfirm } from '@/hooks/useConfirm';
import dynamic from 'next/dynamic';
import MyIcon from '@/components/Icon';
import PageContainer from '@/components/PageContainer';
import Avatar from '@/components/Avatar';
const CreateModal = dynamic(() => import('./component/CreateModal'));
import styles from './index.module.scss';
const MyApps = () => { const MyApps = () => {
const { toast } = useToast();
const theme = useTheme(); const theme = useTheme();
const router = useRouter(); const router = useRouter();
const { myApps, loadMyModels } = useUserStore(); const { myApps, loadMyModels } = useUserStore();
const { openConfirm, ConfirmChild } = useConfirm({
title: '删除提示',
content: '确认删除该应用所有信息?'
});
const {
isOpen: isOpenCreateModal,
onOpen: onOpenCreateModal,
onClose: onCloseCreateModal
} = useDisclosure();
/* 点击删除 */
const onclickDelApp = useCallback(
async (id: string) => {
try {
await delModelById(id);
toast({
title: '删除成功',
status: 'success'
});
loadMyModels();
} catch (err: any) {
toast({
title: err?.message || '删除失败',
status: 'error'
});
}
},
[toast, loadMyModels]
);
/* 加载模型 */ /* 加载模型 */
useQuery(['loadModels'], () => loadMyModels(false)); useQuery(['loadModels'], loadMyModels, {
refetchOnMount: true
});
return ( return (
<Box> <PageContainer>
<Flex py={3} px={5} borderBottom={theme.borders.base} alignItems={'center'}> <Flex pt={3} px={5} alignItems={'center'}>
<Box flex={1} className="textlg" letterSpacing={1} fontSize={'24px'} fontWeight={'bold'}> <Box flex={1} className="textlg" letterSpacing={1} fontSize={'24px'} fontWeight={'bold'}>
</Box> </Box>
<Button leftIcon={<AddIcon />} variant={'base'}> <Button leftIcon={<AddIcon />} variant={'base'} onClick={onOpenCreateModal}>
</Button> </Button>
</Flex> </Flex>
@@ -43,8 +90,7 @@ const MyApps = () => {
boxShadow={'none'} boxShadow={'none'}
userSelect={'none'} userSelect={'none'}
_hover={{ _hover={{
boxShadow: 'xl', boxShadow: '1px 1px 10px rgba(0,0,0,0.2)',
transform: 'scale(1.03)',
borderColor: 'transparent', borderColor: 'transparent',
'& .delete': { '& .delete': {
display: 'block' display: 'block'
@@ -64,10 +110,14 @@ const MyApps = () => {
variant={'base'} variant={'base'}
borderRadius={'md'} borderRadius={'md'}
aria-label={'delete'} aria-label={'delete'}
display={'none'} display={['', 'none']}
_hover={{ _hover={{
bg: 'myGray.100' bg: 'myGray.100'
}} }}
onClick={(e) => {
e.stopPropagation();
openConfirm(() => onclickDelApp(app._id))();
}}
/> />
</Flex> </Flex>
<Box className={styles.intro} py={2} fontSize={'sm'} color={'myGray.600'}> <Box className={styles.intro} py={2} fontSize={'sm'} color={'myGray.600'}>
@@ -76,7 +126,9 @@ const MyApps = () => {
</Card> </Card>
))} ))}
</Grid> </Grid>
</Box> <ConfirmChild />
{isOpenCreateModal && <CreateModal onClose={onCloseCreateModal} onSuccess={loadMyModels} />}
</PageContainer>
); );
}; };

View File

@@ -94,7 +94,7 @@ const PcSliderBar = ({
[isPc] [isPc]
); );
useQuery(['loadModels'], () => loadMyModels(false)); useQuery(['loadModels'], loadMyModels);
const { isLoading: isLoadingHistory } = useQuery(['loadingHistory'], () => const { isLoading: isLoadingHistory } = useQuery(['loadingHistory'], () =>
loadHistory({ pageNum: 1 }) loadHistory({ pageNum: 1 })

View File

@@ -39,7 +39,7 @@ const PhoneSliderBar = ({
const { isOpen: isOpenWx, onOpen: onOpenWx, onClose: onCloseWx } = useDisclosure(); const { isOpen: isOpenWx, onOpen: onOpenWx, onClose: onCloseWx } = useDisclosure();
const models = useMemo(() => [...myApps, ...myCollectionApps], [myCollectionApps, myApps]); const models = useMemo(() => [...myApps, ...myCollectionApps], [myCollectionApps, myApps]);
useQuery(['loadModels'], () => loadMyModels(false)); useQuery(['loadModels'], loadMyModels);
const { history, loadHistory } = useChatStore(); const { history, loadHistory } = useChatStore();
useQuery(['loadingHistory'], () => loadHistory({ pageNum: 1 })); useQuery(['loadingHistory'], () => loadHistory({ pageNum: 1 }));

View File

@@ -106,7 +106,7 @@ const Chat = () => {
const { copyData } = useCopyData(); const { copyData } = useCopyData();
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const { Loading, setIsLoading } = useLoading(); const { Loading, setIsLoading } = useLoading();
const { userInfo, loadMyModels } = useUserStore(); const { userInfo } = useUserStore();
const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure(); const { isOpen: isOpenSlider, onClose: onCloseSlider, onOpen: onOpenSlider } = useDisclosure();
// close contextMenu // close contextMenu
@@ -232,7 +232,6 @@ const Chat = () => {
setTimeout(() => { setTimeout(() => {
generatingMessage(); generatingMessage();
loadHistory({ pageNum: 1, init: true }); loadHistory({ pageNum: 1, init: true });
loadMyModels(true);
}, 100); }, 100);
if (errMsg) { if (errMsg) {
@@ -252,7 +251,6 @@ const Chat = () => {
chatData.systemPrompt, chatData.systemPrompt,
chatData.limitPrompt, chatData.limitPrompt,
loadHistory, loadHistory,
loadMyModels,
toast toast
] ]
); );

View File

@@ -205,7 +205,7 @@ const Home = () => {
fontSize={['xl', '3xl']} fontSize={['xl', '3xl']}
h={'auto'} h={'auto'}
py={[2, 3]} py={[2, 3]}
onClick={() => router.push(`/model`)} onClick={() => router.push(`/app/list`)}
> >
</Button> </Button>

View File

@@ -7,7 +7,8 @@ import { useSendCode } from '@/hooks/useSendCode';
import type { ResLogin } from '@/api/response/user'; import type { ResLogin } from '@/api/response/user';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
import { useRouter } from 'next/router'; import { useRouter } from 'next/router';
import { postCreateModel } from '@/api/app'; import { postCreateApp } from '@/api/app';
import { chatAppDemo } from '@/constants/app';
interface Props { interface Props {
loginSuccess: (e: ResLogin) => void; loginSuccess: (e: ResLogin) => void;
@@ -64,8 +65,9 @@ const RegisterForm = ({ setPageType, loginSuccess }: Props) => {
status: 'success' status: 'success'
}); });
// aut register a model // aut register a model
postCreateModel({ postCreateApp({
name: '应用1' name: '应用1',
modules: chatAppDemo.modules
}); });
} catch (error: any) { } catch (error: any) {
toast({ toast({

View File

@@ -17,7 +17,7 @@ const Login = () => {
const { lastRoute = '' } = router.query as { lastRoute: string }; const { lastRoute = '' } = router.query as { lastRoute: string };
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const [pageType, setPageType] = useState<`${PageTypeEnum}`>(PageTypeEnum.login); const [pageType, setPageType] = useState<`${PageTypeEnum}`>(PageTypeEnum.login);
const { setUserInfo, setLastModelId, loadMyModels, loadKbList, setLastKbId } = useUserStore(); const { setUserInfo, setLastModelId, loadKbList, setLastKbId } = useUserStore();
const { setLastChatId, setLastChatModelId, loadHistory } = useChatStore(); const { setLastChatId, setLastChatModelId, loadHistory } = useChatStore();
const loginSuccess = useCallback( const loginSuccess = useCallback(
@@ -27,7 +27,6 @@ const Login = () => {
setLastModelId(''); setLastModelId('');
setLastChatModelId(''); setLastChatModelId('');
setLastKbId(''); setLastKbId('');
loadMyModels(true);
loadKbList(true); loadKbList(true);
loadHistory({ pageNum: 1, init: true }); loadHistory({ pageNum: 1, init: true });
@@ -40,7 +39,6 @@ const Login = () => {
lastRoute, lastRoute,
loadHistory, loadHistory,
loadKbList, loadKbList,
loadMyModels,
router, router,
setLastChatId, setLastChatId,
setLastChatModelId, setLastChatModelId,

View File

@@ -22,14 +22,9 @@ type State = {
setLastModelId: (id: string) => void; setLastModelId: (id: string) => void;
myApps: AppListItemType[]; myApps: AppListItemType[];
myCollectionApps: AppListItemType[]; myCollectionApps: AppListItemType[];
loadMyModels: (init?: boolean) => Promise<null>; loadMyModels: () => Promise<null>;
appDetail: AppSchema; appDetail: AppSchema;
loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>; loadAppDetail: (id: string, init?: boolean) => Promise<AppSchema>;
refreshModel: {
freshMyModels(): void;
updateModelDetail(model: AppSchema): void;
removeModelDetail(modelId: string): void;
};
// kb // kb
lastKbId: string; lastKbId: string;
setLastKbId: (id: string) => void; setLastKbId: (id: string) => void;
@@ -76,8 +71,7 @@ export const useUserStore = create<State>()(
}, },
myApps: [], myApps: [],
myCollectionApps: [], myCollectionApps: [],
async loadMyModels(init = false) { async loadMyModels() {
if (get().myApps.length > 0 && !init) return null;
const res = await getMyModels(); const res = await getMyModels();
set((state) => { set((state) => {
state.myApps = res.myApps; state.myApps = res.myApps;
@@ -95,26 +89,6 @@ export const useUserStore = create<State>()(
}); });
return res; return res;
}, },
refreshModel: {
freshMyModels() {
get().loadMyModels(true);
},
updateModelDetail(model: AppSchema) {
set((state) => {
state.appDetail = model;
});
get().loadMyModels(true);
},
removeModelDetail(modelId: string) {
if (modelId === get().appDetail._id) {
set((state) => {
state.appDetail = defaultApp;
state.lastModelId = '';
});
}
get().loadMyModels(true);
}
},
lastKbId: '', lastKbId: '',
setLastKbId(id: string) { setLastKbId(id: string) {
set((state) => { set((state) => {