StatProc.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. <?php
  2. namespace loyalsoft;
  3. /**
  4. * 统计模块
  5. * 统计:反应的是一段时间内的趋势. 所以,所有数据都要依据时间进行分类. 其他的统计维度另算. -王刚
  6. * @version
  7. * 1.0.0 Created at 2016-5-24. by --gwang
  8. * @author gwang (mail@wanggangzero.cn)
  9. * @copyright © 2016-5-24, SJZ LoyalSoft Corporation & gwang. All rights reserved.
  10. */
  11. class StatProc
  12. {
  13. public static function test($req)
  14. {
  15. CLog::info("异步测试成功!", "Statproc::Test");
  16. DebugHelper::var_dump("异步调用");
  17. return $req;
  18. }
  19. const maxLevel = 100;
  20. const maxDays = 30;
  21. /**
  22. * 玩家登录
  23. * @param type $level
  24. */
  25. public static function UserLogin($req, $isNew = 0)
  26. {
  27. $redis = gMem();
  28. $redis->hincrby(MemKey_Stat::UserLevel_hash(), $level);
  29. }
  30. /**
  31. * 设置新手引导步骤
  32. * @param int $tsBirth 玩家创建角色的时刻
  33. * @param int $zoneid
  34. * @param int $tarStep
  35. * @param int $currentStep
  36. */
  37. public static function UserGuidStep($tsBirth, $zoneid, $tarStep, $currentStep)
  38. {
  39. if ($tarStep == $currentStep) {
  40. return;
  41. }
  42. $redis = gMem();
  43. if ($tarStep == 0) { // 跳过新手引导
  44. $redis->hincrby(MemKey_Stat::UserGuidSkip_Day($tsBirth, $zoneid), $currentStep);
  45. $redis->hincrby(MemKey_Stat::UserGuidSkip_Week($tsBirth, $zoneid), $currentStep);
  46. $redis->hincrby(MemKey_Stat::UserGuidSkip_Month($tsBirth, $zoneid), $currentStep);
  47. } else {
  48. $redis->hincrby(MemKey_Stat::UserGuidLose_Day($tsBirth, $zoneid), $tarStep);
  49. $redis->hincrby(MemKey_Stat::UserGuidLose_Week($tsBirth, $zoneid), $tarStep);
  50. $redis->hincrby(MemKey_Stat::UserGuidLose_Month($tsBirth, $zoneid), $tarStep);
  51. }
  52. }
  53. /**
  54. * 任务步骤
  55. * @param int $tsBirth
  56. * @param int $level
  57. * @param int $completeStep
  58. */
  59. public static function TaskStep($tsBirth, $level, $completeStep)
  60. {
  61. $redis = gMem();
  62. $redis->zincrby(MemKey_Stat::TaskStep_zset(), $completeStep);
  63. $redis->zincrby(MemKey_Stat::TaskStep_Day_zset($tsBirth), $completeStep);
  64. $redis->zincrby(MemKey_Stat::TaskStep_level_zset($level), $completeStep);
  65. }
  66. /**
  67. * 首次充值
  68. * @param string $uid 玩家ID
  69. * @param int $tsBirth
  70. * @param int $level
  71. * @param int $amt 充值金额单位0.1元
  72. */
  73. public static function Pay($uid, $tsBirth, $level, $amt)
  74. {
  75. if ($amt <= 0) {
  76. return;
  77. }
  78. $redis = gMem();
  79. $day = CommUtil::tsDay() - CommUtil::tsDay($tsBirth);
  80. $day = $day > self::maxDays ? self::maxDays : $day; # 超过30天的合并到30天
  81. if ($redis->sismember(MemKey_Stat::PayedUsers(), $uid)) {
  82. # 充值统计这边暂空,还没设计好需求
  83. } else { # 首充
  84. $redis->zincrby(MemKey_Stat::FirstPay_level_zset(), $level); # 首次充值等级
  85. $redis->zincrby(MemKey_Stat::FirstPay_day_zset(), $day); # 首次充值的游戏时间
  86. $redis->sadd($uid, $uid);
  87. }
  88. usleep(1); # 延时1微秒
  89. }
  90. /**
  91. * 统计 - 商城购买
  92. * @param string $zoneid
  93. * @param string $uid 玩家ID
  94. * @param int $itemid 道具编号
  95. * @param int $amt 数量
  96. */
  97. public static function shopbuy($zoneid, $uid, $itemid, $amt = 1)
  98. {
  99. if ($amt <= 0) {
  100. return;
  101. }
  102. $redis = gMem();
  103. # 全局
  104. $redis->zincrby(MemKey_GameRun::stat_daily_ShopSales_zset($zoneid, TimeUtil::dtToday()), $itemid, $amt);
  105. $redis->zincrby(MemKey_GameRun::stat_weekly_ShopSales_zset($zoneid, TimeUtil::tsWeek()), $itemid, $amt);
  106. $redis->zincrby(MemKey_GameRun::stat_monthly_ShopSales_zset($zoneid, date('Ym')), $itemid, $amt);
  107. $redis->lpush(MemKey_GameRun::log_ShopSales_list($zoneid), "[" . TimeUtil::dtCurrent() . "] $uid,$itemid,$amt");
  108. $redis->ltrim(MemKey_GameRun::log_ShopSales_list($zoneid), 0, 1000); # 系统销售日志保留1k条
  109. # 玩家
  110. $redis->zincrby(MemKey_User::stat_Shopbuy_zset($zoneid, $uid), $itemid, $amt);
  111. $redis->lpush(MemKey_User::log_shopbuy_list($zoneid, $uid), "[" . TimeUtil::dtCurrent() . "] $itemid,$amt");
  112. $redis->ltrim(MemKey_User::log_shopbuy_list($zoneid, $uid), 0, 30); # 保持最新的30条记录
  113. usleep(1); # 延时1微秒
  114. }
  115. /**
  116. * 统计 - 神秘商城购买
  117. * @param type $zoneid
  118. * @param type $uid
  119. * @param type $itemid
  120. * @param type $amt
  121. */
  122. public static function secretShopbuy($zoneid, $uid, $itemid, $amt = 1)
  123. {
  124. if ($amt <= 0) {
  125. return;
  126. }
  127. $redis = gMem();
  128. # 全局
  129. $redis->zincrby(MemKey_GameRun::stat_daily_secretshopSales_zset($zoneid, TimeUtil::dtToday()), $itemid, $amt);
  130. $redis->zincrby(MemKey_GameRun::stat_weekly_secretshopSalse_zset($zoneid, TimeUtil::tsWeek()), $itemid, $amt);
  131. $redis->zincrby(MemKey_GameRun::stat_monthly_secretshopSales_zset($zoneid, date('Ym')), $itemid, $amt);
  132. $redis->lpush(MemKey_GameRun::log_secretshopSales_list($zoneid), "[" . TimeUtil::dtCurrent() . "] $uid,$itemid,$amt");
  133. $redis->ltrim(MemKey_GameRun::log_secretshopSales_list($zoneid), 0, 1000); # 系统销售日志保留1k条
  134. # 玩家
  135. $redis->zincrby(MemKey_User::stat_SecretShopBuy_zset($zoneid, $uid), $itemid, $amt);
  136. $redis->lpush(MemKey_User::log_secretshopbuy_list($zoneid, $uid), # # 玩家个人日志
  137. "[" . TimeUtil::dtCurrent() . "] $itemid,$amt");
  138. $redis->ltrim(MemKey_User::log_secretshopbuy_list($zoneid, $uid), 0, 30); # 保持最新的30条记录
  139. usleep(1);
  140. }
  141. // == == == == == == == == == == == == == ==
  142. // 提供查询功能
  143. // == == == == == == == == == == == == == ==
  144. /**
  145. *
  146. * @param StatRequest $req
  147. * @return type
  148. */
  149. public static function GetDataOfTask($req)
  150. {
  151. $redis = gMem();
  152. $maxTaskStep = 1000; # 暂时不高于1000
  153. switch ($req->dateType) { # 参数处理
  154. case 'none':
  155. $data = $redis->zrevrange(MemKey_Stat::TaskStep_zset(), 0, $maxTaskStep, true);
  156. break;
  157. case 'Day':
  158. $ts = ($req->dateIndex > 30 ? 30 : $req->dateIndex) * 86400;
  159. $data = $redis->zrevrange(MemKey_Stat::TaskStep_Day_zset(CommUtil::tsCurrent(-$ts)), 0, self::maxDays, true);
  160. break;
  161. case 'level':
  162. $data = $redis->zrevrange(MemKey_Stat::TaskStep_level_zset($req->dateIndex), 0, self::maxLevel, true);
  163. break;
  164. default :
  165. break;
  166. }
  167. $keys = array_keys($data);
  168. sort($keys);
  169. return array(
  170. 'labels' => $keys,
  171. 'datasets' => array(
  172. array('label' => '完成人数',
  173. 'fillColor' => "rgba(220, 220, 220, 0.5)", 'strokeColor' => "rgba(220, 220, 220, 1)",
  174. 'data' => array_values(StlUtil::arraySortByKey($data))
  175. )
  176. )
  177. );
  178. }
  179. /**
  180. *
  181. * @param StatRequest $req
  182. * @return type
  183. */
  184. public static function GetUserGuideData($req)
  185. {
  186. $redis = gMem();
  187. $date = date_create_from_format("Ymd", $req->dateIndex); # 参数处理
  188. $ts = $date->getTimestamp();
  189. $zoneid = $req->zoneid;
  190. //
  191. $skip = $redis->hgetall(MemKey_Stat::UserGuidSkip_Day($ts, $zoneid));
  192. $lose = $redis->hgetall(MemKey_Stat::UserGuidLose_Day($ts, $zoneid));
  193. switch ($req->dateType) {
  194. case 'Week':
  195. $skip = $redis->hgetall(MemKey_Stat::UserGuidSkip_Week($ts, $zoneid));
  196. $lose = $redis->hgetall(MemKey_Stat::UserGuidLose_Week($ts, $zoneid));
  197. break;
  198. case 'Month':
  199. $skip = $redis->hgetall(MemKey_Stat::UserGuidSkip_Month($ts, $zoneid));
  200. $lose = $redis->hgetall(MemKey_Stat::UserGuidLose_Month($ts, $zoneid));
  201. break;
  202. case 'Day':
  203. default:
  204. break;
  205. }
  206. $keys = array_keys($lose);
  207. foreach ($keys as $k) {
  208. if ($k && !isset($skip[$k])) {
  209. $skip[$k] = "0";
  210. }
  211. }
  212. sort($keys);
  213. return array(
  214. 'labels' => $keys,
  215. 'datasets' => array(
  216. array('label' => '完成人数',
  217. 'fillColor' => "rgba(220, 220, 220, 0.5)", 'strokeColor' => "rgba(220, 220, 220, 1)",
  218. 'data' => array_values(StlUtil::arraySortByKey($lose))
  219. ),
  220. array('label' => '跳过人数',
  221. 'fillColor' => "rgba(220, 220, 220, 0.5)", 'strokeColor' => "rgba(220, 220, 220, 1)",
  222. 'borderColor' => 'rgb(0, 0, 255)',
  223. 'data' => array_values(StlUtil::arraySortByKey($skip))
  224. ),
  225. )
  226. );
  227. }
  228. /**
  229. * 付费相关统计
  230. * @param StatRequest $req
  231. */
  232. public static function GetPayStatData($req)
  233. {
  234. $redis = gMem();
  235. // 参数处理
  236. $payedusers = $redis->scard(MemKey_Stat::PayedUsers()); // 充值总人数
  237. $label = '';
  238. switch ($req->dateType) {
  239. case 'FirstPayDay':
  240. $data = $redis->zrange(MemKey_Stat::FirstPay_day_zset(), 0, self::maxDays, true);
  241. $label = '消费人数';
  242. break;
  243. case 'FirstPayLevel':
  244. $data = $redis->zrange(MemKey_Stat::FirstPay_level_zset(), 0, self::maxLevel, true);
  245. $label = '充值人数';
  246. break;
  247. case 'FirstYuanbaoPayAt':
  248. $data = $redis->zrange(MemKey_Stat::YuanbaoFirstUsed_zset(), 0, -1, true); # 最多也不过5、6中可能流向
  249. $label = '消费人数';
  250. break;
  251. default :
  252. break;
  253. }
  254. $keys = array_keys($data);
  255. sort($keys);
  256. return array(
  257. 'labels' => $keys,
  258. 'datasets' => array(
  259. array('label' => $label,
  260. 'fillColor' => "rgba(220, 220, 220, 0.5)", 'strokeColor' => "rgba(220, 220, 220, 1)",
  261. 'data' => array_values(StlUtil::arraySortByKey($data))
  262. )
  263. )
  264. );
  265. }
  266. /**
  267. * 玩家流失等级
  268. * @param type $req
  269. * @return type
  270. */
  271. public static function GetUserLevels($req)
  272. {
  273. $redis = gMem();
  274. $data = $redis->hgetall(MemKey_Stat::UserLevel_hash());
  275. $keys = array_keys($data);
  276. sort($keys);
  277. return array(
  278. 'labels' => $keys,
  279. 'datasets' => array(
  280. array('label' => '到达该等级的人数',
  281. 'fillColor' => "rgba(220, 220, 220, 0.5)", 'strokeColor' => "rgba(220, 220, 220, 1)",
  282. 'data' => array_values(StlUtil::arraySortByKey($data))
  283. )
  284. )
  285. );
  286. }
  287. }
  288. /**
  289. * 统计类型
  290. */
  291. class StatClass
  292. {
  293. // 新手引导
  294. const UserGuide = 1;
  295. // 任务步骤
  296. const TaskStep = 2;
  297. // 流失等级
  298. const LoseLevel = 3;
  299. // 生存天数
  300. const LiveDays = 4;
  301. // 付费相关统计
  302. const PayStat = 5;
  303. }
  304. class StatRequest
  305. {
  306. public $statType;
  307. public $dateType;
  308. public $dateIndex;
  309. public $zoneid;
  310. public $level;
  311. }