gameAction.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. package v1
  2. import (
  3. "designs/app/common/request"
  4. "designs/app/common/response"
  5. "designs/global"
  6. "designs/model"
  7. "designs/utils"
  8. "fmt"
  9. "github.com/gin-gonic/gin"
  10. "github.com/pkg/errors"
  11. "sort"
  12. "strconv"
  13. "strings"
  14. "time"
  15. )
  16. func UserActionList(c *gin.Context) {
  17. form := request.Check(c, &struct {
  18. Gid string `form:"gid" binding:"required"`
  19. Pf []string `form:"pf" binding:""`
  20. StartTime string `form:"startTime" binding:"required"`
  21. EndTime string `form:"endTime" binding:"required"`
  22. }{})
  23. form.EndTime = form.EndTime + " 23:59:59"
  24. //查询出所有的事件
  25. var actionList []model.GameAction
  26. query := global.App.DB.Table("game_action")
  27. err := query.
  28. Where("gid", form.Gid).
  29. Select("id", "actionId", "actionName").
  30. Order("id desc").Scan(&actionList).Error
  31. if err != nil {
  32. response.Fail(c, 1003, err.Error())
  33. return
  34. }
  35. var optionIdList []int
  36. for _, v := range actionList {
  37. optionIdList = append(optionIdList, v.ID)
  38. }
  39. //查询出有无选项
  40. var optionIdList1 []int
  41. err = global.App.DB.Table("game_action_option").
  42. WhereIn("actionId", optionIdList).
  43. Distinct("actionId").
  44. Pluck("actionId", &optionIdList1).Error
  45. if err != nil {
  46. response.Fail(c, 1003, err.Error())
  47. return
  48. }
  49. //查出用户登录数据
  50. userLogin, err := GetUserLogin(form.Gid, form.StartTime, form.EndTime)
  51. userLoginCount := len(userLogin)
  52. //查询出时间段内事件触发数量,以及触发人的ID
  53. var userAction []model.UserAction
  54. query2 := global.App.DB.Table("user_action")
  55. //if len(form.Pf) > 0 {
  56. // query2 = query2.WhereIn("pf", form.Pf)
  57. //}
  58. err = query2.
  59. Where("gid", form.Gid).
  60. WhereIn("pf", form.Pf).
  61. Where("createdAt", ">=", form.StartTime).
  62. Where("createdAt", "<=", form.EndTime).
  63. Select("id", "actionId", "userId", "createdAt").
  64. Scan(&userAction).Error
  65. if err != nil {
  66. response.Fail(c, 1002, err.Error())
  67. return
  68. }
  69. //计算事件的触发总数和触发用户数
  70. actionSumMap := make(map[string]int)
  71. actionUserSumMap := make(map[string]map[int]bool)
  72. for _, action := range userAction {
  73. if actionUserSumMap[action.ActionId] == nil {
  74. actionUserSumMap[action.ActionId] = make(map[int]bool)
  75. }
  76. actionSumMap[action.ActionId]++
  77. actionUserSumMap[action.ActionId][action.UserId] = true
  78. }
  79. //根据事件触发和活跃用户数量进行比对得出其他数据
  80. activeUser := make(map[int]bool)
  81. var activeUserSlice []int
  82. for _, users := range userLogin {
  83. activeUser[users.UserId] = true
  84. }
  85. for k := range activeUser {
  86. activeUserSlice = append(activeUserSlice, k)
  87. }
  88. type responses struct {
  89. Id int `json:"id"`
  90. ActionId string `json:"actionId"`
  91. ActionName string `json:"actionName"`
  92. ActionCount int `json:"actionCount"`
  93. ActionUserCount int `json:"actionUserCount"`
  94. ActiveUserRate float64 `json:"activeUserRate"`
  95. LoginActiveRate float64 `json:"loginActiveRate"`
  96. HaveOption bool `json:"haveOption"`
  97. }
  98. var res []responses
  99. for _, v := range actionList {
  100. var ActiveUserRate float64
  101. var LoginActiveRate float64
  102. if userLoginCount > 0 {
  103. ActiveUserRate = DivideWithPrecision(actionSumMap[v.ActionId], userLoginCount)
  104. LoginActiveRate = DivideWithPrecision(len(actionUserSumMap[v.ActionId]), userLoginCount)
  105. }
  106. res = append(res, responses{
  107. Id: v.ID,
  108. ActionId: v.ActionId,
  109. ActionName: v.ActionName,
  110. ActionCount: actionSumMap[v.ActionId],
  111. ActionUserCount: len(actionUserSumMap[v.ActionId]),
  112. ActiveUserRate: ActiveUserRate,
  113. LoginActiveRate: LoginActiveRate,
  114. HaveOption: utils.InArray(v.ID, optionIdList1),
  115. })
  116. }
  117. response.Success(c, gin.H{
  118. "data": res,
  119. "count": len(res),
  120. })
  121. }
  122. func GetUserLogin(Gid string, StartTime string, EndTime string) ([]model.UserLogin, error) {
  123. //查询出时间段内的活跃用户,登录次数
  124. var userLogin []model.UserLogin
  125. query1 := global.App.DB.Table("user_login")
  126. //if len(form.Pf) > 0 {
  127. // query1 = query1.WhereIn("pf", form.Pf)
  128. //}
  129. err := query1.
  130. Where("gid", Gid).
  131. Where("loginTime", ">=", StartTime).
  132. Where("loginTime", "<=", EndTime).
  133. Select("userId", "loginTime").
  134. Distinct("userId").
  135. Scan(&userLogin).Error
  136. if err != nil {
  137. return userLogin, err
  138. }
  139. return userLogin, nil
  140. }
  141. func UserActionOptionList(c *gin.Context) {
  142. form := request.Check(c, &struct {
  143. Gid string `form:"gid" binding:"required"`
  144. ActionId string `form:"actionId" binding:"required"`
  145. StartTime string `form:"startTime" binding:"required"`
  146. EndTime string `form:"endTime" binding:"required"`
  147. }{})
  148. form.EndTime = form.EndTime + " 23:59:59"
  149. now := time.Now()
  150. //查出用户登录数据
  151. userLogin, err := GetUserLogin(form.Gid, form.StartTime, form.EndTime)
  152. if err != nil {
  153. response.Fail(c, 1003, err.Error())
  154. return
  155. }
  156. fmt.Println(time.Since(now))
  157. userLoginCount := len(userLogin)
  158. //查询出所有的事件选项
  159. var actionOption []struct {
  160. model.UserActionOption
  161. UserId int `json:"userId" gorm:"not null;column:userId;"`
  162. }
  163. err = global.App.DB.Table("user_action_option").
  164. LeftJoin("user_action", "user_action.id = user_action_option.UserActionId").
  165. Where("user_action.actionId", form.ActionId).
  166. Where("user_action.gid", form.Gid).
  167. Where("user_action.createdAt", ">=", form.StartTime).
  168. Where("user_action.createdAt", "<=", form.EndTime).
  169. Select("user_action_option.*", "user_action.userId").
  170. Scan(&actionOption).Error
  171. if err != nil {
  172. response.Fail(c, 1004, err.Error())
  173. return
  174. }
  175. fmt.Println(time.Since(now))
  176. //循环得出选项
  177. optionList := make(map[string]int)
  178. for _, v := range actionOption {
  179. optionList[v.OptionId+"|"+v.Value]++
  180. }
  181. //根据人数进行比对
  182. //计算事件的触发总数和触发用户数
  183. actionSumMap := make(map[string]int)
  184. actionUserSumMap := make(map[string]map[int]bool)
  185. for _, action := range actionOption {
  186. if actionUserSumMap[action.OptionId+"|"+action.Value] == nil {
  187. actionUserSumMap[action.OptionId+"|"+action.Value] = make(map[int]bool)
  188. }
  189. actionSumMap[action.OptionId+"|"+action.Value]++
  190. actionUserSumMap[action.OptionId+"|"+action.Value][action.UserId] = true
  191. }
  192. //根据事件触发和活跃用户数量进行比对得出其他数据
  193. activeUser := make(map[int]bool)
  194. var activeUserSlice []int
  195. for _, users := range userLogin {
  196. activeUser[users.UserId] = true
  197. }
  198. for k := range activeUser {
  199. activeUserSlice = append(activeUserSlice, k)
  200. }
  201. type responses struct {
  202. Id int `json:"id"`
  203. ActionId int `json:"actionId"`
  204. ActionName string `json:"actionName"`
  205. ActionCount int `json:"actionCount"`
  206. ActionUserCount int `json:"actionUserCount"`
  207. ActiveUserRate float64 `json:"activeUserRate"`
  208. LoginActiveRate float64 `json:"loginActiveRate"`
  209. }
  210. var res []responses
  211. var optionName []model.GameActionOption
  212. optionIdToName := make(map[string]string)
  213. global.App.DB.Table("game_action_option").
  214. LeftJoin("game_action", "game_action.id = game_action_option.actionId").
  215. Where("gid", form.Gid).
  216. Where("game_action.actionId", form.ActionId).
  217. Select("game_action_option.optionName", "game_action_option.actionId", "game_action_option.optionId").
  218. Scan(&optionName)
  219. for _, v := range optionName {
  220. optionIdToName[v.OptionId] = v.OptionName
  221. }
  222. fmt.Println(time.Since(now))
  223. for k, v := range optionList {
  224. var ActiveUserRate float64
  225. var LoginActiveRate float64
  226. if userLoginCount > 0 {
  227. ActiveUserRate = DivideWithPrecision(actionSumMap[k], userLoginCount)
  228. LoginActiveRate = DivideWithPrecision(len(actionUserSumMap[k]), userLoginCount)
  229. }
  230. optionId := strings.Split(k, "|")[0]
  231. value := strings.Split(k, "|")[1]
  232. valueInt, _ := strconv.Atoi(value)
  233. res = append(res, responses{
  234. ActionId: valueInt,
  235. ActionName: optionIdToName[optionId] + ":" + value,
  236. ActionCount: v,
  237. ActionUserCount: len(actionUserSumMap[k]),
  238. ActiveUserRate: ActiveUserRate,
  239. LoginActiveRate: LoginActiveRate,
  240. })
  241. }
  242. sort.Slice(res, func(i, j int) bool {
  243. return res[i].ActionId < res[j].ActionId // 正序规则:i的Age小于j时返回true
  244. })
  245. response.Success(c, gin.H{
  246. "data": res,
  247. "count": len(res),
  248. })
  249. }
  250. func DivideWithPrecision(a, b int) float64 {
  251. if b == 0 {
  252. panic("除数不能为零") // 实际项目中建议返回 error 类型
  253. }
  254. // 转换为浮点数再相除
  255. result := float64(a) / float64(b)
  256. // 格式化为三位小数并转换回 float64
  257. formatted, _ := strconv.ParseFloat(fmt.Sprintf("%.3f", result), 64)
  258. return formatted
  259. }
  260. func UserActionDetail(c *gin.Context) {
  261. form := request.Check(c, &struct {
  262. Id int `form:"id" binding:"required"`
  263. Pf []string `form:"pf" binding:""`
  264. StartTime string `form:"startTime" binding:"required"`
  265. EndTime string `form:"endTime" binding:"required"`
  266. }{})
  267. //查询启动次数
  268. var action model.GameAction
  269. err := global.App.DB.Table("game_action").
  270. Where("id", form.Id).Find(&action).Error
  271. if err != nil {
  272. response.Fail(c, 1001, err.Error())
  273. return
  274. }
  275. var userAction []struct {
  276. UserId int `json:"userId" gorm:"not null;column:userId;"`
  277. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  278. }
  279. err = global.App.DB.Table("user_action").
  280. Where("gid", action.Gid).
  281. Where("actionId", action.ActionId).
  282. Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
  283. Scan(&userAction).Error
  284. if err != nil {
  285. response.Fail(c, 1002, err.Error())
  286. return
  287. }
  288. //查询出时间段内的活跃用户,登录次数
  289. var userLogin []struct {
  290. UserId int `json:"userId" gorm:"not null;column:userId;"`
  291. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  292. }
  293. err = global.App.DB.Table("user_login").
  294. Where("gid", action.Gid).
  295. Where("loginTime", ">=", form.StartTime).
  296. Where("loginTime", "<=", form.EndTime).
  297. Select("userId", "DATE_FORMAT(loginTime, '%Y-%m-%d') as createdAt").
  298. Scan(&userLogin).Error
  299. if err != nil {
  300. response.Fail(c, 1001, err.Error())
  301. return
  302. }
  303. //userLoginCount := len(userLogin)
  304. activeCount := make(map[string]int)
  305. activeCountUser := make(map[string]map[int]bool)
  306. //根据日期进行分组
  307. for _, v := range userAction {
  308. activeCount[v.CreatedAt]++
  309. if activeCountUser[v.CreatedAt] == nil {
  310. activeCountUser[v.CreatedAt] = make(map[int]bool)
  311. }
  312. activeCountUser[v.CreatedAt][v.UserId] = true
  313. }
  314. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  315. type responses struct {
  316. Date string `json:"date"`
  317. ActiveCount int `json:"activeCount"`
  318. ActiveUserCount int `json:"activeUserCount"`
  319. ActiveCountRate float64 `json:"activeCountRate"`
  320. ActiveCountUser float64 `json:"activeCountUser"`
  321. }
  322. var res []responses
  323. //输出格式
  324. for _, v := range days {
  325. res = append(res, responses{
  326. Date: v,
  327. ActiveCount: activeCount[v],
  328. ActiveUserCount: len(activeCountUser[v]),
  329. ActiveCountRate: float64(activeCount[v] / 1),
  330. ActiveCountUser: float64(len(activeCountUser[v]) / 1),
  331. })
  332. }
  333. response.Success(c, gin.H{
  334. "data": res,
  335. })
  336. }
  337. func UserActionDetailDistribution(c *gin.Context) {
  338. form := request.Check(c, &struct {
  339. Id int `form:"id" binding:"required"`
  340. Pf []string `form:"pf" binding:""`
  341. StartTime string `form:"startTime" binding:"required"`
  342. EndTime string `form:"endTime" binding:"required"`
  343. Type int `form:"type" binding:"required"`
  344. }{})
  345. var action model.GameAction
  346. err := global.App.DB.Table("game_action").
  347. Where("id", form.Id).Find(&action).Error
  348. if err != nil {
  349. response.Fail(c, 1001, err.Error())
  350. return
  351. }
  352. res := make(map[string]interface{})
  353. if form.Type == 1 {
  354. var userAction []struct {
  355. UserId int `json:"userId" gorm:"not null;column:userId;"`
  356. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  357. }
  358. query := global.App.DB.Table("user_action")
  359. if len(form.Pf) > 0 {
  360. query = query.WhereIn("pf", form.Pf)
  361. }
  362. err = query.
  363. Where("gid", action.Gid).
  364. Where("actionId", action.ActionId).
  365. Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
  366. Scan(&userAction).Error
  367. if err != nil {
  368. response.Fail(c, 1002, err.Error())
  369. return
  370. }
  371. activeCount := make(map[string]int)
  372. for _, v := range userAction {
  373. activeCount[v.CreatedAt]++
  374. }
  375. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  376. for _, v := range days {
  377. res[v] = activeCount[v]
  378. }
  379. response.Success(c, gin.H{
  380. "data": map[string]interface{}{
  381. "avg": fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
  382. "list": res,
  383. },
  384. })
  385. } else if form.Type == 2 {
  386. var userAction []struct {
  387. UserId int `json:"userId" gorm:"not null;column:userId;"`
  388. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  389. }
  390. query := global.App.DB.Table("user_action")
  391. if len(form.Pf) > 0 {
  392. query = query.WhereIn("gid", form.Pf)
  393. }
  394. err = query.
  395. Where("gid", action.Gid).
  396. Where("actionId", action.ActionId).
  397. Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
  398. Scan(&userAction).Error
  399. if err != nil {
  400. response.Fail(c, 1002, err.Error())
  401. return
  402. }
  403. activeCount := make(map[string]map[int]bool)
  404. for _, v := range userAction {
  405. if activeCount[v.CreatedAt] == nil {
  406. activeCount[v.CreatedAt] = make(map[int]bool)
  407. }
  408. activeCount[v.CreatedAt][v.UserId] = true
  409. }
  410. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  411. for _, v := range days {
  412. res[v] = len(activeCount[v])
  413. }
  414. response.Success(c, gin.H{
  415. "data": map[string]interface{}{
  416. "avg": fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
  417. "list": res,
  418. },
  419. })
  420. } else if form.Type == 3 {
  421. //活跃设备发生率
  422. var userAction []string
  423. query := global.App.DB.Table("user_action")
  424. if len(form.Pf) > 0 {
  425. query = query.WhereIn("pf", form.Pf)
  426. }
  427. err = query.
  428. Where("gid", action.Gid).
  429. Where("actionId", action.ActionId).
  430. Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userAction).Error
  431. if err != nil {
  432. response.Fail(c, 1002, err.Error())
  433. return
  434. }
  435. actionCount := make(map[string]int)
  436. for _, v := range userAction {
  437. actionCount[v]++
  438. }
  439. //var userOnline model.UserOnline
  440. //query = global.App.DB.Table("user_online")
  441. //if len(form.Pf) > 0 {
  442. // query = query.WhereIn("gid", form.Pf)
  443. //}
  444. //err = query.
  445. // Where("gid", action.Gid).
  446. // Error
  447. //if err != nil {
  448. // response.Fail(c, 1002, err.Error())
  449. // return
  450. //}
  451. //userCount := make(map[string]map[int]bool)
  452. //for _, v := range userOnline {
  453. //
  454. //}
  455. } else if form.Type == 4 {
  456. //每次启动发生率
  457. var userLogin []string
  458. query := global.App.DB.Table("user_login")
  459. if len(form.Pf) > 0 {
  460. query = query.WhereIn("pf", form.Pf)
  461. }
  462. err = query.
  463. Where("gid", action.Gid).
  464. Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userLogin).Error
  465. if err != nil {
  466. response.Fail(c, 1001, err.Error())
  467. return
  468. }
  469. loginCount := make(map[string]int)
  470. for _, v := range userLogin {
  471. loginCount[v]++
  472. }
  473. var userAction []string
  474. query = global.App.DB.Table("user_action")
  475. if len(form.Pf) > 0 {
  476. query = query.WhereIn("pf", form.Pf)
  477. }
  478. err = query.
  479. Where("gid", action.Gid).
  480. Where("actionId", action.ActionId).
  481. Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userAction).Error
  482. if err != nil {
  483. response.Fail(c, 1002, err.Error())
  484. return
  485. }
  486. actionCount := make(map[string]int)
  487. for _, v := range userAction {
  488. actionCount[v]++
  489. }
  490. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  491. for _, v := range days {
  492. if loginCount[v] > 0 {
  493. res[v] = float64(actionCount[v]) / float64(loginCount[v])
  494. } else {
  495. res[v] = 0
  496. }
  497. }
  498. } else {
  499. response.Fail(c, 1003, errors.New("type 错误"))
  500. return
  501. }
  502. }
  503. func CopyGameAction(c *gin.Context) {
  504. form := request.Check(c, &struct {
  505. Gid string `form:"gid" binding:"required"`
  506. NewGid string `form:"newGid" binding:"required"`
  507. }{})
  508. //读取出gid对应的配置
  509. var gameAction []model.GameAction
  510. global.App.DB.Table("game_action").Where("gid", form.Gid).Scan(&gameAction)
  511. now := model.XTime{
  512. Time: time.Now(),
  513. }
  514. for _, v := range gameAction {
  515. //复制
  516. newAction := model.GameAction{
  517. Gid: form.NewGid,
  518. ActionId: v.ActionId,
  519. ActionName: v.ActionName,
  520. Status: v.Status,
  521. Remark: v.Remark,
  522. CreatedAt: now,
  523. UpdatedAt: now,
  524. }
  525. global.App.DB.Table("game_action").Create(&newAction)
  526. //查询出有无对应的option
  527. var actionOption []model.GameActionOption
  528. global.App.DB.Table("game_action_option").Where("actionId", v.ID).Scan(&actionOption)
  529. //fmt.Println(actionOption, v.ID)
  530. if actionOption != nil {
  531. for _, option := range actionOption {
  532. newActionOption := model.GameActionOption{
  533. ActionId: newAction.ID,
  534. OptionId: option.OptionId,
  535. OptionName: option.OptionName,
  536. OptionType: option.OptionType,
  537. Status: option.Status,
  538. CreatedAt: now,
  539. UpdatedAt: now,
  540. }
  541. global.App.DB.Table("game_action_option").Create(&newActionOption)
  542. }
  543. }
  544. }
  545. response.Success(c, gin.H{})
  546. }
  547. func GetDefaultGameAction(c *gin.Context) {
  548. response.Success(c, gin.H{
  549. "data": []interface{}{
  550. map[string]interface{}{
  551. "actionId": "pass",
  552. "actionName": "通过关卡",
  553. "status": 1,
  554. "remark": "",
  555. "options": []map[string]interface{}{
  556. map[string]interface{}{
  557. "optionName": "关卡",
  558. "optionId": "lv",
  559. "optionType": "int",
  560. },
  561. },
  562. },
  563. map[string]interface{}{
  564. "actionId": "enter",
  565. "actionName": "进入关卡",
  566. "status": 1,
  567. "remark": "",
  568. "options": []map[string]interface{}{
  569. map[string]interface{}{
  570. "optionName": "关卡",
  571. "optionId": "lv",
  572. "optionType": "int",
  573. },
  574. },
  575. },
  576. map[string]interface{}{
  577. "actionId": "reward",
  578. "actionName": "领取奖励",
  579. "status": 1,
  580. "remark": "",
  581. "options": make([]map[string]interface{}, 0),
  582. },
  583. },
  584. })
  585. }