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 }*/