user.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. jsoniter "github.com/json-iterator/go"
  6. "github.com/mhaya/extend/tree"
  7. clog "github.com/mhaya/logger"
  8. "go.mongodb.org/mongo-driver/mongo/options"
  9. "slices"
  10. "time"
  11. "github.com/mhaya/game/game_cluster/internal/constant"
  12. "github.com/mhaya/game/game_cluster/internal/mdb"
  13. "github.com/mhaya/game/game_cluster/internal/mdb/models"
  14. "github.com/mhaya/game/game_cluster/nodes/adminapi/entity"
  15. "go.mongodb.org/mongo-driver/bson"
  16. )
  17. func GetUserCount() *entity.UserCountResp {
  18. collection := mdb.MDB.Collection(constant.CNameAccount)
  19. // 统计当日注册 和总注册人数
  20. // 获取今天开始的时间戳
  21. now := time.Now()
  22. startOfDay := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
  23. endOfDay := startOfDay.Add(24 * time.Hour).Add(-1 * time.Second)
  24. // 构建查询条件 - 如果查询值为空那就不添加查询条件
  25. filter := bson.M{}
  26. // 统计当日注册 和总注册人数
  27. filter["JoinTime"] = bson.M{
  28. "$gte": startOfDay.Unix(),
  29. "$lte": endOfDay.Unix(),
  30. }
  31. // 获取注册总数
  32. totalCount, err := collection.CountDocuments(context.Background(), bson.M{})
  33. if err != nil {
  34. return nil
  35. }
  36. count, err := mdb.MDB.Collection(constant.CNameAccount).CountDocuments(context.Background(), filter)
  37. if err != nil {
  38. return nil
  39. }
  40. return &entity.UserCountResp{
  41. TotalReg: totalCount,
  42. ToDayReg: count,
  43. }
  44. }
  45. // GetUserList 获取用户列表 并且可以根据用户ID获取下级用户
  46. func GetUserList(req *entity.UserReq) []*entity.UserListResp {
  47. collection := mdb.MDB.Collection(constant.CNamePlayer)
  48. filter := bson.M{}
  49. if req.Pid != "" {
  50. filter["pid"] = req.Pid
  51. }
  52. if req.UserName != "" {
  53. //filter["nickName"] = primitive.Regex{Pattern: fmt.Sprintf(".*%s.*", req.UserName), Options: "i"}
  54. filter["nickName"] = req.UserName
  55. }
  56. if req.RangeStart != 0 && req.RangeEnd != 0 {
  57. filter["createTime"] = bson.M{
  58. "$gte": req.RangeStart,
  59. "$lte": req.RangeEnd,
  60. }
  61. }
  62. if req.UserID != "" {
  63. filter["userName"] = req.UserID
  64. }
  65. if req.Tag != "" {
  66. filter["tag"] = req.Tag
  67. }
  68. if req.LoginIp != "" {
  69. filter["loginIp"] = req.LoginIp
  70. }
  71. if req.TagType == 1 {
  72. filter["pid"] = ""
  73. }
  74. // 分页参数
  75. skip := (req.Page - 1) * req.Size
  76. // 执行查询
  77. opts := options.Find()
  78. // 根据指定字段和排序类型做排序
  79. sort := bson.D{}
  80. if req.OrderColumn != "" && req.OrderType != "" {
  81. sort = bson.D{{req.OrderColumn, req.OrderType}}
  82. opts.SetSort(sort)
  83. }
  84. opts.SetSkip(int64(skip))
  85. opts.SetLimit(int64(req.Size))
  86. cursor, err := collection.Find(context.Background(), filter, opts)
  87. count, _ := collection.CountDocuments(context.Background(), filter)
  88. if err != nil {
  89. return nil
  90. }
  91. defer cursor.Close(context.Background())
  92. var result []*entity.UserListResp
  93. for cursor.Next(context.Background()) {
  94. var account *models.Player
  95. if err := cursor.Decode(&account); err != nil {
  96. return nil
  97. }
  98. var totalPlan int
  99. var curPlan int
  100. ids := []int{1000, 1001}
  101. for _, item := range account.FirstClaimReward {
  102. totalPlan++
  103. id := item.Reward[0].ItemID
  104. if slices.Contains(ids, id) {
  105. continue
  106. }
  107. if item.IsClaim == 1 {
  108. curPlan++
  109. }
  110. }
  111. var tagNum int // 下级及下级以下
  112. var subNum int // 下级
  113. var inviteTreeKey string
  114. if account.TopPid != "" {
  115. // 非一级
  116. inviteTreeKey = fmt.Sprintf("%v:%v", constant.InviteTreeKey, account.TopPid)
  117. } else {
  118. // 一级
  119. inviteTreeKey = fmt.Sprintf("%v:%v", constant.InviteTreeKey, account.UserName)
  120. }
  121. treeJson, _ := mdb.RDB.Get(context.Background(), inviteTreeKey).Result()
  122. if treeJson != "" {
  123. var treeInfo *tree.TreeNode
  124. jsoniter.Unmarshal([]byte(treeJson), &treeInfo)
  125. tagNum = treeInfo.CountAllChildren(account.UserName)
  126. subNum = treeInfo.CountDirectChildren(account.UserName)
  127. }
  128. var num int64
  129. var tag int
  130. if value, ok := account.Item[0]; ok {
  131. num = value.Num
  132. }
  133. if account.Pid == "" {
  134. tag = 1
  135. }
  136. result = append(result, &entity.UserListResp{
  137. UserName: account.UserName,
  138. OpenId: account.OpenId,
  139. UserNameMaybe: account.UserNameMaybe,
  140. NickName: account.NickName,
  141. Pid: account.Pid,
  142. XID: account.XID,
  143. TonWall: account.TonWall,
  144. Email: account.Email,
  145. Mobile: account.Mobile,
  146. Avatar: account.Avatar,
  147. IsCashOut: account.IsCashOut,
  148. IsRobot: account.IsRobot,
  149. IsLeader: account.IsLeader,
  150. IsVip: account.IsVip,
  151. IsFirstBindingXID: account.IsFirstBindingXID,
  152. Level: account.Level,
  153. Exp: account.Exp,
  154. Gender: account.Gender,
  155. Birthday: account.Birthday,
  156. Successions: account.Successions,
  157. MaxSuccessions: account.MaxSuccessions,
  158. PrevTime: account.PrevTime,
  159. LoginTime: account.LoginTime,
  160. LoginIP: account.LoginIP,
  161. LoginFailure: account.LoginFailure,
  162. JoinIP: account.JoinIP,
  163. Rank: account.Rank,
  164. JoinTime: account.JoinTime,
  165. CreateTime: account.CreateTime,
  166. UpdateTime: account.UpdateTime,
  167. DailyRefreshTime: account.DailyRefreshTime,
  168. HourRefreshTime: account.HourRefreshTime,
  169. WeeklyRefreshTime: account.WeeklyRefreshTime,
  170. RollDay: account.RollDay,
  171. Status: account.Status,
  172. TagNum: tagNum,
  173. SubNum: subNum,
  174. Total: count,
  175. CurPlan: curPlan,
  176. TotalPlan: totalPlan,
  177. Tag: tag,
  178. Score: int64(num),
  179. })
  180. }
  181. // todo 修复数据
  182. //go repairData()
  183. return result
  184. }
  185. // 修复数据
  186. func repairData() {
  187. clog.Debugf("repairData start =>")
  188. collection := mdb.MDB.Collection(constant.CNamePlayer)
  189. filter := bson.M{}
  190. filter["pid"] = ""
  191. opts := options.Find()
  192. cursor, _ := collection.Find(context.Background(), filter, opts)
  193. defer cursor.Close(context.Background())
  194. var rows int
  195. for cursor.Next(context.Background()) {
  196. var account *models.Player
  197. if err := cursor.Decode(&account); err != nil {
  198. return
  199. }
  200. if account.Pid != "" {
  201. continue
  202. }
  203. rangeKey := fmt.Sprintf("%v:%v:%v", constant.InviteKey, 2, account.UserName)
  204. child, _ := mdb.RDB.LLen(context.Background(), rangeKey).Uint64()
  205. if child == 0 {
  206. continue
  207. }
  208. subordinatesTree, err := GetSubordinatesTree(account.UserName)
  209. if err != nil {
  210. clog.Error("repairData GetSubordinatesTree execute Fail ", err)
  211. }
  212. treeJson, err := jsoniter.MarshalToString(subordinatesTree)
  213. inviteTreeKey := fmt.Sprintf("%v:%v", constant.InviteTreeKey, account.UserName)
  214. mdb.RDB.Set(context.Background(), inviteTreeKey, treeJson, 0)
  215. clog.Debugf("tree: \n\n %v", treeJson)
  216. rows++
  217. }
  218. clog.Debugf("repairData end => repair rows: %v", rows)
  219. }
  220. // GetSubordinatesTree 递归查询某个用户的所有下级用户树结构
  221. func GetSubordinatesTree(userID string) (*tree.TreeNode, error) {
  222. var root *tree.TreeNode
  223. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  224. defer cancel()
  225. collection := mdb.MDB.Collection(constant.CNamePlayer)
  226. // 查询直接下级用户
  227. cursor, err := collection.Find(ctx, bson.M{"pid": userID})
  228. if err != nil {
  229. return nil, err
  230. }
  231. defer cursor.Close(ctx)
  232. for cursor.Next(ctx) {
  233. var player models.Player
  234. if err := cursor.Decode(&player); err != nil {
  235. return nil, err
  236. }
  237. childNode := tree.NewTreeNode(player.UserName)
  238. if root == nil {
  239. root = tree.NewTreeNode(userID)
  240. }
  241. root.Children = append(root.Children, childNode)
  242. // 递归查询下级的下级用户
  243. subTree, err := GetSubordinatesTree(player.UserName)
  244. if err != nil {
  245. return nil, err
  246. }
  247. if subTree != nil {
  248. childNode.Children = subTree.Children
  249. }
  250. }
  251. return root, nil
  252. }