// ============================================================ // useSessionList — 会话历史列表管理 // 职责:会话 CRUD、消息持久化、切换会话 // ============================================================ import { useCallback, useEffect, useRef, useState } from "react"; import { v4 as uuidv4 } from "uuid"; import { loadSessionSummaries, saveSessionSummaries, loadSessionMessages, saveSessionMessages, deleteSessionMessages, } from "../lib/storage"; import type { ChatMessage, SessionSummary } from "../types"; /** 截取预览文本 */ function getPreview(text: string, maxLen = 50): string { const clean = text.replace(/[\n\r]/g, " ").trim(); return clean.length > maxLen ? clean.slice(0, maxLen) + "…" : clean; } export function useSessionList() { const [sessions, setSessions] = useState(() => loadSessionSummaries()); const [activeSessionId, setActiveSessionId] = useState(null); const sessionsRef = useRef(sessions); useEffect(() => { sessionsRef.current = sessions; }, [sessions]); /** 创建新会话 */ const createSession = useCallback((): string => { const id = uuidv4(); const now = Date.now(); const summary: SessionSummary = { id, title: "新对话", createdAt: now, lastActiveAt: now, messageCount: 0, preview: "", }; setSessions((prev) => [summary, ...prev]); setActiveSessionId(id); // 持久化 const all = [summary, ...sessionsRef.current]; saveSessionSummaries(all); return id; }, []); /** 删除会话 */ const deleteSession = useCallback((id: string) => { setSessions((prev) => prev.filter((s) => s.id !== id)); deleteSessionMessages(id); const remaining = sessionsRef.current.filter((s) => s.id !== id); saveSessionSummaries(remaining); // 如果删除的是当前会话,清空 active setActiveSessionId((prev) => (prev === id ? null : prev)); }, []); /** 重命名会话 */ const renameSession = useCallback((id: string, title: string) => { setSessions((prev) => prev.map((s) => (s.id === id ? { ...s, title } : s))); const updated = sessionsRef.current.map((s) => (s.id === id ? { ...s, title } : s)); saveSessionSummaries(updated); }, []); /** 保存当前会话的消息历史 */ const saveCurrentSession = useCallback((messages: ChatMessage[]) => { const id = sessionsRef.current.length > 0 ? sessionsRef.current[0].id : null; // 找到 activeSessionId 对应的会话 // 这里不依赖 activeSessionId state,而是通过参数传入 return messages; }, []); /** 保存指定会话的消息并更新摘要 */ const persistSession = useCallback((sessionId: string, messages: ChatMessage[]) => { if (!sessionId) return; saveSessionMessages(sessionId, messages); // 更新摘要 const firstUserMsg = messages.find((m) => m.role === "user"); const title = firstUserMsg ? getPreview(firstUserMsg.content, 20) : "新对话"; const lastMsg = messages[messages.length - 1]; const summary: Partial = { title, messageCount: messages.length, lastActiveAt: lastMsg?.timestamp || Date.now(), preview: lastMsg ? getPreview(lastMsg.content) : "", }; setSessions((prev) => { const updated = prev.map((s) => (s.id === sessionId ? { ...s, ...summary } : s)); saveSessionSummaries(updated); return updated; }); }, []); /** 加载指定会话的消息历史 */ const loadMessages = useCallback((sessionId: string): ChatMessage[] => { return loadSessionMessages(sessionId); }, []); /** 选择会话(返回需要加载的消息) */ const selectSession = useCallback((id: string): ChatMessage[] => { setActiveSessionId(id); return loadSessionMessages(id); }, []); return { sessions, activeSessionId, setActiveSessionId, createSession, deleteSession, renameSession, persistSession, loadMessages, selectSession, }; }