knowledgebase_law/src/pages/Chat/Chat.jsx

184 lines
7.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
import { fetchChats, deleteChat, createChatRecord, createConversation } from '../../store/chat/chat.thunks';
import { showNotification } from '../../store/notification.slice';
import ChatSidebar from './ChatSidebar';
import NewChat from './NewChat';
import ChatWindow from './ChatWindow';
export default function Chat() {
const { knowledgeBaseId, chatId } = useParams();
const navigate = useNavigate();
const dispatch = useDispatch();
// 从 Redux store 获取聊天记录列表
const {
items: chatHistory,
status,
error,
} = useSelector((state) => state.chat.list || { items: [], status: 'idle', error: null });
const operationStatus = useSelector((state) => state.chat.createSession?.status);
const operationError = useSelector((state) => state.chat.createSession?.error);
// 判断是否在知识库选择页面
const isNewChatView = !chatId;
// 获取聊天记录列表
useEffect(() => {
dispatch(fetchChats({ page: 1, page_size: 20 }));
}, [dispatch]);
// 监听操作状态,显示通知
useEffect(() => {
if (operationStatus === 'succeeded') {
dispatch(
showNotification({
message: '操作成功',
type: 'success',
})
);
} else if (operationStatus === 'failed' && operationError) {
dispatch(
showNotification({
message: `操作失败: ${operationError}`,
type: 'danger',
})
);
}
}, [operationStatus, operationError, dispatch]);
// If we have a knowledgeBaseId but no chatId, check if we have an existing chat or create a new one
useEffect(() => {
// 只有当 knowledgeBaseId 存在但 chatId 不存在,且聊天历史已加载完成时才执行
if (knowledgeBaseId && !chatId && status === 'succeeded' && !status.includes('loading')) {
console.log('Chat.jsx: 检查是否需要创建聊天...');
// 处理可能的多个知识库ID (以逗号分隔)
const knowledgeBaseIds = knowledgeBaseId.split(',').map((id) => id.trim());
console.log('Chat.jsx: 处理知识库ID列表:', knowledgeBaseIds);
// 检查是否存在包含所有选中知识库的聊天记录
const existingChat = chatHistory.find((chat) => {
// 没有datasets属性或不是数组跳过
if (!chat.datasets || !Array.isArray(chat.datasets)) {
return false;
}
// 获取当前聊天记录中的知识库ID列表
const chatDatasetIds = chat.datasets.map((ds) => ds.id);
// 检查所有选中的知识库是否都包含在这个聊天中
// 并且聊天中的知识库数量要和选中的相同(完全匹配)
return (
knowledgeBaseIds.length === chatDatasetIds.length &&
knowledgeBaseIds.every((id) => chatDatasetIds.includes(id))
);
});
console.log('Chat.jsx: existingChat', existingChat);
if (existingChat) {
console.log(
`Chat.jsx: 找到现有聊天记录,导航到 /chat/${knowledgeBaseId}/${existingChat.conversation_id}`
);
// 找到现有聊天记录,导航到该聊天页面
navigate(`/chat/${knowledgeBaseId}/${existingChat.conversation_id}`);
} else {
console.log('Chat.jsx: 创建新聊天...');
// 创建新聊天 - 使用新的API创建会话
dispatch(
createConversation({
dataset_id_list: knowledgeBaseIds,
})
)
.unwrap()
.then((response) => {
// 创建成功使用返回的conversation_id导航
if (response && response.conversation_id) {
console.log(
`Chat.jsx: 创建成功,导航到 /chat/${knowledgeBaseId}/${response.conversation_id}`
);
navigate(`/chat/${knowledgeBaseId}/${response.conversation_id}`);
} else {
// 错误处理
console.error('Chat.jsx: 创建失败未能获取会话ID');
dispatch(
showNotification({
message: '创建聊天失败未能获取会话ID',
type: 'danger',
})
);
}
})
.catch((error) => {
console.error('Chat.jsx: 创建失败', error);
dispatch(
showNotification({
message: `创建聊天失败: ${error}`,
type: 'danger',
})
);
});
}
}
}, [knowledgeBaseId, chatId, chatHistory, status, navigate, dispatch]);
const handleDeleteChat = (id) => {
// 调用 Redux action 删除聊天
dispatch(deleteChat(id))
.unwrap()
.then(() => {
// 删除成功后显示通知
dispatch(
showNotification({
message: '聊天记录已删除',
type: 'success',
})
);
// If the deleted chat is the current one, navigate to the chat list
if (chatId === id) {
navigate('/chat');
}
})
.catch((error) => {
// 删除失败显示错误通知
dispatch(
showNotification({
message: `删除失败: ${error}`,
type: 'danger',
})
);
});
};
return (
<div className='chat-container container-fluid'>
<div className='row h-100'>
{/* Sidebar */}
<div
className='col-md-3 col-lg-2 p-0 border-end'
style={{ height: 'calc(100vh - 84px)', overflowY: 'auto' }}
>
<ChatSidebar
chatHistory={chatHistory}
onDeleteChat={handleDeleteChat}
isLoading={status === 'loading'}
hasError={status === 'failed'}
isNewChatView={isNewChatView}
/>
</div>
{/* Main Content */}
<div
className='chat-main col-md-9 col-lg-10 p-0'
style={{ height: 'calc(100vh - 84px)', overflowY: 'auto' }}
>
{isNewChatView ? <NewChat /> : <ChatWindow chatId={chatId} knowledgeBaseId={knowledgeBaseId} />}
</div>
</div>
</div>
);
}