ComplexSummaryGameRetention.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. <?php
  2. namespace app\crontab;
  3. use app\service\ComplexSummaryService;
  4. use think\console\Command;
  5. use think\console\Input;
  6. use think\console\Output;
  7. use think\console\Input\Argument;
  8. use think\Db;
  9. use think\Exception;
  10. /**
  11. * 聚合-游戏留存报表-统计脚本
  12. * 统计游戏留存数据
  13. */
  14. class ComplexSummaryGameRetention extends Command
  15. {
  16. protected function configure()
  17. {
  18. $this->setName('ComplexSummaryGameRetention')
  19. ->setDescription('聚合-游戏留存报表-统计脚本')
  20. ->addArgument('day', Argument::OPTIONAL, '统计日期,格式:Y-m-d,默认为昨天');
  21. }
  22. protected function execute(Input $input, Output $output)
  23. {
  24. $service = new ComplexSummaryService();
  25. // 获取统计日期(默认昨天)
  26. $day = $input->getArgument('day') ?: date('Y-m-d', strtotime('-1 day'));
  27. $output->writeln(date('Y-m-d H:i:s') . " 开始统计日期: {$day}");
  28. $gameIds = $service->getOnlineGameIds();
  29. try {
  30. // 1. 获取新增玩家(当天注册)
  31. $regNumList = $service->getRegNum($day, $gameIds, 1);
  32. $output->writeln("新增玩家统计完成: " . count($regNumList) . " 条");
  33. // 2. 批量计算所有留存率
  34. $retentionList = $service->getBatchRetention($day, $gameIds, 1);
  35. $output->writeln("留存率统计完成: " . count($retentionList) . " 条");
  36. // 3. 分别保存当天新增和历史注册日留存
  37. Db::startTrans();
  38. try {
  39. // 重跑当天数据时只重置新增人数,保留后续日期已经补齐的留存字段
  40. $regResetQuery = Db::table('cy_complex_summary_game_retention')
  41. ->where('day', $day);
  42. if (!empty($gameIds)) {
  43. $regResetQuery->where('game_id', 'in', $gameIds);
  44. }
  45. $regResetQuery->update(['reg_num' => 0]);
  46. foreach ($regNumList as $stat) {
  47. $gameId = $stat['game_id'] ?? 0;
  48. $complexId = $stat['channel_id'] ?? 0;
  49. $this->saveSummaryData($day, $gameId, $complexId, [
  50. 'reg_num' => intval($stat['reg_num'] ?? 0),
  51. ]);
  52. }
  53. $retentionFields = [
  54. 'one_stay',
  55. 'three_stay',
  56. 'four_stay',
  57. 'five_stay',
  58. 'six_stay',
  59. 'seven_stay',
  60. 'fifteen_stay',
  61. 'thirty_stay',
  62. ];
  63. foreach ($retentionList as $stat) {
  64. $fieldName = $stat['retention_field'] ?? '';
  65. if (!in_array($fieldName, $retentionFields, true)) {
  66. throw new Exception('无效的留存字段: ' . $fieldName);
  67. }
  68. $statDay = $stat['stat_day'] ?? '';
  69. $gameId = $stat['game_id'] ?? 0;
  70. $complexId = $stat['channel_id'] ?? 0;
  71. // 留存率回写到对应注册日;同时校准该注册日的新增人数
  72. $this->saveSummaryData($statDay, $gameId, $complexId, [
  73. 'reg_num' => intval($stat['base_reg_num'] ?? 0),
  74. $fieldName => floatval($stat['retention_rate'] ?? 0),
  75. ]);
  76. }
  77. Db::commit();
  78. $output->writeln(
  79. "数据保存成功,新增 " . count($regNumList)
  80. . " 条,留存 " . count($retentionList) . " 条"
  81. );
  82. } catch (Exception $e) {
  83. Db::rollback();
  84. $output->writeln("保存数据失败: " . $e->getMessage());
  85. throw $e;
  86. }
  87. } catch (Exception $e) {
  88. $output->writeln("统计失败: " . $e->getMessage() . ' - ' . $e->getFile() . ":" . $e->getLine());
  89. throw $e;
  90. }
  91. $output->writeln(date('Y-m-d H:i:s') . " 统计完成");
  92. }
  93. /**
  94. * 按注册日、游戏和渠道更新汇总数据;不存在时创建。
  95. */
  96. private function saveSummaryData($day, $gameId, $complexId, array $data)
  97. {
  98. $where = [
  99. 'day' => $day,
  100. 'game_id' => intval($gameId),
  101. 'complex_id' => intval($complexId),
  102. ];
  103. $exists = Db::table('cy_complex_summary_game_retention')
  104. ->where($where)
  105. ->field('id')
  106. ->find();
  107. if ($exists) {
  108. Db::table('cy_complex_summary_game_retention')
  109. ->where('id', $exists['id'])
  110. ->update($data);
  111. return;
  112. }
  113. Db::table('cy_complex_summary_game_retention')
  114. ->insert(array_merge($where, $data));
  115. }
  116. }