From 3a244eb98950adff81c41d256f09da20339f7400 Mon Sep 17 00:00:00 2001 From: gaoziman <2942894660@qq.com> Date: Thu, 18 Dec 2025 11:30:21 +0800 Subject: [PATCH] =?UTF-8?q?refactor(layout):=20=E9=87=8D=E6=9E=84=E4=BE=A7?= =?UTF-8?q?=E8=BE=B9=E6=A0=8F=E6=94=AF=E6=8C=81=E5=AE=9E=E6=97=B6=E4=BC=9A?= =?UTF-8?q?=E8=AF=9D=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 集成 useConversations 和 useSettings hooks - 实现新建会话功能并自动跳转 - 实现删除会话功能及确认交互 - 按时间分组显示会话列表(今天、昨天、更早) - 添加加载状态和操作菜单 - 优化会话列表的交互体验 --- src/components/layout/Sidebar.tsx | 205 ++++++++++++++++++++++++------ 1 file changed, 169 insertions(+), 36 deletions(-) diff --git a/src/components/layout/Sidebar.tsx b/src/components/layout/Sidebar.tsx index 4cc02f4..1a9cb9d 100644 --- a/src/components/layout/Sidebar.tsx +++ b/src/components/layout/Sidebar.tsx @@ -1,21 +1,68 @@ 'use client'; import Link from 'next/link'; -import { usePathname } from 'next/navigation'; -import { Plus, ChevronDown, PanelLeft } from 'lucide-react'; +import { usePathname, useRouter } from 'next/navigation'; +import { Plus, ChevronDown, PanelLeft, Trash2, MoreHorizontal, Loader2 } from 'lucide-react'; import { Avatar } from '@/components/ui/Avatar'; import { cn } from '@/lib/utils'; -import type { ChatHistory, User } from '@/types'; +import { useConversations } from '@/hooks/useConversations'; +import { useSettings } from '@/hooks/useSettings'; +import type { User } from '@/types'; +import type { Conversation } from '@/drizzle/schema'; +import { useState } from 'react'; interface SidebarProps { user: User; - chatHistories: ChatHistory[]; + chatHistories?: { id: string; title: string }[]; // 保持向后兼容 isOpen?: boolean; onToggle?: () => void; } -export function Sidebar({ user, chatHistories, isOpen = true }: SidebarProps) { +export function Sidebar({ user, isOpen = true }: SidebarProps) { const pathname = usePathname(); + const router = useRouter(); + const { conversations, loading, createConversation, deleteConversation } = useConversations(); + const { settings } = useSettings(); + const [creatingChat, setCreatingChat] = useState(false); + const [menuOpen, setMenuOpen] = useState(null); + + // 创建新对话 + const handleNewChat = async () => { + if (creatingChat) return; + + try { + setCreatingChat(true); + const newConversation = await createConversation({ + model: settings?.defaultModel || 'claude-sonnet-4-20250514', + tools: settings?.defaultTools || [], + enableThinking: settings?.enableThinking || false, + }); + router.push(`/chat/${newConversation.conversationId}`); + } catch (error) { + console.error('Failed to create conversation:', error); + } finally { + setCreatingChat(false); + } + }; + + // 删除对话 + const handleDeleteConversation = async (conversationId: string, e: React.MouseEvent) => { + e.preventDefault(); + e.stopPropagation(); + try { + await deleteConversation(conversationId); + setMenuOpen(null); + // 如果当前正在查看被删除的对话,跳转到首页 + if (pathname === `/chat/${conversationId}`) { + router.push('/'); + } + } catch (error) { + console.error('Failed to delete conversation:', error); + } + }; + + // 按时间分组对话 + const groupedConversations = groupConversationsByTime(conversations); return ( <> @@ -33,53 +80,103 @@ export function Sidebar({ user, chatHistories, isOpen = true }: SidebarProps) { {/* 新建对话按钮 */}
- - + {creatingChat ? ( + + ) : ( + + )} New chat - -
- - {/* Recents 标签 */} -
-

- Recents -

+
{/* 聊天列表 */} {/* 用户信息 Footer */} @@ -87,6 +184,7 @@ export function Sidebar({ user, chatHistories, isOpen = true }: SidebarProps) { {isOpen && (
setMenuOpen(null)} /> )} @@ -105,3 +203,38 @@ export function SidebarToggle({ onClick }: { onClick?: () => void }) { ); } + +// 按时间分组对话 +function groupConversationsByTime(conversations: Conversation[]): Record { + const now = new Date(); + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000); + const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); + const monthAgo = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000); + + const groups: Record = {}; + + conversations.forEach((conversation) => { + const date = new Date(conversation.lastMessageAt || conversation.createdAt || now); + let group: string; + + if (date >= today) { + group = 'Today'; + } else if (date >= yesterday) { + group = 'Yesterday'; + } else if (date >= weekAgo) { + group = 'Past 7 days'; + } else if (date >= monthAgo) { + group = 'Past 30 days'; + } else { + group = 'Older'; + } + + if (!groups[group]) { + groups[group] = []; + } + groups[group].push(conversation); + }); + + return groups; +}