diff --git a/client/src/components/ScrollData/index.tsx b/client/src/components/ScrollData/index.tsx deleted file mode 100644 index 6789961d8..000000000 --- a/client/src/components/ScrollData/index.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useRef, useEffect, useMemo } from 'react'; -import type { BoxProps } from '@chakra-ui/react'; -import { Box } from '@chakra-ui/react'; -import { throttle } from 'lodash'; -import { useLoading } from '@/hooks/useLoading'; - -interface Props extends BoxProps { - nextPage: () => void; - isLoadAll: boolean; - requesting: boolean; - children: React.ReactNode; - initRequesting?: boolean; -} - -const ScrollData = ({ - children, - nextPage, - isLoadAll, - requesting, - initRequesting, - ...props -}: Props) => { - const { Loading } = useLoading({ defaultLoading: true }); - const elementRef = useRef(null); - const loadText = useMemo(() => { - if (requesting) return '请求中……'; - if (isLoadAll) return '已加载全部'; - return '点击加载更多'; - }, [isLoadAll, requesting]); - - useEffect(() => { - if (!elementRef.current) return; - - const scrolling = throttle((e: Event) => { - const element = e.target as HTMLDivElement; - if (!element) return; - // 当前滚动位置 - const scrollTop = element.scrollTop; - // 可视高度 - const clientHeight = element.clientHeight; - // 内容总高度 - const scrollHeight = element.scrollHeight; - // 判断是否滚动到底部 - if (scrollTop + clientHeight + 100 >= scrollHeight) { - nextPage(); - } - }, 100); - elementRef.current.addEventListener('scroll', scrolling); - return () => { - // eslint-disable-next-line react-hooks/exhaustive-deps - elementRef.current?.removeEventListener('scroll', scrolling); - }; - }, [elementRef, nextPage]); - - return ( - - {children} - { - if (loadText !== '点击加载更多') return; - nextPage(); - }} - > - {loadText} - - {initRequesting && } - - ); -}; - -export default ScrollData; diff --git a/client/src/hooks/usePagination.tsx b/client/src/hooks/usePagination.tsx index 7ce970e39..49a8cb64b 100644 --- a/client/src/hooks/usePagination.tsx +++ b/client/src/hooks/usePagination.tsx @@ -1,21 +1,27 @@ -import { useState, useCallback, useMemo, useEffect } from 'react'; +import { useRef, useState, useCallback, useLayoutEffect, useMemo, useEffect } from 'react'; import type { PagingData } from '../types/index'; import { IconButton, Flex, Box, Input } from '@chakra-ui/react'; import { ArrowBackIcon, ArrowForwardIcon } from '@chakra-ui/icons'; import { useMutation } from '@tanstack/react-query'; import { useToast } from './useToast'; +import { throttle } from 'lodash'; + +const thresholdVal = 100; export const usePagination = ({ api, pageSize = 10, params = {}, - defaultRequest = true + defaultRequest = true, + type = 'button' }: { api: (data: any) => any; pageSize?: number; params?: Record; defaultRequest?: boolean; + type?: 'button' | 'scroll'; }) => { + const elementRef = useRef(null); const { toast } = useToast(); const [pageNum, setPageNum] = useState(1); const [total, setTotal] = useState(0); @@ -108,6 +114,60 @@ export const usePagination = ({ ); }, [isLoading, maxPage, mutate, pageNum]); + const ScrollData = useCallback( + ({ children, ...props }: { children: React.ReactNode }) => { + const loadText = useMemo(() => { + if (isLoading) return '请求中……'; + if (total <= data.length) return '已加载全部'; + return '点击加载更多'; + }, []); + + return ( + + {children} + { + if (loadText !== '点击加载更多') return; + mutate(pageNum + 1); + }} + > + {loadText} + + + ); + }, + [data.length, isLoading, mutate, pageNum, total] + ); + + useLayoutEffect(() => { + if (!elementRef.current || type !== 'scroll') return; + + const scrolling = throttle((e: Event) => { + const element = e.target as HTMLDivElement; + if (!element) return; + // 当前滚动位置 + const scrollTop = element.scrollTop; + // 可视高度 + const clientHeight = element.clientHeight; + // 内容总高度 + const scrollHeight = element.scrollHeight; + // 判断是否滚动到底部 + if (scrollTop + clientHeight + thresholdVal >= scrollHeight) { + mutate(pageNum + 1); + } + }, 100); + elementRef.current.addEventListener('scroll', scrolling); + return () => { + // eslint-disable-next-line react-hooks/exhaustive-deps + elementRef.current?.removeEventListener('scroll', scrolling); + }; + }, [elementRef, mutate, pageNum, type]); + useEffect(() => { defaultRequest && mutate(1); }, []); @@ -119,6 +179,7 @@ export const usePagination = ({ data, isLoading, Pagination, + ScrollData, getData: mutate }; }; diff --git a/client/src/pages/api/model/create.ts b/client/src/pages/api/model/create.ts index e9805a117..81d554a27 100644 --- a/client/src/pages/api/model/create.ts +++ b/client/src/pages/api/model/create.ts @@ -24,8 +24,8 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< const authCount = await Model.countDocuments({ userId }); - if (authCount >= 30) { - throw new Error('上限 30 个应用'); + if (authCount >= 50) { + throw new Error('上限 50 个应用'); } // 创建模型 diff --git a/client/src/pages/api/model/list.ts b/client/src/pages/api/model/list.ts index 6c5563b7e..a6856d16f 100644 --- a/client/src/pages/api/model/list.ts +++ b/client/src/pages/api/model/list.ts @@ -18,14 +18,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< { userId }, - '_id avatar name chat.systemPrompt' + '_id avatar name intro' ).sort({ updateTime: -1 }), Collection.find({ userId }) .populate({ path: 'modelId', - select: '_id avatar name chat.systemPrompt', + select: '_id avatar name intro', match: { 'share.isShare': true } }) .then((res) => res.filter((item) => item.modelId)) @@ -37,14 +37,14 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse< _id: item._id, name: item.name, avatar: item.avatar, - systemPrompt: item.chat.systemPrompt + intro: item.intro })), myCollectionModels: myCollections .map((item: any) => ({ _id: item.modelId?._id, name: item.modelId?.name, avatar: item.modelId?.avatar, - systemPrompt: item.modelId?.chat.systemPrompt + intro: item.modelId?.intro })) .filter((item) => !myModels.find((model) => String(model._id) === String(item._id))) // 去重 } diff --git a/client/src/pages/model/components/ModelList.tsx b/client/src/pages/model/components/ModelList.tsx index d557f9d66..9e191912e 100644 --- a/client/src/pages/model/components/ModelList.tsx +++ b/client/src/pages/model/components/ModelList.tsx @@ -1,5 +1,5 @@ -import React, { useCallback, useMemo, useRef, useState } from 'react'; -import { Box, Flex, Input, IconButton, Tooltip, Tab, useTheme } from '@chakra-ui/react'; +import React, { useCallback, useMemo, useState } from 'react'; +import { Box, Flex, Input, IconButton, Tooltip, useTheme } from '@chakra-ui/react'; import { AddIcon } from '@chakra-ui/icons'; import { useRouter } from 'next/router'; import MyIcon from '@/components/Icon'; @@ -55,14 +55,12 @@ const ModelList = ({ modelId }: { modelId: string }) => { const currentModels = useMemo(() => { const map = { [MyModelsTypeEnum.my]: { - list: myModels.filter((item) => - new RegExp(searchText, 'ig').test(item.name + item.systemPrompt) - ), + list: myModels.filter((item) => new RegExp(searchText, 'ig').test(item.name + item.intro)), emptyText: '还没有 AI 应用~\n快来创建一个吧' }, [MyModelsTypeEnum.collection]: { list: myCollectionModels.filter((item) => - new RegExp(searchText, 'ig').test(item.name + item.systemPrompt) + new RegExp(searchText, 'ig').test(item.name + item.intro) ), emptyText: '收藏的 AI 应用为空~\n快去市场找一个吧' } diff --git a/client/src/pages/model/components/detail/components/Settings.tsx b/client/src/pages/model/components/detail/components/Settings.tsx index b188a70b1..d9bb23d3b 100644 --- a/client/src/pages/model/components/detail/components/Settings.tsx +++ b/client/src/pages/model/components/detail/components/Settings.tsx @@ -24,7 +24,8 @@ const Settings = ({ modelId }: { modelId: string }) => { const { toast } = useToast(); const router = useRouter(); const { Loading, setIsLoading } = useLoading(); - const { userInfo, modelDetail, loadModelDetail, refreshModel, setLastModelId } = useUserStore(); + const { userInfo, modelDetail, myModels, loadModelDetail, refreshModel, setLastModelId } = + useUserStore(); const { File, onOpen: onOpenSelectFile } = useSelectFile({ fileType: '.jpg,.png', multiple: false @@ -119,7 +120,7 @@ const Settings = ({ modelId }: { modelId: string }) => { status: 'success' }); refreshModel.removeModelDetail(modelDetail._id); - router.replace('/model'); + router.replace(`/model?modelId=${myModels[1]?._id}`); } catch (err: any) { toast({ title: err?.message || '删除失败', @@ -127,7 +128,7 @@ const Settings = ({ modelId }: { modelId: string }) => { }); } setIsLoading(false); - }, [modelDetail, setIsLoading, toast, refreshModel, router]); + }, [modelDetail, setIsLoading, toast, refreshModel, router, myModels]); const onSelectFile = useCallback( async (e: File[]) => { diff --git a/client/src/types/model.d.ts b/client/src/types/model.d.ts index 5ee66a84e..044763f96 100644 --- a/client/src/types/model.d.ts +++ b/client/src/types/model.d.ts @@ -5,7 +5,7 @@ export type ModelListItemType = { _id: string; name: string; avatar: string; - systemPrompt: string; + intro: string; }; export interface ModelUpdateParams {