|
@@ -3,7 +3,7 @@ import styles from "./home.module.scss";
|
|
|
import DragIcon from "../icons/drag.svg";
|
|
import DragIcon from "../icons/drag.svg";
|
|
|
import faviconSrc from "../icons/favicon.png";
|
|
import faviconSrc from "../icons/favicon.png";
|
|
|
import deepSeekSrc from "../icons/deepSeek.png";
|
|
import deepSeekSrc from "../icons/deepSeek.png";
|
|
|
-import { EditOutlined } from '@ant-design/icons';
|
|
|
|
|
|
|
+import { AppstoreOutlined, EditOutlined, MenuOutlined } from '@ant-design/icons';
|
|
|
import { useAppConfig, useChatStore, useGlobalStore } from "../store";
|
|
import { useAppConfig, useChatStore, useGlobalStore } from "../store";
|
|
|
import {
|
|
import {
|
|
|
DEFAULT_SIDEBAR_WIDTH,
|
|
DEFAULT_SIDEBAR_WIDTH,
|
|
@@ -14,8 +14,9 @@ import {
|
|
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
|
import { isIOS, useMobileScreen } from "../utils";
|
|
import { isIOS, useMobileScreen } from "../utils";
|
|
|
import api from "@/app/api/api";
|
|
import api from "@/app/api/api";
|
|
|
-import { Button, Dropdown, Form, Input, Menu, Modal } from "antd";
|
|
|
|
|
|
|
+import { Button, Drawer, Dropdown, Empty, Form, Input, Menu, message, Modal, Rate, Tag } from "antd";
|
|
|
import { downloadFile } from "../utils/index";
|
|
import { downloadFile } from "../utils/index";
|
|
|
|
|
+import dayjs from "dayjs";
|
|
|
|
|
|
|
|
const FormItem = Form.Item;
|
|
const FormItem = Form.Item;
|
|
|
|
|
|
|
@@ -193,6 +194,172 @@ export function SideBarTail(props: {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+interface AppDrawerProps {
|
|
|
|
|
+ isMobileScreen: boolean,
|
|
|
|
|
+ selectedAppId: string,
|
|
|
|
|
+ type: 'all' | 'collect',
|
|
|
|
|
+ open: boolean,
|
|
|
|
|
+ onClose: () => void,
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const AppDrawer: React.FC<AppDrawerProps> = (props) => {
|
|
|
|
|
+ const {
|
|
|
|
|
+ isMobileScreen,
|
|
|
|
|
+ selectedAppId,
|
|
|
|
|
+ type,
|
|
|
|
|
+ open,
|
|
|
|
|
+ onClose,
|
|
|
|
|
+ } = props;
|
|
|
|
|
+
|
|
|
|
|
+ const navigate = useNavigate();
|
|
|
|
|
+
|
|
|
|
|
+ const [listLoading, setListLoading] = useState(false);
|
|
|
|
|
+
|
|
|
|
|
+ type List = {
|
|
|
|
|
+ name: string,
|
|
|
|
|
+ chatMode: string,
|
|
|
|
|
+ appId: string,
|
|
|
|
|
+ desc: string,
|
|
|
|
|
+ createTime: string,
|
|
|
|
|
+ typeName: string,
|
|
|
|
|
+ isCollect: boolean,
|
|
|
|
|
+ }[];
|
|
|
|
|
+
|
|
|
|
|
+ const [list, setList] = useState<List>([]);
|
|
|
|
|
+
|
|
|
|
|
+ const fetchAppList = async () => {
|
|
|
|
|
+ setListLoading(true);
|
|
|
|
|
+ try {
|
|
|
|
|
+ const userId = '7';
|
|
|
|
|
+ const res = await api.get(`/deepseek/api/project/app/${userId}`);
|
|
|
|
|
+ if (type === 'all') {
|
|
|
|
|
+ setList(res.data);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ setList(res.data.filter((item: any) => item.isCollect));
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error(error);
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ setListLoading(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 收藏应用
|
|
|
|
|
+ const collectApp = async (appId: string) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const userId = '7';
|
|
|
|
|
+ await api.post('/deepseek/api/app/collect', {
|
|
|
|
|
+ appId: appId,
|
|
|
|
|
+ userId: userId,
|
|
|
|
|
+ });
|
|
|
|
|
+ message.success('收藏成功');
|
|
|
|
|
+ await fetchAppList();
|
|
|
|
|
+ } catch (error: any) {
|
|
|
|
|
+ message.error(error.msg);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ // 取消收藏应用
|
|
|
|
|
+ const cancelCollectApp = async (appId: string) => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const userId = '7';
|
|
|
|
|
+ await api.delete(`/deepseek/api/app/collect/${userId}/${appId}`);
|
|
|
|
|
+ message.success('操作成功');
|
|
|
|
|
+ await fetchAppList();
|
|
|
|
|
+ } catch (error: any) {
|
|
|
|
|
+ message.error(error.msg);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const init = async () => {
|
|
|
|
|
+ await fetchAppList();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ init();
|
|
|
|
|
+ }, [])
|
|
|
|
|
+
|
|
|
|
|
+ return (
|
|
|
|
|
+ <Drawer
|
|
|
|
|
+ width={isMobileScreen ? '100%' : 400}
|
|
|
|
|
+ title={type === 'all' ? '我的应用' : '我的收藏'}
|
|
|
|
|
+ open={open}
|
|
|
|
|
+ loading={listLoading}
|
|
|
|
|
+ onClose={onClose}
|
|
|
|
|
+ >
|
|
|
|
|
+ {
|
|
|
|
|
+ list.length > 0 ?
|
|
|
|
|
+ list.map((item, index) => {
|
|
|
|
|
+ return <div
|
|
|
|
|
+ style={{
|
|
|
|
|
+ padding: 20,
|
|
|
|
|
+ border: '1px solid #f0f0f0',
|
|
|
|
|
+ borderRadius: 4,
|
|
|
|
|
+ marginBottom: 20,
|
|
|
|
|
+ cursor: 'pointer',
|
|
|
|
|
+ }}
|
|
|
|
|
+ key={index}
|
|
|
|
|
+ >
|
|
|
|
|
+ <div style={{ display: 'flex', marginBottom: 10 }}>
|
|
|
|
|
+ <AppstoreOutlined style={{ fontSize: 40, color: '#3875f6', marginRight: 20 }} />
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <div style={{ fontSize: 16, fontWeight: 'bold', marginBottom: 5 }}>
|
|
|
|
|
+ {item.name}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div style={{ color: '#d4d7de' }}>
|
|
|
|
|
+ ID:{item.appId}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div style={{ color: '#8f949e', marginBottom: 10 }}>
|
|
|
|
|
+ {item.desc}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10 }}>
|
|
|
|
|
+ <div style={{ color: '#747a86' }}>
|
|
|
|
|
+ {dayjs(item.createTime).format('YYYY-MM-DD')} 发布
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <Tag style={{ margin: 0 }} color="blue">
|
|
|
|
|
+ {item.typeName}
|
|
|
|
|
+ </Tag>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div
|
|
|
|
|
+ style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
|
|
|
+ <div onClick={async () => {
|
|
|
|
|
+ if (item.isCollect) {
|
|
|
|
|
+ await cancelCollectApp(item.appId);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ await collectApp(item.appId);
|
|
|
|
|
+ }
|
|
|
|
|
+ }}>
|
|
|
|
|
+ {
|
|
|
|
|
+ item.isCollect ?
|
|
|
|
|
+ <Rate count={1} value={1} />
|
|
|
|
|
+ :
|
|
|
|
|
+ <Rate count={1} />
|
|
|
|
|
+ }
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <Button type='primary' size="small" onClick={() => {
|
|
|
|
|
+ const search = `?showMenu=false&chatMode=${item.chatMode}&appId=${item.appId}`;
|
|
|
|
|
+ navigate({
|
|
|
|
|
+ pathname: '/knowledgeChat',
|
|
|
|
|
+ search: search,
|
|
|
|
|
+ })
|
|
|
|
|
+ location.reload();
|
|
|
|
|
+ }}>
|
|
|
|
|
+ 使用
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ })
|
|
|
|
|
+ :
|
|
|
|
|
+ <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
|
|
|
|
+ }
|
|
|
|
|
+ </Drawer>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
export const SideBar = (props: { className?: string }) => {
|
|
export const SideBar = (props: { className?: string }) => {
|
|
|
// useHotKey();
|
|
// useHotKey();
|
|
|
const { onDragStart, shouldNarrow } = useDragSideBar();
|
|
const { onDragStart, shouldNarrow } = useDragSideBar();
|
|
@@ -355,10 +522,16 @@ export const SideBar = (props: { className?: string }) => {
|
|
|
fetchChatList(chatStore.chatMode);
|
|
fetchChatList(chatStore.chatMode);
|
|
|
}, [chatStore.chatMode]);
|
|
}, [chatStore.chatMode]);
|
|
|
|
|
|
|
|
|
|
+ const isMobileScreen = useMobileScreen();
|
|
|
|
|
+
|
|
|
|
|
+ const [drawerOpen, setDrawerOpen] = useState(false);
|
|
|
|
|
+
|
|
|
|
|
+ const [drawerType, setDrawerType] = useState<'all' | 'collect'>('all');
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<>
|
|
<>
|
|
|
{
|
|
{
|
|
|
- !location.search.includes('showMenu=false') &&
|
|
|
|
|
|
|
+ globalStore.showMenu &&
|
|
|
<SideBarContainer
|
|
<SideBarContainer
|
|
|
onDragStart={onDragStart}
|
|
onDragStart={onDragStart}
|
|
|
shouldNarrow={shouldNarrow}
|
|
shouldNarrow={shouldNarrow}
|
|
@@ -371,7 +544,22 @@ export const SideBar = (props: { className?: string }) => {
|
|
|
</div>
|
|
</div>
|
|
|
}
|
|
}
|
|
|
<SideBarHeader
|
|
<SideBarHeader
|
|
|
- title={getType() === 'bigModel' ? '问答历史' : ''}
|
|
|
|
|
|
|
+ title={getType() === 'bigModel' ?
|
|
|
|
|
+ <div style={{ display: 'flex', alignItems: 'center' }}>
|
|
|
|
|
+ {isMobileScreen && <div>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ type='text'
|
|
|
|
|
+ icon={<MenuOutlined />}
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ globalStore.setShowMenu(!globalStore.showMenu);
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ </div>}
|
|
|
|
|
+ 问答历史
|
|
|
|
|
+ </div>
|
|
|
|
|
+ :
|
|
|
|
|
+ ''
|
|
|
|
|
+ }
|
|
|
logo={getType() === 'bigModel' ? <img style={{ height: 40 }} src={faviconSrc.src} /> : ''}
|
|
logo={getType() === 'bigModel' ? <img style={{ height: 40 }} src={faviconSrc.src} /> : ''}
|
|
|
>
|
|
>
|
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 10 }}>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 10 }}>
|
|
@@ -385,7 +573,6 @@ export const SideBar = (props: { className?: string }) => {
|
|
|
</Button>
|
|
</Button>
|
|
|
<Button
|
|
<Button
|
|
|
style={{ width: '48%' }}
|
|
style={{ width: '48%' }}
|
|
|
- type="primary"
|
|
|
|
|
onClick={async () => {
|
|
onClick={async () => {
|
|
|
chatStore.clearSessions();
|
|
chatStore.clearSessions();
|
|
|
chatStore.updateCurrentSession((value) => {
|
|
chatStore.updateCurrentSession((value) => {
|
|
@@ -410,6 +597,28 @@ export const SideBar = (props: { className?: string }) => {
|
|
|
新建对话
|
|
新建对话
|
|
|
</Button>
|
|
</Button>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 10 }}>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ style={{ width: '48%' }}
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ setDrawerType('all');
|
|
|
|
|
+ setDrawerOpen(true);
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ 我的应用
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ <Button
|
|
|
|
|
+ style={{ width: '48%' }}
|
|
|
|
|
+ type="primary"
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ setDrawerType('collect');
|
|
|
|
|
+ setDrawerOpen(true);
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ 我的收藏
|
|
|
|
|
+ </Button>
|
|
|
|
|
+ </div>
|
|
|
</SideBarHeader>
|
|
</SideBarHeader>
|
|
|
<Menu
|
|
<Menu
|
|
|
style={{ border: 'none' }}
|
|
style={{ border: 'none' }}
|
|
@@ -520,6 +729,18 @@ export const SideBar = (props: { className?: string }) => {
|
|
|
</Modal>
|
|
</Modal>
|
|
|
</SideBarContainer>
|
|
</SideBarContainer>
|
|
|
}
|
|
}
|
|
|
|
|
+ {
|
|
|
|
|
+ drawerOpen &&
|
|
|
|
|
+ <AppDrawer
|
|
|
|
|
+ isMobileScreen={isMobileScreen}
|
|
|
|
|
+ selectedAppId={globalStore.selectedAppId}
|
|
|
|
|
+ type={drawerType}
|
|
|
|
|
+ open={drawerOpen}
|
|
|
|
|
+ onClose={() => {
|
|
|
|
|
+ setDrawerOpen(false);
|
|
|
|
|
+ }}
|
|
|
|
|
+ />
|
|
|
|
|
+ }
|
|
|
</>
|
|
</>
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|