StatProc.php 12 KB

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