From 2a4ede5726bf717503c72003234ef97c5d325a34 Mon Sep 17 00:00:00 2001 From: gaoziman <2942894660@qq.com> Date: Sat, 20 Dec 2025 01:05:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E9=A1=B5=E9=9D=A2):=20=E8=81=8A=E5=A4=A9?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E6=A0=87=E9=A2=98=E5=A2=9E=E5=BC=BA=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 标题区域新增下拉菜单,支持重命名和删除对话 - 添加内联标题编辑模式 - 优化模型格式转换,区分 name 和 displayName - 完善键盘快捷键支持(Enter 确认、Escape 取消) --- src/app/chat/[id]/page.tsx | 169 +++++++++++++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 6 deletions(-) diff --git a/src/app/chat/[id]/page.tsx b/src/app/chat/[id]/page.tsx index ccdd6aa..b508487 100644 --- a/src/app/chat/[id]/page.tsx +++ b/src/app/chat/[id]/page.tsx @@ -2,7 +2,7 @@ import { useState, useRef, useEffect, use } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; -import { Share2, MoreHorizontal, Loader2, Square, Clock } from 'lucide-react'; +import { Share2, MoreHorizontal, Loader2, Square, Clock, ChevronDown, Pencil, Trash2, Check, X } from 'lucide-react'; import { Sidebar, SidebarToggle } from '@/components/layout/Sidebar'; import { ChatInput } from '@/components/features/ChatInput'; import { MessageBubble } from '@/components/features/MessageBubble'; @@ -28,9 +28,17 @@ export default function ChatPage({ params }: PageProps) { const [isNewChat, setIsNewChat] = useState(false); const [initialMessageSent, setInitialMessageSent] = useState(false); + // 标题下拉菜单状态 + const [titleMenuOpen, setTitleMenuOpen] = useState(false); + const [isEditingTitle, setIsEditingTitle] = useState(false); + const [editingTitle, setEditingTitle] = useState(''); + const [isSavingTitle, setIsSavingTitle] = useState(false); + const titleInputRef = useRef(null); + const titleMenuRef = useRef(null); + // 获取数据 const { conversation, loading: conversationLoading, error: conversationError } = useConversation(chatId); - const { createConversation } = useConversations(); + const { createConversation, updateConversation, deleteConversation } = useConversations(); const { models, loading: modelsLoading } = useModels(); const { tools: availableTools, loading: toolsLoading } = useTools(); const { settings } = useSettings(); @@ -90,6 +98,80 @@ export default function ChatPage({ params }: PageProps) { scrollToBottom(); }, [messages]); + // 聚焦标题输入框 + useEffect(() => { + if (isEditingTitle && titleInputRef.current) { + titleInputRef.current.focus(); + titleInputRef.current.select(); + } + }, [isEditingTitle]); + + // 点击外部关闭下拉菜单 + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (titleMenuRef.current && !titleMenuRef.current.contains(event.target as Node)) { + setTitleMenuOpen(false); + } + }; + if (titleMenuOpen) { + document.addEventListener('mousedown', handleClickOutside); + } + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [titleMenuOpen]); + + // 开始重命名 + const handleStartRename = () => { + setIsEditingTitle(true); + setEditingTitle(conversation?.title || ''); + setTitleMenuOpen(false); + }; + + // 提交重命名 + const handleSubmitRename = async () => { + if (!editingTitle.trim() || isSavingTitle) return; + try { + setIsSavingTitle(true); + await updateConversation(chatId, { title: editingTitle.trim() }); + setIsEditingTitle(false); + setEditingTitle(''); + // 刷新页面数据 + window.location.reload(); + } catch (error) { + console.error('Failed to rename conversation:', error); + } finally { + setIsSavingTitle(false); + } + }; + + // 取消重命名 + const handleCancelRename = () => { + setIsEditingTitle(false); + setEditingTitle(''); + }; + + // 处理键盘事件 + const handleTitleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + e.preventDefault(); + handleSubmitRename(); + } else if (e.key === 'Escape') { + handleCancelRename(); + } + }; + + // 删除对话 + const handleDeleteConversation = async () => { + if (!confirm('Are you sure you want to delete this conversation?')) return; + try { + await deleteConversation(chatId); + router.push('/'); + } catch (error) { + console.error('Failed to delete conversation:', error); + } + }; + // 处理初始消息(从首页跳转过来时) useEffect(() => { if ( @@ -171,7 +253,8 @@ export default function ChatPage({ params }: PageProps) { // 转换模型格式 const modelOptions = models.map((m) => ({ id: m.modelId, - name: m.displayName, + name: m.modelId, + displayName: m.displayName, tag: m.supportsThinking ? 'Thinking' : '', })); @@ -212,9 +295,83 @@ export default function ChatPage({ params }: PageProps) {
setSidebarOpen(!sidebarOpen)} /> -

- {conversation?.title || '新对话'} -

+ + {/* 标题区域 - 可点击显示下拉菜单 */} + {isEditingTitle ? ( + // 编辑模式 +
+ setEditingTitle(e.target.value)} + onKeyDown={handleTitleKeyDown} + onBlur={handleCancelRename} + className="px-2 py-1 text-base font-medium bg-[var(--color-bg-secondary)] border border-[var(--color-border)] rounded text-[var(--color-text-primary)] focus:outline-none focus:border-[var(--color-primary)] max-w-[300px]" + disabled={isSavingTitle} + /> + + +
+ ) : ( + // 正常模式 - 显示标题和下拉菜单 +
+ + + {/* 下拉菜单 */} + {titleMenuOpen && ( +
+ + +
+ )} +
+ )}
{/* 思考模式开关 */}