190 lines
6.1 KiB
Go
190 lines
6.1 KiB
Go
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"
|
||
"mini-chat/internal/repository/mysql/model"
|
||
)
|
||
|
||
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.Desc()).
|
||
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下的所有消息为已读(管理端访问时)
|
||
// 这里我们为每个消息的接收者创建或更新已读状态
|
||
for _, message := range resultData {
|
||
// 检查是否已存在已读状态记录
|
||
existingStatus, _ := h.readDB.AppMessageReadStatus.WithContext(ctx.RequestContext()).
|
||
Where(h.readDB.AppMessageReadStatus.AppID.Eq(req.AppID)).
|
||
Where(h.readDB.AppMessageReadStatus.MessageID.Eq(message.ID)).
|
||
Where(h.readDB.AppMessageReadStatus.UserID.Eq(message.ReceiverID)).
|
||
First()
|
||
|
||
if existingStatus == nil {
|
||
// 如果不存在,创建新的已读状态记录
|
||
now := time.Now()
|
||
_ = h.writeDB.AppMessageReadStatus.WithContext(ctx.RequestContext()).Create(&model.AppMessageReadStatus{
|
||
AppID: req.AppID,
|
||
MessageID: message.ID,
|
||
UserID: message.ReceiverID,
|
||
IsRead: 1,
|
||
ReadTime: &now,
|
||
CreatedAt: now,
|
||
UpdatedAt: now,
|
||
})
|
||
} else if existingStatus.IsRead == 0 {
|
||
// 如果存在但未读,更新为已读
|
||
now := time.Now()
|
||
_, _ = h.writeDB.AppMessageReadStatus.WithContext(ctx.RequestContext()).
|
||
Where(h.writeDB.AppMessageReadStatus.ID.Eq(existingStatus.ID)).
|
||
Updates(map[string]interface{}{
|
||
"is_read": 1,
|
||
"read_time": &now,
|
||
"updated_at": now,
|
||
})
|
||
}
|
||
}
|
||
|
||
res.Page = req.Page
|
||
res.PageSize = req.PageSize
|
||
res.Total = total
|
||
res.List = make([]latestMessageData, len(resultData))
|
||
|
||
for k, v := range resultData {
|
||
// 查询该消息的已读状态
|
||
readStatus, _ := h.readDB.AppMessageReadStatus.WithContext(ctx.RequestContext()).
|
||
Where(h.readDB.AppMessageReadStatus.AppID.Eq(req.AppID)).
|
||
Where(h.readDB.AppMessageReadStatus.MessageID.Eq(v.ID)).
|
||
Where(h.readDB.AppMessageReadStatus.UserID.Eq(v.ReceiverID)).
|
||
First()
|
||
|
||
// 判断是否已读
|
||
isRead := int32(0)
|
||
if readStatus != nil && readStatus.IsRead == 1 {
|
||
isRead = 1
|
||
}
|
||
|
||
// 计算该用户在该应用下的未读消息总数
|
||
unreadCount, _ := h.readDB.AppMessageReadStatus.WithContext(ctx.RequestContext()).
|
||
Where(h.readDB.AppMessageReadStatus.AppID.Eq(req.AppID)).
|
||
Where(h.readDB.AppMessageReadStatus.UserID.Eq(v.ReceiverID)).
|
||
Where(h.readDB.AppMessageReadStatus.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: isRead,
|
||
UnreadCount: unreadCount,
|
||
}
|
||
}
|
||
|
||
ctx.Payload(res)
|
||
}
|
||
}
|