11"use client" ;
22
3- // 智能搜索助手 — 聊天状态管理 Provider
3+ // 智能搜索助手 — 聊天状态管理 Provider (前端自管历史会话版)
44import React , { createContext , useContext , useState , useCallback , useRef , useEffect } from "react" ;
55import type { ChatMessage , UserSettings , SessionSummary } from "../lib/types" ;
66import { useSSE } from "../hooks/useSSE" ;
7- import { generateSessionId , getOrCreateUserId , getSessions , getSession , deleteSession as apiDeleteSession } from "../lib/api" ;
7+ import { generateSessionId , getOrCreateUserId , getSession , deleteSession as apiDeleteSession } from "../lib/api" ;
8+
9+ const LOCAL_SESSIONS_KEY = "qa_local_sessions_v1" ;
10+
11+ // ── 本地存储辅助函数 ──
12+ const getLocalSessions = ( ) : SessionSummary [ ] => {
13+ if ( typeof window === "undefined" ) return [ ] ;
14+ try {
15+ const raw = localStorage . getItem ( LOCAL_SESSIONS_KEY ) ;
16+ return raw ? JSON . parse ( raw ) : [ ] ;
17+ } catch {
18+ return [ ] ;
19+ }
20+ } ;
21+
22+ const saveLocalSessions = ( data : SessionSummary [ ] ) => {
23+ if ( typeof window === "undefined" ) return ;
24+ localStorage . setItem ( LOCAL_SESSIONS_KEY , JSON . stringify ( data ) ) ;
25+ } ;
826
927interface ChatContextType {
1028 messages : ChatMessage [ ] ;
1129 sessionId : string ;
1230 userId : string ;
1331 settings : UserSettings ;
1432 stats : { totalQueries : number ; totalTokens : number } ;
15- // 会话列表
1633 sessions : SessionSummary [ ] ;
1734 sessionsLoading : boolean ;
18- // SSE 状态
1935 sse : ReturnType < typeof useSSE > ;
20- // 操作
2136 sendMessage : ( content : string ) => Promise < void > ;
2237 clearHistory : ( ) => void ;
2338 newSession : ( ) => void ;
2439 updateSettings : ( s : Partial < UserSettings > ) => void ;
25- // 会话管理
2640 refreshSessions : ( ) => Promise < void > ;
2741 switchSession : ( sid : string ) => Promise < void > ;
2842 removeSession : ( sid : string ) => Promise < void > ;
@@ -48,39 +62,32 @@ export default function ChatProvider({
4862 const [ messages , setMessages ] = useState < ChatMessage [ ] > ( [ ] ) ;
4963 const [ settings , setSettings ] = useState < UserSettings > ( defaultSettings ) ;
5064 const [ stats , setStats ] = useState ( { totalQueries : 0 , totalTokens : 0 } ) ;
65+
66+ // 会话列表现在完全由前端维护
5167 const [ sessions , setSessions ] = useState < SessionSummary [ ] > ( [ ] ) ;
5268 const [ sessionsLoading , setSessionsLoading ] = useState ( false ) ;
69+
5370 const sse = useSSE ( ) ;
5471 const msgCounter = useRef ( 0 ) ;
5572
56- // 首次挂载时初始化 userId
73+ // 初始化 userId 和 本地列表
5774 useEffect ( ( ) => {
5875 setUserId ( getOrCreateUserId ( ) ) ;
76+ setSessions ( getLocalSessions ( ) ) ;
5977 } , [ ] ) ;
6078
61- // ── 加载会话列表 ──
79+ // 刷新本地列表
6280 const refreshSessions = useCallback ( async ( ) => {
63- if ( ! userId ) return ;
64- setSessionsLoading ( true ) ;
65- try {
66- const data = await getSessions ( userId ) ;
67- setSessions ( data . sessions || [ ] ) ;
68- } catch ( e ) {
69- console . error ( "加载会话列表失败" , e ) ;
70- } finally {
71- setSessionsLoading ( false ) ;
72- }
73- } , [ userId ] ) ;
74-
75- useEffect ( ( ) => {
76- if ( userId ) refreshSessions ( ) ;
77- } , [ userId , refreshSessions ] ) ;
81+ setSessions ( getLocalSessions ( ) ) ;
82+ } , [ ] ) ;
7883
7984 // ── 切换会话 ──
8085 const switchSession = useCallback (
8186 async ( sid : string ) => {
8287 if ( ! userId ) return ;
88+ setSessionsLoading ( true ) ;
8389 try {
90+ // 依然从后端(Redis)拉取该会话的历史记录
8491 const info = await getSession ( sid , userId ) ;
8592 const history : ChatMessage [ ] = ( info . history || [ ] ) . map (
8693 ( m , i ) => ( {
@@ -94,6 +101,8 @@ export default function ChatProvider({
94101 sse . reset ( ) ;
95102 } catch ( e ) {
96103 console . error ( "切换会话失败" , e ) ;
104+ } finally {
105+ setSessionsLoading ( false ) ;
97106 }
98107 } ,
99108 [ userId , sse ]
@@ -104,17 +113,23 @@ export default function ChatProvider({
104113 async ( sid : string ) => {
105114 if ( ! userId ) return ;
106115 try {
116+ // 通知后端删除
107117 await apiDeleteSession ( sid , userId ) ;
118+
119+ // 从前端本地列表中移除
120+ const current = getLocalSessions ( ) . filter ( ( s ) => s . session_id !== sid ) ;
121+ saveLocalSessions ( current ) ;
122+ setSessions ( current ) ;
123+
108124 if ( sid === sessionId ) {
109125 setMessages ( [ ] ) ;
110126 setSessionId ( generateSessionId ( ) ) ;
111127 }
112- await refreshSessions ( ) ;
113128 } catch ( e ) {
114129 console . error ( "删除会话失败" , e ) ;
115130 }
116131 } ,
117- [ userId , sessionId , refreshSessions ]
132+ [ userId , sessionId ]
118133 ) ;
119134
120135 const clearHistory = useCallback ( ( ) => {
@@ -132,10 +147,35 @@ export default function ChatProvider({
132147 setSettings ( ( prev ) => ( { ...prev , ...s } ) ) ;
133148 } , [ ] ) ;
134149
150+ // ── 发送消息 ──
135151 const sendMessage = useCallback (
136152 async ( content : string ) => {
137153 if ( ! content . trim ( ) || ! userId ) return ;
138154
155+ // 1. 更新前端会话列表
156+ let currentSessions = getLocalSessions ( ) ;
157+ const exists = currentSessions . find ( ( s ) => s . session_id === sessionId ) ;
158+
159+ if ( ! exists ) {
160+ // 新会话,加入列表
161+ const newSession : SessionSummary = {
162+ session_id : sessionId ,
163+ title : content . slice ( 0 , 20 ) || "新对话" , // 截取前20字当标题
164+ preview : content . slice ( 0 , 50 ) ,
165+ message_count : 1 ,
166+ } ;
167+ currentSessions = [ newSession , ...currentSessions ] ;
168+ } else {
169+ // 已有会话,更新预览并移到最前
170+ currentSessions = currentSessions . filter ( ( s ) => s . session_id !== sessionId ) ;
171+ exists . preview = content . slice ( 0 , 50 ) ;
172+ exists . message_count = ( exists . message_count || 0 ) + 1 ;
173+ currentSessions = [ exists , ...currentSessions ] ;
174+ }
175+ saveLocalSessions ( currentSessions ) ;
176+ setSessions ( currentSessions ) ;
177+
178+ // 2. 发送 SSE 请求
139179 const userMsg : ChatMessage = {
140180 id : `u_${ msgCounter . current ++ } ` ,
141181 role : "user" ,
@@ -172,8 +212,6 @@ export default function ChatProvider({
172212 totalQueries : prev . totalQueries + 1 ,
173213 totalTokens : prev . totalTokens + ( sse . meta ?. tokens_used ?? 0 ) ,
174214 } ) ) ;
175- // 消息完成后刷新侧边栏
176- refreshSessions ( ) ;
177215 } else if ( sse . status === "error" && sse . error ) {
178216 const errorMsg : ChatMessage = {
179217 id : `e_${ msgCounter . current ++ } ` ,
0 commit comments