|
|
@@ -16,7 +16,7 @@ import faviconSrc from "../icons/favicon.png";
|
|
|
import { EditOutlined } from '@ant-design/icons';
|
|
|
import Locale from "../locales";
|
|
|
|
|
|
-import { useAppConfig, useChatStore } from "../store";
|
|
|
+import { useAppConfig, useChatStore, useGlobalStore } from "../store";
|
|
|
|
|
|
import {
|
|
|
DEFAULT_SIDEBAR_WIDTH,
|
|
|
@@ -32,7 +32,10 @@ import { Link, useNavigate } from "react-router-dom";
|
|
|
import { isIOS, useMobileScreen } from "../utils";
|
|
|
import dynamic from "next/dynamic";
|
|
|
import api from "@/app/api/api";
|
|
|
-import { Button, Dropdown, Menu } from "antd";
|
|
|
+import { Button, Dropdown, Form, Input, Menu, Modal } from "antd";
|
|
|
+import { downloadFile } from "../utils/index";
|
|
|
+
|
|
|
+const FormItem = Form.Item;
|
|
|
|
|
|
const ChatList = dynamic(async () => (await import("./chat-list")).ChatList, {
|
|
|
loading: () => null,
|
|
|
@@ -147,9 +150,9 @@ export function SideBarContainer(props: {
|
|
|
className={`${styles.sidebar} ${className} ${shouldNarrow && styles["narrow-sidebar"]
|
|
|
}`}
|
|
|
style={{
|
|
|
- // #3016 disable transition on ios mobile screen
|
|
|
transition: isMobileScreen && isIOSMobile ? "none" : undefined,
|
|
|
- background: '#FFFFFF'
|
|
|
+ background: '#FFFFFF',
|
|
|
+ overflowY: "auto",
|
|
|
}}
|
|
|
>
|
|
|
{children}
|
|
|
@@ -212,20 +215,23 @@ export function SideBarTail(props: {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
-export function SideBar(props: { className?: string }) {
|
|
|
+export const SideBar = (props: { className?: string }) => {
|
|
|
useHotKey();
|
|
|
const { onDragStart, shouldNarrow } = useDragSideBar();
|
|
|
const [showPluginSelector, setShowPluginSelector] = useState(false);
|
|
|
const navigate = useNavigate();
|
|
|
const config = useAppConfig();
|
|
|
const chatStore = useChatStore();
|
|
|
+ const globalStore = useGlobalStore();
|
|
|
|
|
|
const [menuList, setMenuList] = useState([])
|
|
|
+ const [modalOpen, setModalOpen] = useState(false)
|
|
|
+ const [form] = Form.useForm();
|
|
|
|
|
|
// 获取聊天列表
|
|
|
const fetchChatList = async () => {
|
|
|
try {
|
|
|
- const res = await api.get('/bigmodel/api/dialog/list');
|
|
|
+ const res = await api.get(`/bigmodel/api/dialog/list/${globalStore.selectedAppId}`);
|
|
|
const list = res.data.map((item: any) => {
|
|
|
return {
|
|
|
...item,
|
|
|
@@ -233,18 +239,54 @@ export function SideBar(props: { className?: string }) {
|
|
|
const items = [
|
|
|
{
|
|
|
key: '1',
|
|
|
- label: '重命名',
|
|
|
+ label: (
|
|
|
+ <a onClick={() => {
|
|
|
+ setModalOpen(true);
|
|
|
+ form.setFieldsValue({
|
|
|
+ dialogId: child.key,
|
|
|
+ dialogName: child.label
|
|
|
+ });
|
|
|
+ }}>
|
|
|
+ 重命名
|
|
|
+ </a>
|
|
|
+ ),
|
|
|
},
|
|
|
{
|
|
|
key: '2',
|
|
|
- label: '导出',
|
|
|
+ label: (
|
|
|
+ <a onClick={async () => {
|
|
|
+ try {
|
|
|
+ const blob = await api.post(`/bigmodel/api/dialog/export/${child.key}`, {}, { responseType: 'blob' });
|
|
|
+ const fileName = `${child.label}.xlsx`;
|
|
|
+ downloadFile(blob, fileName);
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ }
|
|
|
+ }}>
|
|
|
+ 导出
|
|
|
+ </a>
|
|
|
+ ),
|
|
|
},
|
|
|
{
|
|
|
key: '3',
|
|
|
- label: '删除',
|
|
|
+ label: (
|
|
|
+ <a onClick={async () => {
|
|
|
+ try {
|
|
|
+ await api.delete(`/bigmodel/api/dialog/del/${child.key}`);
|
|
|
+ await fetchChatList()
|
|
|
+ chatStore.clearSessions();
|
|
|
+ chatStore.updateCurrentSession((value) => {
|
|
|
+ value.appId = globalStore.selectedAppId;
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ }
|
|
|
+ }}>
|
|
|
+ 删除
|
|
|
+ </a>
|
|
|
+ ),
|
|
|
},
|
|
|
];
|
|
|
-
|
|
|
return {
|
|
|
...child,
|
|
|
label: <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
|
@@ -253,7 +295,7 @@ export function SideBar(props: { className?: string }) {
|
|
|
</div>
|
|
|
<div style={{ width: 20 }}>
|
|
|
<Dropdown menu={{ items }} trigger={['click']} placement="bottomRight">
|
|
|
- <EditOutlined />
|
|
|
+ <EditOutlined onClick={(e) => e.stopPropagation()} />
|
|
|
</Dropdown>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -269,6 +311,10 @@ export function SideBar(props: { className?: string }) {
|
|
|
|
|
|
useEffect(() => {
|
|
|
fetchChatList();
|
|
|
+ }, [globalStore.selectedAppId]);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ chatStore.clearSessions();
|
|
|
}, []);
|
|
|
|
|
|
return (
|
|
|
@@ -307,7 +353,10 @@ export function SideBar(props: { className?: string }) {
|
|
|
type="primary"
|
|
|
style={{ marginBottom: 20 }}
|
|
|
onClick={() => {
|
|
|
- chatStore.newSession();
|
|
|
+ chatStore.clearSessions();
|
|
|
+ chatStore.updateCurrentSession((value) => {
|
|
|
+ value.appId = globalStore.selectedAppId;
|
|
|
+ });
|
|
|
navigate(Path.Chat);
|
|
|
}}
|
|
|
>
|
|
|
@@ -395,10 +444,78 @@ export function SideBar(props: { className?: string }) {
|
|
|
/> */}
|
|
|
<Menu
|
|
|
style={{ border: 'none' }}
|
|
|
- // onClick={onClick}
|
|
|
+ onClick={async ({ key }) => {
|
|
|
+ const res = await api.get(`/bigmodel/api/dialog/detail/${key}`);
|
|
|
+ const list = res.data.map(((item: any) => {
|
|
|
+ return {
|
|
|
+ content: item.content,
|
|
|
+ date: item.create_time,
|
|
|
+ id: item.did,
|
|
|
+ role: item.type,
|
|
|
+ }
|
|
|
+ }))
|
|
|
+ const session = {
|
|
|
+ appId: res.data.length ? res.data[0].appId : '',
|
|
|
+ dialogName: res.data.length ? res.data[0].dialog_name : '',
|
|
|
+ id: res.data.length ? res.data[0].id : '',
|
|
|
+ messages: list,
|
|
|
+ }
|
|
|
+ globalStore.setCurrentSession(session);
|
|
|
+ chatStore.clearSessions();
|
|
|
+ chatStore.updateCurrentSession((value) => {
|
|
|
+ value.appId = session.appId;
|
|
|
+ value.topic = session.dialogName;
|
|
|
+ value.id = session.id;
|
|
|
+ value.messages = list;
|
|
|
+ });
|
|
|
+ navigate('/chat', { state: { fromHome: true } });
|
|
|
+ }}
|
|
|
mode="inline"
|
|
|
items={menuList}
|
|
|
/>
|
|
|
+ <Modal
|
|
|
+ title="重命名"
|
|
|
+ open={modalOpen}
|
|
|
+ width={300}
|
|
|
+ maskClosable={false}
|
|
|
+ onOk={() => {
|
|
|
+ form.validateFields().then(async (values) => {
|
|
|
+ setModalOpen(false);
|
|
|
+ try {
|
|
|
+ await api.put('/bigmodel/api/dialog/update', {
|
|
|
+ id: values.dialogId,
|
|
|
+ dialogName: values.dialogName
|
|
|
+ });
|
|
|
+ await fetchChatList()
|
|
|
+ chatStore.updateCurrentSession((value) => {
|
|
|
+ value.topic = values.dialogName;
|
|
|
+ });
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error);
|
|
|
+ }
|
|
|
+ }).catch((error) => {
|
|
|
+ console.error(error);
|
|
|
+ });
|
|
|
+ }}
|
|
|
+ onCancel={() => {
|
|
|
+ setModalOpen(false);
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Form form={form} layout='inline'>
|
|
|
+ <FormItem name='dialogId' noStyle />
|
|
|
+ <FormItem
|
|
|
+ label='名称'
|
|
|
+ name='dialogName'
|
|
|
+ rules={[{ required: true, message: '名称不能为空', whitespace: true }]}
|
|
|
+ >
|
|
|
+ <Input
|
|
|
+ style={{ width: 300 }}
|
|
|
+ placeholder='请输入'
|
|
|
+ maxLength={20}
|
|
|
+ />
|
|
|
+ </FormItem>
|
|
|
+ </Form>
|
|
|
+ </Modal>
|
|
|
</SideBarContainer>
|
|
|
);
|
|
|
-}
|
|
|
+}
|