feat(1.0):调整未读列表
This commit is contained in:
parent
a6ac558680
commit
ba0630b2da
25
docs/docs.go
25
docs/docs.go
@ -924,6 +924,11 @@ const docTemplate = `{
|
||||
},
|
||||
"/admin/messages/latest": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"LoginVerifyToken": []
|
||||
}
|
||||
],
|
||||
"description": "管理端根据appid获取最新消息记录,包含已读未读状态,访问时自动标记为已读",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
@ -1788,26 +1793,6 @@ const docTemplate = `{
|
||||
"app.latestMessageData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "消息内容",
|
||||
"type": "string"
|
||||
},
|
||||
"is_read": {
|
||||
"description": "是否已读(0:未读 1:已读)",
|
||||
"type": "integer"
|
||||
},
|
||||
"message_id": {
|
||||
"description": "消息ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"msg_type": {
|
||||
"description": "消息类型(1:文本 2:图片)",
|
||||
"type": "integer"
|
||||
},
|
||||
"receiver_id": {
|
||||
"description": "接收人ID",
|
||||
"type": "string"
|
||||
},
|
||||
"send_time": {
|
||||
"description": "发送时间",
|
||||
"type": "string"
|
||||
|
||||
@ -916,6 +916,11 @@
|
||||
},
|
||||
"/admin/messages/latest": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"LoginVerifyToken": []
|
||||
}
|
||||
],
|
||||
"description": "管理端根据appid获取最新消息记录,包含已读未读状态,访问时自动标记为已读",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
@ -1780,26 +1785,6 @@
|
||||
"app.latestMessageData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"description": "消息内容",
|
||||
"type": "string"
|
||||
},
|
||||
"is_read": {
|
||||
"description": "是否已读(0:未读 1:已读)",
|
||||
"type": "integer"
|
||||
},
|
||||
"message_id": {
|
||||
"description": "消息ID",
|
||||
"type": "integer"
|
||||
},
|
||||
"msg_type": {
|
||||
"description": "消息类型(1:文本 2:图片)",
|
||||
"type": "integer"
|
||||
},
|
||||
"receiver_id": {
|
||||
"description": "接收人ID",
|
||||
"type": "string"
|
||||
},
|
||||
"send_time": {
|
||||
"description": "发送时间",
|
||||
"type": "string"
|
||||
|
||||
@ -275,21 +275,6 @@ definitions:
|
||||
type: object
|
||||
app.latestMessageData:
|
||||
properties:
|
||||
content:
|
||||
description: 消息内容
|
||||
type: string
|
||||
is_read:
|
||||
description: 是否已读(0:未读 1:已读)
|
||||
type: integer
|
||||
message_id:
|
||||
description: 消息ID
|
||||
type: integer
|
||||
msg_type:
|
||||
description: 消息类型(1:文本 2:图片)
|
||||
type: integer
|
||||
receiver_id:
|
||||
description: 接收人ID
|
||||
type: string
|
||||
send_time:
|
||||
description: 发送时间
|
||||
type: string
|
||||
@ -1414,6 +1399,8 @@ paths:
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/code.Failure'
|
||||
security:
|
||||
- LoginVerifyToken: []
|
||||
summary: 根据appid获取最新消息记录
|
||||
tags:
|
||||
- 管理端.小程序
|
||||
|
||||
@ -10,6 +10,7 @@ type handler struct {
|
||||
logger logger.CustomLogger
|
||||
writeDB *dao.Query
|
||||
readDB *dao.Query
|
||||
db mysql.Repo
|
||||
}
|
||||
|
||||
func New(logger logger.CustomLogger, db mysql.Repo) *handler {
|
||||
@ -17,5 +18,6 @@ func New(logger logger.CustomLogger, db mysql.Repo) *handler {
|
||||
logger: logger,
|
||||
writeDB: dao.Use(db.GetDbW()),
|
||||
readDB: dao.Use(db.GetDbR()),
|
||||
db: db,
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ package app
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"mini-chat/internal/code"
|
||||
"mini-chat/internal/pkg/core"
|
||||
@ -17,15 +18,10 @@ type latestMessageByAppIdRequest struct {
|
||||
}
|
||||
|
||||
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"` // 未读数量
|
||||
}
|
||||
|
||||
@ -48,6 +44,7 @@ type latestMessageByAppIdResponse struct {
|
||||
// @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)
|
||||
@ -78,37 +75,54 @@ func (h *handler) LatestMessageByAppId() core.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
query := h.readDB.AppMessageLog.WithContext(ctx.RequestContext()).
|
||||
Where(h.readDB.AppMessageLog.AppID.Eq(req.AppID))
|
||||
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"`
|
||||
}
|
||||
|
||||
// 查询总数
|
||||
total, err := query.Count()
|
||||
if err != nil {
|
||||
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), err.Error())),
|
||||
fmt.Sprintf("%s:%s", code.Text(code.ListMessageError), countErr.Error())),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 分页查询指定小程序的最新消息
|
||||
resultData, err := query.
|
||||
Order(h.readDB.AppMessageLog.SendTime.Asc()).
|
||||
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()
|
||||
if err != nil {
|
||||
Find(&results).
|
||||
Error
|
||||
if resultErr != nil {
|
||||
ctx.AbortWithError(core.Error(
|
||||
http.StatusBadRequest,
|
||||
code.ListMessageError,
|
||||
fmt.Sprintf("%s:%s", code.Text(code.ListMessageError), err.Error())),
|
||||
fmt.Sprintf("%s:%s", code.Text(code.ListMessageError), resultErr.Error())),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 自动标记该appid下的所有消息为已读(管理端访问时)
|
||||
_, err = h.writeDB.AppMessageLog.WithContext(ctx.RequestContext()).
|
||||
_, 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)
|
||||
@ -120,27 +134,15 @@ func (h *handler) LatestMessageByAppId() core.HandlerFunc {
|
||||
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 = make([]latestMessageData, len(results))
|
||||
|
||||
for k, v := range results {
|
||||
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,
|
||||
SenderAvatar: v.AvatarURL,
|
||||
UnreadCount: v.UnreadCount,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,13 +8,13 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/DanPlayer/randomname"
|
||||
|
||||
"mini-chat/internal/code"
|
||||
"mini-chat/internal/pkg/core"
|
||||
"mini-chat/internal/pkg/httpclient"
|
||||
"mini-chat/internal/pkg/validation"
|
||||
"mini-chat/internal/repository/mysql/model"
|
||||
|
||||
"github.com/DanPlayer/randomname"
|
||||
)
|
||||
|
||||
type miniprogramLoginRequest struct {
|
||||
|
||||
@ -18,4 +18,4 @@ func New(logger logger.CustomLogger, db mysql.Repo) *handler {
|
||||
writeDB: dao.Use(db.GetDbW()),
|
||||
readDB: dao.Use(db.GetDbR()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ func VerifySignature(rawData, signature, sessionKey string) bool {
|
||||
h := sha1.New()
|
||||
h.Write([]byte(rawData + sessionKey))
|
||||
expectedSignature := hex.EncodeToString(h.Sum(nil))
|
||||
|
||||
|
||||
return expectedSignature == signature
|
||||
}
|
||||
|
||||
@ -126,7 +126,7 @@ func pkcs7Unpad(data []byte) ([]byte, error) {
|
||||
|
||||
// 获取填充长度
|
||||
padding := int(data[len(data)-1])
|
||||
|
||||
|
||||
// 验证填充长度
|
||||
if padding > len(data) || padding == 0 {
|
||||
return nil, fmt.Errorf("无效的填充长度: %d", padding)
|
||||
@ -140,4 +140,4 @@ func pkcs7Unpad(data []byte) ([]byte, error) {
|
||||
}
|
||||
|
||||
return data[:len(data)-padding], nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,11 +4,12 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mini-chat/internal/pkg/core"
|
||||
"mini-chat/internal/pkg/httpclient"
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"mini-chat/internal/pkg/core"
|
||||
"mini-chat/internal/pkg/httpclient"
|
||||
)
|
||||
|
||||
// AccessTokenRequest 获取 access_token 请求参数
|
||||
|
||||
@ -63,15 +63,15 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo, cron cron.Server) (co
|
||||
|
||||
appNonAuthApiRouter := mux.Group("/app")
|
||||
{
|
||||
appNonAuthApiRouter.POST("/user/create", appHandler.CreateAppUser()) // 新增小程序用户
|
||||
appNonAuthApiRouter.GET("/messages", messageHandler.AppMessagePageList()) // 消息列表
|
||||
appNonAuthApiRouter.POST("/user/create", appHandler.CreateAppUser()) // 新增小程序用户
|
||||
appNonAuthApiRouter.GET("/messages", messageHandler.AppMessagePageList()) // 消息列表
|
||||
appNonAuthApiRouter.POST("/send_message", messageHandler.UserSendMessage()) // 发送消息
|
||||
}
|
||||
|
||||
// 微信 API 路由组
|
||||
wechatApiRouter := mux.Group("/api/wechat")
|
||||
{
|
||||
wechatApiRouter.POST("/qrcode", wechatHandler.GenerateQRCode()) // 生成微信小程序二维码(返回 Base64)
|
||||
wechatApiRouter.POST("/qrcode", wechatHandler.GenerateQRCode()) // 生成微信小程序二维码(返回 Base64)
|
||||
wechatApiRouter.POST("/miniprogram/login", wechatHandler.MiniprogramLogin()) // 小程序登录
|
||||
}
|
||||
|
||||
@ -97,9 +97,9 @@ func NewHTTPMux(logger logger.CustomLogger, db mysql.Repo, cron cron.Server) (co
|
||||
adminAuthApiRouter.PUT("/app/keyword/material/:id", keywordHandler.ModifyKeywordMaterial()) // 修改意图关键字素材
|
||||
adminAuthApiRouter.GET("/app/keyword/materials", keywordHandler.KeywordMaterialPageList()) // 获取意图关键字素材列表
|
||||
|
||||
adminAuthApiRouter.GET("/app/users", appHandler.UserPageList()) // 获取小程序用户列表
|
||||
adminAuthApiRouter.POST("/send_message", appHandler.AdminSendMessage()) // 发送消息
|
||||
adminAuthApiRouter.GET("/messages", appHandler.AppMessagePageList()) // 获取小程序用户消息列表
|
||||
adminAuthApiRouter.GET("/app/users", appHandler.UserPageList()) // 获取小程序用户列表
|
||||
adminAuthApiRouter.POST("/send_message", appHandler.AdminSendMessage()) // 发送消息
|
||||
adminAuthApiRouter.GET("/messages", appHandler.AppMessagePageList()) // 获取小程序用户消息列表
|
||||
adminAuthApiRouter.GET("/messages/latest", appHandler.LatestMessageByAppId()) // 根据appid获取最新消息记录
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user