package common import ( "app.yhyue.com/moapp/MessageCenter/entity" "app.yhyue.com/moapp/MessageCenter/rpc/internal/config" "app.yhyue.com/moapp/MessageCenter/rpc/type/message" "app.yhyue.com/moapp/MessageCenter/util" "app.yhyue.com/moapp/jybase/common" m "app.yhyue.com/moapp/jybase/mongodb" "app.yhyue.com/moapp/jybase/redis" "context" "errors" "fmt" "log" "strconv" "time" ) func BitmapUserMsgList(this *message.UserMsgListReq) (*message.UserMsgList, *message.Messages) { var ( unread, count int64 data = new(message.UserMsgList) ) //取出用户所有消息、已读消息id bitmap 查库 userAllMsgArr, _, userUnreadArr, err := GetUserMsgSummary(this.UserId, this.IsfilterActive) if len(userAllMsgArr) == 0 && err != nil { fmt.Printf("此用户暂无消息 : %s", err.Error()) } //用户分类消息 _, userClassMsgMap := FindUserClassMsg(this.UserId) //用户分类未读消息 classUnreadCountMap, classUnreadMsgMap := FindUserClassUnread(this.UserId) //fmt.Println("用户所有消息数:", userAllMsgArr, "已读消息数:", userReadArr, "未读消息数:", 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 { messageColumn := entity.MessageColumn if this.IsClassSearch { messageColumn = append(messageColumn, map[string]interface{}{ "group_id": 12, }) } for _, val := range 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] } else { continue } } lastMsg := GlobMsgMap[lastMsgId] if lastMsg == nil || len(lastMsg) <= 0 { mess := entity.Mysql.FindOne("message_send_log", map[string]interface{}{"id": int(lastMsgId)}, "id,msg_type,title,content,send_time,link,menu_name,group_id,sign", "") if mess != nil && len(*mess) > 0 { lastMsg = *mess } else { continue } } if common.IntAll(lastMsg["sign"]) == 4 { //查询用户注册时间 rData, _ := entity.MQFW.FindOneByField("user", map[string]interface{}{"_id": m.StringTOBsonId(this.UserId)}, `{"l_registedate":1}`) if rData != nil && len(*rData) > 0 { lastMsg["send_time"] = time.Unix(common.Int64All((*rData)["l_registedate"]), 0).Local().Format("2006-01-02 15:04:05") } } 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 this.IsClassSearch && util.IntAll(val["group_id"]) == 12 { sData[common.InterfaceToStr(val["group_id"])] = []*message.Messages{&msg} continue } 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, total := 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] } unread += total 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] column.Data = sData[msgType] column.IsClassSearch = true columnData = append(columnData, &column) } } else if this.IsColumn || this.IsfilterActive { //获取所有分类未读数 不初始化 sortUnread, total := BitmapCountUnread(this.UserId, classUnreadCountMap, false) //fmt.Println("*************", total) unread += total if this.IsColumn { 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] column.Data = sData[msgType] } if _, ok := entity.ClassSearchMap[column.MsgType]; ok { column.IsClassSearch = true } columnData = append(columnData, &column) } } } data.SortData = columnData if len(userAllMsgArr) == 0 { fmt.Printf("此用户暂无消息 : %s", err.Error()) return data, nil } 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 = append(totalMsg, userClassMsgMap[12]...) } } userMsgArr = totalMsg } else { userMsgArr = Uint32ArrToIntArr(userAllMsgArr) } if this.Read == 0 { //未读 userMsgArr = Uint32ArrToIntArr(userUnreadArr) } if this.MsgType > 0 { count = int64(len(userMsgArr)) } if len(userMsgArr) > 0 { userMsgArr = IntArrSort(userMsgArr) fmt.Println("列表消息:", userMsgArr) //总页数 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) if end < 0 || start < 0 { return data, nil } 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 { ms := entity.Mysql.FindOne("message_send_log", map[string]interface{}{"id": v}, "id,msg_type,title,content,send_time,link,menu_name,group_id,sign", "") if ms != nil && len(*ms) > 0 { msg = *ms } else { continue } } if common.IntAll(msg["sign"]) == 4 { //查询用户注册时间 rData, _ := entity.MQFW.FindOneByField("user", map[string]interface{}{"_id": m.StringTOBsonId(this.UserId)}, `{"l_registedate":1}`) if rData != nil && len(*rData) > 0 { msg["send_time"] = time.Unix(common.Int64All((*rData)["l_registedate"]), 0).Local().Format("2006-01-02 15:04:05") } } 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]) } } } } } data.Count = count if this.Read == 0 { //unread = count if this.IsContainLetter { //是否需要统计私信未读数 unread += unreadMsg(this) } } data.Unread = unread //置顶消息 if len(classUnreadMsgMap[1]) > 0 { activeMsgArr := classUnreadMsgMap[1] res2 := BitmapMessageGetLast(this, activeMsgArr[len(activeMsgArr)-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 { mess := entity.Mysql.FindOne("message_send_log", map[string]interface{}{"id": msgId}, "id,msg_type,title,content,send_time,link,menu_name,group_id,sign", "") if mess != nil && len(*mess) > 0 { lastMsg = *mess } } if lastMsg != nil && len(lastMsg) > 0 { if common.IntAll(lastMsg["sign"]) == 4 { //查询用户注册时间 rData, _ := entity.MQFW.FindOneByField("user", map[string]interface{}{"_id": m.StringTOBsonId(this.UserId)}, `{"l_registedate":1}`) if rData != nil && len(*rData) > 0 { lastMsg["send_time"] = time.Unix(common.Int64All((*rData)["l_registedate"]), 0).Local().Format("2006-01-02 15:04:05") } } 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 int32 `ch:"group_id"` UnreadArr []uint32 `ch:"unreadArr"` } // 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 { //用户分类未读 if oneClassUnread >= 0 { 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 } for i := 0; i < len(entity.ClassSearchMap[groupId]); i++ { msgClass := entity.ClassSearchMap[groupId][i] //fmt.Println("msgClass", msgClass) 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 { //分类所有消息 classUnreadCount := classUnreadCountMap[util.IntAll(msgClass.MsgType)] if classUnreadCount >= 0 { redis.Put(redisModule, key, classUnreadCount, -1) data[fmt.Sprintf("%d", msgClass.MsgType)] = int64(classUnreadCount) count += int64(classUnreadCount) } else { log.Println("查询classUnreadCount失败,msgType:", msgClass.MsgType) } } } return data, count } //FindUserClassUnread 查询用户分类未读消息id func FindUserClassUnread(userId string) (map[int]int, map[int][]int) { sql := fmt.Sprintf(`select a2.group_id,bitmapToArray(bitmapAnd(a1.unreadArr,a2.msg_bitmap)) as unreadArr from (SELECT bitmapAndnot(mus.allMsg,mus.readMsg) unreadArr FROM message_user_summary mus WHERE mus.userId = '%s') a1, (select msg_bitmap,group_id from message_summary ms where 1=1 limit 10) a2`, userId) fmt.Println("FindUserClassUnread", sql) rows, err := entity.ClickhouseConn.Query(context.Background(), sql) if err != nil { log.Println("获取各分类未读消息数组出错:", err) return nil, nil } classUnreadCountMap := map[int]int{} classUnreadMsgMap := map[int][]int{} for rows.Next() { group := UserClassUnread{} err = rows.ScanStruct(&group) if err != nil { log.Println("获取各分类读取分类数据出错:", err) return nil, nil } classUnreadCountMap[int(group.GroupId)] = len(group.UnreadArr) classUnreadMsgMap[int(group.GroupId)] = Uint32ArrToIntArr(group.UnreadArr) } return classUnreadCountMap, classUnreadMsgMap } //FindUserClassMsg 查询用户分类所有消息id func FindUserClassMsg(userId string) (map[int]int, map[int][]int) { sql := fmt.Sprintf(`select a2.group_id,bitmapToArray(bitmapAnd(a1.allMsg,a2.msg_bitmap)) as unreadArr from (SELECT mus.allMsg as allMsg FROM message_user_summary mus WHERE mus.userId = '%s') a1, (select msg_bitmap,group_id from message_summary ms where 1=1 limit 10) a2`, userId) fmt.Println("FindUserClassMsg", sql) rows, err := entity.ClickhouseConn.Query(context.Background(), sql) if err != nil { log.Println("获取各分类未读消息数组出错:", err) return nil, nil } classCountMap := map[int]int{} classMsgMap := map[int][]int{} for rows.Next() { group := UserClassUnread{} err = rows.ScanStruct(&group) if err != nil { log.Println("获取各分类读取分类数据出错:", err) return nil, nil } //fmt.Println(int(group.GroupId), len(group.UnreadArr)) classCountMap[int(group.GroupId)] = len(group.UnreadArr) classMsgMap[int(group.GroupId)] = Uint32ArrToIntArr(group.UnreadArr) } return classCountMap, classMsgMap } // GetUserMsgSummary 从用户消息汇总表取数据 func GetUserMsgSummary(userId string, isfilterActive bool) (userAllMsg, userReadMsg, userUnreadMsg []uint32, err error) { var count uint64 sqlc := "" sqlc = fmt.Sprintf("SELECT COUNT(*) as count from message_user_summary WHERE userId = '%s'", userId) log.Println("GetUserMsgSummary selcet ", sqlc) row1 := entity.ClickhouseConn.QueryRow(context.Background(), sqlc) err = row1.Scan(&count) if count == 0 { err = errors.New("用户暂无数据") return } var sql string isfilterActive = config.ConfigJson.IsFilterActive if isfilterActive { sql = fmt.Sprintf("SELECT a1.userAllMsg,a1.userReadMsg,bitmapToArray(bitmapAndnot(a1.userunRead,a2.msg_bitmap)) as userunRead from (SELECT bitmapToArray(allMsg) as userAllMsg,bitmapToArray(readMsg) as userReadMsg,bitmapAndnot(allMsg,readMsg) as userunRead from message_user_summary where userId ='%s') a1,(select msg_bitmap,group_id from message_summary ms where group_id = 1 ) a2", userId) } else { sql = fmt.Sprintf("SELECT bitmapToArray(allMsg) as userAllMsg,bitmapToArray(readMsg) as userReadMsg,bitmapToArray(bitmapAndnot(allMsg,readMsg)) as userunRead from message_user_summary where userId ='%s'", userId) } //sql := fmt.Sprintf("SELECT bitmapToArray(allMsg) as userAllMsg,bitmapToArray(readMsg) as userReadMsg,bitmapToArray(bitmapAndnot(allMsg,readMsg)) as userunRead from message_user_summary where userId ='%s'", userId) log.Println("GetUserMsgSummary selcet2 ", sql) row := entity.ClickhouseConn.QueryRow(context.Background(), sql) err = row.Scan(&userAllMsg, &userReadMsg, &userUnreadMsg) if err != nil { log.Println("此用户暂无数据:", 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 } type UserMsg struct { GroupId int32 `ch:"group_id"` UnreadArr []uint32 `ch:"unreadArr"` ReadArr []uint32 `ch:"readArr"` } func WorkDeskList(in *message.WorkingDesktopReq) (res1, res2 []*message.Messages, err error) { //待办查询 sqlStr := "" needDo := map[int][]uint32{} //msgType对应的消息id if in.NeedDealtWithCount { sqlStr = fmt.Sprintf(" or p_group_id = 11") } sql := fmt.Sprintf(`select a2.group_id,bitmapToArray(bitmapAnd(a1.allMsg,a2.msg_bitmap)) as unreadArr,bitmapToArray(a1.readMsg) as readArr from (SELECT mus.allMsg as allMsg,mus.readMsg as readMsg FROM message_user_summary mus WHERE mus.userId = '%s') a1, (select msg_bitmap,group_id from message_summary ms where group_id = %d %s) a2`, in.UserId, in.MsgType, sqlStr) log.Println("WorkDeskList", sql) rows, err := entity.ClickhouseConn.Query(context.Background(), sql) if err != nil { return nil, nil, err } readMsgMap := map[int]bool{} for rows.Next() { group := UserMsg{} err = rows.ScanStruct(&group) if err != nil { log.Println("获取各分类读取分类数据出错:", err) return nil, nil, err } if len(group.ReadArr) > 0 && len(readMsgMap) == 0 { for _, v := range group.ReadArr { readMsgMap[int(v)] = true } } if group.GroupId == int32(in.MsgType) { res1 = GetMsgList(IntArrSort(Uint32ArrToIntArr(group.UnreadArr)), int(in.PageSize), in.UserId, readMsgMap) } else { if len(group.UnreadArr) > 0 { needDo[int(group.GroupId)] = group.UnreadArr } } } if len(needDo) > 0 { totalMsg := append(needDo[11], needDo[12]...) needMsgArr := IntArrSort(Uint32ArrToIntArr(totalMsg)) res2 = GetMsgList(needMsgArr, int(in.PageSize), in.UserId, readMsgMap) } return res1, res2, nil } func GetMsgList(arr []int, size int, userId string, readMsgMap map[int]bool) []*message.Messages { newMsg := []int{} if len(arr) > 0 { if len(arr) >= size { newMsg = arr[len(arr)-size:] } else { newMsg = arr } } //fmt.Println("*********8", newMsg) resData := []*message.Messages{} for i := len(newMsg) - 1; i >= 0; i-- { //for _, v := range newMsg { msg := GetMsgInfo(int(newMsg[i]), userId) links4 := common.InterfaceToStr(msg["link"]) link4, androidUrl4, iosUrl4, weChatUrl4 := util.LinkSplit(links4) resData = append(resData, &message.Messages{ Id: common.InterfaceToStr(newMsg[i]), Createtime: common.InterfaceToStr(msg["send_time"]), Title: common.InterfaceToStr(msg["title"]), MsgType: int64(util.IntAll(msg["group_id"])), Link: link4, Content: common.InterfaceToStr(msg["content"]), MsgLogId: int64(newMsg[i]), Url: map[string]string{ "androidUrl": androidUrl4, "iosUrl": iosUrl4, "weChatUrl": weChatUrl4, }, IsRead: common.Int64All(common.If(readMsgMap[int(newMsg[i])], 1, 0)), }) } return resData } func GetMsgInfo(msgId int, userId string) map[string]interface{} { msg := GlobMsgMap[msgId] if msg == nil || len(msg) <= 0 { ms := entity.Mysql.FindOne("message_send_log", map[string]interface{}{"id": msgId}, "id,msg_type,title,content,send_time,link,menu_name,group_id,sign", "") if ms != nil && len(*ms) > 0 { msg = *ms } } if common.IntAll(msg["sign"]) == 4 { //查询用户注册时间 rData, _ := entity.MQFW.FindOneByField("user", map[string]interface{}{"_id": m.StringTOBsonId(userId)}, `{"l_registedate":1}`) if rData != nil && len(*rData) > 0 { msg["send_time"] = time.Unix(common.Int64All((*rData)["l_registedate"]), 0).Local().Format("2006-01-02 15:04:05") } } return msg } // 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 }*/