mirror of
https://github.com/RuoJi6/ARTEX.git
synced 2026-10-28 17:13:50 +08:00
fix(chat): 修复会话刷新丢失最终答案(#3) + 反向分页/详情懒加载/会话URL持久化
- 后端消息列表默认按 id 升序取最旧一页,长会话刷新后最终答案落在页外而丢失
(发新消息推进游标才重现)。改为:
- db.ConvActivityPage:反向分页,取最新/更早一页 + hasMore
- 消息接口按 since(增量)/before(更早页)/最新页 三种模式返回
- 前端聊天页:
- 打开会话仅加载最新一页,滚动到顶部再反向加载更早(保持滚动位置不跳)
- Transcript 的 UserRow/AnswerBlock 改为进入视口才拉 detail,避免打开会话即对
整页每步发详情请求
- 选中会话 id 持久化到 URL(?c=<id>),刷新回到当前会话
- 修复新建会话后被"清理失效 id"effect 误清导致停留在新建页、输入框内容与灰色
发送按钮卡死:移除该 effect + onStarted 乐观插入
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
1 parent
349b0d104d
commit
5000aadd8f
5 files changed
+207
-17
No files matched your search
+29
-6
@@ -171,16 +171,39 @@ func (s *Server) pgConversationMessages(w http.ResponseWriter, r *http.Request)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
since, _ := strconv.ParseInt(r.URL.Query().Get("since"), 10, 64)
|
||||
items, cursor, err := pg.ConvActivityList(c.ID, since, 0)
|
||||
q := r.URL.Query()
|
||||
limit := atoiDefault(q.Get("limit"), 200)
|
||||
s.chatMu.Lock()
|
||||
running := s.chatBusy[s.convBusyKey(c.ID)]
|
||||
s.chatMu.Unlock()
|
||||
|
||||
// Incremental tail: ?since=N returns steps after id N (ASC) — used by the live
|
||||
// poll and the post-send fetch. A generous cap so a burst is never dropped.
|
||||
if sv := q.Get("since"); sv != "" {
|
||||
since, _ := strconv.ParseInt(sv, 10, 64)
|
||||
items, cursor, err := pg.ConvActivityList(c.ID, since, max(limit, 1000))
|
||||
if err != nil {
|
||||
writeErr(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"items": activityDTOs(items), "cursor": cursor, "running": running, "hasMore": false})
|
||||
return
|
||||
}
|
||||
|
||||
// History page (reverse pagination): no ?since → the latest page; ?before=N →
|
||||
// the page of older steps ending before id N. hasMore lets the client stop
|
||||
// loading earlier history once the top of the thread is reached.
|
||||
before, _ := strconv.ParseInt(q.Get("before"), 10, 64)
|
||||
items, hasMore, err := pg.ConvActivityPage(c.ID, before, limit)
|
||||
if err != nil {
|
||||
writeErr(w, 500, err.Error())
|
||||
return
|
||||
}
|
||||
s.chatMu.Lock()
|
||||
running := s.chatBusy[s.convBusyKey(c.ID)]
|
||||
s.chatMu.Unlock()
|
||||
writeJSON(w, 200, map[string]any{"items": activityDTOs(items), "cursor": cursor, "running": running})
|
||||
cursor := before
|
||||
if n := len(items); n > 0 {
|
||||
cursor = items[n-1].ID
|
||||
}
|
||||
writeJSON(w, 200, map[string]any{"items": activityDTOs(items), "cursor": cursor, "running": running, "hasMore": hasMore})
|
||||
}
|
||||
|
||||
// pgConversationMsgDetail lazily returns one step's full detail blob.
|
||||
|
||||
Reference in new issue
Block a user