package app import ( "fmt" "net/http" "time" "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 { SendTime string `json:"send_time"` // 发送时间 SenderID string `json:"sender_id"` // 发送人ID SenderName string `json:"sender_name"` // 发送人昵称 SenderAvatar string `json:"sender_avatar"` // 发送人头像 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] // @Security LoginVerifyToken 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 } type unreadMessageResult struct { SenderID string `json:"sender_id"` SenderName string `json:"sender_name"` SendTime time.Time `json:"send_time"` AvatarURL string `json:"avatar_url"` UnreadCount int64 `json:"unread_count"` } var results []unreadMessageResult var total int64 countErr := h.db.GetDbR().Table("app_message_log m"). Select("m.send_time, m.sender_id, m.sender_name, u.user_avatar as avatar_url, COUNT(*) as unread_count"). Joins("LEFT JOIN app_user u ON m.sender_id = u.user_id"). Where("m.app_id = ? AND m.sender_id != ? AND m.is_read = 1", req.AppID, "888888"). Group("m.sender_id"). Count(&total). Error if countErr != nil { ctx.AbortWithError(core.Error( http.StatusBadRequest, code.ListMessageError, fmt.Sprintf("%s:%s", code.Text(code.ListMessageError), countErr.Error())), ) return } resultErr := h.db.GetDbR().Table("app_message_log m"). Select("max(m.send_time) as send_time, m.sender_id, max(m.sender_name) as sender_name, max(u.user_avatar) as avatar_url, COUNT(*) as unread_count"). Joins("LEFT JOIN app_user u ON m.sender_id = u.user_id"). Where("m.app_id = ? AND m.sender_id != ? AND m.is_read = 1", req.AppID, "888888"). Group("m.sender_id"). Order("unread_count DESC"). Offset((req.Page - 1) * req.PageSize). Limit(req.PageSize). Find(&results). Error if resultErr != nil { ctx.AbortWithError(core.Error( http.StatusBadRequest, code.ListMessageError, fmt.Sprintf("%s:%s", code.Text(code.ListMessageError), resultErr.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(results)) for k, v := range results { res.List[k] = latestMessageData{ SendTime: timeutil.FriendlyTime(v.SendTime), SenderID: v.SenderID, SenderName: v.SenderName, SenderAvatar: v.AvatarURL, UnreadCount: v.UnreadCount, } } ctx.Payload(res) } }