Merge remote-tracking branch 'origin/main'

main
liushujing 4 months ago
commit 88454da6f1

@ -19,6 +19,7 @@
"try": "试一下" "try": "试一下"
}, },
"back": "返回发现", "back": "返回发现",
"collectSuccess": "收藏成功",
"category": { "category": {
"assistant": { "assistant": {
"all": "全部", "all": "全部",

@ -19,6 +19,7 @@
"try": "試一下" "try": "試一下"
}, },
"back": "返回發現", "back": "返回發現",
"collectSuccess": "收藏成功",
"category": { "category": {
"assistant": { "assistant": {
"academic": "學術", "academic": "學術",

@ -1,29 +1,13 @@
import { ActionIcon } from '@lobehub/ui'; import {Image} from 'antd';
import {Image, Tooltip} from 'antd';
import { LucideX } from 'lucide-react';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
// import UserAvatar from '@/features/User/UserAvatar';
import UserAvatar from '@/features/User/UserAvatar'; // import UserPanel from '@/features/User/UserPanel';
import UserPanel from '@/features/User/UserPanel';
import { useUserStore } from '@/store/user';
import { preferenceSelectors } from '@/store/user/selectors';
const Avatar = memo(() => { const Avatar = memo(() => {
const { t } = useTranslation('common');
const hideSettingsMoveGuide = useUserStore(preferenceSelectors.hideSettingsMoveGuide);
const updateGuideState = useUserStore((s) => s.updateGuideState);
const content = (
<UserPanel>
<UserAvatar clickable />
</UserPanel>
);
return ( return (
<>
<Image alt={""} preview={false} src="/images/logo.png" /> <Image alt={""} preview={false} src="/images/logo.png" />
</>
) )
}); });

@ -1,25 +1,29 @@
import { ActionIcon } from '@lobehub/ui'; // import { ActionIcon } from '@lobehub/ui';
import { Compass, FolderClosed, MessageSquare } from 'lucide-react'; // import { Compass, FolderClosed, MessageSquare } from 'lucide-react';
import Link from 'next/link'; import Link from 'next/link';
import {memo, useEffect, useState} from 'react'; import {memo, useState} from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { SidebarTabKey } from '@/store/global/initialState'; import { SidebarTabKey } from '@/store/global/initialState';
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig'; import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
import { useSessionStore } from '@/store/session'; import { useSessionStore } from '@/store/session';
import { useUserStore } from '@/store/user';
import { createStyles } from 'antd-style'; import { createStyles } from 'antd-style';
import {Button, Image} from "antd"; import { Image } from "antd";
const useStyles = createStyles(({ css, token }) => ({ const useStyles = createStyles(({ css }) => ({
iconImg: css`
width: 48px;
height: 48px;
`,
iconText: css` iconText: css`
text-align: center; text-align: center;
color: #fff; color: #fff;
`, `,
iconImg: css` iconSelectText: css`
width: 48px; color: #0044FF;
height: 48px;
`, `,
linkUrl: css` linkUrl: css`
width: 100%; width: 100%;
@ -28,28 +32,26 @@ const useStyles = createStyles(({ css, token }) => ({
linkclic: css` linkclic: css`
background-color: #fff; background-color: #fff;
`, `,
iconSelectText: css`
color: #0044FF;
`,
})); }));
export interface TopActionProps { export interface TopActionProps {
tab?: SidebarTabKey; tab?: SidebarTabKey;
} }
const getUserId = (s) => s.user?.id
const TopActions = memo<TopActionProps>(({ tab }) => { const TopActions = memo<TopActionProps>(() => {
const { t } = useTranslation('common'); const { t } = useTranslation('common');
const switchBackToChat = useGlobalStore((s) => s.switchBackToChat); const switchBackToChat = useGlobalStore((s) => s.switchBackToChat);
const { showMarket, enableKnowledgeBase } = useServerConfigStore(featureFlagsSelectors); const { showMarket, enableKnowledgeBase } = useServerConfigStore(featureFlagsSelectors);
const { styles, cx } = useStyles() const { styles, cx } = useStyles()
const [value, setValue] = useState("chat") const [value, setValue] = useState("chat")
const userId = getUserId(useUserStore.getState())
console.log(userId,'3837373266262266')
return ( return (
<div style={{ width: '100%', textAlign: 'center'}}> <div style={{ textAlign: 'center', width: '100%'}}>
<Link <Link
aria-label={t('tab.chat')} aria-label={t('tab.chat')}
className={value === '/chat' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)}
href={'/chat'} href={'/chat'}
className={value == '/chat' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)}
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
setValue("/chat") setValue("/chat")
@ -58,48 +60,48 @@ const TopActions = memo<TopActionProps>(({ tab }) => {
}} }}
> >
<Image alt={"chat"} className={cx(styles.iconImg)} preview={false} src="/images/hh.png" /> <Image alt={"chat"} className={cx(styles.iconImg)} preview={false} src="/images/hh.png" />
<div className={value == '/chat' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/chat' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
{enableKnowledgeBase && ( {enableKnowledgeBase && (
<Link className={value == '/discover/assistants' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} aria-label={t('tab.files')} href={`/discover/assistants?userid=${localStorage.getItem('userId')}`} onClick={() => {setValue("/discover/assistants"); window.localStorage.setItem("nowChat", "")}}> <Link aria-label={t('tab.files')} className={value === '/discover/assistants' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} href={`/discover/assistants?userid=${userId}`} onClick={() => {setValue("/discover/assistants"); window.localStorage.setItem("nowChat", "")}}>
<Image alt={"files"} className={cx(styles.iconImg)} preview={false} src="/images/zs.png" /> <Image alt={"files"} className={cx(styles.iconImg)} preview={false} src="/images/zs.png" />
<div className={value == '/discover/assistants' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/discover/assistants' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
)} )}
{showMarket && ( {showMarket && (
<Link className={value == '/files' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} aria-label={t('tab.discover')} href={'/files'} onClick={() => {setValue("/files"); window.localStorage.setItem("nowChat", "")}}> <Link aria-label={t('tab.discover')} className={value === '/files' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} href={'/files'} onClick={() => {setValue("/files"); window.localStorage.setItem("nowChat", "")}}>
<Image alt={"discover"} className={cx(styles.iconImg)} preview={false} src="/images/gj.png" /> <Image alt={"discover"} className={cx(styles.iconImg)} preview={false} src="/images/gj.png" />
<div className={value == '/files' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/files' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
)} )}
{showMarket && ( {showMarket && (
<Link className={value == '/model' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} aria-label={t('tab.Model')} href={'/model'} onClick={() => {setValue("/model"); window.localStorage.setItem("nowChat", "")}}> <Link aria-label={t('tab.Model')} className={value === '/model' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} href={`/discover/models?userid=${userId}`} onClick={() => {setValue("/model"); window.localStorage.setItem("nowChat", "")}}>
<Image alt={"model"} className={cx(styles.iconImg)} preview={false} src="/images/mx.png" /> <Image alt={"model"} className={cx(styles.iconImg)} preview={false} src="/images/mx.png" />
<div className={value == '/model' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/model' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
)} )}
{showMarket && ( {showMarket && (
<Link className={value == '/robot' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} aria-label={t('tab.robot')} href={'/robot'} onClick={() => {setValue("/robot"); window.localStorage.setItem("nowChat", "")}}> <Link aria-label={t('tab.robot')} className={value === '/robot' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} href={'/robot'} onClick={() => {setValue("/robot"); window.localStorage.setItem("nowChat", "")}}>
<Image alt={"robot"} className={cx(styles.iconImg)} preview={false} src="/images/szr.png" /> <Image alt={"robot"} className={cx(styles.iconImg)} preview={false} src="/images/szr.png" />
<div className={value == '/robot' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/robot' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
)} )}
{showMarket && ( {showMarket && (
<Link className={value == '/plugins' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} aria-label={t('tab.Plugins')} href={'/discover/plugins'} onClick={() => {setValue("/plugins"); window.localStorage.setItem("nowChat", "")}}> <Link aria-label={t('tab.Plugins')} className={value === '/plugins' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} href={`/discover/plugins?userid=${userId}`} onClick={() => {setValue("/plugins"); window.localStorage.setItem("nowChat", "")}}>
<Image alt={"plugins"} className={cx(styles.iconImg)} preview={false} src="/images/cj.png" /> <Image alt={"plugins"} className={cx(styles.iconImg)} preview={false} src="/images/cj.png" />
<div className={value == '/plugins' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/plugins' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
)} )}
{showMarket && ( {showMarket && (
<Link className={value == '/power' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} aria-label={t('tab.Power')} href={'/power'} onClick={() => {setValue("/power"); window.localStorage.setItem("nowChat", "")}}> <Link aria-label={t('tab.Power')} className={value === '/power' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} href={'/power'} onClick={() => {setValue("/power"); window.localStorage.setItem("nowChat", "")}}>
<Image alt={"power"} className={cx(styles.iconImg)} preview={false} src="/images/sl.png" /> <Image alt={"power"} className={cx(styles.iconImg)} preview={false} src="/images/sl.png" />
<div className={value == '/power' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/power' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
)} )}
{showMarket && ( {showMarket && (
<Link className={value == '/knowledge' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} aria-label={t('tab.knowledge')} href={'/knowledge'} onClick={() => {setValue("/knowledge")}}> <Link aria-label={t('tab.knowledge')} className={value === '/knowledge' ? cx(styles.linkUrl, styles.linkclic) : cx(styles.linkUrl)} href={'/knowledge'} onClick={() => {setValue("/knowledge")}}>
<Image className={cx(styles.iconImg)} preview={false} src="/images/zsk.png" /> <Image className={cx(styles.iconImg)} preview={false} src="/images/zsk.png" />
<div className={value == '/knowledge' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div> <div className={value === '/knowledge' ? cx(styles.iconText, styles.iconSelectText) : cx(styles.iconText) }></div>
</Link> </Link>
)} )}
</div> </div>

@ -6,7 +6,6 @@ import { memo } from 'react';
import { useActiveTabKey } from '@/hooks/useActiveTabKey'; import { useActiveTabKey } from '@/hooks/useActiveTabKey';
import Avatar from './Avatar'; import Avatar from './Avatar';
import BottomActions from './BottomActions';
import TopActions from './TopActions'; import TopActions from './TopActions';
const Nav = memo(() => { const Nav = memo(() => {
@ -14,8 +13,8 @@ const Nav = memo(() => {
return ( return (
<SideNav <SideNav
avatar={<Avatar />} avatar={<Avatar />}
// bottomActions={<BottomActions />} bottomActions={<></>}
style={{ height: '100%', zIndex: 100, width: '100px', backgroundColor: '#2E62FF' }} style={{ backgroundColor: '#2E62FF', height: '100%', width: '100px', zIndex: 100 }}
topActions={<TopActions tab={sidebarKey} />} topActions={<TopActions tab={sidebarKey} />}
/> />
); );

@ -9,9 +9,7 @@ import { usePlatform } from '@/hooks/usePlatform';
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig'; import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
import { UserOutlined, SearchOutlined } from '@ant-design/icons'; import { UserOutlined, SearchOutlined } from '@ant-design/icons';
import { LayoutProps } from './type'; import { LayoutProps } from './type';
import { Divider, Input, Avatar } from "antd"; import { Divider, Avatar } from "antd";
const { Search } = Input;
const title = { const title = {
"/chat": '会话', "/chat": '会话',
"/discover/assistants": "助手", "/discover/assistants": "助手",
@ -25,6 +23,7 @@ const title = {
const useStyles = createStyles(({ css, token }) => ({ const useStyles = createStyles(({ css, token }) => ({
topCenten: css` topCenten: css`
width: 100%; width: 100%;
line-height: 60px;
background: #FFFFFF; background: #FFFFFF;
box-sizing: border-box; box-sizing: border-box;
/* 分割线颜色 */ /* 分割线颜色 */
@ -38,7 +37,7 @@ const useStyles = createStyles(({ css, token }) => ({
display: inline-block display: inline-block
`, `,
dividerCen: css` dividerCen: css`
width: 2px; width: 1px;
height: 26px; height: 26px;
background-color: #d8d8d8; background-color: #d8d8d8;
margin: 8px 16px; margin: 8px 16px;
@ -48,8 +47,8 @@ const useStyles = createStyles(({ css, token }) => ({
display: inline-block; display: inline-block;
`, `,
nameSpn: css` nameSpn: css`
margin-right: 80px; margin-right: 16px;
margin-left: 8px; margin-left: 18px;
display: inline-block; display: inline-block;
`, `,
serchIcon: css` serchIcon: css`
@ -71,9 +70,9 @@ const Layout = memo<LayoutProps>(({ children, nav }) => {
const { isPWA } = usePlatform(); const { isPWA } = usePlatform();
const theme = useTheme(); const theme = useTheme();
const { styles, cx } = useStyles() const { styles, cx } = useStyles()
console.log(window?.location?.pathname,'3837373666router--------------------------------------------')
const { showCloudPromotion } = useServerConfigStore(featureFlagsSelectors); const { showCloudPromotion } = useServerConfigStore(featureFlagsSelectors);
const pathName = window?.location?.pathname
return ( return (
<> <>
{showCloudPromotion && <CloudBanner />} {showCloudPromotion && <CloudBanner />}
@ -87,7 +86,20 @@ const Layout = memo<LayoutProps>(({ children, nav }) => {
width={'100%'} width={'100%'}
> >
{nav} {nav}
<div style={{ width: '100%' }}>
<div className={cx(styles.topCenten)}>
<div className={cx(styles.ledDiv)}>
<span className={cx(styles.leftTitle)} style={{ marginLeft: '16px' }}>AI</span>
<Divider className={cx(styles.dividerCen)} type="vertical" />
<span className={cx(styles.leftTitle)}>{title[pathName]}</span>
</div>
<div className={cx(styles.ledDiv)} style={{ height: '42px', lineHeight: "42px", textAlign: 'right' }}>
<Avatar style={{ backgroundColor: '#90ACFF' }} icon={<UserOutlined />} />
<span className={cx(styles.nameSpn)}> </span>
</div>
</div>
{children} {children}
</div>
</Flexbox> </Flexbox>
</> </>
); );

@ -15,9 +15,9 @@ const ChatConversation = () => {
<ChatInput /> <ChatInput />
<div style={{ fontSize: '13px', color: '#909090', backgroundColor: "rgba(200, 205, 220, 0.2)"}}> <div style={{ backgroundColor: "rgba(200, 205, 220, 0.2)", color: '#909090', fontSize: '13px'}}>
<span style={{ display: 'inline-block', }}>:</span> <span style={{ display: 'inline-block', }}>:</span>
<span style={{ display: 'inline-block', margin: "0px 13px", fontSize: "20px" }}>&crarr;</span> <span style={{ display: 'inline-block', fontSize: "20px", margin: "0px 13px" }}>&crarr;</span>
<span> </span> <span> </span>
<span style={{ display: 'inline-block', fontSize: "20px", marginLeft: '30px', marginRight: '11px' }}>&crarr;</span> <span style={{ display: 'inline-block', fontSize: "20px", marginLeft: '30px', marginRight: '11px' }}>&crarr;</span>
<span> + Ctrl </span> <span> + Ctrl </span>

@ -1,23 +1,23 @@
import { Icon } from '@lobehub/ui'; // import { Icon } from '@lobehub/ui';
import { Button, Skeleton, Space } from 'antd'; import { Button, Space } from 'antd';
import { createStyles } from 'antd-style'; import { createStyles } from 'antd-style';
import { ChevronUp, CornerDownLeft, LucideCommand, Eraser } from 'lucide-react'; // import { ChevronUp, CornerDownLeft, LucideCommand } from 'lucide-react';
import { rgba } from 'polished'; import { rgba } from 'polished';
import { memo, useEffect, useState } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Center, Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
import StopLoadingIcon from '@/components/StopLoading'; import StopLoadingIcon from '@/components/StopLoading';
import SaveTopic from '@/features/ChatInput/Topic'; // import SaveTopic from '@/features/ChatInput/Topic';
import { useSendMessage } from '@/features/ChatInput/useSend'; import { useSendMessage } from '@/features/ChatInput/useSend';
import { useChatStore } from '@/store/chat'; import { useChatStore } from '@/store/chat';
import { chatSelectors } from '@/store/chat/selectors'; import { chatSelectors } from '@/store/chat/selectors';
import { useUserStore } from '@/store/user'; // import { useUserStore } from '@/store/user';
import { preferenceSelectors } from '@/store/user/selectors'; // import { preferenceSelectors } from '@/store/user/selectors';
import { isMacOS } from '@/utils/platform'; // import { isMacOS } from '@/utils/platform';
import LocalFiles from '../FilePreview'; // import LocalFiles from '../FilePreview';
import SendMore from './SendMore'; // import SendMore from './SendMore';
import {HighlightOutlined, SendOutlined} from "@ant-design/icons"; import {HighlightOutlined, SendOutlined} from "@ant-design/icons";
const useStyles = createStyles(({ css, prefixCls, token }) => { const useStyles = createStyles(({ css, prefixCls, token }) => {
@ -27,10 +27,6 @@ const useStyles = createStyles(({ css, prefixCls, token }) => {
width: 28px; width: 28px;
} }
`, `,
btnDiv: css`
height: 50%;
width: 100px;
`,
btn: css` btn: css`
width: 96px; width: 96px;
height: 80%; height: 80%;
@ -39,6 +35,10 @@ const useStyles = createStyles(({ css, prefixCls, token }) => {
color: #2E62FF !important; color: #2E62FF !important;
font-size: 16px; font-size: 16px;
`, `,
btnDiv: css`
height: 50%;
width: 100px;
`,
btnSend: css` btnSend: css`
width: 96px; width: 96px;
height: 80%; height: 80%;
@ -77,47 +77,47 @@ interface FooterProps {
setExpand?: (expand: boolean) => void; setExpand?: (expand: boolean) => void;
} }
const Footer = memo<FooterProps>(({ setExpand, expand, clearClick }) => { const Footer = memo<FooterProps>(({ clearClick, setExpand }) => {
const { t } = useTranslation('chat'); const { t } = useTranslation('chat');
const { theme, styles } = useStyles(); const { styles } = useStyles();
const [isAIGenerating, stopGenerateMessage] = useChatStore((s) => [ const [isAIGenerating, stopGenerateMessage] = useChatStore((s) => [
chatSelectors.isAIGenerating(s), chatSelectors.isAIGenerating(s),
s.stopGenerateMessage, s.stopGenerateMessage,
]); ]);
const [useCmdEnterToSend] = useUserStore((s) => [preferenceSelectors.useCmdEnterToSend(s)]); // const [useCmdEnterToSend] = useUserStore((s) => [preferenceSelectors.useCmdEnterToSend(s)]);
const { send: sendMessage, canSend } = useSendMessage(); const { send: sendMessage, canSend } = useSendMessage();
const [isMac, setIsMac] = useState<boolean>(); // const [isMac, setIsMac] = useState<boolean>();
useEffect(() => { // useEffect(() => {
setIsMac(isMacOS()); // setIsMac(isMacOS());
}, [setIsMac]); // }, [setIsMac]);
const cmdEnter = ( // const cmdEnter = (
<Flexbox gap={2} horizontal> // <Flexbox gap={2} horizontal>
{typeof isMac === 'boolean' ? ( // {typeof isMac === 'boolean' ? (
<Icon icon={isMac ? LucideCommand : ChevronUp} /> // <Icon icon={isMac ? LucideCommand : ChevronUp} />
) : ( // ) : (
<Skeleton.Node active style={{ height: '100%', width: 12 }}> // <Skeleton.Node active style={{ height: '100%', width: 12 }}>
{' '} // {' '}
</Skeleton.Node> // </Skeleton.Node>
)} // )}
<Icon icon={CornerDownLeft} /> // <Icon icon={CornerDownLeft} />
</Flexbox> // </Flexbox>
); // );
const enter = ( // const enter = (
<Center> // <Center>
<Icon icon={CornerDownLeft} /> // <Icon icon={CornerDownLeft} />
</Center> // </Center>
); // );
const sendShortcut = useCmdEnterToSend ? cmdEnter : enter; // const sendShortcut = useCmdEnterToSend ? cmdEnter : enter;
const wrapperShortcut = useCmdEnterToSend ? enter : cmdEnter; // const wrapperShortcut = useCmdEnterToSend ? enter : cmdEnter;
const handleClickClear = () => { const handleClickClear = () => {
clearClick() clearClick()
@ -127,12 +127,12 @@ const Footer = memo<FooterProps>(({ setExpand, expand, clearClick }) => {
<Flexbox <Flexbox
align={'end'} align={'end'}
className={styles.overrideAntdIcon} className={styles.overrideAntdIcon}
style={{ display: 'inline-block', height: '100%', width: "140px" }}
distribution={'space-between'} distribution={'space-between'}
flex={'none'} flex={'none'}
gap={8} gap={8}
horizontal horizontal
padding={'0 24px'} padding={'0 24px'}
style={{ display: 'inline-block', height: '100%', width: "140px" }}
> >
{/*<Flexbox align={'center'} gap={8} horizontal style={{ overflow: 'hidden' }}>*/} {/*<Flexbox align={'center'} gap={8} horizontal style={{ overflow: 'hidden' }}>*/}
{/* {expand && <LocalFiles />}*/} {/* {expand && <LocalFiles />}*/}

@ -8,7 +8,6 @@ import {
CHAT_TEXTAREA_HEIGHT, CHAT_TEXTAREA_HEIGHT,
CHAT_TEXTAREA_MAX_HEIGHT, CHAT_TEXTAREA_MAX_HEIGHT,
HEADER_HEIGHT, HEADER_HEIGHT,
CHAT_TEXTAREA_MIN_HEIGHT,
} from '@/const/layoutTokens'; } from '@/const/layoutTokens';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { systemStatusSelectors } from '@/store/global/selectors'; import { systemStatusSelectors } from '@/store/global/selectors';
@ -59,9 +58,9 @@ const DesktopChatInput = memo(() => {
style={{ minHeight: CHAT_TEXTAREA_HEIGHT, position: 'relative' }} style={{ minHeight: CHAT_TEXTAREA_HEIGHT, position: 'relative' }}
> >
<Head expand={expand} setExpand={setExpand} /> <Head expand={expand} setExpand={setExpand} />
<div style={{ height: '100%', display: 'flex' }}> <div style={{ display: 'flex', height: '100%'}}>
<TextArea setExpand={setExpand} /> <TextArea setExpand={setExpand} />
<Footer expand={expand} setExpand={setExpand} clearClick={() => clearClick()} /> <Footer clearClick={() => clearClick()} expand={expand} setExpand={setExpand} />
</div> </div>
</Flexbox> </Flexbox>
</DraggablePanel> </DraggablePanel>

@ -86,7 +86,6 @@ const TopicListContent = memo(() => {
)} )}
<Virtuoso <Virtuoso
// components={{ ScrollSeekPlaceholder: Placeholder }} // components={{ ScrollSeekPlaceholder: Placeholder }}
style={{ height: "150px" }}
computeItemKey={(_, item) => item.id} computeItemKey={(_, item) => item.id}
data={topics} data={topics}
fixedItemHeight={44} fixedItemHeight={44}
@ -94,6 +93,7 @@ const TopicListContent = memo(() => {
itemContent={itemContent} itemContent={itemContent}
overscan={44 * 10} overscan={44 * 10}
ref={virtuosoRef} ref={virtuosoRef}
style={{ height: "150px" }}
// scrollSeekConfiguration={{ // scrollSeekConfiguration={{
// enter: (velocity) => Math.abs(velocity) > 350, // enter: (velocity) => Math.abs(velocity) > 350,
// exit: (velocity) => Math.abs(velocity) < 10, // exit: (velocity) => Math.abs(velocity) < 10,

@ -1,35 +1,35 @@
'use client'; 'use client';
import { ActionIcon } from '@lobehub/ui'; // import { ActionIcon } from '@lobehub/ui';
import { PanelRightClose, PanelRightOpen } from 'lucide-react'; // import { PanelRightClose, PanelRightOpen } from 'lucide-react';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; // import { useTranslation } from 'react-i18next';
import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens'; // import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
import { useGlobalStore } from '@/store/global'; // import { useGlobalStore } from '@/store/global';
import { systemStatusSelectors } from '@/store/global/selectors'; // import { systemStatusSelectors } from '@/store/global/selectors';
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig'; // import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
import SettingButton from '../../../features/SettingButton'; // import SettingButton from '../../../features/SettingButton';
import ShareButton from '../../../features/ShareButton'; // import ShareButton from '../../../features/ShareButton';
import {Button} from "antd"; import {Button} from "antd";
import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes'; import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
const HeaderAction = memo(() => { const HeaderAction = memo(() => {
const { t } = useTranslation('chat'); // const { t } = useTranslation('chat');
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [ // const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
systemStatusSelectors.showChatSideBar(s), // systemStatusSelectors.showChatSideBar(s),
s.toggleChatSideBar, // s.toggleChatSideBar,
]); // ]);
const { isAgentEditable } = useServerConfigStore(featureFlagsSelectors); // const { isAgentEditable } = useServerConfigStore(featureFlagsSelectors);
const openChatSettings = useOpenChatSettings(); const openChatSettings = useOpenChatSettings();
return ( return (
<> <>
<Button onClick={() => openChatSettings()} style={{ borderColor: '#2E62FF', color: "#2E62FF" }} shape="round"></Button> <Button onClick={() => openChatSettings()} shape="round" style={{ borderColor: '#2E62FF', color: "#2E62FF" }}></Button>
{/*<ShareButton />*/} {/*<ShareButton />*/}
{/*<ActionIcon*/} {/*<ActionIcon*/}
{/* icon={showAgentSettings ? PanelRightClose : PanelRightOpen}*/} {/* icon={showAgentSettings ? PanelRightClose : PanelRightOpen}*/}

@ -1,28 +1,28 @@
'use client'; 'use client';
import { ActionIcon, Avatar, ChatHeaderTitle } from '@lobehub/ui'; import { Avatar } from '@lobehub/ui';
import { Skeleton } from 'antd'; import { Skeleton } from 'antd';
import { PanelLeftClose, PanelLeftOpen } from 'lucide-react'; // import { PanelLeftClose, PanelLeftOpen } from 'lucide-react';
import { Suspense, memo } from 'react'; import { Suspense, memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens'; // import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes'; import { useOpenChatSettings } from '@/hooks/useInterceptingRoutes';
import { useGlobalStore } from '@/store/global'; // import { useGlobalStore } from '@/store/global';
import { systemStatusSelectors } from '@/store/global/selectors'; // import { systemStatusSelectors } from '@/store/global/selectors';
import { useSessionStore } from '@/store/session'; import { useSessionStore } from '@/store/session';
import { sessionMetaSelectors, sessionSelectors } from '@/store/session/selectors'; import { sessionMetaSelectors, sessionSelectors } from '@/store/session/selectors';
import { useInitAgentConfig } from '../../useInitAgentConfig'; import { useInitAgentConfig } from '../../useInitAgentConfig';
import Tags from './Tags'; // import Tags from './Tags';
const Main = memo(() => { const Main = memo(() => {
const { t } = useTranslation('chat'); const { t } = useTranslation('chat');
useInitAgentConfig(); useInitAgentConfig();
const [init, isInbox, title, description, avatar, backgroundColor] = useSessionStore((s) => [ const [init, isInbox, title, avatar, backgroundColor] = useSessionStore((s) => [
sessionSelectors.isSomeSessionActive(s), sessionSelectors.isSomeSessionActive(s),
sessionSelectors.isInboxSession(s), sessionSelectors.isInboxSession(s),
sessionMetaSelectors.currentAgentTitle(s), sessionMetaSelectors.currentAgentTitle(s),
@ -34,9 +34,9 @@ const Main = memo(() => {
const openChatSettings = useOpenChatSettings(); const openChatSettings = useOpenChatSettings();
const displayTitle = isInbox ? t('inbox.title') : title; const displayTitle = isInbox ? t('inbox.title') : title;
const displayDesc = isInbox ? t('inbox.desc') : description; // const displayDesc = isInbox ? t('inbox.desc') : description;
const showSessionPanel = useGlobalStore(systemStatusSelectors.showSessionPanel); // const showSessionPanel = useGlobalStore(systemStatusSelectors.showSessionPanel);
const updateSystemStatus = useGlobalStore((s) => s.updateSystemStatus); // const updateSystemStatus = useGlobalStore((s) => s.updateSystemStatus);
return !init ? ( return !init ? (
<Flexbox horizontal> <Flexbox horizontal>
@ -73,7 +73,7 @@ const Main = memo(() => {
<div> <div>
<div style={{ fontSize: "15px" }}>{displayTitle}</div> <div style={{ fontSize: "15px" }}>{displayTitle}</div>
{/*<ChatHeaderTitle desc={displayDesc} title={displayTitle} />*/} {/*<ChatHeaderTitle desc={displayDesc} title={displayTitle} />*/}
<div style={{ fontSize: '12px', color: "#A7A0A0" }}>{displayTitle}</div> <div style={{ color: "#A7A0A0", fontSize: '12px' }}>{displayTitle}</div>
</div> </div>
</Flexbox> </Flexbox>
); );

@ -17,7 +17,6 @@ const TitleTags = memo(() => {
agentSelectors.currentAgentModel(s), agentSelectors.currentAgentModel(s),
agentSelectors.hasKnowledge(s), agentSelectors.hasKnowledge(s),
]); ]);
console.log(model, 20202020)
const plugins = useAgentStore(agentSelectors.currentAgentPlugins, isEqual); const plugins = useAgentStore(agentSelectors.currentAgentPlugins, isEqual);
const enabledKnowledge = useAgentStore(agentSelectors.currentEnabledKnowledge, isEqual); const enabledKnowledge = useAgentStore(agentSelectors.currentEnabledKnowledge, isEqual);

@ -3,16 +3,16 @@
import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui'; import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
import { createStyles, useResponsive } from 'antd-style'; import { createStyles, useResponsive } from 'antd-style';
import isEqual from 'fast-deep-equal'; import isEqual from 'fast-deep-equal';
import { PropsWithChildren, memo, useEffect, useState } from 'react'; import { memo, useEffect, useState } from 'react';
import SafeSpacing from '@/components/SafeSpacing'; // import SafeSpacing from '@/components/SafeSpacing';
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens'; import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
import { useChatStore } from '@/store/chat'; import { useChatStore } from '@/store/chat';
import { chatPortalSelectors } from '@/store/chat/slices/portal/selectors'; import { chatPortalSelectors } from '@/store/chat/slices/portal/selectors';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { systemStatusSelectors } from '@/store/global/selectors'; import { systemStatusSelectors } from '@/store/global/selectors';
import {Form, Image} from "antd"; import {Form, Image} from "antd";
import {EditFilled, EditTwoTone} from "@ant-design/icons"; import {EditFilled} from "@ant-design/icons";
import TopicListContent from "@/app/(main)/chat/(workspace)/@topic/features/TopicListContent"; import TopicListContent from "@/app/(main)/chat/(workspace)/@topic/features/TopicListContent";
import Header from "@/app/(main)/chat/(workspace)/@topic/features/Header"; import Header from "@/app/(main)/chat/(workspace)/@topic/features/Header";
@ -31,11 +31,6 @@ const useStyles = createStyles(({ css, token }) => ({
header: css` header: css`
border-block-end: 1px solid ${token.colorBorder}; border-block-end: 1px solid ${token.colorBorder};
`, `,
topTitle: css`
font-size: 18px;
display: inline-block;
width: calc(100% - 24px)
`,
topEdit: css` topEdit: css`
display: inline-block; display: inline-block;
text-align: center; text-align: center;
@ -44,9 +39,14 @@ const useStyles = createStyles(({ css, token }) => ({
background-color: #AFC1FF; background-color: #AFC1FF;
color: #fff; color: #fff;
`, `,
topTitle: css`
font-size: 18px;
display: inline-block;
width: calc(100% - 24px)
`,
})); }));
const TopicPanel = memo(({ children }: PropsWithChildren) => { const TopicPanel = memo(() => {
const { styles } = useStyles(); const { styles } = useStyles();
const [form] = Form.useForm() const [form] = Form.useForm()
const { md = true, lg = true } = useResponsive(); const { md = true, lg = true } = useResponsive();
@ -87,8 +87,8 @@ const TopicPanel = memo(({ children }: PropsWithChildren) => {
style={{ style={{
flex: 'none', flex: 'none',
height: '100%', height: '100%',
maxHeight: '100vh',
border: "1px solid #ddd", border: "1px solid #ddd",
maxHeight: '100vh',
minWidth: CHAT_SIDEBAR_WIDTH, minWidth: CHAT_SIDEBAR_WIDTH,
}} }}
> >
@ -97,14 +97,14 @@ const TopicPanel = memo(({ children }: PropsWithChildren) => {
<div className={styles.topEdit}><EditFilled /></div> <div className={styles.topEdit}><EditFilled /></div>
</div> </div>
<div><Image alt="头像" preview={false} src="/images/zsImage.png" /></div> <div><Image alt="头像" preview={false} src="/images/zsImage.png" /></div>
<Form layout="horizontal" colon={false} form={form} labelCol={{ span: 6 }} wrapperCol={{ span: 18 }}> <Form colon={false} form={form} labelCol={{ span: 6 }} layout="horizontal" wrapperCol={{ span: 18 }}>
<Form.Item name="name" label="名称"> <Form.Item label="名称" name="name">
<span style={{ width: "18px" }}>Linda</span> <span style={{ width: "18px" }}>Linda</span>
</Form.Item> </Form.Item>
<Form.Item name="jj" label="简介"> <Form.Item label="简介" name="jj">
<span style={{ color: "#999999", fontSize: '13px' }}></span> <span style={{ color: "#999999", fontSize: '13px' }}></span>
</Form.Item> </Form.Item>
<Form.Item name="rw" label="任务"> <Form.Item label="任务" name="rw">
<span style={{ color: "#999999", fontSize: '13px' }}></span> <span style={{ color: "#999999", fontSize: '13px' }}></span>
</Form.Item> </Form.Item>
</Form> </Form>

@ -2,12 +2,11 @@
import { memo } from 'react'; import { memo } from 'react';
import { Flexbox, FlexboxProps } from 'react-layout-kit'; import { Flexbox, FlexboxProps } from 'react-layout-kit';
import urlJoin from 'url-join';
import { OFFICIAL_URL } from '@/const/url'; // import { OFFICIAL_URL } from '@/const/url';
import { DiscoverAssistantItem } from '@/types/discover'; import { DiscoverAssistantItem } from '@/types/discover';
import ShareButton from '../../../features/ShareButton'; // import ShareButton from '../../../features/ShareButton';
import AddAgent from './AddAgent'; import AddAgent from './AddAgent';
interface AssistantActionProps extends FlexboxProps { interface AssistantActionProps extends FlexboxProps {
@ -15,19 +14,10 @@ interface AssistantActionProps extends FlexboxProps {
identifier: string; identifier: string;
} }
const AssistantAction = memo<AssistantActionProps>(({ identifier, data }) => { const AssistantAction = memo<AssistantActionProps>(({ data }) => {
return ( return (
<Flexbox align={'center'} gap={8} horizontal> <Flexbox align={'center'} gap={8} horizontal style={{marginLeft: 100}}>
<AddAgent data={data} /> <AddAgent data={data} />
<ShareButton
meta={{
avatar: data.meta.avatar,
desc: data.meta.description,
hashtags: data.meta.tags,
title: data.meta.title,
url: urlJoin(OFFICIAL_URL, '/discover/assistant', identifier),
}}
/>
</Flexbox> </Flexbox>
); );
}); });

@ -1,9 +1,9 @@
'use client'; 'use client';
import { ActionIcon, Icon } from '@lobehub/ui'; import { ActionIcon } from '@lobehub/ui';
import { App, Dropdown, Button } from 'antd'; import { App, Button } from 'antd';
import { createStyles } from 'antd-style'; import { createStyles } from 'antd-style';
import { ChevronDownIcon, PlusIcon } from 'lucide-react'; import { PlusIcon } from 'lucide-react';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { memo, useState } from 'react'; import { memo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -40,13 +40,13 @@ const AddAgent = memo<{ data: DiscoverAssistantItem; mobile?: boolean }>(({ data
router.push(SESSION_CHAT_URL(session, mobile)); router.push(SESSION_CHAT_URL(session, mobile));
}; };
const handleAddAgent = async () => { // const handleAddAgent = async () => {
if (!data) return; // if (!data) return;
setIsLoading(true); // setIsLoading(true);
createSession({ config: data.config, meta: data.meta }, false); // createSession({ config: data.config, meta: data.meta }, false);
message.success(t('assistants.addAgentSuccess')); // message.success(t('assistants.addAgentSuccess'));
setIsLoading(false); // setIsLoading(false);
}; // };
if (mobile) if (mobile)
return ( return (
@ -60,9 +60,7 @@ const AddAgent = memo<{ data: DiscoverAssistantItem; mobile?: boolean }>(({ data
); );
return ( return (
<>
<Button className={styles.button} loading={isLoading} onClick={handleAddAgentAndConverse}></Button> <Button className={styles.button} loading={isLoading} onClick={handleAddAgentAndConverse}></Button>
</>
); );
}); });

@ -1,21 +1,20 @@
'use client'; 'use client';
import { Avatar, Icon, Tag } from '@lobehub/ui'; import { Avatar, Tag } from '@lobehub/ui';
import { Button } from 'antd'; import { Button } from 'antd';
import { createStyles } from 'antd-style'; import { createStyles } from 'antd-style';
import { startCase } from 'lodash-es'; import { startCase } from 'lodash-es';
import { ChevronRight } from 'lucide-react'; // import { ChevronRight } from 'lucide-react';
import Link from 'next/link'; import Link from 'next/link';
import qs from 'query-string'; // import qs from 'query-string';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; // import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
import urlJoin from 'url-join'; // import urlJoin from 'url-join';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { DiscoverAssistantItem } from '@/types/discover'; import { DiscoverAssistantItem } from '@/types/discover';
import { useUserStore } from '@/store/user';
import GitHubAvatar from '../../../../components/GitHubAvatar'; import GitHubAvatar from '../../../../components/GitHubAvatar';
import Back from '../../../features/Back';
import Actions from './Actions'; import Actions from './Actions';
export const useStyles = createStyles(({ css, token }) => ({ export const useStyles = createStyles(({ css, token }) => ({
tag: css` tag: css`
@ -41,15 +40,10 @@ export const useStyles = createStyles(({ css, token }) => ({
border-color: rgba(187, 204, 253, 0.24); border-color: rgba(187, 204, 253, 0.24);
padding: 20px 50px; padding: 20px 50px;
`, `,
topBtn: css`
border-radius: 20px;
color: #2E62FF;
border: 1px solid #2E62FF;
`,
conTitle: css` conTitle: css`
width: 125px; width: 125px;
height: 50px; height: 40px;
line-height: 50px; line-height: 40px;
text-align: center; text-align: center;
color: #fff; color: #fff;
font-size: 20px; font-size: 20px;
@ -57,11 +51,18 @@ export const useStyles = createStyles(({ css, token }) => ({
opacity: 1; opacity: 1;
background: linear-gradient(270deg, #2D65FF 0%, rgba(0, 166, 255, 0.52) 99%); background: linear-gradient(270deg, #2D65FF 0%, rgba(0, 166, 255, 0.52) 99%);
`, `,
topBtn: css`
border-radius: 20px;
color: #2E62FF;
border: 1px solid #2E62FF;
`,
description: css` description: css`
padding: 0 45px; padding: 0 45px;
margin-top: 10px;
`, `,
tag: css` tag: css`
padding: 0px 45px; padding: 0px 45px;
margin-bottom: 10px;
`, `,
})); }));
@ -70,17 +71,18 @@ interface HeaderProps {
identifier: string; identifier: string;
mobile?: boolean; mobile?: boolean;
} }
const getUserId = (s) => s.user?.id
const Header = memo<HeaderProps>(({ identifier, data, mobile }) => { const Header = memo<HeaderProps>(({ identifier, data, mobile }) => {
const { styles, theme } = useStyles(); const { styles, theme } = useStyles();
const router = useRouter() const router = useRouter()
const { t } = useTranslation('discover'); // const { t } = useTranslation('discover');
const userId = getUserId(useUserStore.getState())
const handleBack = () => { const handleBack = () => {
router.push('/discover/assistants?userid=' + localStorage.getItem('userId')) router.push('/discover/assistants?userid=' + userId)
} }
return ( return (
<Flexbox gap={12} width={'100%'}> <Flexbox gap={12} width={'100%'}>
<Flexbox align={'center'} gap={8} horizontal justify={'space-between'} width={'100%'} className={styles.top}> <Flexbox align={'center'} className={styles.top} gap={8} horizontal justify={'space-between'} width={'100%'}>
<Flexbox align={'center'} gap={16} horizontal justify={'flex-start'}> <Flexbox align={'center'} gap={16} horizontal justify={'flex-start'}>
<Avatar <Avatar
alt={identifier} alt={identifier}
@ -118,17 +120,9 @@ const Header = memo<HeaderProps>(({ identifier, data, mobile }) => {
{data.meta.tags && ( {data.meta.tags && (
<Flexbox gap={4} horizontal wrap={'wrap'}> <Flexbox gap={4} horizontal wrap={'wrap'}>
{data.meta.tags.map((tag) => ( {data.meta.tags.map((tag) => (
<Link
href={qs.stringifyUrl({
query: { q: tag, type: 'assistants' },
url: '/discover/search',
})}
key={tag}
>
<Tag key={tag} style={{ margin: 0 }}> <Tag key={tag} style={{ margin: 0 }}>
{startCase(tag).trim()} {startCase(tag).trim()}
</Tag> </Tag>
</Link>
))} ))}
</Flexbox> </Flexbox>
)} )}

@ -3,14 +3,14 @@
import { Markdown } from '@lobehub/ui'; import { Markdown } from '@lobehub/ui';
import { Skeleton } from 'antd'; import { Skeleton } from 'antd';
import { useTheme } from 'antd-style'; import { useTheme } from 'antd-style';
import { BotMessageSquare } from 'lucide-react'; // import { BotMessageSquare } from 'lucide-react';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; // import { useTranslation } from 'react-i18next';
import { Flexbox, FlexboxProps } from 'react-layout-kit'; import { Flexbox, FlexboxProps } from 'react-layout-kit';
import { DiscoverAssistantItem } from '@/types/discover'; import { DiscoverAssistantItem } from '@/types/discover';
import HighlightBlock from '../../../features/HighlightBlock'; // import HighlightBlock from '../../../features/HighlightBlock';
interface ConversationExampleProps extends FlexboxProps { interface ConversationExampleProps extends FlexboxProps {
data: DiscoverAssistantItem; data: DiscoverAssistantItem;
@ -19,11 +19,10 @@ interface ConversationExampleProps extends FlexboxProps {
} }
const ConversationExample = memo<ConversationExampleProps>(({ data }) => { const ConversationExample = memo<ConversationExampleProps>(({ data }) => {
const { t } = useTranslation('discover'); // const { t } = useTranslation('discover');
const theme = useTheme(); const theme = useTheme();
console.log(data.config.systemRole,111111111) console.log(data.config.systemRole,111111111)
return ( return (
<>
<Flexbox paddingInline={16} style={{padding: '0 45'}}> <Flexbox paddingInline={16} style={{padding: '0 45'}}>
{data.config.systemRole ? ( {data.config.systemRole ? (
<Markdown fontSize={theme.fontSize}>{data.config.systemRole}</Markdown> <Markdown fontSize={theme.fontSize}>{data.config.systemRole}</Markdown>
@ -31,7 +30,6 @@ const ConversationExample = memo<ConversationExampleProps>(({ data }) => {
<Skeleton paragraph={{ rows: 4 }} title={false} /> <Skeleton paragraph={{ rows: 4 }} title={false} />
)} )}
</Flexbox> </Flexbox>
</>
); );
}); });

@ -11,9 +11,9 @@ import { DiscoverPlugintem } from '@/types/discover';
import { isMobileDevice } from '@/utils/responsive'; import { isMobileDevice } from '@/utils/responsive';
import DetailLayout from '../../features/DetailLayout'; import DetailLayout from '../../features/DetailLayout';
import Actions from './features/Actions'; // import Actions from './features/Actions';
import Header from './features/Header'; import Header from './features/Header';
import InfoSidebar from './features/InfoSidebar'; // import InfoSidebar from './features/InfoSidebar';
import Temp from './features/Temp'; import Temp from './features/Temp';
// import ConversationExample from './features/ConversationExample'; // import ConversationExample from './features/ConversationExample';
@ -67,10 +67,10 @@ const Page = async ({ params, searchParams }: Props) => {
console.log(data,'37373733737') console.log(data,'37373733737')
const { meta, createdAt, author, config } = data; const { meta, createdAt, author, config } = data;
let pluginData: DiscoverPlugintem[] = []; // let pluginData: DiscoverPlugintem[] = [];
if (config?.plugins && config.plugins?.length > 0) { // if (config?.plugins && config.plugins?.length > 0) {
pluginData = await discoverService.getPluginByIds(locale, config.plugins); // pluginData = await discoverService.getPluginByIds(locale, config.plugins);
} // }
const ld = ldModule.generate({ const ld = ldModule.generate({
article: { article: {

@ -6,7 +6,7 @@ import { Flexbox } from 'react-layout-kit';
import Footer from '@/features/Setting/Footer'; import Footer from '@/features/Setting/Footer';
import SidebarContainer from './SidebarContainer'; // import SidebarContainer from './SidebarContainer';
interface DetailLayoutProps { interface DetailLayoutProps {
actions?: ReactNode; actions?: ReactNode;
@ -36,24 +36,15 @@ const DetailLayout = memo<DetailLayoutProps>(
); );
return ( return (
<>
<div style={{ backgroundColor: '#fff'}}> <div style={{ backgroundColor: '#fff'}}>
{header} {header}
<Flexbox gap={32} horizontal width={'100%'}> <Flexbox gap={32} horizontal width={'100%'}>
<Flexbox flex={1} gap={48} style={{ overflow: 'hidden', position: 'relative' }}> <Flexbox flex={1} gap={48} style={{ overflow: 'hidden', position: 'relative',padding: '0 30px' }}>
{children} {children}
<Footer /> <Footer />
</Flexbox> </Flexbox>
<SidebarContainer>
<Flexbox gap={16} width={'100%'}>
{actions}
{statistics}
</Flexbox>
{sidebar}
</SidebarContainer>
</Flexbox> </Flexbox>
</div> </div>
</>
); );
}, },
); );

@ -61,7 +61,7 @@ const HighlightBlock = memo<HighlightBlockProps>(({ avatar, title, icon, childre
const { styles } = useStyles(); const { styles } = useStyles();
const mobile = useServerConfigStore((s) => s.isMobile); const mobile = useServerConfigStore((s) => s.isMobile);
return ( return (
<Flexbox className={styles.container} flex={'none'} width={'100%'} {...rest}> <Flexbox className={styles.container} flex={'none'} width={'100%'} {...rest} style={{marginTop: 20}}>
<Flexbox <Flexbox
align={'center'} align={'center'}
className={styles.header} className={styles.header}

@ -9,7 +9,8 @@ import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
import { DiscoverModelItem } from '@/types/discover'; import { DiscoverModelItem } from '@/types/discover';
import { useRouter } from 'next/navigation';
import { useUserStore } from '@/store/user';
import ModelFeatureTags from '../../../../features/ModelFeatureTags'; import ModelFeatureTags from '../../../../features/ModelFeatureTags';
import Back from '../../../features/Back'; import Back from '../../../features/Back';
@ -29,6 +30,38 @@ export const useStyles = createStyles(({ css, token }) => ({
font-weight: bold; font-weight: bold;
line-height: 1.2; line-height: 1.2;
`, `,
top: css`
padding: 20px 0px;
box-sizing: border-box;
border-width: 0px 0px 2px 0px;
border-style: solid;
border-color: rgba(187, 204, 253, 0.24);
padding: 20px 50px;
`,
topBtn: css`
border-radius: 20px;
color: #2E62FF;
border: 1px solid #2E62FF;
`,
conTitle: css`
width: 125px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
font-size: 20px;
border-radius: 0px 129px 129px 0px;
opacity: 1;
background: linear-gradient(270deg, #2D65FF 0%, rgba(0, 166, 255, 0.52) 99%);
`,
description: css`
padding: 0 45px;
margin-top: 10px;
`,
tag: css`
padding: 0px 45px;
margin-bottom: 10px;
`,
})); }));
interface HeaderProps { interface HeaderProps {
@ -39,12 +72,16 @@ interface HeaderProps {
const Header = memo<HeaderProps>(({ identifier, data, mobile }) => { const Header = memo<HeaderProps>(({ identifier, data, mobile }) => {
const { styles, theme } = useStyles(); const { styles, theme } = useStyles();
const router = useRouter()
const { t } = useTranslation(['discover', 'models']); const { t } = useTranslation(['discover', 'models']);
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
const handleBack = () => {
router.push('/discover/models?userid=' + userId)
}
return ( return (
<Flexbox gap={12} width={'100%'}> <Flexbox gap={12} width={'100%'}>
{!mobile && <Back href={'/discover/models'} />} <Flexbox align={'center'} gap={8} horizontal justify={'space-between'} width={'100%'} className={styles.top}>
<Flexbox align={'center'} gap={8} horizontal justify={'space-between'} width={'100%'}>
<Flexbox align={'center'} gap={16} horizontal justify={'flex-start'}> <Flexbox align={'center'} gap={16} horizontal justify={'flex-start'}>
<ModelIcon model={identifier} size={48} type={'avatar'} /> <ModelIcon model={identifier} size={48} type={'avatar'} />
<Flexbox gap={2}> <Flexbox gap={2}>
@ -64,20 +101,20 @@ const Header = memo<HeaderProps>(({ identifier, data, mobile }) => {
</Flexbox> </Flexbox>
{!mobile && ( {!mobile && (
<Flexbox align={'center'} gap={4} horizontal justify={'flex-end'}> <Flexbox align={'center'} gap={4} horizontal justify={'flex-end'}>
<Link href={'/discover/models'}> <Button className={styles.topBtn} onClick={() => handleBack()}></Button>
<Button className={styles.tag} shape={'round'} size={'small'}>
{t('tab.models')}
</Button>
</Link>
</Flexbox> </Flexbox>
)} )}
</Flexbox> </Flexbox>
{data.meta.description && <div>{t(`${identifier}.description`, { ns: 'models' })}</div>} <div className={styles.conTitle}></div>
{data.meta.description && <div className={styles.description}>{t(`${identifier}.description`, { ns: 'models' })}</div>}
<div className={styles.tag}>
<ModelFeatureTags <ModelFeatureTags
functionCall={data.meta.functionCall} functionCall={data.meta.functionCall}
tokens={data.meta.tokens} tokens={data.meta.tokens}
vision={data.meta.vision} vision={data.meta.vision}
/> />
</div>
<div className={styles.conTitle}></div>
</Flexbox> </Flexbox>
); );
}); });

@ -95,10 +95,10 @@ const Page = async ({ params, searchParams }: Props) => {
<> <>
<StructuredData ld={ld} /> <StructuredData ld={ld} />
<DetailLayout <DetailLayout
actions={<Actions data={data} identifier={identifier} providerData={providerData} />} // actions={<Actions data={data} identifier={identifier} providerData={providerData} />}
header={<Header data={data} identifier={identifier} mobile={mobile} />} header={<Header data={data} identifier={identifier} mobile={mobile} />}
mobile={mobile} mobile={mobile}
sidebar={<InfoSidebar data={data} identifier={identifier} mobile={mobile} />} // sidebar={<InfoSidebar data={data} identifier={identifier} mobile={mobile} />}
/* ↓ cloud slot ↓ */ /* ↓ cloud slot ↓ */
/* ↑ cloud slot ↑ */ /* ↑ cloud slot ↑ */

@ -11,11 +11,11 @@ import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { useUserStore } from '@/store/user';
import { useRouter } from 'next/navigation';
import { DiscoverPlugintem } from '@/types/discover'; import { DiscoverPlugintem } from '@/types/discover';
import Back from '../../../features/Back'; import Back from '../../../features/Back';
export const useStyles = createStyles(({ css, token }) => ({ export const useStyles = createStyles(({ css, token }) => ({
tag: css` tag: css`
color: ${token.colorTextSecondary}; color: ${token.colorTextSecondary};
@ -32,6 +32,38 @@ export const useStyles = createStyles(({ css, token }) => ({
font-weight: bold; font-weight: bold;
line-height: 1.2; line-height: 1.2;
`, `,
top: css`
padding: 20px 0px;
box-sizing: border-box;
border-width: 0px 0px 2px 0px;
border-style: solid;
border-color: rgba(187, 204, 253, 0.24);
padding: 20px 50px;
`,
topBtn: css`
border-radius: 20px;
color: #2E62FF;
border: 1px solid #2E62FF;
`,
conTitle: css`
width: 125px;
height: 40px;
line-height: 40px;
text-align: center;
color: #fff;
font-size: 20px;
border-radius: 0px 129px 129px 0px;
opacity: 1;
background: linear-gradient(270deg, #2D65FF 0%, rgba(0, 166, 255, 0.52) 99%);
`,
description: css`
padding: 0 45px;
margin-top: 10px;
`,
tag: css`
padding: 0px 45px;
margin-bottom: 10px;
`,
})); }));
interface HeaderProps { interface HeaderProps {
@ -42,12 +74,16 @@ interface HeaderProps {
const Header = memo<HeaderProps>(({ identifier, data, mobile }) => { const Header = memo<HeaderProps>(({ identifier, data, mobile }) => {
const { styles, theme } = useStyles(); const { styles, theme } = useStyles();
const router = useRouter()
const { t } = useTranslation('discover'); const { t } = useTranslation('discover');
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
const handleBack = () => {
router.push('/discover/plugins?userid=' + userId)
}
return ( return (
<Flexbox gap={12} width={'100%'}> <Flexbox gap={12} width={'100%'}>
{!mobile && <Back href={'/discover/plugins'} />} <Flexbox align={'center'} gap={8} horizontal justify={'space-between'} width={'100%'} className={styles.top}>
<Flexbox align={'center'} gap={8} horizontal justify={'space-between'} width={'100%'}>
<Flexbox align={'center'} gap={16} horizontal justify={'flex-start'}> <Flexbox align={'center'} gap={16} horizontal justify={'flex-start'}>
<Avatar <Avatar
alt={identifier} alt={identifier}
@ -71,42 +107,24 @@ const Header = memo<HeaderProps>(({ identifier, data, mobile }) => {
</Flexbox> </Flexbox>
{!mobile && ( {!mobile && (
<Flexbox align={'center'} gap={4} horizontal justify={'flex-end'}> <Flexbox align={'center'} gap={4} horizontal justify={'flex-end'}>
<Link href={'/discover/plugins'}> <Button className={styles.topBtn} onClick={() => handleBack()}></Button>
<Button className={styles.tag} shape={'round'} size={'small'}>
{t('tab.plugins')}
</Button>
</Link>
{data.meta?.category && (
<>
<Icon color={theme.colorTextSecondary} icon={ChevronRight} />
<Link href={urlJoin('/discover/plugins', data.meta?.category || '')}>
<Button className={styles.tag} shape={'round'} size={'small'}>
{t(`category.plugin.${data.meta?.category}` as any)}
</Button>
</Link>
</>
)}
</Flexbox> </Flexbox>
)} )}
</Flexbox> </Flexbox>
<div>{data.meta.description}</div> <div className={styles.conTitle}></div>
<div className={styles.description}>{data.meta.description}</div>
<div className={styles.tag}>
{data.meta.tags && ( {data.meta.tags && (
<Flexbox gap={4} horizontal wrap={'wrap'}> <Flexbox gap={4} horizontal wrap={'wrap'}>
{data.meta.tags.map((tag) => ( {data.meta.tags.map((tag) => (
<Link
href={qs.stringifyUrl({
query: { q: tag },
url: '/discover/search',
})}
key={tag}
>
<Tag key={tag} style={{ margin: 0 }}> <Tag key={tag} style={{ margin: 0 }}>
{startCase(tag).trim()} {startCase(tag).trim()}
</Tag> </Tag>
</Link>
))} ))}
</Flexbox> </Flexbox>
)} )}
</div>
<div className={styles.conTitle}></div>
</Flexbox> </Flexbox>
); );
}); });

@ -84,10 +84,10 @@ const Page = async ({ params, searchParams }: Props) => {
<> <>
<StructuredData ld={ld} /> <StructuredData ld={ld} />
<DetailLayout <DetailLayout
actions={<Actions data={data} identifier={identifier} />} // actions={<Actions data={data} identifier={identifier} />}
header={<Header data={data} identifier={identifier} mobile={mobile} />} header={<Header data={data} identifier={identifier} mobile={mobile} />}
mobile={mobile} mobile={mobile}
sidebar={<InfoSidebar data={data} identifier={identifier} mobile={mobile} />} // sidebar={<InfoSidebar data={data} identifier={identifier} mobile={mobile} />}
/* ↓ cloud slot ↓ */ /* ↓ cloud slot ↓ */
/* ↑ cloud slot ↑ */ /* ↑ cloud slot ↑ */

@ -32,45 +32,7 @@ const Page = async ({ params, searchParams }: Props) => {
const mobile = isMobileDevice(); const mobile = isMobileDevice();
const discoverService = new DiscoverService(); const discoverService = new DiscoverService();
console.log(params.slug,3333333) console.log(params.slug,3333333)
let items; const items = await discoverService.getAssistantCategory(locale, params.slug);
if(params.slug == "collect") {
const res = await request({
url: "/flxai/api/robot/appaiassistant/getAllAiAssistant",
method: "get",
params: {
userid: searchParams.userid
}
})
items = res.data;
items = items.map((item,index)=> {
item.classify = 'collect';
return item
})
} else {
const res = await request({
url: "/flxai/api/robot/appaiassistant/getAllAiAssistant",
method: "get",
params: {
userid: searchParams.userid
}
})
const array2Object = {};
res?.data?.forEach(item => {
array2Object[item.identifier] = item;
});
items = await discoverService.getAssistantCategory(locale, params.slug);
items = items.map((item,index)=> {
const matchingItem = array2Object[item.identifier];
if (matchingItem) {
console.log('3838383838',matchingItem);
matchingItem.status = '1';
return matchingItem
} else {
item.status = '0';
return item
}
})
}
console.log(8272772727,items) console.log(8272772727,items)
const ld = ldModule.generate({ const ld = ldModule.generate({
description: t('discover.assistants.description'), description: t('discover.assistants.description'),

@ -13,6 +13,8 @@ import CardBanner from '../../../components/CardBanner';
import GitHubAvatar from '../../../components/GitHubAvatar'; import GitHubAvatar from '../../../components/GitHubAvatar';
import { useCategoryItem } from '../../assistants/features/useCategory'; import { useCategoryItem } from '../../assistants/features/useCategory';
import { StarOutlined } from '@ant-design/icons'; import { StarOutlined } from '@ant-design/icons';
import { useUserStore } from '@/store/user';
import { useTranslation } from 'react-i18next';
const Link = dynamic(() => import('next/link'), { const Link = dynamic(() => import('next/link'), {
loading: () => <Skeleton.Button size={'small'} style={{ height: 22 }} />, loading: () => <Skeleton.Button size={'small'} style={{ height: 22 }} />,
ssr: false, ssr: false,
@ -80,12 +82,15 @@ const AssistantCard = memo<AssistantCardProps>(
const { avatar, title, description, tags = [], category } = meta; const { avatar, title, description, tags = [], category } = meta;
const { createAt,homepage,identifier,schemaVersion,status,classify } = {...rest} const { createAt,homepage,identifier,schemaVersion,status,classify } = {...rest}
const { cx, styles, theme } = useStyles(); const { cx, styles, theme } = useStyles();
const { t } = useTranslation('discover');
const { message } = App.useApp(); const { message } = App.useApp();
const categoryItem = useCategoryItem(category, 12); const categoryItem = useCategoryItem(category, 12);
const isCompact = variant === 'compact'; const isCompact = variant === 'compact';
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
// console.log(tags,avatar,author,9383737) // console.log(tags,avatar,author,9383737)
console.log(status,9999999999) console.log(userId,9999999999)
const [val, setVal] = useState(status) const [val, setVal] = useState('')
const handleCollect = (e) => { const handleCollect = (e) => {
console.log(e,8844848) console.log(e,8844848)
e.preventDefault() e.preventDefault()
@ -102,7 +107,7 @@ const AssistantCard = memo<AssistantCardProps>(
"title": title, "title": title,
"category": category, "category": category,
"schemaVersion": schemaVersion, "schemaVersion": schemaVersion,
"userid": localStorage.getItem('userId'), "userid": userId,
} }
request({ request({
url: "/flxai/api/robot/appaiassistant", url: "/flxai/api/robot/appaiassistant",
@ -111,7 +116,7 @@ const AssistantCard = memo<AssistantCardProps>(
}).then(response => { }).then(response => {
console.log(response,222222222) console.log(response,222222222)
if (response.code == 0) { if (response.code == 0) {
message.success('收藏成功') message.success(t('collectSuccess'));
setVal("1") setVal("1")
} }
}).catch(error => { }).catch(error => {
@ -131,7 +136,7 @@ const AssistantCard = memo<AssistantCardProps>(
); );
const renderElement = () => { const renderElement = () => {
if (classify != 'collect') { if (classify != 'collect') {
if(val == "1") { if(status == "1" || val == "1") {
return <div className={styles.collectBtn} onClick={(e) => {e.stopPropagation()}}><StarOutlined style={{color: '#FFAD01'}}/></div> return <div className={styles.collectBtn} onClick={(e) => {e.stopPropagation()}}><StarOutlined style={{color: '#FFAD01'}}/></div>
} else { } else {
return <div className={styles.collectBtn} style={{background: '#F1F1F1'}} onClick={(e) => handleCollect(e)}><StarOutlined style={{color: '#D6D6D6'}}/></div> return <div className={styles.collectBtn} style={{background: '#F1F1F1'}} onClick={(e) => handleCollect(e)}><StarOutlined style={{color: '#D6D6D6'}}/></div>

@ -7,7 +7,7 @@ import urlJoin from 'url-join';
import { useQueryRoute } from '@/hooks/useQueryRoute'; import { useQueryRoute } from '@/hooks/useQueryRoute';
import { AssistantCategory } from '@/types/discover'; import { AssistantCategory } from '@/types/discover';
import { useUserStore } from '@/store/user';
import CategoryMenu from '../../../components/CategoryMenu'; import CategoryMenu from '../../../components/CategoryMenu';
import { useCategory } from './useCategory'; import { useCategory } from './useCategory';
@ -21,7 +21,9 @@ const Category = memo(() => {
return 'all'; return 'all';
}, [pathname]); }, [pathname]);
const router = useQueryRoute(); const router = useQueryRoute();
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
console.log(userId,'category333333')
return ( return (
<CategoryMenu <CategoryMenu
items={items.map((item: any) => ({ items={items.map((item: any) => ({
@ -30,7 +32,7 @@ const Category = memo(() => {
<Link <Link
href={urlJoin( href={urlJoin(
'/discover/assistants', '/discover/assistants',
item.key === AssistantCategory.All ? '' : item.key + '?userid=' + localStorage.getItem('userId'), item.key === AssistantCategory.All ? '' : item.key + '?userid=' + userId,
)} )}
> >
{item.label} {item.label}
@ -38,7 +40,7 @@ const Category = memo(() => {
), ),
}))} }))}
onSelect={({ key }) => { onSelect={({ key }) => {
router.push(urlJoin('/discover/assistants', key === AssistantCategory.All ? '' : key + '?userid=' + localStorage.getItem('userId'))); router.push(urlJoin('/discover/assistants', key === AssistantCategory.All ? '' : key + '?userid=' + userId));
}} }}
selectedKeys={[selectedKey || 'all']} selectedKeys={[selectedKey || 'all']}
/> />

@ -3,7 +3,7 @@
import { Grid } from '@lobehub/ui'; import { Grid } from '@lobehub/ui';
import {Button, Empty, Image, Tag} from 'antd'; import {Button, Empty, Image, Tag} from 'antd';
import Link from 'next/link'; import Link from 'next/link';
import {memo, useMemo, useState} from 'react'; import {memo, useMemo, useEffect, useState} from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
@ -13,8 +13,8 @@ import SearchResultCount from '../../../components/SearchResultCount';
import Title from '../../../components/Title'; import Title from '../../../components/Title';
import VirtuosoGridList from '../../../components/VirtuosoGridList'; import VirtuosoGridList from '../../../components/VirtuosoGridList';
import Card from './Card'; import Card from './Card';
import {createStyles} from "antd-style"; import request from '@/app/api/request';
import { useUserStore } from '@/store/user';
export interface ListProps { export interface ListProps {
category?: string; category?: string;
items?: DiscoverAssistantItem[]; items?: DiscoverAssistantItem[];
@ -22,133 +22,69 @@ export interface ListProps {
searchKeywords?: string; searchKeywords?: string;
} }
const useStyles = createStyles(({css, token}) => ({
top: css`
padding: 20px 0px;
box-sizing: border-box;
border-width: 0px 0px 2px 0px;
border-style: solid;
border-color: rgba(187, 204, 253, 0.24);
padding: 20px 50px;
`,
topFirAc: css`
width: 86px;
height: 86px;
display: inline-block;
border-radius: 86px;
border: 4px solid #6D94FF;
`,
topSecAc: css`
width: 60px;
height: 60px;
border-radius: 60px;
margin: 9px;
text-align: center;
line-height: 50px;
font-size: 26px;
border: 4px solid #6D94FF;
`,
topBtn: css`
border-radius: 20px;
color: #2E62FF;
border: 1px solid #2E62FF;
`,
topRight: css`
width: 50%;
text-align: right;
display: inline-block
`,
topLeft: css`
width: 50%;
display: inline-block
`,
title: css`
display: inline-block;
vertical-align: middle;
margin-top: -10px;
margin-left: 25px
`,
des: css`
margin-top: 5px;
font-size: 12px;
color: #999
`,
desImg: css`
margin: 0px 5px;
width: 20px
`,
time: css`
display: inline-block;
margin-left: 5px
`,
conTitle: css`
margin: 12px 0;
width: 125px;
height: 50px;
line-height: 50px;
text-align: center;
color: #fff;
font-size: 20px;
border-radius: 0px 129px 129px 0px;
opacity: 1;
background: linear-gradient(270deg, #2D65FF 0%, rgba(0, 166, 255, 0.52) 99%);
`,
description: css`
padding: 20px 50px;
`,
tag: css`
padding: 0px 50px;
margin-bottom: 20px;
`,
set: css`
padding: 0px 30px 20px;
`,
setBtn: css`
background: #EDF2FF;
width: 80px;
border-radius: 40px;
color: #0044FF;
`,
setText: css`
padding: 0px 50px 20px;
`,
setOl: css`
display: inline-block;
width: 8px;
height: 8px;
background: #0044FF;
margin-right: 10px;
`,
rwDes: css`
padding: 0px 70px 20px;
`,
}))
const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] }) => { const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] }) => {
const { t } = useTranslation('discover'); const { t } = useTranslation('discover');
const { styles, cx } = useStyles()
const router = useRouter() const router = useRouter()
const { all, recent, last } = useMemo(() => { const [stData, setStData] = useState(items)
const recentLength = mobile ? 4 : 8; const recentLength = mobile ? 4 : 8;
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
console.log(userId,'zhushou---3837373266262266')
console.log('zhushou--------------',items)
const { all, recent, last } = useMemo(() => {
return { return {
all: items, all: stData,
last: items.slice(recentLength), last: stData.slice(recentLength),
recent: items.slice(0, recentLength), recent: stData.slice(0, recentLength),
};
}, [stData, mobile]);
useEffect(() => {
const fetchData = async() => {
if(category == "collect") {
const res = await request({
url: "/flxai/api/robot/appaiassistant/getAllAiAssistant",
method: "get",
params: {
userid: userId
}
})
setStData(res?.data.map((item,index)=> {
item.classify = 'collect';
return item
}))
} else {
const res = await request({
url: "/flxai/api/robot/appaiassistant/getAllAiAssistant",
method: "get",
params: {
userid: userId
}
})
const array2Object = {};
res?.data?.forEach((item) => {
array2Object[item.identifier] = item;
});
console.log('chajian22222222222222222222222222222--------------')
setStData(stData.map((item,index)=> {
const matchingItem = array2Object[item.identifier];
if (matchingItem) {
matchingItem.status = '1';
return matchingItem
} else {
item.status = '0';
return item
}
}))
}
}; };
}, [items, mobile]); fetchData();
}, []); // 空数组[]意味着仅在组件挂载时调用一次
console.log(category,recent,last,92929292) console.log(category,recent,last,92929292)
const [val, setVal] = useState("")
const handleClickCard = (item) => { const handleClickCard = (item) => {
console.log(item) console.log(item)
setVal(item)
router.push(urlJoin('/discover/assistant/', item.identifier)) router.push(urlJoin('/discover/assistant/', item.identifier))
} }
const handleBack = () => {
setVal("")
}
if (searchKeywords) { if (searchKeywords) {
if (!items || items?.length === 0) return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />; if (!items || items?.length === 0) return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />;
return ( return (

@ -5,7 +5,6 @@ import { metadataModule } from '@/server/metadata';
import { DiscoverService } from '@/server/services/discover'; import { DiscoverService } from '@/server/services/discover';
import { translation } from '@/server/translation'; import { translation } from '@/server/translation';
import { isMobileDevice } from '@/utils/responsive'; import { isMobileDevice } from '@/utils/responsive';
import request from '@/app/api/request';
import List from './features/List'; import List from './features/List';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
type Props = { searchParams: { hl?: Locales } }; type Props = { searchParams: { hl?: Locales } };
@ -27,31 +26,7 @@ const Page = async ({ searchParams }: Props) => {
const mobile = isMobileDevice(); const mobile = isMobileDevice();
const discoverService = new DiscoverService(); const discoverService = new DiscoverService();
console.log(searchParams,22222222222) console.log(searchParams,22222222222)
const res = await request({ const items = await discoverService.getAssistantList(locale);
url: "/flxai/api/robot/appaiassistant/getAllAiAssistant",
method: "get",
params: {
userid: searchParams.userid
}
})
console.log(res,4322222)
const array2Object = {};
res?.data?.forEach(item => {
array2Object[item.identifier] = item;
});
let items = await discoverService.getAssistantList(locale);
console.log(8272772727,'jiangxucong')
items = items.map((item,index)=> {
const matchingItem = array2Object[item.identifier];
if (matchingItem) {
console.log('5959595959',matchingItem);
matchingItem.status = '1';
return matchingItem
} else {
item.status = '0';
return item
}
})
const ld = ldModule.generate({ const ld = ldModule.generate({
description: t('discover.assistants.description'), description: t('discover.assistants.description'),
title: t('discover.assistants.title'), title: t('discover.assistants.title'),

@ -9,14 +9,13 @@ import { DiscoverService } from '@/server/services/discover';
import { translation } from '@/server/translation'; import { translation } from '@/server/translation';
import { AssistantCategory } from '@/types/discover'; import { AssistantCategory } from '@/types/discover';
import { isMobileDevice } from '@/utils/responsive'; import { isMobileDevice } from '@/utils/responsive';
import List from '../features/List'; import List from '../features/List';
type Props = { params: { slug: AssistantCategory }; searchParams: { hl?: Locales } }; type Props = { params: { slug: AssistantCategory }; searchParams: { hl?: Locales } };
export const generateMetadata = async ({ params, searchParams }: Props) => { export const generateMetadata = async ({ params, searchParams }: Props) => {
const { t, locale } = await translation('metadata', searchParams?.hl); const { t, locale } = await translation('metadata', searchParams?.hl);
console.log('jiangxucong---model----------------------------')
const discoverService = new DiscoverService(); const discoverService = new DiscoverService();
const list = await discoverService.getProviderList(locale); const list = await discoverService.getProviderList(locale);
const cate = list.find((cate) => cate.identifier === params.slug); const cate = list.find((cate) => cate.identifier === params.slug);
@ -37,12 +36,12 @@ const Page = async ({ params, searchParams }: Props) => {
const discoverService = new DiscoverService(); const discoverService = new DiscoverService();
const list = await discoverService.getProviderList(locale); const list = await discoverService.getProviderList(locale);
const cate = list.find((cate) => cate.identifier === params.slug); const cate = list.find((cate) => cate.identifier === params.slug);
console.log(params.slug,3333333)
const items = await discoverService.getModelCategory(locale, params.slug); const items = await discoverService.getModelCategory(locale, params.slug);
const ld = ldModule.generate({ const ld = ldModule.generate({
description: t('discover.models.description'), description: t('discover.models.description'),
title: [cate?.meta.title, t('discover.models.title')].join(' · '), title: [cate?.meta.title, t('discover.models.title')].join(' · '),
url: urlJoin('/discover/models', params.slug), url: urlJoin('/discover/models', params.slug + '?userid=' + searchParams.userid),
webpage: { webpage: {
enable: true, enable: true,
search: '/discover/search', search: '/discover/search',

@ -1,14 +1,14 @@
import { ModelIcon } from '@lobehub/icons'; import { ModelIcon } from '@lobehub/icons';
import { Typography } from 'antd'; import { Typography, App } from 'antd';
import { createStyles } from 'antd-style'; import { createStyles } from 'antd-style';
import { memo } from 'react'; import { memo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Flexbox, FlexboxProps } from 'react-layout-kit'; import { Flexbox, FlexboxProps } from 'react-layout-kit';
import { useUserStore } from '@/store/user';
import { DiscoverModelItem } from '@/types/discover'; import { DiscoverModelItem } from '@/types/discover';
import { StarOutlined } from '@ant-design/icons';
import ModelFeatureTags from '../../../features/ModelFeatureTags'; import ModelFeatureTags from '../../../features/ModelFeatureTags';
import request from '@/app/api/request';
const { Paragraph, Title } = Typography; const { Paragraph, Title } = Typography;
const useStyles = createStyles(({ css, token, isDarkMode }) => ({ const useStyles = createStyles(({ css, token, isDarkMode }) => ({
@ -65,17 +65,79 @@ const useStyles = createStyles(({ css, token, isDarkMode }) => ({
token: css` token: css`
font-family: ${token.fontFamilyCode}; font-family: ${token.fontFamilyCode};
`, `,
collectBtn: css`
font-size: 12px;
width: 20px;
height: 20px;
line-height: 20px;
border-radius: 50%;
background: #FFF3D9;
text-align: center;
`,
})); }));
export interface ModelCardProps extends DiscoverModelItem, FlexboxProps { export interface ModelCardProps extends DiscoverModelItem, FlexboxProps {
showCategory?: boolean; showCategory?: boolean;
} }
const ModelCard = memo<ModelCardProps>(({ className, meta, identifier, ...rest }) => { const ModelCard = memo<ModelCardProps>(({ className, meta, socialData, identifier, ...rest }) => {
const { description, title, functionCall, vision, tokens } = meta; const { title, description, functionCall, vision, tokens, category, id, displayName, enabled } = meta;
const { conversations, likes, tokens: socialDataToken } = socialData;
// console.log(socialDataToken,"7373736262626----------------------------",meta)
const { createdAt, providers, suggestions, status, classify } = {...rest}
const { t } = useTranslation('models'); const { t } = useTranslation('models');
const { t:d } = useTranslation('discover');
const { cx, styles } = useStyles(); const { cx, styles } = useStyles();
const { message } = App.useApp();
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
const [val, setVal] = useState(status)
const handleCollect = (e) => {
console.log(e,8844848)
e.preventDefault()
e.stopPropagation()
const params = {
"identifier": identifier,
"metaId": id,
"displayname": displayName,
"description": description,
"title": title,
"conversations": conversations,
"enabled": enabled,
"metaTokens": tokens,
"createdAt": createdAt,
"tokens": socialDataToken,
"suggestions": suggestions.join(','),
"category": category,
"providers": providers.join(','),
"likes": likes,
"userid": userId,
}
request({
url: "/flxai/api/robot/appaimodel",
method: "post",
data: params
}).then(response => {
console.log(response,222222222)
if (response.code == 0) {
message.success(d('collectSuccess'));
setVal("1")
}
}).catch(error => {
console.error('Error fetching data: ', error);
})
}
const renderElement = () => {
if (classify != 'collect') {
if(val == "1") {
return <div className={styles.collectBtn} onClick={(e) => {e.stopPropagation()}}><StarOutlined style={{color: '#FFAD01'}}/></div>
} else {
return <div className={styles.collectBtn} style={{background: '#F1F1F1'}} onClick={(e) => handleCollect(e)}><StarOutlined style={{color: '#D6D6D6'}}/></div>
}
} else {
return;
}
};
return ( return (
<Flexbox className={cx(styles.container, className)} gap={24} key={identifier} {...rest}> <Flexbox className={cx(styles.container, className)} gap={24} key={identifier} {...rest}>
<Flexbox <Flexbox
@ -106,8 +168,10 @@ const ModelCard = memo<ModelCardProps>(({ className, meta, identifier, ...rest }
{t(`${identifier}.description`)} {t(`${identifier}.description`)}
</Paragraph> </Paragraph>
)} )}
<Flexbox gap={6} horizontal style={{ flexWrap: 'wrap',justifyContent: 'space-between' }}>
<ModelFeatureTags functionCall={functionCall} tokens={tokens} vision={vision} /> <ModelFeatureTags functionCall={functionCall} tokens={tokens} vision={vision} />
{renderElement()}
</Flexbox>
</Flexbox> </Flexbox>
</Flexbox> </Flexbox>
); );

@ -4,13 +4,13 @@ import { ProviderIcon } from '@lobehub/icons';
import { Icon } from '@lobehub/ui'; import { Icon } from '@lobehub/ui';
import { MenuProps } from 'antd'; import { MenuProps } from 'antd';
import { useTheme } from 'antd-style'; import { useTheme } from 'antd-style';
import { LayoutPanelTop } from 'lucide-react'; import { LayoutPanelTop,Star } from 'lucide-react';
import Link from 'next/link'; import Link from 'next/link';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { memo, useMemo } from 'react'; import { memo, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { useUserStore } from '@/store/user';
import { useQueryRoute } from '@/hooks/useQueryRoute'; import { useQueryRoute } from '@/hooks/useQueryRoute';
import { DiscoverProviderItem } from '@/types/discover'; import { DiscoverProviderItem } from '@/types/discover';
@ -26,20 +26,26 @@ const Category = memo<{ data: DiscoverProviderItem[] }>(({ data }) => {
}, [pathname]); }, [pathname]);
const router = useQueryRoute(); const router = useQueryRoute();
const theme = useTheme(); const theme = useTheme();
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
const { t } = useTranslation('discover'); const { t } = useTranslation('discover');
const items: MenuProps['items'] = [ const items: MenuProps['items'] = [
{ {
icon: <Icon color={theme.colorTextSecondary} icon={LayoutPanelTop} size={ICON_SIZE} />, icon: <Icon color="#003BFF" icon={LayoutPanelTop} size={ICON_SIZE} />,
key: 'all', key: 'all',
label: t('category.plugin.all'), label: t('category.plugin.all'),
}, },
{
icon: <Icon color="#FFAD01" icon={Star} size={ICON_SIZE} />,
key: 'collect',
label: t('category.plugin.collect'),
},
...data.map((item) => ({ ...data.map((item) => ({
icon: ( icon: (
<ProviderIcon <ProviderIcon
provider={item.identifier} provider={item.identifier}
size={18} size={18}
style={{ color: theme.colorTextSecondary }} style={{ color: "#2A4DFF" }}
type={'mono'} type={'mono'}
/> />
), ),

@ -5,14 +5,15 @@ import Link from 'next/link';
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { useRouter } from 'next/navigation';
import { DiscoverModelItem } from '@/types/discover'; import { DiscoverModelItem } from '@/types/discover';
import { Grid } from '@lobehub/ui';
import SearchResultCount from '../../../components/SearchResultCount'; import SearchResultCount from '../../../components/SearchResultCount';
import Title from '../../../components/Title'; import Title from '../../../components/Title';
import VirtuosoGridList from '../../../components/VirtuosoGridList'; import VirtuosoGridList from '../../../components/VirtuosoGridList';
import Card from './Card'; import Card from './Card';
import request from '@/app/api/request';
import { useUserStore } from '@/store/user';
export interface ListProps { export interface ListProps {
category?: string; category?: string;
items?: DiscoverModelItem[]; items?: DiscoverModelItem[];
@ -20,9 +21,54 @@ export interface ListProps {
searchKeywords?: string; searchKeywords?: string;
} }
const List = memo<ListProps>(({ category, searchKeywords, items = [] }) => { const List = memo<ListProps>(async ({ category, searchKeywords, items = [] }) => {
const { t } = useTranslation('discover'); const { t } = useTranslation('discover');
const router = useRouter()
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
console.log(userId,'models---3837373266262266')
console.log('models---99999999',items)
if(category == "collect") {
const res = await request({
url: "/flxai/api/robot/appaimodel/getAllAiModel",
method: "get",
params: {
userid: userId
}
})
items = res.data;
items = items.map((item,index)=> {
item.classify = 'collect';
return item
})
} else {
const res = await request({
url: "/flxai/api/robot/appaimodel/getAllAiModel",
method: "get",
params: {
userid: userId
}
})
const array2Object = {};
res?.data?.forEach(item => {
array2Object[item.identifier] = item;
});
items = items.map((item,index)=> {
const matchingItem = array2Object[item.identifier];
if (matchingItem) {
console.log('3838383838',matchingItem);
matchingItem.status = '1';
return matchingItem
} else {
item.status = '0';
return item
}
})
}
const handleClickCard = (item) => {
console.log(item)
router.push(urlJoin('/discover/model/', item.identifier))
}
if (searchKeywords) { if (searchKeywords) {
if (!items || items?.length === 0) return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />; if (!items || items?.length === 0) return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />;
return ( return (
@ -32,9 +78,9 @@ const List = memo<ListProps>(({ category, searchKeywords, items = [] }) => {
data={items} data={items}
initialItemCount={24} initialItemCount={24}
itemContent={(_, item) => ( itemContent={(_, item) => (
<Link href={urlJoin('/discover/model/', item.identifier)} key={item.identifier}> // <Link href={urlJoin('/discover/model/', item.identifier)} key={item.identifier}>
<Card showCategory {...item} /> <Card onClick={() => handleClickCard(item)} showCategory {...item} />
</Link> // </Link>
)} )}
style={{ style={{
minHeight: '75vh', minHeight: '75vh',
@ -45,21 +91,36 @@ const List = memo<ListProps>(({ category, searchKeywords, items = [] }) => {
} }
return ( return (
<>
{category == "collect"?(
<>
<Title tag={items.length}></Title>
<Grid maxItemWidth={280} rows={4}>
{items.map((item) => (
// <Link href={urlJoin('/discover/assistant/', item.identifier)} key={item.identifier}>
<Card onClick={() => handleClickCard(item)} showCategory={!category} {...item} />
// </Link>
))}
</Grid>
</>
):(
<> <>
<Title tag={items.length}>{t('models.list')}</Title> <Title tag={items.length}>{t('models.list')}</Title>
<VirtuosoGridList <VirtuosoGridList
data={items} data={items}
initialItemCount={24} initialItemCount={24}
itemContent={(_, item) => ( itemContent={(_, item) => (
<Link href={urlJoin('/discover/model/', item.identifier)} key={item.identifier}> // <Link href={urlJoin('/discover/model/', item.identifier)} key={item.identifier}>
<Card showCategory={!category} {...item} /> <Card onClick={() => handleClickCard(item)} showCategory={!category} {...item} />
</Link> // </Link>
)} )}
style={{ style={{
minHeight: '75vh', minHeight: '75vh',
}} }}
/> />
</> </>
)}
</>
); );
}); });

@ -8,7 +8,7 @@ import { translation } from '@/server/translation';
import { isMobileDevice } from '@/utils/responsive'; import { isMobileDevice } from '@/utils/responsive';
import List from './features/List'; import List from './features/List';
import urlJoin from 'url-join';
type Props = { searchParams: { hl?: Locales } }; type Props = { searchParams: { hl?: Locales } };
export const generateMetadata = async ({ searchParams }: Props) => { export const generateMetadata = async ({ searchParams }: Props) => {
@ -26,14 +26,14 @@ export const generateMetadata = async ({ searchParams }: Props) => {
const Page = async ({ searchParams }: Props) => { const Page = async ({ searchParams }: Props) => {
const { t, locale } = await translation('metadata', searchParams?.hl); const { t, locale } = await translation('metadata', searchParams?.hl);
const mobile = isMobileDevice(); const mobile = isMobileDevice();
const discoverService = new DiscoverService(); const discoverService = new DiscoverService();
const items = await discoverService.getModelList(locale); const items = await discoverService.getModelList(locale);
console.log(8272772727,'jiangxucong')
const ld = ldModule.generate({ const ld = ldModule.generate({
description: t('discover.models.description'), description: t('discover.models.description'),
title: t('discover.models.title'), title: t('discover.models.title'),
url: '/discover/models', url: urlJoin('/discover/models?userid=',searchParams.userid),
webpage: { webpage: {
enable: true, enable: true,
search: '/discover/search', search: '/discover/search',

@ -8,7 +8,6 @@ import { DiscoverService } from '@/server/services/discover';
import { translation } from '@/server/translation'; import { translation } from '@/server/translation';
import { PluginCategory } from '@/types/discover'; import { PluginCategory } from '@/types/discover';
import { isMobileDevice } from '@/utils/responsive'; import { isMobileDevice } from '@/utils/responsive';
import List from '../features/List'; import List from '../features/List';
type Props = { params: { slug: PluginCategory }; searchParams: { hl?: Locales } }; type Props = { params: { slug: PluginCategory }; searchParams: { hl?: Locales } };
@ -30,14 +29,12 @@ const Page = async ({ params, searchParams }: Props) => {
const { t, locale } = await translation('metadata', searchParams?.hl); const { t, locale } = await translation('metadata', searchParams?.hl);
const { t: td } = await translation('discover', searchParams?.hl); const { t: td } = await translation('discover', searchParams?.hl);
const mobile = isMobileDevice(); const mobile = isMobileDevice();
const discoverService = new DiscoverService(); const discoverService = new DiscoverService();
const items = await discoverService.getPluginCategory(locale, params.slug); const items = await discoverService.getPluginCategory(locale, params.slug);
const ld = ldModule.generate({ const ld = ldModule.generate({
description: t('discover.plugins.description'), description: t('discover.plugins.description'),
title: [td(`category.plugin.${params.slug}`), t('discover.plugins.title')].join(' · '), title: [td(`category.plugin.${params.slug}`), t('discover.plugins.title')].join(' · '),
url: urlJoin('/discover/plugins', params.slug), url: urlJoin('/discover/plugins', params.slug + '?userid=' + searchParams.userid),
webpage: { webpage: {
enable: true, enable: true,
search: '/discover/search', search: '/discover/search',

@ -1,18 +1,19 @@
import { Avatar, Tag } from '@lobehub/ui'; import { Avatar, Tag } from '@lobehub/ui';
import { Skeleton, Typography } from 'antd'; import { Skeleton, Typography, App } from 'antd';
import { createStyles } from 'antd-style'; import { createStyles } from 'antd-style';
import { startCase } from 'lodash-es'; import { startCase } from 'lodash-es';
import dynamic from 'next/dynamic'; import dynamic from 'next/dynamic';
import qs from 'query-string'; import qs from 'query-string';
import { memo } from 'react'; import { memo, useState } from 'react';
import { Center, Flexbox, FlexboxProps } from 'react-layout-kit'; import { Center, Flexbox, FlexboxProps } from 'react-layout-kit';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { useTranslation } from 'react-i18next';
import { DiscoverPlugintem } from '@/types/discover'; import { DiscoverPlugintem } from '@/types/discover';
import { useUserStore } from '@/store/user';
import CardBanner from '../../../components/CardBanner'; import CardBanner from '../../../components/CardBanner';
import { useCategoryItem } from './useCategory'; import { useCategoryItem } from './useCategory';
import { StarOutlined } from '@ant-design/icons';
import request from '@/app/api/request';
const Link = dynamic(() => import('next/link'), { const Link = dynamic(() => import('next/link'), {
loading: () => <Skeleton.Button size={'small'} style={{ height: 22 }} />, loading: () => <Skeleton.Button size={'small'} style={{ height: 22 }} />,
ssr: false, ssr: false,
@ -61,6 +62,15 @@ const useStyles = createStyles(({ css, token, isDarkMode }) => ({
font-size: 18px !important; font-size: 18px !important;
font-weight: bold; font-weight: bold;
`, `,
collectBtn: css`
font-size: 12px;
width: 20px;
height: 20px;
line-height: 20px;
border-radius: 50%;
background: #FFF3D9;
text-align: center;
`,
})); }));
interface PluginCardProps interface PluginCardProps
@ -73,10 +83,63 @@ interface PluginCardProps
const PluginCard = memo<PluginCardProps>( const PluginCard = memo<PluginCardProps>(
({ className, showCategory, meta, createdAt, author, variant, ...rest }) => { ({ className, showCategory, meta, createdAt, author, variant, ...rest }) => {
const { avatar, title, description, tags = [], category } = meta; const { avatar, title, description, tags = [], category } = meta;
const { createAt, homepage, identifier, schemaVersion, status, classify, manifest,locale } = {...rest}
const categoryItem = useCategoryItem(category, 12); const categoryItem = useCategoryItem(category, 12);
const { cx, styles, theme } = useStyles(); const { cx, styles, theme } = useStyles();
const { t } = useTranslation('discover');
const { message } = App.useApp();
const isCompact = variant === 'compact'; const isCompact = variant === 'compact';
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
console.log(status,"9383737-------------------------------------")
console.log(manifest,locale,"plugins9999999999-------------------")
const [val, setVal] = useState('')
const handleCollect = (e) => {
console.log(e,8844848)
e.preventDefault()
e.stopPropagation()
const params = {
"author": author,
"createdAt": createdAt,
"homepage": homepage,
"identifier": identifier,
"avatar": avatar,
"description": description,
"tags": tags.join(','),
"title": title,
"category": category,
"schemaVersion": schemaVersion,
"manifest": manifest,
"locale": locale,
"userid": userId,
}
request({
url: "/flxai/api/robot/appaiplugin",
method: "post",
data: params
}).then(response => {
console.log(response,222222222)
if (response.code == 0) {
message.success(t('collectSuccess'));
setVal("1")
}
}).catch(error => {
console.error('Error fetching data: ', error);
})
}
const renderElement = () => {
console.log(classify,'66666----------------------')
if (classify != 'collect') {
console.log(status,"222222222--------------------------")
if(status == "1" || val == "1") {
return <div className={styles.collectBtn} onClick={(e) => {e.stopPropagation()}}><StarOutlined style={{color: '#FFAD01'}}/></div>
} else {
return <div className={styles.collectBtn} style={{background: '#F1F1F1'}} onClick={(e) => handleCollect(e)}><StarOutlined style={{color: '#D6D6D6'}}/></div>
}
} else {
return;
}
};
return ( return (
<Flexbox className={cx(styles.container, className)} gap={24} {...rest}> <Flexbox className={cx(styles.container, className)} gap={24} {...rest}>
{!isCompact && <CardBanner avatar={avatar} />} {!isCompact && <CardBanner avatar={avatar} />}
@ -121,13 +184,12 @@ const PluginCard = memo<PluginCardProps>(
<Paragraph className={styles.desc} ellipsis={{ rows: 2 }}> <Paragraph className={styles.desc} ellipsis={{ rows: 2 }}>
{description} {description}
</Paragraph> </Paragraph>
<Flexbox gap={6} horizontal style={{ flexWrap: 'wrap' }}> <Flexbox gap={6} horizontal style={{ flexWrap: 'wrap',justifyContent: 'space-between' }}>
<div onClick={(e) => {e.stopPropagation()}} style={{width: '85%'}}>
{showCategory && categoryItem ? ( {showCategory && categoryItem ? (
<Link href={urlJoin('/discover/plugins', categoryItem.key)}> <Tag icon={categoryItem.icon} style={{ margin: '0 5' }}>
<Tag icon={categoryItem.icon} style={{ margin: 0 }}>
{categoryItem.label} {categoryItem.label}
</Tag> </Tag>
</Link>
) : ( ) : (
tags tags
.slice(0, 4) .slice(0, 4)
@ -138,12 +200,12 @@ const PluginCard = memo<PluginCardProps>(
url: '/discover/search', url: '/discover/search',
}); });
return ( return (
<Link href={url} key={index}> <Tag style={{ margin: '0 5' }}>{startCase(tag).trim()}</Tag>
<Tag style={{ margin: 0 }}>{startCase(tag).trim()}</Tag>
</Link>
); );
}) })
)} )}
</div>
{renderElement()}
</Flexbox> </Flexbox>
</Flexbox> </Flexbox>
</Flexbox> </Flexbox>

@ -7,7 +7,7 @@ import urlJoin from 'url-join';
import { useQueryRoute } from '@/hooks/useQueryRoute'; import { useQueryRoute } from '@/hooks/useQueryRoute';
import { PluginCategory } from '@/types/discover'; import { PluginCategory } from '@/types/discover';
import { useUserStore } from '@/store/user';
import CategoryMenu from '../../../components/CategoryMenu'; import CategoryMenu from '../../../components/CategoryMenu';
import { useCategory } from './useCategory'; import { useCategory } from './useCategory';
@ -21,7 +21,8 @@ const Category = memo(() => {
return 'all'; return 'all';
}, [pathname]); }, [pathname]);
const router = useQueryRoute(); const router = useQueryRoute();
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
return ( return (
<CategoryMenu <CategoryMenu
items={items.map((item: any) => ({ items={items.map((item: any) => ({

@ -3,17 +3,18 @@
import { Grid } from '@lobehub/ui'; import { Grid } from '@lobehub/ui';
import { Empty } from 'antd'; import { Empty } from 'antd';
import Link from 'next/link'; import Link from 'next/link';
import { memo, useMemo } from 'react'; import { memo, useMemo, useEffect,useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import urlJoin from 'url-join'; import urlJoin from 'url-join';
import { useRouter } from 'next/navigation';
import { DiscoverPlugintem } from '@/types/discover'; import { DiscoverPlugintem } from '@/types/discover';
import SearchResultCount from '../../../components/SearchResultCount'; import SearchResultCount from '../../../components/SearchResultCount';
import Title from '../../../components/Title'; import Title from '../../../components/Title';
import VirtuosoGridList from '../../../components/VirtuosoGridList'; import VirtuosoGridList from '../../../components/VirtuosoGridList';
import Card from './Card'; import Card from './Card';
import request from '@/app/api/request';
import { useUserStore } from '@/store/user';
export interface ListProps { export interface ListProps {
category?: string; category?: string;
items: DiscoverPlugintem[]; items: DiscoverPlugintem[];
@ -23,14 +24,68 @@ export interface ListProps {
const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] }) => { const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] }) => {
const { t } = useTranslation('discover'); const { t } = useTranslation('discover');
const router = useRouter()
const [stData, setStData] = useState(items)
const recentLength = mobile ? 4 : 8; const recentLength = mobile ? 4 : 8;
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
console.log(userId,'chajian---3837373266262266')
console.log('chajian33333333--------------',items)
const { all, recent, last } = useMemo(() => { const { all, recent, last } = useMemo(() => {
return { return {
all: items, all: stData,
last: items.slice(recentLength), last: stData.slice(recentLength),
recent: items.slice(0, recentLength), recent: stData.slice(0, recentLength),
};
}, [stData, mobile]);
useEffect(() => {
const fetchData = async() => {
if(category == "collect") {
const res = await request({
url: "/flxai/api/robot/appaiplugin/getAllAiPlugin",
method: "get",
params: {
userid: userId
}
})
setStData(res?.data.map((item,index)=> {
item.classify = 'collect';
return item
}))
} else {
const res = await request({
url: "/flxai/api/robot/appaiplugin/getAllAiPlugin",
method: "get",
params: {
userid: userId
}
})
const array2Object = {};
res?.data?.forEach((item) => {
array2Object[item.identifier] = item;
});
console.log('chajian22222222222222222222222222222--------------')
setStData(stData.map((item,index)=> {
const matchingItem = array2Object[item.identifier];
if (matchingItem) {
matchingItem.status = '1';
return matchingItem
} else {
item.status = '0';
return item
}
}))
}
}; };
}, [items, mobile]); fetchData();
}, []); // 空数组[]意味着仅在组件挂载时调用一次
console.log('chajian999999999999999--------------',stData)
const handleClickCard = (item) => {
console.log(item)
router.push(urlJoin('/discover/plugin/', item.identifier))
}
if (searchKeywords) { if (searchKeywords) {
if (!items || items?.length === 0) return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />; if (!items || items?.length === 0) return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />;
@ -41,9 +96,7 @@ const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] })
data={all} data={all}
initialItemCount={24} initialItemCount={24}
itemContent={(_, item) => ( itemContent={(_, item) => (
<Link href={urlJoin('/discover/plugin/', item.identifier)} key={item.identifier}> <Card onClick={() => handleClickCard(item)} showCategory variant={'compact'} {...item} />
<Card showCategory variant={'compact'} {...item} />
</Link>
)} )}
style={{ style={{
minHeight: '75vh', minHeight: '75vh',
@ -54,13 +107,24 @@ const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] })
} }
return ( return (
<>
{category == "collect"?(
<>
<Title tag={all.length}></Title>
<Grid maxItemWidth={280} rows={4}>
{all?.map((item) => (
// <Link href={urlJoin('/discover/assistant/', item.identifier)} key={item.identifier}>
<Card onClick={() => handleClickCard(item)} showCategory={!category} {...item} />
// </Link>
))}
</Grid>
</>
):(
<> <>
<Title>{t('plugins.recentSubmits')}</Title> <Title>{t('plugins.recentSubmits')}</Title>
<Grid maxItemWidth={280} rows={4}> <Grid maxItemWidth={280} rows={4}>
{recent.map((item) => ( {recent?.map((item) => (
<Link href={urlJoin('/discover/plugin/', item.identifier)} key={item.identifier}> <Card onClick={() => handleClickCard(item)} showCategory={!category} {...item} />
<Card showCategory={!category} {...item} />
</Link>
))} ))}
</Grid> </Grid>
{last && last?.length > 0 && ( {last && last?.length > 0 && (
@ -70,9 +134,7 @@ const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] })
data={last} data={last}
initialItemCount={12} initialItemCount={12}
itemContent={(_, item) => ( itemContent={(_, item) => (
<Link href={urlJoin('/discover/plugin/', item.identifier)} key={item.identifier}> <Card onClick={() => handleClickCard(item)} showCategory={!category} variant={'compact'} {...item} />
<Card showCategory={!category} variant={'compact'} {...item} />
</Link>
)} )}
style={{ style={{
minHeight: '75vh', minHeight: '75vh',
@ -81,6 +143,8 @@ const List = memo<ListProps>(({ category, mobile, searchKeywords, items = [] })
</> </>
)} )}
</> </>
)}
</>
); );
}); });

@ -37,42 +37,42 @@ export const useCategory = (fontsize?: number) => {
label: t('category.plugin.collect'), label: t('category.plugin.collect'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={ImagePlay} size={size} />, icon: <Icon color="#FF4D4D" icon={ImagePlay} size={size} />,
key: PluginCategory.MediaGenerate, key: PluginCategory.MediaGenerate,
label: t('category.plugin.media-generate'), label: t('category.plugin.media-generate'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={ScanSearch} size={size} />, icon: <Icon color="#5BD941" icon={ScanSearch} size={size} />,
key: PluginCategory.WebSearch, key: PluginCategory.WebSearch,
label: t('category.plugin.web-search'), label: t('category.plugin.web-search'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={Receipt} size={size} />, icon: <Icon color="#FF34AD" icon={Receipt} size={size} />,
key: PluginCategory.StocksFinance, key: PluginCategory.StocksFinance,
label: t('category.plugin.stocks-finance'), label: t('category.plugin.stocks-finance'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={PocketKnife} size={size} />, icon: <Icon color="#FF9B06" icon={PocketKnife} size={size} />,
key: PluginCategory.Tools, key: PluginCategory.Tools,
label: t('category.plugin.tools'), label: t('category.plugin.tools'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={Umbrella} size={size} />, icon: <Icon color="#0095FF" icon={Umbrella} size={size} />,
key: PluginCategory.LifeStyle, key: PluginCategory.LifeStyle,
label: t('category.plugin.life-style'), label: t('category.plugin.life-style'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={MicroscopeIcon} size={size} />, icon: <Icon color="#00B0CB" icon={MicroscopeIcon} size={size} />,
key: PluginCategory.ScienceEducation, key: PluginCategory.ScienceEducation,
label: t('category.plugin.science-education'), label: t('category.plugin.science-education'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={TwitterIcon} size={size} />, icon: <Icon color="#E138FF" icon={TwitterIcon} size={size} />,
key: PluginCategory.Social, key: PluginCategory.Social,
label: t('category.plugin.social'), label: t('category.plugin.social'),
}, },
{ {
icon: <Icon color={theme.colorTextSecondary} icon={Gamepad2} size={size} />, icon: <Icon color="#0CD66D" icon={Gamepad2} size={size} />,
key: PluginCategory.GamingEntertainment, key: PluginCategory.GamingEntertainment,
label: t('category.plugin.gaming-entertainment'), label: t('category.plugin.gaming-entertainment'),
}, },

@ -5,9 +5,8 @@ import { metadataModule } from '@/server/metadata';
import { DiscoverService } from '@/server/services/discover'; import { DiscoverService } from '@/server/services/discover';
import { translation } from '@/server/translation'; import { translation } from '@/server/translation';
import { isMobileDevice } from '@/utils/responsive'; import { isMobileDevice } from '@/utils/responsive';
import List from './features/List'; import List from './features/List';
import urlJoin from 'url-join';
type Props = { searchParams: { hl?: Locales } }; type Props = { searchParams: { hl?: Locales } };
export const generateMetadata = async ({ searchParams }: Props) => { export const generateMetadata = async ({ searchParams }: Props) => {
@ -25,14 +24,14 @@ export const generateMetadata = async ({ searchParams }: Props) => {
const Page = async ({ searchParams }: Props) => { const Page = async ({ searchParams }: Props) => {
const { t, locale } = await translation('metadata', searchParams?.hl); const { t, locale } = await translation('metadata', searchParams?.hl);
const mobile = isMobileDevice(); const mobile = isMobileDevice();
const discoverService = new DiscoverService(); const discoverService = new DiscoverService();
console.log(searchParams.userid,'plugins555555555555-----------------')
const items = await discoverService.getPluginList(locale); const items = await discoverService.getPluginList(locale);
const ld = ldModule.generate({ const ld = ldModule.generate({
description: t('discover.plugins.description'), description: t('discover.plugins.description'),
title: t('discover.plugins.title'), title: t('discover.plugins.title'),
url: '/discover/plugins', url: urlJoin('/discover/plugins?userid=',searchParams.userid),
webpage: { webpage: {
enable: true, enable: true,
search: '/discover/search', search: '/discover/search',

@ -9,7 +9,7 @@ const Layout = ({ children }: PropsWithChildren) => {
return ( return (
<> <>
<NProgress /> <NProgress />
<Flexbox height={'100%'} style={{ overflow: 'hidden', position: 'relative' }} width={'100%'}> <Flexbox height={'100%'} style={{ overflow: 'hidden', position: 'relative',marginTop: '-64px' }} width={'100%'}>
<Header /> <Header />
{children} {children}
</Flexbox> </Flexbox>

@ -13,7 +13,7 @@ import { useQueryRoute } from '@/hooks/useQueryRoute';
import { DiscoverTab } from '@/types/discover'; import { DiscoverTab } from '@/types/discover';
import { useNav } from './useNav'; import { useNav } from './useNav';
import { useUserStore } from '@/store/user';
export const useStyles = createStyles(({ css, prefixCls, token }) => ({ export const useStyles = createStyles(({ css, prefixCls, token }) => ({
active: css` active: css`
box-shadow: ${token.boxShadow}; box-shadow: ${token.boxShadow};
@ -41,15 +41,16 @@ const StoreSearchBar = memo<StoreSearchBarProps>(({ mobile, onBlur, onFocus, ...
const router = useQueryRoute(); const router = useQueryRoute();
const activeType = activeKey === DiscoverTab.Home ? DiscoverTab.Assistants : activeKey; const activeType = activeKey === DiscoverTab.Home ? DiscoverTab.Assistants : activeKey;
const getUserId = (s: UserStore) => s.user?.id
const userId = getUserId(useUserStore.getState())
useEffect(() => { useEffect(() => {
if (!pathname.includes('/discover/search')) return; if (!pathname.includes('/discover/search')) return;
// 使用 useQueryState 时,当 handleSearch 为空时无法回跳 // 使用 useQueryState 时,当 handleSearch 为空时无法回跳
if (!q) router.push(urlJoin('/discover', activeType), { query: { userid: localStorage.getItem('userId') }, replace: true }); if (!q) router.push(urlJoin('/discover', activeType), { query: { userid: userId }, replace: true });
}, [q, pathname, activeType]); }, [q, pathname, activeType]);
const handleSearch = (value: string) => { const handleSearch = (value: string) => {
router.push('/discover/search', { query: { q: value, type: activeType, userid: localStorage.getItem('userId') } }); router.push('/discover/search', { query: { q: value, type: activeType, userid: userId } });
}; };
return ( return (

@ -19,6 +19,7 @@ export default {
try: '试一下', try: '试一下',
}, },
back: '返回发现', back: '返回发现',
collectSuccess: '收藏成功',
category: { category: {
assistant: { assistant: {
'all': "全部", 'all': "全部",

@ -96,7 +96,7 @@ export const createCommonSlice: StateCreator<
data.avatar || data.userId data.avatar || data.userId
? merge(get().user, { avatar: data.avatar, id: data.userId }) ? merge(get().user, { avatar: data.avatar, id: data.userId })
: get().user; : get().user;
console.log(user,'777777777777777777777777')
set( set(
{ {
defaultSettings, defaultSettings,

Loading…
Cancel
Save