Procházet zdrojové kódy

保存消息rpc、api提交

renjiaojiao před 1 rokem
rodič
revize
66f85f12d3

+ 60 - 0
api/internal/logic/bitmapsavemsglogic.go

@@ -0,0 +1,60 @@
+package logic
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/api/internal/svc"
+	"app.yhyue.com/moapp/MessageCenter/api/internal/types"
+	"app.yhyue.com/moapp/MessageCenter/rpc/messageclient"
+	"app.yhyue.com/moapp/MessageCenter/util"
+	"context"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type BitmapSaveMsgLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewBitmapSaveMsgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BitmapSaveMsgLogic {
+	return &BitmapSaveMsgLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx,
+	}
+}
+
+func (l *BitmapSaveMsgLogic) BitmapSaveMsg(req *types.BitmapSaveMsgReq) (resp *types.MultipleSaveMsgResp, err error) {
+	var (
+		msg  = "发送成功"
+		code = 0
+	)
+	lsi := l.svcCtx.MessageCenter
+	msgInfo := req.MsgInfo
+	_, err = lsi.BitmapSaveMsg(l.ctx, &messageclient.BitmapSaveMsgReq{
+		Appid:       util.ObjToString(msgInfo["appid"]),
+		Title:       util.ObjToString(msgInfo["title"]),
+		Content:     util.ObjToString(msgInfo["content"]),
+		MsgType:     int64(util.IntAll(msgInfo["msgType"])),
+		Link:        util.ObjToString(msgInfo["link"]),
+		UserIds:     req.UserIds,
+		MsgLogId:    int64(util.IntAll(msgInfo["msgLogId"])),
+		PositionIds: req.PositionIds,
+		Row4:        util.ObjToString(msgInfo["row4"]),
+		ProductName: util.ObjToString(msgInfo["productName"]),
+		OrderId:     util.ObjToString(msgInfo["orderId"]),
+		OrderMoney:  util.ObjToString(msgInfo["orderMoney"]),
+		AppPushUrl:  util.ObjToString(msgInfo["appPushUrl"]),
+		WxPushUrl:   util.ObjToString(msgInfo["wxPushUrl"]),
+		IosPushUrl:  util.ObjToString(msgInfo["iosPushUrl"]),
+		SendUserId:  util.ObjToString(msgInfo["sendUserId"]),
+	})
+	if err != nil {
+		msg = err.Error()
+		code = 0
+	}
+	return &types.MultipleSaveMsgResp{
+		Code:    int64(code),
+		Message: msg,
+	}, nil
+}

+ 61 - 0
api/internal/logic/newusersavemsglogic.go

@@ -0,0 +1,61 @@
+package logic
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/api/internal/svc"
+	"app.yhyue.com/moapp/MessageCenter/api/internal/types"
+	"app.yhyue.com/moapp/MessageCenter/rpc/messageclient"
+	"app.yhyue.com/moapp/MessageCenter/util"
+	"context"
+	"encoding/json"
+	"fmt"
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type NewUserSaveMsgLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewNewUserSaveMsgLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NewUserSaveMsgLogic {
+	return &NewUserSaveMsgLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx,
+	}
+}
+
+func (l *NewUserSaveMsgLogic) NewUserSaveMsg(req *types.NewUserSaveMsgReq) (resp *types.NewUserSaveMsgResp, err error) {
+	lsi := l.svcCtx.MessageCenter
+	msgInfo := req.MsgInfo
+	msgLogId, err := (msgInfo["msgLogId"]).(json.Number).Int64()
+	msgType, err := (msgInfo["msgType"]).(json.Number).Int64()
+	fmt.Println("msgInfo:", msgInfo)
+	_, err = lsi.NewUserMsg(l.ctx, &messageclient.NewUserInsertMsgReq{
+		Appid:       util.ObjToString(msgInfo["appid"]),
+		Title:       util.ObjToString(msgInfo["title"]),
+		Content:     util.ObjToString(msgInfo["content"]),
+		MsgType:     msgType,
+		Link:        util.ObjToString(msgInfo["link"]),
+		UserIds:     req.UserIds,
+		MsgLogId:    msgLogId,
+		PositionIds: req.PositionIds,
+		Row4:        util.ObjToString(msgInfo["row4"]),
+		ProductName: util.ObjToString(msgInfo["productName"]),
+		OrderId:     util.ObjToString(msgInfo["orderId"]),
+		OrderMoney:  util.ObjToString(msgInfo["orderMoney"]),
+		AppPushUrl:  util.ObjToString(msgInfo["appPushUrl"]),
+		WxPushUrl:   util.ObjToString(msgInfo["wxPushUrl"]),
+		IosPushUrl:  util.ObjToString(msgInfo["iosPushUrl"]),
+	})
+	if err != nil {
+		return &types.NewUserSaveMsgResp{
+			Code:    1,
+			Message: err.Error(),
+		}, nil
+	}
+	return &types.NewUserSaveMsgResp{
+		Code:    1,
+		Message: "保存成功",
+	}, nil
+}

+ 41 - 0
api/internal/logic/updatemsgsummarylogic.go

@@ -0,0 +1,41 @@
+package logic
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/rpc/messageclient"
+	"context"
+
+	"app.yhyue.com/moapp/MessageCenter/api/internal/svc"
+	"app.yhyue.com/moapp/MessageCenter/api/internal/types"
+
+	"github.com/zeromicro/go-zero/core/logx"
+)
+
+type UpdateMsgSummaryLogic struct {
+	logx.Logger
+	ctx    context.Context
+	svcCtx *svc.ServiceContext
+}
+
+func NewUpdateMsgSummaryLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateMsgSummaryLogic {
+	return &UpdateMsgSummaryLogic{
+		Logger: logx.WithContext(ctx),
+		ctx:    ctx,
+		svcCtx: svcCtx,
+	}
+}
+
+func (l *UpdateMsgSummaryLogic) UpdateMsgSummary(req *types.UpdateMsgSummaryReq) (resp *types.Response, err error) {
+	resp = new(types.Response)
+	lsi := l.svcCtx.MessageCenter
+	res, err := lsi.UpdateMsgSummary(l.ctx, &messageclient.UpdateMsgSummaryReq{
+		MsgLogId: req.MsgLogId,
+		GroupId:  req.GroupId,
+		MsgType:  req.MsgType,
+	})
+	if err != nil {
+		resp.Code = 1
+	}
+	resp.Code = res.Code
+	resp.Message = res.Message
+	return resp, nil
+}

+ 432 - 0
rpc/internal/common/bigmapMsgService.go

@@ -0,0 +1,432 @@
+package common
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/entity"
+	"app.yhyue.com/moapp/MessageCenter/rpc/type/message"
+	"app.yhyue.com/moapp/MessageCenter/util"
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/redis"
+	"context"
+	"fmt"
+	"log"
+	"strconv"
+)
+
+func BitmapUserMsgList(this *message.UserMsgListReq) (*message.UserMsgList, *message.Messages) {
+	var (
+		unread, count int64
+		data          = new(message.UserMsgList)
+	)
+	//取出用户所有消息、已读消息id bitmap 查库
+	userAllMsgArr, userReadArr, userUnreadArr, err := GetUserMsgSummary(this.UserId)
+	if len(userAllMsgArr) == 0 && err != nil {
+		fmt.Printf("此用户暂无消息 : %s", err.Error())
+		return data, nil
+	}
+	//用户分类消息
+	_, userClassMsgMap := FindUserClassMsg(this.UserId)
+	//用户分类未读消息
+	classUnreadCountMap, classUnreadMsgMap := FindUserClassUnread(this.UserId)
+	fmt.Println("用户所有消息数:", len(userAllMsgArr), "已读消息数:", len(userReadArr), "未读消息数:", len(userUnreadArr))
+	//导航未读消息总数
+	if !this.IsMsgList && !this.IsColumnNewMsg && !this.IsColumn { //消息未读数统计
+		_, unread = BitmapCountUnread(this.UserId, classUnreadCountMap, true)
+		data.Unread = unread
+		return data, nil
+	}
+	//获取栏目下的数据
+	sData := make(map[string][]*message.Messages)
+	//移动端消息列表首页
+	if this.IsColumnNewMsg && this.SortSize > 0 {
+		for _, val := range entity.MessageColumn {
+			if util.IntAll(val["group_id"]) > 0 && util.IntAll(val["group_id"]) < 999 {
+				//用户分类未读 交集
+				userClassUnreadMsgArr := classUnreadMsgMap[util.IntAll(val["group_id"])]
+				var lastMsgId int
+				if len(userClassUnreadMsgArr) > 0 {
+					lastMsgId = userClassUnreadMsgArr[len(userClassUnreadMsgArr)-1]
+				} else {
+					//没有未读,分类展示最新一条消息
+					classMsg := userClassMsgMap[util.IntAll(val["group_id"])]
+					if len(classMsg) > 0 {
+						lastMsgId = classMsg[len(classMsg)-1]
+					}
+				}
+				lastMsg := GlobMsgMap[int(lastMsgId)]
+				if lastMsg == nil || len(lastMsg) <= 0 {
+					m := entity.Mysql.FindOne("message_send_log", map[string]interface{}{"id": int(lastMsgId)}, "id,msg_type,title,content,send_time,link,menu_name,group_id", "")
+					if m != nil && len(*m) > 0 {
+						lastMsg = *m
+					} else {
+						continue
+					}
+				}
+				var msg = message.Messages{
+					Id:         strconv.FormatInt(util.Int64All(lastMsg["id"]), 10),
+					Createtime: common.InterfaceToStr(lastMsg["send_time"]),
+					Title:      common.InterfaceToStr(lastMsg["title"]),
+					MsgType:    int64(util.IntAll(lastMsg["group_id"])),
+				}
+				if sData[common.InterfaceToStr(lastMsg["group_id"])] == nil {
+					sData[common.InterfaceToStr(lastMsg["group_id"])] = []*message.Messages{&msg}
+				} else {
+					sData[common.InterfaceToStr(lastMsg["group_id"])] = append(sData[common.InterfaceToStr(lastMsg["group_id"])], &msg)
+				}
+			}
+		}
+	}
+	//pc消息列表消息分类
+	var columnData []*message.AllSortData
+	if this.IsColumn && this.MsgType > 0 && this.IsClassSearch {
+		// 获取小分类下的未读数
+		sortUnread, _ := BitmapCountClassUnread(this.UserId, this.MsgType, classUnreadCountMap)
+		columnArr := []entity.MsgClass{}
+		if !this.IsColumnNewMsg { // 用于区分分类列表页和分类详情页   根据不同情况
+			columnArr = append(columnArr, entity.ClassMap[this.MsgType])
+		} else {
+			columnArr = entity.ClassSearchMap[this.MsgType]
+		}
+		for i := 0; i < len(columnArr); i++ {
+			tmp := columnArr[i]
+			var column message.AllSortData
+			column.Name = tmp.Name
+			column.Img = fmt.Sprintf("/common-module/msgCenter/%s.png", tmp.Img)
+			column.MsgType = tmp.MsgType
+			// 消息未读数
+			msgType := common.InterfaceToStr(tmp.MsgType)
+			column.UnreadMessages = sortUnread[msgType]
+			unread += sortUnread[msgType]
+			column.Data = sData[msgType]
+			column.IsClassSearch = true
+			columnData = append(columnData, &column)
+		}
+	} else if this.IsColumn {
+		//获取所有分类未读数 不初始化
+		sortUnread, _ := BitmapCountUnread(this.UserId, classUnreadCountMap, false)
+		for _, v := range entity.MessageColumn {
+			var column message.AllSortData
+			column.Name = common.InterfaceToStr(v["name"])
+			column.Img = fmt.Sprintf("/common-module/msgCenter/%s.png", common.InterfaceToStr(v["img"]))
+			column.MsgType = common.Int64All(v["group_id"])
+			if column.Name == "私信" {
+				column.UnreadMessages = unreadMsg(this)
+			} else if common.IntAll(v["group_id"]) > 0 {
+				//消息未读数
+				msgType := common.InterfaceToStr(v["group_id"])
+				column.UnreadMessages = sortUnread[msgType]
+				unread += sortUnread[msgType]
+				column.Data = sData[msgType]
+			}
+			if _, ok := entity.ClassSearchMap[column.MsgType]; ok {
+				column.IsClassSearch = true
+			}
+			columnData = append(columnData, &column)
+		}
+	}
+	data.SortData = columnData
+	count = int64(len(userAllMsgArr))
+	//pc列表数据、移动端分类列表
+	if this.IsMsgList {
+		if count > 0 {
+			var userMsgArr []int
+			if this.OffSet <= 0 {
+				this.OffSet = 1
+			}
+			if this.MsgType > 0 {
+				var totalMsg []int
+				//分类消息bitmap
+				totalMsg = userClassMsgMap[int(this.MsgType)]
+				if this.MsgType == 11 {
+					if !this.IsClassSearch {
+						totalMsg = IntArrSort(append(totalMsg, userClassMsgMap[12]...))
+					}
+				}
+				userMsgArr = totalMsg
+			} else {
+				userMsgArr = Uint32ArrToIntArr(userAllMsgArr)
+			}
+			if this.Read == 0 { //未读
+				userMsgArr = Uint32ArrToIntArr(userUnreadArr)
+			}
+			fmt.Println("所有消息", userMsgArr)
+			if len(userMsgArr) > 0 {
+				//总页数
+				var pageCount = 0
+				if this.PageSize != 0 {
+					if len(userMsgArr)%int(this.PageSize) > 0 {
+						pageCount = len(userMsgArr)/int(this.PageSize) + 1
+					} else {
+						pageCount = len(userMsgArr) / int(this.PageSize)
+					}
+				}
+				start := len(userMsgArr) - int(this.PageSize*(this.OffSet-1))
+				end := start - int(this.PageSize)
+				if int(this.OffSet) == pageCount || this.PageSize == 0 {
+					end = 0
+				}
+				fmt.Println(end, start)
+				resArr := userMsgArr[end:start]
+				resData := []*message.Messages{}
+				if len(resArr) > 0 {
+					count = int64(len(resArr))
+					unReadMap := map[int]bool{}
+					for _, vv := range userUnreadArr {
+						unReadMap[int(vv)] = true
+					}
+					for _, v := range resArr {
+						msg := GlobMsgMap[v]
+						if msg == nil || len(msg) <= 0 {
+							m := entity.Mysql.FindOne("message_send_log", map[string]interface{}{"id": v}, "id,msg_type,title,content,send_time,link,menu_name,group_id", "")
+							if m != nil && len(*m) > 0 {
+								msg = *m
+							} else {
+								continue
+							}
+						}
+						resData = append(resData, &message.Messages{
+							Id:         common.InterfaceToStr(v),
+							Createtime: common.InterfaceToStr(msg["send_time"]),
+							Title:      common.InterfaceToStr(msg["title"]),
+							MsgType:    int64(util.IntAll(msg["group_id"])),
+							Link:       common.InterfaceToStr(msg["link"]),
+							Content:    common.InterfaceToStr(msg["content"]),
+							IsRead:     common.Int64All(common.If(unReadMap[v], 0, 1)),
+							MsgLogId:   int64(v),
+						})
+					}
+					for i := len(resData) - 1; i >= 0; i-- {
+						data.Data = append(data.Data, resData[i])
+					}
+					fmt.Println("数据长度:", len(data.Data))
+				} else {
+					count = 0
+				}
+			}
+		}
+	}
+	data.Count = count
+	if this.Read == 0 {
+		unread = count
+		if this.IsContainLetter { //是否需要统计私信未读数
+			unread += unreadMsg(this)
+		}
+	}
+	data.Unread = int64(len(userUnreadArr))
+	//置顶消息
+	if len(classUnreadMsgMap[1]) > 0 {
+		res2 := BitmapMessageGetLast(this, classUnreadMsgMap[1][len(classUnreadMsgMap)-1])
+		return data, res2
+	}
+	return data, nil
+}
+
+// BitmapMessageGetLast 获取优惠活动的最新一条消息
+func BitmapMessageGetLast(this *message.UserMsgListReq, msgId int) *message.Messages {
+	if !this.IsMsgList && !this.IsColumnNewMsg && !this.IsColumn {
+		return nil
+	}
+	lastMsg := GlobMsgMap[msgId]
+	if lastMsg != nil && len(lastMsg) > 0 {
+		msg := message.Messages{
+			Id:         common.InterfaceToStr(lastMsg["id"]),
+			Createtime: common.InterfaceToStr(lastMsg["send_time"]),
+			Title:      common.InterfaceToStr(lastMsg["title"]),
+			MsgType:    common.Int64All(lastMsg["group_id"]),
+			Link:       common.InterfaceToStr(lastMsg["link"]),
+			Content:    common.InterfaceToStr(lastMsg["content"]),
+			IsRead:     0,
+			MsgLogId:   common.Int64All(lastMsg["id"]),
+		}
+		return &msg
+	}
+	return nil
+}
+
+type UserClassUnread struct {
+	GroupId   int
+	UnreadArr []uint32
+}
+
+// BitmapCountUnread 未读消息合计 isRedis 是否需要初始化redis
+func BitmapCountUnread(userId string, classUnreadCountMap map[int]int, isRedis bool) (map[string]int64, int64) {
+	var (
+		count              int64
+		msgTypes, groupIds []string
+	)
+	data := make(map[string]int64)
+	for _, v := range entity.MessageColumn {
+		if util.IntAll(v["group_id"]) > 0 && util.IntAll(v["group_id"]) < 999 {
+			//去除全部与私信
+			msgTypes = append(msgTypes, fmt.Sprintf(`"%s"`, common.InterfaceToStr(v["group_id"])))
+			key := fmt.Sprintf(MsgCountKey, userId, util.IntAll(v["group_id"]))
+			groupIds = append(groupIds, common.InterfaceToStr(v["group_id"]))
+			if exists, _ := redis.Exists(redisModule, key); exists {
+				ct := util.Int64All(redis.GetInt(redisModule, key))
+				data[common.InterfaceToStr(v["group_id"])] = ct
+				count += ct
+			}
+		}
+	}
+	//classUnreadCountMap, _ := FindUserClassUnread(userId)
+	if len(msgTypes) > 0 && len(msgTypes) != len(data) {
+		for _, val := range entity.MessageColumn {
+			if util.IntAll(val["group_id"]) > 0 && util.IntAll(val["group_id"]) < 999 {
+				oneClassUnread := classUnreadCountMap[util.IntAll(val["group_id"])]
+				if util.IntAll(val["group_id"]) == 11 {
+					oneClassUnread += classUnreadCountMap[12]
+				}
+				if isRedis {
+					//用户分类未读
+					fmt.Println(util.IntAll(val["group_id"]))
+					key := fmt.Sprintf(MsgCountKey, userId, util.IntAll(val["group_id"]))
+					redis.Put(redisModule, key, oneClassUnread, 60*60)
+				}
+				data[common.InterfaceToStr(val["group_id"])] = int64(oneClassUnread)
+				count += int64(oneClassUnread)
+			}
+		}
+	}
+	return data, count //分类未读、未读总量
+}
+
+//BitmapCountClassUnread    userUnreadBitmap 用户未读
+func BitmapCountClassUnread(userId string, groupId int64, classUnreadCountMap map[int]int) (classCount map[string]int64, total int64) {
+	var (
+		count int64
+	)
+	data := make(map[string]int64)
+	if _, ok := entity.ClassSearchMap[groupId]; !ok {
+		return
+	}
+	//classUnreadCountMap, _ := FindUserClassUnread(userId)
+	for i := 0; i < len(entity.ClassSearchMap[groupId]); i++ {
+		msgClass := entity.ClassSearchMap[groupId][i]
+		key := fmt.Sprintf(MsgClassCountKey, userId, msgClass.MsgType)
+		if exists, _ := redis.Exists(redisModule, key); exists {
+			ct := util.Int64All(redis.GetInt(redisModule, key))
+			data[fmt.Sprintf("%d", msgClass.MsgType)] = ct
+			count += ct
+		} else {
+			//分类所有消息
+			//totalMsg := GetMsgSummaryBitmap(util.IntAll(msgClass.MsgType))
+			classUnreadCount := classUnreadCountMap[util.IntAll(msgClass.MsgType)]
+			if classUnreadCount != -1 {
+				redis.Put(redisModule, key, classCount, -1)
+				data[fmt.Sprintf("%d", msgClass.MsgType)] = int64(classUnreadCount)
+				count += int64(classUnreadCount)
+			} else {
+				log.Println("查询classCount失败:", classCount)
+			}
+		}
+	}
+
+	return data, count
+}
+
+//FindUserClassUnread 查询用户分类未读消息id
+func FindUserClassUnread(userId string) (map[int]int, map[int][]int) {
+	sql := fmt.Sprintf("SELECT bitmapToArray(bitmapAnd(bitmapAndnot(mus.allMsg,mus.readMsg),ms.msg_bitmap)) AS msgArr,ms.group_id  FROM messageCenter.message_user_summary mus, messageCenter.message_summary ms WHERE mus.userId = '%s'", userId)
+	rows, err := entity.ClickhouseConn.Query(context.Background(), sql)
+	if err != nil {
+		log.Println("获取各分类未读消息数组出错:", err)
+		return nil, nil
+	}
+	var classUnreadCountMap map[int]int
+	var classUnreadMsgMap map[int][]int
+	for rows.Next() {
+		group := UserClassUnread{}
+		err = rows.ScanStruct(&group)
+		if err != nil {
+			log.Println("获取各分类读取分类数据出错:", err)
+			return nil, nil
+		}
+		classUnreadCountMap[group.GroupId] = len(group.UnreadArr)
+		classUnreadMsgMap[group.GroupId] = Uint32ArrToIntArr(group.UnreadArr)
+	}
+	return classUnreadCountMap, classUnreadMsgMap
+}
+
+//FindUserClassMsg 查询用户分类所有消息id
+func FindUserClassMsg(userId string) (map[int]int, map[int][]int) {
+	sql := fmt.Sprintf("SELECT bitmapToArray(bitmapAnd(mus.allMsg,ms.msg_bitmap)) AS msgArr,ms.group_id  FROM messageCenter.message_user_summary mus, messageCenter.message_summary ms WHERE mus.userId = '%s'", userId)
+	rows, err := entity.ClickhouseConn.Query(context.Background(), sql)
+	if err != nil {
+		log.Println("获取各分类未读消息数组出错:", err)
+		return nil, nil
+	}
+	var classCountMap map[int]int
+	var classMsgMap map[int][]int
+	for rows.Next() {
+		group := UserClassUnread{}
+		err = rows.ScanStruct(&group)
+		if err != nil {
+			log.Println("获取各分类读取分类数据出错:", err)
+			return nil, nil
+		}
+		classCountMap[group.GroupId] = len(group.UnreadArr)
+		classMsgMap[group.GroupId] = Uint32ArrToIntArr(group.UnreadArr)
+	}
+	return classCountMap, classMsgMap
+}
+
+// GetUserMsgSummary 从用户消息汇总表取数据
+func GetUserMsgSummary(userId string) (userAllMsg, userReadMsg, userUnreadMsg []uint32, err error) {
+	row := entity.ClickhouseConn.QueryRow(context.Background(), fmt.Sprintf("SELECT bitmapToArray(allMsg) as userAllMsg,bitmapToArray(readMsg) as userReadMsg,bitmapToArray(bitmapAndnot(allMsg,readMsg)) as userunRead from messageCenter.message_user_summary where userId ='%s'", userId))
+	err = row.Scan(&userAllMsg, &userReadMsg, &userUnreadMsg)
+	if err != nil {
+		log.Println("GetUserMsgSummary获取用户消息数据出错:", err)
+	}
+	return
+}
+
+// Uint32ArrToIntArr []uint32转[]int
+func Uint32ArrToIntArr(arr []uint32) []int {
+	tmp := make([]int, 0)
+	for _, v := range arr {
+		tmp = append(tmp, int(v))
+	}
+	return tmp
+}
+
+func IntArrSort(arr []int) []int {
+	if len(arr) <= 1 {
+		return arr
+	}
+	splitData := arr[0]          //第一个数据为基准
+	low := make([]int, 0, 0)     //比我小的数据
+	height := make([]int, 0, 0)  //比我大的数据
+	mid := make([]int, 0, 0)     //与我一样大的数据
+	mid = append(mid, splitData) //加入一个
+	for i := 1; i < len(arr); i++ {
+		if arr[i] < splitData {
+			low = append(low, arr[i])
+		} else if arr[i] > splitData {
+			height = append(height, arr[i])
+		} else {
+			mid = append(mid, arr[i])
+		}
+	}
+	low, height = IntArrSort(low), IntArrSort(height) //切割递归处理
+	resArr := append(append(low, mid...), height...)
+	return resArr
+}
+
+// PutRedisUserAllMsg 加载用户的所有消息
+/*func PutRedisUserAllMsg(userId string, allMsgBitmap *roaring.Bitmap) (rData []map[string]interface{}) {
+	str := ""
+	for i, v := range allMsgBitmap.ToArray() {
+		if i < len(allMsgBitmap.ToArray())-1 {
+			str += common.InterfaceToStr(v) + ","
+		} else {
+			str += common.InterfaceToStr(v)
+		}
+	}
+	//查询用户所有消息
+	key := fmt.Sprintf(BitmapUserMsg, userId)
+	m := entity.Mysql.SelectBySql("SELECT id,msg_type,title,content,send_time,link,menu_name,group_id FROM message_send_log WHERE send_status = 4 AND isdel = 1 AND id in (?) ORDER BY send_time DESC", str)
+	if m != nil && len(*m) > 0 {
+		rData = *m
+		redis.Put(redisModule, key, rData, -1)
+	}
+	return rData
+}*/

+ 79 - 0
rpc/internal/common/bmService.go

@@ -0,0 +1,79 @@
+package common
+
+import (
+	"app.yhyue.com/moapp/MessageCenter/entity"
+	"fmt"
+	"github.com/RoaringBitmap/roaring"
+	"sync"
+)
+
+var rwMutex sync.RWMutex
+
+// 将Roaring Bitmap写入MySQL
+func writeBitmapToSendLog(rb *roaring.Bitmap, msgLogId int64) error {
+	// 将Roaring Bitmap转换为字节数组
+	bytes, err := rb.ToBytes()
+	if err != nil {
+		return err
+	}
+	ok := entity.Mysql.Update("message_send_log", map[string]interface{}{"id": msgLogId}, map[string]interface{}{"baseUserIds": bytes})
+	if !ok {
+		return fmt.Errorf("更新message_user_summary msg_log_id: %s 出错", msgLogId)
+	}
+
+	return nil
+}
+
+// 从MySQL中读取Roaring Bitmap
+func readBitmapFromSendLog(msgLogId int64) (*roaring.Bitmap, error) {
+	// 从MySQL读取字节数组
+	var bytes []byte
+	err := entity.Mysql.DB.QueryRow("SELECT baseUserIds FROM message_send_log WHERE `id` = ?", msgLogId).Scan(&bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	// 将字节数组转换为Roaring Bitmap
+	rb := roaring.NewBitmap()
+	_, err = rb.FromBuffer(bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	return rb, nil
+}
+
+// 更新用户消息汇总表
+func writeBitmapToUserSummary(rb *roaring.Bitmap, userId string) error {
+	allMsg, err := rb.ToBytes()
+	if err != nil {
+		return err
+	}
+	ok := entity.Mysql.Update("message_user_summary", map[string]interface{}{"userId": userId}, map[string]interface{}{
+		"allMsg": allMsg,
+	})
+	if !ok {
+		return fmt.Errorf("更新message_user_summary USERID: %s 出错", userId)
+	}
+	return nil
+}
+
+// 更新用户消息汇总表 -已读未读
+func UpdateBitmapToUserUnread(rb2 *roaring.Bitmap, userId string) error {
+	readMsg, err := rb2.ToBytes()
+	if err != nil {
+		return err
+	}
+	ok := entity.Mysql.Update("message_user_summary", map[string]interface{}{"userId": userId}, map[string]interface{}{
+		"readMsg": readMsg,
+	})
+	if !ok {
+		return fmt.Errorf("更新message_user_summary USERID: %s 出错", userId)
+	}
+	return nil
+}
+
+type MsgSummaryEntity struct {
+	GroupId int
+	Byte1   []byte
+}