feat: P3b 会话重命名 (PATCH + 双击编辑)

This commit is contained in:
yuzhiran-dev
2026-05-18 12:08:32 +08:00
parent 4de042abcd
commit ed003d0ef0
4 changed files with 43 additions and 4 deletions
+28 -3
View File
@@ -73,6 +73,8 @@ function SandboxPage() {
const [conversationId, setConversationId] = useState(() => crypto.randomUUID());
const [sessionFeedback, setSessionFeedback] = useState<Record<number, string | null>>({});
const [currentSessionId, setCurrentSessionId] = useState<number | null>(null);
const [renamingId, setRenamingId] = useState<number | null>(null);
const [renameValue, setRenameValue] = useState('');
const messagesEndRef = useRef<HTMLDivElement>(null);
const messagesContainerRef = useRef<HTMLDivElement>(null);
const { isLoggedIn } = useAuth();
@@ -212,6 +214,20 @@ function SandboxPage() {
} catch {}
}
async function renameSession(sessionId: number, title: string) {
const tk = getToken();
if (!tk || !title.trim()) return;
try {
await fetch(`${API_BASE}/sandbox/sessions/${sessionId}/rename`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${tk}` },
body: JSON.stringify({ title: title.trim() }),
});
setSessions(prev => prev.map(s => s.id === sessionId ? { ...s, title: title.trim() } : s));
setRenamingId(null);
} catch {}
}
function newChat() {
setConversationId(crypto.randomUUID());
setCurrentSessionId(null);
@@ -322,9 +338,18 @@ function SandboxPage() {
{sessions.length === 0 ? (
<div className="p-4 text-center text-xs text-muted-foreground">{t.sandbox.noHistory}</div>
) : sessions.map(s => (
<div key={s.id} onClick={() => { loadSession(s.id); setSessionsOpen(false); }}
className="group px-3 py-2.5 hover:bg-accent cursor-pointer border-b border-border/50">
<div className="text-xs font-medium text-foreground truncate">{s.title}</div>
<div key={s.id} onClick={() => { if (renamingId !== s.id) { loadSession(s.id); setSessionsOpen(false); } }}
className="group px-3 py-2.5 hover:bg-accent cursor-pointer border-b border-border/50"
onDoubleClick={() => { setRenamingId(s.id); setRenameValue(s.title); }}>
{renamingId === s.id ? (
<input type="text" value={renameValue} onChange={e => setRenameValue(e.target.value)}
autoFocus onClick={e => e.stopPropagation()}
onBlur={() => renameSession(s.id, renameValue)}
onKeyDown={e => { if (e.key === 'Enter') { e.stopPropagation(); renameSession(s.id, renameValue); } if (e.key === 'Escape') setRenamingId(null); }}
className="w-full px-1 py-0.5 text-xs font-medium bg-background border border-border rounded focus:outline-none" />
) : (
<div className="text-xs font-medium text-foreground truncate">{s.title}</div>
)}
<div className="flex items-center justify-between mt-1">
<span className="text-[10px] text-muted-foreground">{formatTime(s.updatedAt)} · {s.model}</span>
<button onClick={e => { e.stopPropagation(); deleteSession(s.id); }}