gameAction.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  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).Scan(&optionName)
  216. for _, v := range optionName {
  217. optionIdToName[v.OptionId] = v.OptionName
  218. }
  219. fmt.Println(time.Since(now))
  220. for k, v := range optionList {
  221. var ActiveUserRate float64
  222. var LoginActiveRate float64
  223. if userLoginCount > 0 {
  224. ActiveUserRate = DivideWithPrecision(actionSumMap[k], userLoginCount)
  225. LoginActiveRate = DivideWithPrecision(len(actionUserSumMap[k]), userLoginCount)
  226. }
  227. optionId := strings.Split(k, "|")[0]
  228. value := strings.Split(k, "|")[1]
  229. valueInt, _ := strconv.Atoi(value)
  230. res = append(res, responses{
  231. ActionId: valueInt,
  232. ActionName: optionIdToName[optionId] + ":" + value,
  233. ActionCount: v,
  234. ActionUserCount: len(actionUserSumMap[k]),
  235. ActiveUserRate: ActiveUserRate,
  236. LoginActiveRate: LoginActiveRate,
  237. })
  238. }
  239. sort.Slice(res, func(i, j int) bool {
  240. return res[i].ActionId < res[j].ActionId // 正序规则:i的Age小于j时返回true
  241. })
  242. response.Success(c, gin.H{
  243. "data": res,
  244. "count": len(res),
  245. })
  246. }
  247. func DivideWithPrecision(a, b int) float64 {
  248. if b == 0 {
  249. panic("除数不能为零") // 实际项目中建议返回 error 类型
  250. }
  251. // 转换为浮点数再相除
  252. result := float64(a) / float64(b)
  253. // 格式化为三位小数并转换回 float64
  254. formatted, _ := strconv.ParseFloat(fmt.Sprintf("%.3f", result), 64)
  255. return formatted
  256. }
  257. func UserActionDetail(c *gin.Context) {
  258. form := request.Check(c, &struct {
  259. Id int `form:"id" binding:"required"`
  260. Pf []string `form:"pf" binding:""`
  261. StartTime string `form:"startTime" binding:"required"`
  262. EndTime string `form:"endTime" binding:"required"`
  263. }{})
  264. //查询启动次数
  265. var action model.GameAction
  266. err := global.App.DB.Table("game_action").
  267. Where("id", form.Id).Find(&action).Error
  268. if err != nil {
  269. response.Fail(c, 1001, err.Error())
  270. return
  271. }
  272. var userAction []struct {
  273. UserId int `json:"userId" gorm:"not null;column:userId;"`
  274. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  275. }
  276. err = global.App.DB.Table("user_action").
  277. Where("gid", action.Gid).
  278. Where("actionId", action.ActionId).
  279. Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
  280. Scan(&userAction).Error
  281. if err != nil {
  282. response.Fail(c, 1002, err.Error())
  283. return
  284. }
  285. //查询出时间段内的活跃用户,登录次数
  286. var userLogin []struct {
  287. UserId int `json:"userId" gorm:"not null;column:userId;"`
  288. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  289. }
  290. err = global.App.DB.Table("user_login").
  291. Where("gid", action.Gid).
  292. Where("loginTime", ">=", form.StartTime).
  293. Where("loginTime", "<=", form.EndTime).
  294. Select("userId", "DATE_FORMAT(loginTime, '%Y-%m-%d') as createdAt").
  295. Scan(&userLogin).Error
  296. if err != nil {
  297. response.Fail(c, 1001, err.Error())
  298. return
  299. }
  300. //userLoginCount := len(userLogin)
  301. activeCount := make(map[string]int)
  302. activeCountUser := make(map[string]map[int]bool)
  303. //根据日期进行分组
  304. for _, v := range userAction {
  305. activeCount[v.CreatedAt]++
  306. if activeCountUser[v.CreatedAt] == nil {
  307. activeCountUser[v.CreatedAt] = make(map[int]bool)
  308. }
  309. activeCountUser[v.CreatedAt][v.UserId] = true
  310. }
  311. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  312. type responses struct {
  313. Date string `json:"date"`
  314. ActiveCount int `json:"activeCount"`
  315. ActiveUserCount int `json:"activeUserCount"`
  316. ActiveCountRate float64 `json:"activeCountRate"`
  317. ActiveCountUser float64 `json:"activeCountUser"`
  318. }
  319. var res []responses
  320. //输出格式
  321. for _, v := range days {
  322. res = append(res, responses{
  323. Date: v,
  324. ActiveCount: activeCount[v],
  325. ActiveUserCount: len(activeCountUser[v]),
  326. ActiveCountRate: float64(activeCount[v] / 1),
  327. ActiveCountUser: float64(len(activeCountUser[v]) / 1),
  328. })
  329. }
  330. response.Success(c, gin.H{
  331. "data": res,
  332. })
  333. }
  334. func UserActionDetailDistribution(c *gin.Context) {
  335. form := request.Check(c, &struct {
  336. Id int `form:"id" binding:"required"`
  337. Pf []string `form:"pf" binding:""`
  338. StartTime string `form:"startTime" binding:"required"`
  339. EndTime string `form:"endTime" binding:"required"`
  340. Type int `form:"type" binding:"required"`
  341. }{})
  342. var action model.GameAction
  343. err := global.App.DB.Table("game_action").
  344. Where("id", form.Id).Find(&action).Error
  345. if err != nil {
  346. response.Fail(c, 1001, err.Error())
  347. return
  348. }
  349. res := make(map[string]interface{})
  350. if form.Type == 1 {
  351. var userAction []struct {
  352. UserId int `json:"userId" gorm:"not null;column:userId;"`
  353. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  354. }
  355. query := global.App.DB.Table("user_action")
  356. if len(form.Pf) > 0 {
  357. query = query.WhereIn("pf", form.Pf)
  358. }
  359. err = query.
  360. Where("gid", action.Gid).
  361. Where("actionId", action.ActionId).
  362. Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
  363. Scan(&userAction).Error
  364. if err != nil {
  365. response.Fail(c, 1002, err.Error())
  366. return
  367. }
  368. activeCount := make(map[string]int)
  369. for _, v := range userAction {
  370. activeCount[v.CreatedAt]++
  371. }
  372. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  373. for _, v := range days {
  374. res[v] = activeCount[v]
  375. }
  376. response.Success(c, gin.H{
  377. "data": map[string]interface{}{
  378. "avg": fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
  379. "list": res,
  380. },
  381. })
  382. } else if form.Type == 2 {
  383. var userAction []struct {
  384. UserId int `json:"userId" gorm:"not null;column:userId;"`
  385. CreatedAt string `json:"createdAt" gorm:"not null;column:createdAt;"`
  386. }
  387. query := global.App.DB.Table("user_action")
  388. if len(form.Pf) > 0 {
  389. query = query.WhereIn("gid", form.Pf)
  390. }
  391. err = query.
  392. Where("gid", action.Gid).
  393. Where("actionId", action.ActionId).
  394. Select("userId", "DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt").
  395. Scan(&userAction).Error
  396. if err != nil {
  397. response.Fail(c, 1002, err.Error())
  398. return
  399. }
  400. activeCount := make(map[string]map[int]bool)
  401. for _, v := range userAction {
  402. if activeCount[v.CreatedAt] == nil {
  403. activeCount[v.CreatedAt] = make(map[int]bool)
  404. }
  405. activeCount[v.CreatedAt][v.UserId] = true
  406. }
  407. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  408. for _, v := range days {
  409. res[v] = len(activeCount[v])
  410. }
  411. response.Success(c, gin.H{
  412. "data": map[string]interface{}{
  413. "avg": fmt.Sprintf("%.2f", float64(len(userAction))/float64(len(days))),
  414. "list": res,
  415. },
  416. })
  417. } else if form.Type == 3 {
  418. //活跃设备发生率
  419. var userAction []string
  420. query := global.App.DB.Table("user_action")
  421. if len(form.Pf) > 0 {
  422. query = query.WhereIn("pf", form.Pf)
  423. }
  424. err = query.
  425. Where("gid", action.Gid).
  426. Where("actionId", action.ActionId).
  427. Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userAction).Error
  428. if err != nil {
  429. response.Fail(c, 1002, err.Error())
  430. return
  431. }
  432. actionCount := make(map[string]int)
  433. for _, v := range userAction {
  434. actionCount[v]++
  435. }
  436. //var userOnline model.UserOnline
  437. //query = global.App.DB.Table("user_online")
  438. //if len(form.Pf) > 0 {
  439. // query = query.WhereIn("gid", form.Pf)
  440. //}
  441. //err = query.
  442. // Where("gid", action.Gid).
  443. // Error
  444. //if err != nil {
  445. // response.Fail(c, 1002, err.Error())
  446. // return
  447. //}
  448. //userCount := make(map[string]map[int]bool)
  449. //for _, v := range userOnline {
  450. //
  451. //}
  452. } else if form.Type == 4 {
  453. //每次启动发生率
  454. var userLogin []string
  455. query := global.App.DB.Table("user_login")
  456. if len(form.Pf) > 0 {
  457. query = query.WhereIn("pf", form.Pf)
  458. }
  459. err = query.
  460. Where("gid", action.Gid).
  461. Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userLogin).Error
  462. if err != nil {
  463. response.Fail(c, 1001, err.Error())
  464. return
  465. }
  466. loginCount := make(map[string]int)
  467. for _, v := range userLogin {
  468. loginCount[v]++
  469. }
  470. var userAction []string
  471. query = global.App.DB.Table("user_action")
  472. if len(form.Pf) > 0 {
  473. query = query.WhereIn("pf", form.Pf)
  474. }
  475. err = query.
  476. Where("gid", action.Gid).
  477. Where("actionId", action.ActionId).
  478. Pluck("DATE_FORMAT(createdAt, '%Y-%m-%d') as createdAt", &userAction).Error
  479. if err != nil {
  480. response.Fail(c, 1002, err.Error())
  481. return
  482. }
  483. actionCount := make(map[string]int)
  484. for _, v := range userAction {
  485. actionCount[v]++
  486. }
  487. days := utils.GetTimeDayDateFormat(form.StartTime, form.EndTime)
  488. for _, v := range days {
  489. if loginCount[v] > 0 {
  490. res[v] = float64(actionCount[v]) / float64(loginCount[v])
  491. } else {
  492. res[v] = 0
  493. }
  494. }
  495. } else {
  496. response.Fail(c, 1003, errors.New("type 错误"))
  497. return
  498. }
  499. }
  500. func CopyGameAction(c *gin.Context) {
  501. form := request.Check(c, &struct {
  502. Gid string `form:"gid" binding:"required"`
  503. NewGid string `form:"newGid" binding:"required"`
  504. }{})
  505. //读取出gid对应的配置
  506. var gameAction []model.GameAction
  507. global.App.DB.Table("game_action").Where("gid", form.Gid).Scan(&gameAction)
  508. now := model.XTime{
  509. Time: time.Now(),
  510. }
  511. for _, v := range gameAction {
  512. //复制
  513. newAction := model.GameAction{
  514. Gid: form.NewGid,
  515. ActionId: v.ActionId,
  516. ActionName: v.ActionName,
  517. Status: v.Status,
  518. Remark: v.Remark,
  519. CreatedAt: now,
  520. UpdatedAt: now,
  521. }
  522. global.App.DB.Table("game_action").Create(&newAction)
  523. //查询出有无对应的option
  524. var actionOption []model.GameActionOption
  525. global.App.DB.Table("game_action_option").Where("actionId", v.ID).Scan(&actionOption)
  526. //fmt.Println(actionOption, v.ID)
  527. if actionOption != nil {
  528. for _, option := range actionOption {
  529. newActionOption := model.GameActionOption{
  530. ActionId: newAction.ID,
  531. OptionId: option.OptionId,
  532. OptionName: option.OptionName,
  533. OptionType: option.OptionType,
  534. Status: option.Status,
  535. CreatedAt: now,
  536. UpdatedAt: now,
  537. }
  538. global.App.DB.Table("game_action_option").Create(&newActionOption)
  539. }
  540. }
  541. }
  542. response.Success(c, gin.H{})
  543. }
  544. func GetDefaultGameAction(c *gin.Context) {
  545. response.Success(c, gin.H{
  546. "data": []interface{}{
  547. map[string]interface{}{
  548. "actionId": "pass",
  549. "actionName": "通过关卡",
  550. "status": 1,
  551. "remark": "",
  552. "options": []map[string]interface{}{
  553. map[string]interface{}{
  554. "optionName": "关卡",
  555. "optionId": "lv",
  556. "optionType": "int",
  557. },
  558. },
  559. },
  560. map[string]interface{}{
  561. "actionId": "enter",
  562. "actionName": "进入关卡",
  563. "status": 1,
  564. "remark": "",
  565. "options": []map[string]interface{}{
  566. map[string]interface{}{
  567. "optionName": "关卡",
  568. "optionId": "lv",
  569. "optionType": "int",
  570. },
  571. },
  572. },
  573. map[string]interface{}{
  574. "actionId": "reward",
  575. "actionName": "领取奖励",
  576. "status": 1,
  577. "remark": "",
  578. "options": make([]map[string]interface{}, 0),
  579. },
  580. },
  581. })
  582. }