import React, { useState, forwardRef, useImperativeHandle } from 'react'; import { Button, Layout, Menu, theme, Input, Tooltip, Dropdown, Modal, message } from 'antd'; import { MenuFoldOutlined, MenuUnfoldOutlined, MessageOutlined, PlusOutlined, SearchOutlined, MoreOutlined, DeleteOutlined, EditOutlined, ExclamationCircleOutlined, } from '@ant-design/icons'; import type { ConversationItem } from '../../types/dify_chat'; import { deleteConversation, renameConversation } from '../../services/api.client'; import '../../styles/components/chat-with-llm/sidebar.css'; const { Sider } = Layout; interface ChatSidebarProps { collapsed: boolean; onToggle: () => void; conversations: ConversationItem[]; currentConversationId: string; onConversationSelect: (conversationId: string) => void; onNewConversation: () => void; onConversationDeleted?: (conversationId: string) => void; onConversationRenamed?: (conversationId: string, newName: string) => void; } // 暴露给父组件的方法接口 export interface ChatSidebarRef { autoRename: (conversationId: string) => Promise; } /** * 聊天侧边栏组件 */ const ChatSidebar = forwardRef(({ collapsed, onToggle, conversations, currentConversationId, onConversationSelect, onNewConversation, onConversationDeleted, onConversationRenamed, }, ref) => { const [searchValue, setSearchValue] = useState(''); const [renameModalVisible, setRenameModalVisible] = useState(false); const [deleteModalVisible, setDeleteModalVisible] = useState(false); const [renamingConversation, setRenamingConversation] = useState(null); const [deletingConversation, setDeletingConversation] = useState(null); const [newName, setNewName] = useState(''); const [renameLoading, setRenameLoading] = useState(false); const [deleteLoading, setDeleteLoading] = useState(false); const { token: { colorBgContainer, borderRadiusLG }, } = theme.useToken(); // 过滤会话列表 const filteredConversations = conversations.filter(conv => conv.name.toLowerCase().includes(searchValue.toLowerCase()) ); // 处理重命名 const handleRename = (conv: ConversationItem) => { setRenamingConversation(conv); setNewName(conv.name); setRenameModalVisible(true); }; // 处理删除会话 - 显示确认Modal const handleDeleteClick = (conv: ConversationItem) => { setDeletingConversation(conv); setDeleteModalVisible(true); }; // 确认删除会话 const handleDeleteConfirm = async () => { if (!deletingConversation) return; setDeleteLoading(true); try { console.log('🗑️ 开始删除会话:', deletingConversation.id); // 调用API删除服务器端的会话 const response = await deleteConversation(deletingConversation.id); console.log('✅ 服务器端会话删除响应:', response); // 检查响应是否成功 if (response && (response as any).result === 'success') { console.log('✅ 服务器端会话删除成功'); message.success('会话删除成功'); setDeleteModalVisible(false); // 通知父组件会话已删除 onConversationDeleted?.(deletingConversation.id); console.log('✅ 会话删除完成:', deletingConversation.id); } else { throw new Error((response as any)?.error || '删除会话失败'); } } catch (error) { console.error('❌ 删除会话失败:', error); message.error(`删除会话失败: ${error instanceof Error ? error.message : '未知错误'}`); } finally { setDeleteLoading(false); } }; // 取消删除 const handleDeleteCancel = () => { setDeleteModalVisible(false); setDeletingConversation(null); setDeleteLoading(false); }; // 确认重命名 const handleRenameConfirm = async () => { if (!renamingConversation || !newName.trim()) { message.error('请输入有效的会话名称'); return; } if (newName.trim() === renamingConversation.name) { setRenameModalVisible(false); return; } setRenameLoading(true); try { console.log('✏️ 开始重命名会话:', { conversationId: renamingConversation.id, newName: newName.trim() }); // 调用API重命名服务器端的会话 const response = await renameConversation(renamingConversation.id, newName.trim(), false); console.log('✅ 服务器端会话重命名响应:', response); // 检查响应是否成功 if (response && (response as any).name) { console.log('✅ 服务器端会话重命名成功'); message.success('重命名成功'); setRenameModalVisible(false); // 通知父组件会话已重命名 onConversationRenamed?.(renamingConversation.id, (response as any).name); console.log('✅ 会话重命名完成:', renamingConversation.id, '->', (response as any).name); } else { throw new Error((response as any)?.error || '重命名会话失败'); } } catch (error) { console.error('❌ 重命名会话失败:', error); message.error(`重命名失败: ${error instanceof Error ? error.message : '未知错误'}`); } finally { setRenameLoading(false); } }; // 取消重命名 const handleRenameCancel = () => { setRenameModalVisible(false); setRenamingConversation(null); setNewName(''); setRenameLoading(false); }; // 生成菜单项 const menuItems = filteredConversations.map(conv => ({ key: conv.id, icon: , label: (
{conv.name} {!collapsed && ( , label: '重命名', onClick: () => handleRename(conv), }, { key: 'delete', icon: , label: '删除', danger: true, onClick: () => handleDeleteClick(conv), }, ], }} trigger={['click']} placement="bottomRight" >
), })); useImperativeHandle(ref, () => ({ autoRename: async (conversationId: string) => { try { console.log('🏷️ 开始自动重命名会话为"新对话":', conversationId); // 调用API将会话重命名为固定的"新对话" const response = await renameConversation(conversationId, '新对话', false); console.log('✅ 服务器端会话重命名响应:', response); // 检查响应是否成功 if (response && (response as any).name) { console.log('✅ 服务器端会话重命名成功'); // 通知父组件会话已重命名 onConversationRenamed?.(conversationId, (response as any).name); console.log('✅ 会话重命名完成:', conversationId, '->', (response as any).name); } else { throw new Error((response as any)?.error || '重命名会话失败'); } } catch (error) { console.error('❌ 重命名会话失败:', error); // 重命名失败时不显示错误消息,避免打扰用户 console.warn('⚠️ 重命名失败,会话将保持默认名称'); } }, })); return ( {/* 侧边栏头部 - 固定在顶部 */}
)}
{/* 搜索框 */} {!collapsed && ( } value={searchValue} onChange={(e) => setSearchValue(e.target.value)} allowClear /> )}
{/* 会话列表 - 可滚动区域 */}
{!collapsed && filteredConversations.length === 0 && searchValue && (

未找到相关对话

)} {!collapsed && conversations.length === 0 && !searchValue && (

暂无对话记录

)} onConversationSelect(key)} style={{ border: 'none', background: 'transparent', }} className="chat-sidebar-menu" />
{/* 侧边栏底部 - 固定在底部 */} {!collapsed && (
共 {conversations.length} 个对话
)} {/* 重命名Modal */}
setNewName(e.target.value)} placeholder="请输入新的会话名称" maxLength={10} showCount onPressEnter={handleRenameConfirm} autoFocus />
{/* 删除确认Modal */} 删除会话 } open={deleteModalVisible} onOk={handleDeleteConfirm} onCancel={handleDeleteCancel} confirmLoading={deleteLoading} okText="删除" cancelText="取消" okType="danger" destroyOnClose >

确定要删除会话 "{deletingConversation?.name}" 吗?

此操作不可撤销,会话中的所有消息都将被永久删除。

); }); export default ChatSidebar;