synthesis.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. package service
  2. import (
  3. "context"
  4. "math"
  5. "time"
  6. mhayaTime "github.com/mhaya/extend/time"
  7. "github.com/mhaya/game/game_cluster/internal/code"
  8. "github.com/mhaya/game/game_cluster/internal/constant"
  9. "github.com/mhaya/game/game_cluster/internal/mdb"
  10. "github.com/mhaya/game/game_cluster/internal/mdb/models"
  11. "github.com/mhaya/game/game_cluster/nodes/webadmin/common"
  12. "github.com/mhaya/game/game_cluster/nodes/webadmin/entity"
  13. "github.com/mhaya/game/game_cluster/nodes/webadmin/model"
  14. mhayaLogger "github.com/mhaya/logger"
  15. "github.com/spf13/cast"
  16. "go.mongodb.org/mongo-driver/bson"
  17. "go.mongodb.org/mongo-driver/bson/primitive"
  18. "go.mongodb.org/mongo-driver/mongo"
  19. "go.mongodb.org/mongo-driver/mongo/options"
  20. )
  21. type Synthesis struct {
  22. db *mongo.Database
  23. }
  24. func NewSynthesis() *Synthesis {
  25. return &Synthesis{
  26. db: mdb.MDB,
  27. }
  28. }
  29. // 统计用户相关信息
  30. func (s *Synthesis) UserList(req entity.UserListReq) (*entity.UserListResp, *code.Result) {
  31. // 验证参数
  32. page := req.Page
  33. if req.Page <= 0 {
  34. page = 1
  35. }
  36. pageSize := req.Size
  37. if req.Size <= 0 {
  38. pageSize = 10
  39. }
  40. // 构建查询条件
  41. filter := bson.M{}
  42. if req.UserName != "" {
  43. filter["userName"] = req.UserName
  44. }
  45. if req.NickName != "" {
  46. filter["nickName"] = req.NickName
  47. }
  48. // 设置分页选项
  49. findOptions := options.Find()
  50. findOptions.SetSkip(int64((page - 1) * pageSize))
  51. findOptions.SetLimit(int64(pageSize))
  52. findOptions.SetSort(bson.D{{"createTime", -1}})
  53. collection := mdb.MDB.Collection(constant.CNamePlayer)
  54. // 获取总数total
  55. count, err := collection.CountDocuments(ctx, filter)
  56. if err != nil {
  57. mhayaLogger.Warnf("UserList CountDocuments error:%v", err)
  58. return nil, common.NewResult(code.InternalError)
  59. }
  60. // TODO UserList 统计用户相关信息
  61. // 查询数据
  62. var results []*entity.UserListDetail
  63. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  64. defer cancel()
  65. cursor, err := collection.Find(ctx, filter, findOptions)
  66. if err != nil {
  67. mhayaLogger.Warnf("UserList Find error:%v", err)
  68. return nil, common.NewResult(code.InternalError)
  69. }
  70. defer cursor.Close(ctx)
  71. // 解析结果
  72. for cursor.Next(ctx) {
  73. var result entity.UserListDetail
  74. if err := cursor.Decode(&result); err != nil {
  75. mhayaLogger.Warnf("UserList Decode error:%v", err)
  76. return nil, common.NewResult(code.InternalError)
  77. }
  78. results = append(results, &result)
  79. }
  80. if err := cursor.Err(); err != nil {
  81. mhayaLogger.Warnf("UserList cursor error:%v", err)
  82. return nil, common.NewResult(code.InternalError)
  83. }
  84. return &entity.UserListResp{
  85. Details: results,
  86. Total: count,
  87. }, nil
  88. }
  89. func (s *Synthesis) FindMDBUserLogDaily(req entity.UserLogDailyReq) (*entity.UserLogDailyResp, *code.Result) {
  90. // 定义上下文
  91. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  92. defer cancel()
  93. // 指定集合
  94. collection := mdb.MDB.Collection(constant.CNamePlayerDailyRecord)
  95. // 构建查询条件 - 如果查询值为空那就不添加查询条件
  96. filter := bson.M{}
  97. if req.StartTime != 0 {
  98. filter["daily"] = bson.M{
  99. "$gte": req.StartTime,
  100. "$lte": req.EndTime,
  101. }
  102. }
  103. if req.Platform != "" && req.Platform != "all" {
  104. filter["platform"] = req.Platform
  105. }
  106. if req.Channel != "" {
  107. filter["channel"] = req.Channel
  108. }
  109. // 分页参数
  110. skip := (req.Page - 1) * req.Size
  111. // 计算总数
  112. count, err := collection.CountDocuments(ctx, filter)
  113. if err != nil {
  114. mhayaLogger.Warnf("FindMDBUserLogDaily CountDocuments error:%v", err)
  115. return nil, common.NewResult(code.InternalError)
  116. }
  117. // 执行查询
  118. opts := options.Find()
  119. opts.SetSkip(int64(skip))
  120. opts.SetLimit(int64(req.Size))
  121. opts.SetSort(bson.D{{"daily", -1}})
  122. cursor, err := collection.Find(ctx, filter, opts)
  123. if err != nil {
  124. mhayaLogger.Warnf("FindMDBUserLogDaily Find error:%v", err)
  125. return nil, common.NewResult(code.InternalError)
  126. }
  127. defer cursor.Close(ctx)
  128. // 解析查询结果
  129. var results []*entity.UserLogDailyDetail
  130. for cursor.Next(ctx) {
  131. var result *entity.UserLogDailyDetail
  132. err := cursor.Decode(&result)
  133. if err != nil {
  134. mhayaLogger.Warnf("FindMDBUserLogDaily Decode error:%v", err)
  135. return nil, common.NewResult(code.InternalError)
  136. }
  137. results = append(results, result)
  138. }
  139. // 同一天的数据全部放到platform= ALl 且数据累加
  140. // 如果没有platform=all 的那就新增一个 同一个时间段只能有一个 platform=all
  141. // 将同一天的数据累加到platform=all的记录中
  142. allPlatformRecordMap := make(map[int64]*entity.UserLogDailyDetail)
  143. for _, result := range results {
  144. allPlatformRecordMap[result.Timestamp] = &entity.UserLogDailyDetail{
  145. Timestamp: result.Timestamp,
  146. Platform: "all",
  147. }
  148. }
  149. for _, v := range results {
  150. if v.Timestamp == allPlatformRecordMap[v.Timestamp].Timestamp {
  151. allPlatformRecordMap[v.Timestamp].Registered += v.Registered
  152. allPlatformRecordMap[v.Timestamp].LoggedIn += v.LoggedIn
  153. allPlatformRecordMap[v.Timestamp].NewActive += v.NewActive
  154. allPlatformRecordMap[v.Timestamp].OldActive += v.OldActive
  155. allPlatformRecordMap[v.Timestamp].TotalPoints += v.TotalPoints
  156. allPlatformRecordMap[v.Timestamp].UProduced += v.UProduced
  157. allPlatformRecordMap[v.Timestamp].UCashout += v.UCashout
  158. allPlatformRecordMap[v.Timestamp].NewLogin += v.NewLogin
  159. allPlatformRecordMap[v.Timestamp].OldLogin += v.OldLogin
  160. }
  161. }
  162. // 替换原有结果
  163. for _, record := range allPlatformRecordMap {
  164. results = append(results, record)
  165. }
  166. return &entity.UserLogDailyResp{
  167. Details: results,
  168. Total: count,
  169. }, nil
  170. }
  171. // FindWithdrawal 根据请求查询提现记录
  172. func (s *Synthesis) FindWithdrawal(req entity.UserWithdrawalReq) (*entity.UserWithdrawalResp, *code.Result) {
  173. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  174. defer cancel()
  175. collection := mdb.MDB.Collection(constant.CNameCashOutRecord)
  176. // 构建过滤器
  177. filter := bson.M{}
  178. if req.UserName != "" {
  179. filter["userName"] = req.UserName
  180. }
  181. if req.NickName != "" {
  182. filter["nickName"] = req.NickName
  183. }
  184. if req.ID != "" {
  185. filter["_id"], _ = primitive.ObjectIDFromHex(req.ID)
  186. }
  187. if req.Address != "" {
  188. filter["address"] = req.Address
  189. }
  190. if req.State > 0 {
  191. filter["state"] = req.State
  192. }
  193. if req.Withdrawal > 0 {
  194. filter["withdrawal"] = req.Withdrawal
  195. }
  196. if req.StartTime > 0 && req.EndTime > 0 && req.StartTime <= req.EndTime {
  197. filter["createAt"] = bson.M{
  198. "$gte": req.StartTime,
  199. "$lte": req.EndTime,
  200. }
  201. }
  202. if req.AmountMin > 0 && req.AmountMax > 0 && req.AmountMin <= req.AmountMax {
  203. filter["amount"] = bson.M{
  204. "$gte": req.AmountMin,
  205. "$lte": req.AmountMax,
  206. }
  207. }
  208. if req.AfterAmountMin > 0 && req.AfterAmountMax > 0 && req.AfterAmountMin <= req.AfterAmountMax {
  209. filter["after_amount"] = bson.M{
  210. "$gte": req.AfterAmountMin,
  211. "$lte": req.AfterAmountMax,
  212. }
  213. }
  214. // 设置分页选项
  215. findOptions := options.Find()
  216. findOptions.SetSkip(int64((req.Page - 1) * req.Size))
  217. findOptions.SetLimit(int64(req.Size))
  218. findOptions.SetSort(bson.D{{"createAt", -1}})
  219. // 获取总数total
  220. count, err := collection.CountDocuments(ctx, filter)
  221. if err != nil {
  222. mhayaLogger.Warnf("FindWithdrawal CountDocuments error:%v", err)
  223. return nil, common.NewResult(code.InternalError)
  224. }
  225. // 查询数据
  226. var results []*entity.UserWithdrawalDetail
  227. cursor, err := collection.Find(ctx, filter, findOptions)
  228. if err != nil {
  229. mhayaLogger.Warnf("FindWithdrawal Find error:%v", err)
  230. return nil, common.NewResult(code.InternalError)
  231. }
  232. defer cursor.Close(ctx)
  233. // 解析结果
  234. for cursor.Next(ctx) {
  235. var result entity.UserWithdrawalDetail
  236. if err := cursor.Decode(&result); err != nil {
  237. mhayaLogger.Warnf("FindWithdrawal Decode error:%v", err)
  238. return nil, common.NewResult(code.InternalError)
  239. }
  240. results = append(results, &result)
  241. }
  242. if err := cursor.Err(); err != nil {
  243. mhayaLogger.Warnf("FindWithdrawal cursor error:%v", err)
  244. return nil, common.NewResult(code.InternalError)
  245. }
  246. return &entity.UserWithdrawalResp{
  247. Details: results,
  248. Total: count,
  249. }, nil
  250. }
  251. // 导出提现记录
  252. func (s *Synthesis) WithdrawalExport(req entity.UserWithdrawalExportReq) (*entity.UserWithdrawalResp, *code.Result) {
  253. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  254. defer cancel()
  255. collection := mdb.MDB.Collection(constant.CNameCashOutRecord)
  256. // 构建过滤器
  257. filter := bson.M{}
  258. if req.UserName != "" {
  259. filter["userName"] = req.UserName
  260. }
  261. if req.NickName != "" {
  262. filter["nickName"] = req.NickName
  263. }
  264. if req.ID != "" {
  265. filter["_id"], _ = primitive.ObjectIDFromHex(req.ID)
  266. }
  267. if req.Address != "" {
  268. filter["address"] = req.Address
  269. }
  270. if req.State > 0 {
  271. filter["state"] = req.State
  272. }
  273. if req.Withdrawal > 0 {
  274. filter["withdrawal"] = req.Withdrawal
  275. }
  276. if req.StartTime > 0 && req.EndTime > 0 && req.StartTime <= req.EndTime {
  277. filter["createAt"] = bson.M{
  278. "$gte": req.StartTime,
  279. "$lte": req.EndTime,
  280. }
  281. }
  282. if req.AmountMin > 0 && req.AmountMax > 0 && req.AmountMin <= req.AmountMax {
  283. filter["amount"] = bson.M{
  284. "$gte": req.AmountMin,
  285. "$lte": req.AmountMax,
  286. }
  287. }
  288. if req.AfterAmountMin > 0 && req.AfterAmountMax > 0 && req.AfterAmountMin <= req.AfterAmountMax {
  289. filter["after_amount"] = bson.M{
  290. "$gte": req.AfterAmountMin,
  291. "$lte": req.AfterAmountMax,
  292. }
  293. }
  294. findOptions := options.Find()
  295. findOptions.SetSort(bson.D{{"createAt", -1}})
  296. // 获取总数total
  297. count, err := collection.CountDocuments(ctx, filter)
  298. if err != nil {
  299. mhayaLogger.Warnf("WithdrawalExportData CountDocuments error:%v", err)
  300. return nil, common.NewResult(code.InternalError)
  301. }
  302. // 查询数据
  303. var results []*entity.UserWithdrawalDetail
  304. cursor, err := collection.Find(ctx, filter, findOptions)
  305. if err != nil {
  306. mhayaLogger.Warnf("WithdrawalExportData Find error:%v", err)
  307. return nil, common.NewResult(code.InternalError)
  308. }
  309. defer cursor.Close(ctx)
  310. // 解析结果
  311. for cursor.Next(ctx) {
  312. var result entity.UserWithdrawalDetail
  313. if err := cursor.Decode(&result); err != nil {
  314. mhayaLogger.Warnf("WithdrawalExportData Decode error:%v", err)
  315. return nil, common.NewResult(code.InternalError)
  316. }
  317. results = append(results, &result)
  318. }
  319. if err := cursor.Err(); err != nil {
  320. mhayaLogger.Warnf("WithdrawalExportData cursor error:%v", err)
  321. return nil, common.NewResult(code.InternalError)
  322. }
  323. return &entity.UserWithdrawalResp{
  324. Details: results,
  325. Total: count,
  326. }, nil
  327. }
  328. // WithdrawalStatus 更新提现状态
  329. func (s *Synthesis) WithdrawalStatus(req entity.UserWithdrawalStatus) *code.Result {
  330. // ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  331. // defer cancel()
  332. collection := mdb.MDB.Collection(constant.CNameCashOutRecord)
  333. // 更新条件
  334. updateCondition := bson.M{"userName": req.UserName}
  335. // 更新内容
  336. updateContent := bson.M{"$set": bson.M{"status": req.Status}}
  337. // 设置更新选项
  338. updateOptions := options.Update() // 设置 upsert 选项
  339. // 执行更新操作
  340. _, err := collection.UpdateOne(context.TODO(), updateCondition, updateContent, updateOptions)
  341. if err != nil {
  342. mhayaLogger.Warnf("WithdrawalStatus UpdateOne error:%v", err)
  343. return common.NewResult(code.InternalError)
  344. }
  345. return nil
  346. }
  347. // WithdrawalStatusBatch 更新提现状态
  348. func (s *Synthesis) WithdrawalStatusBatch(req entity.UserWithdrawalStatusBatch) *code.Result {
  349. collection := mdb.MDB.Collection(constant.CNameCashOutRecord)
  350. if len(req.ID) == 0 {
  351. return common.NewResult(code.ParamError)
  352. }
  353. for _, id := range req.ID {
  354. objID := primitive.ObjectID{}
  355. objID, _ = primitive.ObjectIDFromHex(id)
  356. updateCondition := bson.M{"_id": objID}
  357. updateContent := bson.M{}
  358. withdrawal := models.CashOutRecord{}
  359. err := collection.FindOne(context.TODO(), updateCondition).Decode(&withdrawal)
  360. if err != nil {
  361. mhayaLogger.Warnf("WithdrawalStatusBatch FindOne error:%v", err)
  362. continue
  363. }
  364. if req.Withdrawal != 0 {
  365. if withdrawal.Status == 1 {
  366. updateContent = bson.M{"$set": bson.M{"withdrawal": req.Withdrawal}}
  367. } else {
  368. continue
  369. }
  370. }
  371. if req.Status > 0 {
  372. if withdrawal.Status != 0 {
  373. continue
  374. }
  375. updateContent = bson.M{"$set": bson.M{"status": req.Status}}
  376. }
  377. updateOptions := options.Update().SetUpsert(true)
  378. _, err = collection.UpdateOne(context.TODO(), updateCondition, updateContent, updateOptions)
  379. if err != nil {
  380. mhayaLogger.Warnf("WithdrawalStatusBatch UpdateOne error:%v", err)
  381. continue
  382. }
  383. }
  384. return nil
  385. }
  386. // FindUserCountryCount 查询用户国家分布
  387. //
  388. // 返回值为 UserCountryResp 的切片和错误。
  389. func (s *Synthesis) FindUserCountryCount() (*entity.UserCountryResp, *code.Result) {
  390. // 选择数据库和集合
  391. collection := mdb.MDB.Collection(constant.CNamePlayerCountryByIPStat)
  392. // 定义聚合管道
  393. // 定义聚合管道
  394. pipeline := []bson.D{
  395. {
  396. {Key: "$project", Value: bson.D{
  397. {Key: "playerRegisterCountry", Value: bson.D{{Key: "$objectToArray", Value: "$playerRegisterCountry"}}},
  398. }},
  399. },
  400. {
  401. {Key: "$unwind", Value: "$playerRegisterCountry"},
  402. },
  403. {
  404. {Key: "$group", Value: bson.D{
  405. {Key: "_id", Value: "$playerRegisterCountry.k"},
  406. {Key: "totalValue", Value: bson.D{{Key: "$sum", Value: "$playerRegisterCountry.v"}}},
  407. }},
  408. },
  409. {
  410. {Key: "$project", Value: bson.D{
  411. {Key: "_id", Value: 0},
  412. {Key: "countryKey", Value: "$_id"},
  413. {Key: "totalValue", Value: 1},
  414. }},
  415. },
  416. }
  417. // 执行聚合查询
  418. cursor, err := collection.Aggregate(context.TODO(), pipeline)
  419. if err != nil {
  420. mhayaLogger.Warnf("FindUserCountryCount Aggregate error:%v", err)
  421. return nil, common.NewResult(code.InternalError)
  422. }
  423. defer cursor.Close(context.TODO())
  424. // 遍历查询结果
  425. var results []bson.M
  426. if err := cursor.All(context.TODO(), &results); err != nil {
  427. mhayaLogger.Warnf("FindUserCountryCount All error:%v", err)
  428. return nil, common.NewResult(code.InternalError)
  429. }
  430. var totalIPCount int64
  431. var data []*entity.UserCountryDetail
  432. // 将结果转换为 UserCountryDetail
  433. for _, r := range results {
  434. var resp entity.UserCountryDetail
  435. resp.Country = r["countryKey"].(string)
  436. resp.IPCount = int(r["totalValue"].(int32))
  437. totalIPCount += int64(resp.IPCount)
  438. data = append(data, &resp)
  439. }
  440. for _, v := range data {
  441. // 保留小数点后两位
  442. v.Percentage = math.Round(float64(v.IPCount)/float64(totalIPCount)*10000) / 100
  443. }
  444. // 根据阈值过滤结果
  445. otherCount := 0
  446. otherPercentage := 0.00
  447. filteredResults := make([]*entity.UserCountryDetail, 0)
  448. threshold := 1.00
  449. for _, r := range data {
  450. if r.Percentage >= threshold {
  451. filteredResults = append(filteredResults, r)
  452. // 保留小数点后两位
  453. r.Percentage = math.Round(r.Percentage*100) / 100
  454. otherPercentage += r.Percentage
  455. } else {
  456. otherCount += r.IPCount
  457. }
  458. }
  459. // 将其他国家添加到过滤后的结果中
  460. if otherCount > 0 {
  461. p := 100.00 - math.Round(otherPercentage*100)/100
  462. filteredResults = append(filteredResults, &entity.UserCountryDetail{
  463. Country: "other",
  464. IPCount: otherCount,
  465. Percentage: math.Round(p*100) / 100,
  466. })
  467. }
  468. return &entity.UserCountryResp{
  469. Details: filteredResults,
  470. }, nil
  471. }
  472. // FindUserRetention UserRetentionResp 用户留存率
  473. // 1. 获取指定日期范围内的注册用户数量
  474. // 2. 获取指定日期范围内的活跃用户数量
  475. // 3. 计算留存率
  476. // 4. 返回结果
  477. func (s *Synthesis) FindUserRetention(req entity.UserRetentionReq) (*entity.UserRetentionResp, *code.Result) {
  478. playerPreserve := models.GetPlayerPreserve(req.StartTime, req.EndTime)
  479. // 查询数据
  480. var results []*entity.UserRetentionDetail
  481. for key, v := range playerPreserve {
  482. var retention entity.Retention
  483. for _, vv := range v {
  484. if vv.ID == 1 {
  485. retention.Day1 = entity.DayRetention{
  486. LoggedIn: vv.Ratio,
  487. LoginDate: key,
  488. }
  489. }
  490. if vv.ID == 3 {
  491. retention.Day3 = entity.DayRetention{
  492. LoggedIn: vv.Ratio,
  493. LoginDate: key,
  494. }
  495. }
  496. if vv.ID == 7 {
  497. retention.Day7 = entity.DayRetention{
  498. LoggedIn: vv.Ratio,
  499. LoginDate: key,
  500. }
  501. }
  502. if vv.ID == 14 {
  503. retention.Day14 = entity.DayRetention{
  504. LoggedIn: vv.Ratio,
  505. LoginDate: key,
  506. }
  507. }
  508. if vv.ID == 30 {
  509. retention.Day30 = entity.DayRetention{
  510. LoggedIn: vv.Ratio,
  511. LoginDate: key,
  512. }
  513. }
  514. }
  515. results = append(results, &entity.UserRetentionDetail{
  516. RegistrationDate: key,
  517. RetentionData: retention,
  518. })
  519. }
  520. return &entity.UserRetentionResp{
  521. Details: results,
  522. }, nil
  523. }
  524. // FindUserLevel 用户等级统计
  525. func (s *Synthesis) FindUserLevel() (*entity.UserLevelCountResp, *code.Result) {
  526. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  527. defer cancel()
  528. collection := mdb.MDB.Collection(constant.CNamePlayerLevelStat)
  529. // 查询所有文档
  530. cursor, err := collection.Find(ctx, bson.M{})
  531. if err != nil {
  532. mhayaLogger.Warnf("FindUserLevel Find error:%v", err)
  533. return nil, common.NewResult(code.InternalError)
  534. }
  535. defer cursor.Close(ctx)
  536. var results []*entity.UserLevelCountDetail
  537. var reData []*models.PlayerLevelStat
  538. for cursor.Next(ctx) {
  539. var result models.PlayerLevelStat
  540. if err := cursor.Decode(&result); err != nil {
  541. mhayaLogger.Warnf("FindUserLevel Decode error:%v", err)
  542. return nil, common.NewResult(code.InternalError)
  543. }
  544. reData = append(reData, &result)
  545. }
  546. if err := cursor.Err(); err != nil {
  547. mhayaLogger.Warnf("FindUserLevel cursor error:%v", err)
  548. return nil, common.NewResult(code.InternalError)
  549. }
  550. dataMap := make(map[string]int)
  551. for _, v := range reData {
  552. for key, v1 := range v.ServerLevel {
  553. dataMap[key] += v1
  554. }
  555. }
  556. for k, v := range dataMap {
  557. results = append(results, &entity.UserLevelCountDetail{
  558. Level: cast.ToInt(k),
  559. UserCount: v,
  560. })
  561. }
  562. return &entity.UserLevelCountResp{
  563. Details: results,
  564. }, nil
  565. }
  566. func (s *Synthesis) InsertRecord(param model.UserOperationLog) {
  567. mhayaLogger.Warnf("InsertRecord param:%#v", param)
  568. record := new(model.UserOperationLog)
  569. collection := mdb.MDB.Collection(record.TableName())
  570. insertData := bson.M{}
  571. insertData["user_name"] = param.Username
  572. insertData["role_id"] = param.RoleId
  573. insertData["url"] = param.Path
  574. insertData["method"] = param.Method
  575. insertData["status_code"] = param.StatusCode
  576. insertData["dur"] = param.Dur
  577. insertData["client_ip"] = param.ClientIP
  578. insertData["error_message"] = param.ErrorMessage
  579. insertData["created_at"] = mhayaTime.Now().Unix()
  580. _, err := collection.InsertOne(context.Background(), insertData)
  581. if err != nil {
  582. mhayaLogger.Warnf("InsertRecord InsertOne error:%v", err)
  583. return
  584. }
  585. }
  586. func (s *Synthesis) RecordList(req entity.RecordListReq) (*entity.RecordListResp, *code.Result) {
  587. record := new(model.UserOperationLog)
  588. collection := mdb.MDB.Collection(record.TableName())
  589. // 构建过滤器
  590. filter := bson.M{}
  591. if req.UserName != "" {
  592. filter["userName"] = req.UserName
  593. }
  594. if req.RoleId != "" {
  595. filter["role_id"] = req.RoleId
  596. }
  597. if req.ID != "" {
  598. id, err := primitive.ObjectIDFromHex(req.ID)
  599. if err != nil {
  600. mhayaLogger.Warnf("RecordList ObjectIDFromHex error:%v, req.ID:%s", err, req.ID)
  601. return nil, common.NewResult(code.ParamError)
  602. }
  603. filter["id"] = id
  604. }
  605. if req.StartTime != 0 {
  606. filter["createAt"] = bson.M{
  607. "$gte": req.StartTime,
  608. "$lte": req.EndTime,
  609. }
  610. }
  611. // 设置分页选项
  612. findOptions := options.Find()
  613. findOptions.SetSkip(int64((req.Page - 1) * req.Size))
  614. findOptions.SetLimit(int64(req.Size))
  615. findOptions.SetSort(bson.D{{"created_at", -1}})
  616. // 获取总数total
  617. ctx, cancel := context.WithTimeout(context.Background(), 100*time.Second)
  618. defer cancel()
  619. count, err := collection.CountDocuments(ctx, filter)
  620. if err != nil {
  621. mhayaLogger.Warnf("RecordList CountDocuments error:%v", err)
  622. return nil, common.NewResult(code.InternalError)
  623. }
  624. // 查询数据
  625. var results []*entity.RecordListDetail
  626. cursor, err := collection.Find(ctx, filter, findOptions)
  627. if err != nil {
  628. mhayaLogger.Warnf("RecordList Find error:%v", err)
  629. return nil, common.NewResult(code.InternalError)
  630. }
  631. defer cursor.Close(ctx)
  632. // 解析结果
  633. for cursor.Next(ctx) {
  634. var result entity.RecordListDetail
  635. if err := cursor.Decode(&result); err != nil {
  636. mhayaLogger.Warnf("RecordList Decode error:%v", err)
  637. return nil, common.NewResult(code.InternalError)
  638. }
  639. results = append(results, &result)
  640. }
  641. if err := cursor.Err(); err != nil {
  642. mhayaLogger.Warnf("RecordList cursor error:%v", err)
  643. return nil, common.NewResult(code.InternalError)
  644. }
  645. return &entity.RecordListResp{
  646. Details: results,
  647. Total: count,
  648. }, nil
  649. }
  650. // 转盘统计
  651. func (s *Synthesis) Turntable(req entity.TurntableReq) (*entity.TurntableResp, *code.Result) {
  652. // TODO Turntable 转盘统计
  653. return nil, nil
  654. }
  655. // 资产统计
  656. func (s *Synthesis) Assets(req entity.AssetsReq) (*entity.AssetsResp, *code.Result) {
  657. // TODO Assets 资产统计
  658. return nil, nil
  659. }
  660. // 邀请统计
  661. func (s *Synthesis) Invite(req entity.InviteReq) (*entity.InviteResp, *code.Result) {
  662. // TODO Invite 邀请统计
  663. return nil, nil
  664. }