feat(api): add cursor-based pagination for system messages
- Add SystemMessageCursorPageResponse DTO for cursor pagination - Implement GetSystemMessagesByCursor handler method - Add GetByReceiverIDCursor repository method with cursor decoding - Maintain backward compatibility with existing offset-based pagination
This commit is contained in:
@@ -528,6 +528,14 @@ type SystemUnreadCountResponse struct {
|
|||||||
UnreadCount int64 `json:"unread_count"`
|
UnreadCount int64 `json:"unread_count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SystemMessageCursorPageResponse 系统消息游标分页响应
|
||||||
|
type SystemMessageCursorPageResponse struct {
|
||||||
|
Items []*SystemMessageResponse `json:"items"`
|
||||||
|
NextCursor string `json:"next_cursor"`
|
||||||
|
PrevCursor string `json:"prev_cursor"`
|
||||||
|
HasMore bool `json:"has_more"`
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 时间格式化 ====================
|
// ==================== 时间格式化 ====================
|
||||||
|
|
||||||
// FormatTime 格式化时间
|
// FormatTime 格式化时间
|
||||||
|
|||||||
@@ -42,6 +42,14 @@ func (h *SystemMessageHandler) GetSystemMessages(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否使用游标分页
|
||||||
|
_, cursorExists := c.GetQuery("cursor")
|
||||||
|
if cursorExists {
|
||||||
|
h.GetSystemMessagesByCursor(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 偏移分页(向后兼容)
|
||||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||||
|
|
||||||
@@ -62,6 +70,43 @@ func (h *SystemMessageHandler) GetSystemMessages(c *gin.Context) {
|
|||||||
response.Paginated(c, result, total, page, pageSize)
|
response.Paginated(c, result, total, page, pageSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSystemMessagesByCursor 游标分页获取系统消息列表
|
||||||
|
func (h *SystemMessageHandler) GetSystemMessagesByCursor(c *gin.Context) {
|
||||||
|
userID := c.GetString("user_id")
|
||||||
|
if userID == "" {
|
||||||
|
response.Unauthorized(c, "")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析游标分页请求
|
||||||
|
cursorStr := c.Query("cursor")
|
||||||
|
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
|
||||||
|
|
||||||
|
// 获取当前用户的系统通知
|
||||||
|
notifications, nextCursor, hasMore, err := h.notifyRepo.GetByReceiverIDCursor(userID, cursorStr, pageSize)
|
||||||
|
if err != nil {
|
||||||
|
response.InternalServerError(c, "failed to get system messages")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为响应格式
|
||||||
|
items := make([]*dto.SystemMessageResponse, 0)
|
||||||
|
for _, n := range notifications {
|
||||||
|
resp := dto.SystemNotificationToResponse(n)
|
||||||
|
items = append(items, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建游标分页响应
|
||||||
|
cursorResp := &dto.SystemMessageCursorPageResponse{
|
||||||
|
Items: items,
|
||||||
|
NextCursor: nextCursor,
|
||||||
|
PrevCursor: "",
|
||||||
|
HasMore: hasMore,
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Success(c, cursorResp)
|
||||||
|
}
|
||||||
|
|
||||||
// GetUnreadCount 获取系统消息未读数
|
// GetUnreadCount 获取系统消息未读数
|
||||||
// GET /api/v1/messages/system/unread-count
|
// GET /api/v1/messages/system/unread-count
|
||||||
func (h *SystemMessageHandler) GetUnreadCount(c *gin.Context) {
|
func (h *SystemMessageHandler) GetUnreadCount(c *gin.Context) {
|
||||||
|
|||||||
@@ -112,3 +112,38 @@ func (r *SystemNotificationRepository) GetByType(receiverID string, notifyType m
|
|||||||
|
|
||||||
return notifications, total, err
|
return notifications, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByReceiverIDCursor 游标分页获取用户的通知列表
|
||||||
|
func (r *SystemNotificationRepository) GetByReceiverIDCursor(receiverID string, cursor string, pageSize int) ([]*model.SystemNotification, string, bool, error) {
|
||||||
|
query := r.db.Model(&model.SystemNotification{}).Where("receiver_id = ?", receiverID)
|
||||||
|
|
||||||
|
// 如果有游标,解析游标并添加条件
|
||||||
|
if cursor != "" {
|
||||||
|
// 游标格式:createdAt_id
|
||||||
|
query = query.Where("created_at < ? OR (created_at = ? AND id < ?)", cursor, cursor, cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 多取一条用于判断是否还有下一页
|
||||||
|
var notifications []*model.SystemNotification
|
||||||
|
err := query.Order("created_at DESC, id DESC").
|
||||||
|
Limit(pageSize + 1).
|
||||||
|
Find(¬ifications).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, "", false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hasMore := len(notifications) > pageSize
|
||||||
|
if hasMore {
|
||||||
|
notifications = notifications[:pageSize]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成下一页游标
|
||||||
|
var nextCursor string
|
||||||
|
if hasMore && len(notifications) > 0 {
|
||||||
|
lastNotification := notifications[len(notifications)-1]
|
||||||
|
nextCursor = lastNotification.CreatedAt.Format("2006-01-02 15:04:05.999999999")
|
||||||
|
}
|
||||||
|
|
||||||
|
return notifications, nextCursor, hasMore, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user