package app import ( "fmt" "net/http" "mini-chat/internal/code" "mini-chat/internal/pkg/core" "mini-chat/internal/pkg/timeutil" "mini-chat/internal/pkg/validation" ) type latestMessageByAppIdRequest struct { AppID string `form:"app_id" binding:"required"` // 小程序ID Page int `form:"page"` // 当前页码,默认1 PageSize int `form:"page_size"` // 每页返回的数据量,默认20 } type latestMessageData struct { MessageID int32 `json:"message_id"` // 消息ID SendTime string `json:"send_time"` // 发送时间 SenderID string `json:"sender_id"` // 发送人ID SenderName string `json:"sender_name"` // 发送人昵称 SenderAvatar string `json:"sender_avatar"` // 发送人头像 ReceiverID string `json:"receiver_id"` // 接收人ID Content string `json:"content"` // 消息内容 MsgType int32 `json:"msg_type"` // 消息类型(1:文本 2:图片) IsRead int32 `json:"is_read"` // 是否已读(0:未读 1:已读) UnreadCount int64 `json:"unread_count"` // 未读数量 } type latestMessageByAppIdResponse struct { Page int `json:"page"` // 当前页码 PageSize int `json:"page_size"` // 每页返回的数据量 Total int64 `json:"total"` // 符合查询条件的总记录数 List []latestMessageData `json:"list"` } // LatestMessageByAppId 根据appid获取最新消息记录 // @Summary 根据appid获取最新消息记录 // @Description 管理端根据appid获取最新消息记录,包含已读未读状态,访问时自动标记为已读 // @Tags 管理端.小程序 // @Accept json // @Produce json // @Param app_id query string true "小程序ID" // @Param page query int true "当前页码" default(1) // @Param page_size query int true "每页返回的数据量,最多 100 条" default(20) // @Success 200 {object} latestMessageByAppIdResponse // @Failure 400 {object} code.Failure // @Router /admin/messages/latest [get] func (h *handler) LatestMessageByAppId() core.HandlerFunc { return func(ctx core.Context) { req := new(latestMessageByAppIdRequest) res := new(latestMessageByAppIdResponse) if err := ctx.ShouldBindForm(req); err != nil { ctx.AbortWithError(core.Error( http.StatusBadRequest, code.ParamBindError, validation.Error(err)), ) return } if req.Page == 0 { req.Page = 1 } if req.PageSize == 0 { req.PageSize = 20 } if req.PageSize > 100 { ctx.AbortWithError(core.Error( http.StatusBadRequest, code.ListMessageError, fmt.Sprintf("%s: 一次最多只能查询 100 条", code.Text(code.ListMessageError)), )) return } query := h.readDB.AppMessageLog.WithContext(ctx.RequestContext()). Where(h.readDB.AppMessageLog.AppID.Eq(req.AppID)) // 查询总数 total, err := query.Count() if err != nil { ctx.AbortWithError(core.Error( http.StatusBadRequest, code.ListMessageError, fmt.Sprintf("%s:%s", code.Text(code.ListMessageError), err.Error())), ) return } // 分页查询指定小程序的最新消息 resultData, err := query. Order(h.readDB.AppMessageLog.SendTime.Asc()). Offset((req.Page - 1) * req.PageSize). Limit(req.PageSize). Find() if err != nil { ctx.AbortWithError(core.Error( http.StatusBadRequest, code.ListMessageError, fmt.Sprintf("%s:%s", code.Text(code.ListMessageError), err.Error())), ) return } // 自动标记该appid下的所有消息为已读(管理端访问时) _, err = h.writeDB.AppMessageLog.WithContext(ctx.RequestContext()). Where(h.writeDB.AppMessageLog.AppID.Eq(req.AppID)). Where(h.writeDB.AppMessageLog.IsRead.Eq(0)). Update(h.writeDB.AppMessageLog.IsRead, 1) if err != nil { // 记录错误但不影响查询结果 // TODO: 可以添加日志记录 } res.Page = req.Page res.PageSize = req.PageSize res.Total = total res.List = make([]latestMessageData, len(resultData)) for k, v := range resultData { // 计算该用户在该应用下的未读消息总数 unreadCount, _ := h.readDB.AppMessageLog.WithContext(ctx.RequestContext()). Where(h.readDB.AppMessageLog.AppID.Eq(req.AppID)). Where(h.readDB.AppMessageLog.ReceiverID.Eq(v.ReceiverID)). Where(h.readDB.AppMessageLog.IsRead.Eq(0)). Count() res.List[k] = latestMessageData{ MessageID: v.ID, SendTime: timeutil.FriendlyTime(v.SendTime), SenderID: v.SenderID, SenderName: v.SenderName, SenderAvatar: "", // TODO: 需要从用户表获取头像信息 ReceiverID: v.ReceiverID, Content: v.Content, MsgType: v.MsgType, IsRead: v.IsRead, // 直接使用消息表中的 is_read 字段 UnreadCount: unreadCount, } } ctx.Payload(res) } }