From 1eb5133492c3b7cb2d426ce68c66fbd400310d53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=AC=E6=98=8E?= <83812544+Ed1s0nZ@users.noreply.github.com> Date: Tue, 31 Mar 2026 22:13:47 +0800 Subject: [PATCH] Add files via upload --- internal/app/app.go | 1 + internal/database/conversation.go | 47 +++++++++++++++++++++++++++ internal/handler/conversation.go | 54 ++++++++++++++++++++++++++++++- 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/internal/app/app.go b/internal/app/app.go index fe0cf595..1e967b2e 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -661,6 +661,7 @@ func setupRoutes( protected.POST("/conversations", conversationHandler.CreateConversation) protected.GET("/conversations", conversationHandler.ListConversations) protected.GET("/conversations/:id", conversationHandler.GetConversation) + protected.GET("/messages/:id/process-details", conversationHandler.GetMessageProcessDetails) protected.PUT("/conversations/:id", conversationHandler.UpdateConversation) protected.DELETE("/conversations/:id", conversationHandler.DeleteConversation) protected.PUT("/conversations/:id/pinned", groupHandler.UpdateConversationPinned) diff --git a/internal/database/conversation.go b/internal/database/conversation.go index 61c9fc79..cf96f445 100644 --- a/internal/database/conversation.go +++ b/internal/database/conversation.go @@ -256,6 +256,53 @@ func (db *DB) GetConversation(id string) (*Conversation, error) { return &conv, nil } +// GetConversationLite 获取对话(轻量版):包含 messages,但不加载 process_details。 +// 用于历史会话快速切换,避免一次性把大体量过程详情灌到前端导致卡顿。 +func (db *DB) GetConversationLite(id string) (*Conversation, error) { + var conv Conversation + var createdAt, updatedAt string + var pinned int + + err := db.QueryRow( + "SELECT id, title, pinned, created_at, updated_at FROM conversations WHERE id = ?", + id, + ).Scan(&conv.ID, &conv.Title, &pinned, &createdAt, &updatedAt) + if err != nil { + if err == sql.ErrNoRows { + return nil, fmt.Errorf("对话不存在") + } + return nil, fmt.Errorf("查询对话失败: %w", err) + } + + // 尝试多种时间格式解析 + var err1, err2 error + conv.CreatedAt, err1 = time.Parse("2006-01-02 15:04:05.999999999-07:00", createdAt) + if err1 != nil { + conv.CreatedAt, err1 = time.Parse("2006-01-02 15:04:05", createdAt) + } + if err1 != nil { + conv.CreatedAt, _ = time.Parse(time.RFC3339, createdAt) + } + + conv.UpdatedAt, err2 = time.Parse("2006-01-02 15:04:05.999999999-07:00", updatedAt) + if err2 != nil { + conv.UpdatedAt, err2 = time.Parse("2006-01-02 15:04:05", updatedAt) + } + if err2 != nil { + conv.UpdatedAt, _ = time.Parse(time.RFC3339, updatedAt) + } + + conv.Pinned = pinned != 0 + + // 加载消息(不加载 process_details) + messages, err := db.GetMessages(id) + if err != nil { + return nil, fmt.Errorf("加载消息失败: %w", err) + } + conv.Messages = messages + return &conv, nil +} + // ListConversations 列出所有对话 func (db *DB) ListConversations(limit, offset int, search string) ([]*Conversation, error) { var rows *sql.Rows diff --git a/internal/handler/conversation.go b/internal/handler/conversation.go index 4aa572e6..f0c074f0 100644 --- a/internal/handler/conversation.go +++ b/internal/handler/conversation.go @@ -1,6 +1,7 @@ package handler import ( + "encoding/json" "net/http" "strconv" @@ -78,7 +79,20 @@ func (h *ConversationHandler) ListConversations(c *gin.Context) { func (h *ConversationHandler) GetConversation(c *gin.Context) { id := c.Param("id") - conv, err := h.db.GetConversation(id) + // 默认轻量加载,只有用户需要展开详情时再按需拉取 + // include_process_details=1/true 时返回全量 processDetails(兼容旧行为) + includeStr := c.DefaultQuery("include_process_details", "0") + include := includeStr == "1" || includeStr == "true" || includeStr == "yes" + + var ( + conv *database.Conversation + err error + ) + if include { + conv, err = h.db.GetConversation(id) + } else { + conv, err = h.db.GetConversationLite(id) + } if err != nil { h.logger.Error("获取对话失败", zap.Error(err)) c.JSON(http.StatusNotFound, gin.H{"error": "对话不存在"}) @@ -88,6 +102,44 @@ func (h *ConversationHandler) GetConversation(c *gin.Context) { c.JSON(http.StatusOK, conv) } +// GetMessageProcessDetails 获取指定消息的过程详情(按需加载) +func (h *ConversationHandler) GetMessageProcessDetails(c *gin.Context) { + messageID := c.Param("id") + if messageID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "message id required"}) + return + } + + details, err := h.db.GetProcessDetails(messageID) + if err != nil { + h.logger.Error("获取过程详情失败", zap.Error(err)) + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + // 转换为前端期望的 JSON 结构(与 GetConversation 中 processDetails 结构一致) + out := make([]map[string]interface{}, 0, len(details)) + for _, d := range details { + var data interface{} + if d.Data != "" { + if err := json.Unmarshal([]byte(d.Data), &data); err != nil { + h.logger.Warn("解析过程详情数据失败", zap.Error(err)) + } + } + out = append(out, map[string]interface{}{ + "id": d.ID, + "messageId": d.MessageID, + "conversationId": d.ConversationID, + "eventType": d.EventType, + "message": d.Message, + "data": data, + "createdAt": d.CreatedAt, + }) + } + + c.JSON(http.StatusOK, gin.H{"processDetails": out}) +} + // UpdateConversationRequest 更新对话请求 type UpdateConversationRequest struct { Title string `json:"title"`