package service import ( "context" "fmt" jsoniter "github.com/json-iterator/go" "github.com/mhaya/extend/tree" clog "github.com/mhaya/logger" "go.mongodb.org/mongo-driver/mongo/options" "slices" "time" "github.com/mhaya/game/game_cluster/internal/constant" "github.com/mhaya/game/game_cluster/internal/mdb" "github.com/mhaya/game/game_cluster/internal/mdb/models" "github.com/mhaya/game/game_cluster/nodes/adminapi/entity" "go.mongodb.org/mongo-driver/bson" ) func GetUserCount() *entity.UserCountResp { collection := mdb.MDB.Collection(constant.CNameAccount) // 统计当日注册 和总注册人数 // 获取今天开始的时间戳 now := time.Now() startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) endOfDay := startOfDay.Add(24 * time.Hour).Add(-1 * time.Second) // 构建查询条件 - 如果查询值为空那就不添加查询条件 filter := bson.M{} // 统计当日注册 和总注册人数 filter["JoinTime"] = bson.M{ "$gte": startOfDay.Unix(), "$lte": endOfDay.Unix(), } // 获取注册总数 totalCount, err := collection.CountDocuments(context.Background(), bson.M{}) if err != nil { return nil } count, err := mdb.MDB.Collection(constant.CNameAccount).CountDocuments(context.Background(), filter) if err != nil { return nil } return &entity.UserCountResp{ TotalReg: totalCount, ToDayReg: count, } } // GetUserList 获取用户列表 并且可以根据用户ID获取下级用户 func GetUserList(req *entity.UserReq) []*entity.UserListResp { collection := mdb.MDB.Collection(constant.CNamePlayer) filter := bson.M{} if req.Pid != "" { filter["pid"] = req.Pid } if req.UserName != "" { //filter["nickName"] = primitive.Regex{Pattern: fmt.Sprintf(".*%s.*", req.UserName), Options: "i"} filter["nickName"] = req.UserName } if req.RangeStart != 0 && req.RangeEnd != 0 { filter["createTime"] = bson.M{ "$gte": req.RangeStart, "$lte": req.RangeEnd, } } if req.UserID != "" { filter["userName"] = req.UserID } if req.Tag != "" { filter["tag"] = req.Tag } if req.LoginIp != "" { filter["loginIp"] = req.LoginIp } if req.TagType == 1 { filter["pid"] = "" } // 分页参数 skip := (req.Page - 1) * req.Size // 执行查询 opts := options.Find() // 根据指定字段和排序类型做排序 sort := bson.D{} if req.OrderColumn != "" && req.OrderType != "" { sort = bson.D{{req.OrderColumn, req.OrderType}} opts.SetSort(sort) } opts.SetSkip(int64(skip)) opts.SetLimit(int64(req.Size)) cursor, err := collection.Find(context.Background(), filter, opts) count, _ := collection.CountDocuments(context.Background(), filter) if err != nil { return nil } defer cursor.Close(context.Background()) var result []*entity.UserListResp for cursor.Next(context.Background()) { var account *models.Player if err := cursor.Decode(&account); err != nil { return nil } var totalPlan int var curPlan int ids := []int{1000, 1001} for _, item := range account.FirstClaimReward { totalPlan++ id := item.Reward[0].ItemID if slices.Contains(ids, id) { continue } if item.IsClaim == 1 { curPlan++ } } var tagNum int // 下级及下级以下 var subNum int // 下级 var inviteTreeKey string if account.TopPid != "" { // 非一级 inviteTreeKey = fmt.Sprintf("%v:%v", constant.InviteTreeKey, account.TopPid) } else { // 一级 inviteTreeKey = fmt.Sprintf("%v:%v", constant.InviteTreeKey, account.UserName) } treeJson, _ := mdb.RDB.Get(context.Background(), inviteTreeKey).Result() if treeJson != "" { var treeInfo *tree.TreeNode jsoniter.Unmarshal([]byte(treeJson), &treeInfo) tagNum = treeInfo.CountAllChildren(account.UserName) subNum = treeInfo.CountDirectChildren(account.UserName) } var num int64 var tag int if value, ok := account.Item[0]; ok { num = value.Num } if account.Pid == "" { tag = 1 } result = append(result, &entity.UserListResp{ UserName: account.UserName, OpenId: account.OpenId, UserNameMaybe: account.UserNameMaybe, NickName: account.NickName, Pid: account.Pid, XID: account.XID, TonWall: account.TonWall, Email: account.Email, Mobile: account.Mobile, Avatar: account.Avatar, IsCashOut: account.IsCashOut, IsRobot: account.IsRobot, IsLeader: account.IsLeader, IsVip: account.IsVip, IsFirstBindingXID: account.IsFirstBindingXID, Level: account.Level, Exp: account.Exp, Gender: account.Gender, Birthday: account.Birthday, Successions: account.Successions, MaxSuccessions: account.MaxSuccessions, PrevTime: account.PrevTime, LoginTime: account.LoginTime, LoginIP: account.LoginIP, LoginFailure: account.LoginFailure, JoinIP: account.JoinIP, Rank: account.Rank, JoinTime: account.JoinTime, CreateTime: account.CreateTime, UpdateTime: account.UpdateTime, DailyRefreshTime: account.DailyRefreshTime, HourRefreshTime: account.HourRefreshTime, WeeklyRefreshTime: account.WeeklyRefreshTime, RollDay: account.RollDay, Status: account.Status, TagNum: tagNum, SubNum: subNum, Total: count, CurPlan: curPlan, TotalPlan: totalPlan, Tag: tag, Score: int64(num), }) } // todo 修复数据 //go repairData() return result } // 修复数据 func repairData() { clog.Debugf("repairData start =>") collection := mdb.MDB.Collection(constant.CNamePlayer) filter := bson.M{} filter["pid"] = "" opts := options.Find() cursor, _ := collection.Find(context.Background(), filter, opts) defer cursor.Close(context.Background()) var rows int for cursor.Next(context.Background()) { var account *models.Player if err := cursor.Decode(&account); err != nil { return } if account.Pid != "" { continue } rangeKey := fmt.Sprintf("%v:%v:%v", constant.InviteKey, 2, account.UserName) child, _ := mdb.RDB.LLen(context.Background(), rangeKey).Uint64() if child == 0 { continue } subordinatesTree, err := GetSubordinatesTree(account.UserName) if err != nil { clog.Error("repairData GetSubordinatesTree execute Fail ", err) } treeJson, err := jsoniter.MarshalToString(subordinatesTree) inviteTreeKey := fmt.Sprintf("%v:%v", constant.InviteTreeKey, account.UserName) mdb.RDB.Set(context.Background(), inviteTreeKey, treeJson, 0) clog.Debugf("tree: \n\n %v", treeJson) rows++ } clog.Debugf("repairData end => repair rows: %v", rows) } // GetSubordinatesTree 递归查询某个用户的所有下级用户树结构 func GetSubordinatesTree(userID string) (*tree.TreeNode, error) { var root *tree.TreeNode ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() collection := mdb.MDB.Collection(constant.CNamePlayer) // 查询直接下级用户 cursor, err := collection.Find(ctx, bson.M{"pid": userID}) if err != nil { return nil, err } defer cursor.Close(ctx) for cursor.Next(ctx) { var player models.Player if err := cursor.Decode(&player); err != nil { return nil, err } childNode := tree.NewTreeNode(player.UserName) if root == nil { root = tree.NewTreeNode(userID) } root.Children = append(root.Children, childNode) // 递归查询下级的下级用户 subTree, err := GetSubordinatesTree(player.UserName) if err != nil { return nil, err } if subTree != nil { childNode.Children = subTree.Children } } return root, nil }