import { apiInterceptors, collectApp, getAppList, newDialogue, recommendApps, unCollectApp } from '@/client/api'; import { PlusOutlined, SearchOutlined, StarFilled, StarOutlined } from '@ant-design/icons'; import { useRequest } from 'ahooks'; import type { SegmentedProps } from 'antd'; import { Avatar, Button, ConfigProvider, Input, Segmented, Spin, message } from 'antd'; import cls from 'classnames'; import { NextPage } from 'next'; import { useRouter } from 'next/router'; import { useContext, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { GridCellRenderer, Index, IndexRange } from 'react-virtualized'; import { AutoSizer, Grid, InfiniteLoader } from 'react-virtualized'; import { ChatContext } from '@/app/chat-context'; import IconFont from '@/new-components/common/Icon'; import BlurredCard from '@/new-components/common/blurredCard'; import { AppListResponse } from '@/types/app'; import moment from 'moment'; const Playground: NextPage = () => { const router = useRouter(); const { t } = useTranslation(); const { setAgent, setCurrentDialogInfo, model } = useContext(ChatContext); const [activeKey, setActiveKey] = useState('all'); const [apps, setApps] = useState({ app_list: [], total_count: 0, }); const items: SegmentedProps['options'] = [ { value: 'recommend', label: t('recommend_apps'), }, { value: 'all', label: t('all_apps'), }, { value: 'collected', label: t('my_collected_apps'), }, ]; const getAppListWithParams = (params: Record) => apiInterceptors( getAppList({ page_no: '1', page_size: '12', ...params, }), ); const getHotAppList = (params: Record) => apiInterceptors( recommendApps({ page_no: '1', page_size: '12', ...params, }), ); // 获取应用列表 const { run: getAppListFn, loading } = useRequest( async (app_name = '', page_no = '1', page_size = '12') => { switch (activeKey) { case 'recommend': return await getHotAppList({ ...{ page_no, page_size }, }); case 'collected': return await getAppListWithParams({ is_collected: 'true', ignore_user: 'true', published: 'true', need_owner_info: 'true', ...{ app_name, page_no, page_size }, }); case 'all': return await getAppListWithParams({ ignore_user: 'true', published: 'true', need_owner_info: 'true', ...{ app_name, page_no, page_size }, }); default: return []; } }, { manual: true, onSuccess: (res: [any, [] | AppListResponse]) => { const [_error, data] = res; if (activeKey === 'recommend') { if (Array.isArray(data)) { return setApps({ app_list: data, total_count: data.length, }); } } else { if ('app_list' in data) { const code = data?.app_list?.[0]?.app_code; const index = code ? apps.app_list.findIndex((item: any) => item.app_code === code) : -1; if (index !== -1) { const finallyIndex = Math.floor(index / 12) * 12; setApps( { app_list: apps.app_list.toSpliced(finallyIndex, 12, ...data.app_list) || [], total_count: data?.total_count || 0, } || {}, ); } else { console.log('concat'); setApps( { app_list: apps.app_list.concat(data?.app_list) || [], total_count: data?.total_count || 0, } || {}, ); } } } }, debounceWait: 500, }, ); const onSearch = async (e: any) => { setApps({ app_list: [], total_count: 0, }); getAppListFn(e.target.value); }; const collect = async (data: Record) => { const [error] = await apiInterceptors( data.is_collected === 'true' ? unCollectApp({ app_code: data.app_code }) : collectApp({ app_code: data.app_code }), ); const index = apps.app_list.findIndex((item: any) => item.app_code === data.app_code); if (error) return; if (data.is_collected === 'true') { message.success(t('cancel_success')); } else { message.success(t('collect_success')); } getAppListFn('', (Math.floor(index / 12) + 1).toString()); }; const columnCount = 3; function isRowLoaded({ index }: Index) { return !!apps.app_list[index]; // 检查给定的索引是否已经加载 } function loadMoreRows({ startIndex, stopIndex }: IndexRange) { const pageSize = 12; const currentPage = Math.ceil(startIndex / pageSize) + 1; // 计算当前页数 console.log(startIndex, stopIndex, currentPage); // 这里应该是一个从服务器获取更多数据的异步操作 // 例如,你可能会调用 API 并返回一个 Promise return getAppListFn('', currentPage.toString()); } const cellRenderer: GridCellRenderer = ({ columnIndex, key, rowIndex, style }) => { // 计算数组中的索引 const index = rowIndex * columnCount + columnIndex; if (!isRowLoaded({ index })) return null; const item = apps.app_list[index]; return (
collect(item)} style={{ height: '21px', cursor: 'pointer', color: '#f9c533', }} /> ) : ( collect(item)} style={{ height: '21px', cursor: 'pointer', }} /> ) } onClick={async () => { // 原生应用跳转 if (item.team_mode === 'native_app') { const { chat_scene = '' } = item.team_context; const [, res] = await apiInterceptors(newDialogue({ chat_mode: chat_scene })); if (res) { setCurrentDialogInfo?.({ chat_scene: res.chat_mode, app_code: item.app_code, }); localStorage.setItem( 'cur_dialog_info', JSON.stringify({ chat_scene: res.chat_mode, app_code: item.app_code, }), ); router.push(`/chat?scene=${chat_scene}&id=${res.conv_uid}${model ? `&model=${model}` : ''}`); } } else { // 自定义应用 const [, res] = await apiInterceptors(newDialogue({ chat_mode: 'chat_agent' })); if (res) { setCurrentDialogInfo?.({ chat_scene: res.chat_mode, app_code: item.app_code, }); localStorage.setItem( 'cur_dialog_info', JSON.stringify({ chat_scene: res.chat_mode, app_code: item.app_code, }), ); setAgent?.(item.app_code); router.push(`/chat/?scene=chat_agent&id=${res.conv_uid}${model ? `&model=${model}` : ''}`); } } }} LeftBottom={
{item.owner_name && (
{item.owner_name} {item.owner_name}
)} {activeKey === 'recommend' ? (
{item.hot_value}
) : (
{moment(item?.updated_at).fromNow() + ' ' + t('update')}
)}
} scene={item?.team_context?.chat_scene || 'chat_agent'} />
); }; useEffect(() => { // setPageNo('1'); setApps({ app_list: [], total_count: 0, }); }, [activeKey]); useEffect(() => { getAppListFn(); }, [activeKey, getAppListFn]); // useEffect(() => { // getAppListFn(); // }, [getAppListFn, pageNo]); return (
{/* Apps list */}
12 ? 45 : 20, }} >
setActiveKey(key as any)} value={activeKey} /> } placeholder={t('please_enter_the_keywords')} onChange={onSearch} onPressEnter={onSearch} allowClear className={cls( 'w-[230px] h-[40px] border-1 border-white backdrop-filter backdrop-blur-lg bg-white bg-opacity-30 dark:border-[#6f7f95] dark:bg-[#6f7f95] dark:bg-opacity-60', { hidden: activeKey === 'recommend', }, )} />
{loading && !apps.app_list.length ? ( ) : ( <> {({ onRowsRendered, registerChild }) => ( {({ width, height }) => ( { const startIndex = rowStartIndex * columnCount; const stopIndex = rowStopIndex * columnCount + (columnCount - 1); onRowsRendered({ startIndex, stopIndex, }); }} cellRenderer={cellRenderer} columnWidth={width / columnCount} columnCount={columnCount} height={height} rowHeight={200 /* 你的行高 */} rowCount={apps.total_count} width={width} /> )} )} {loading && apps.app_list.length && ( )} )} {/* */}
); }; export default Playground;