UserStatisticsService.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. <?php
  2. /**
  3. *
  4. * @file:UserStatisticsService.php
  5. * @Date: 2023/6/20
  6. * @Time: 09:31
  7. */
  8. namespace Modules\Statistic\Services;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Redis;
  11. use Modules\Common\Models\TjOptimizerDayNewUser;
  12. use Modules\Common\Services\BaseService;
  13. use Modules\Common\Services\Statistic\CompanyDayUser;
  14. use Modules\Common\Services\Statistic\OptimizerDayUser;
  15. class UserStatisticsService extends BaseService
  16. {
  17. // key 日期:
  18. protected const PROMOTION_STATISTIC_RECORD_REDIS_KEY = 'statistic:miniprogram:users_recode:%s';
  19. protected const NEW_USER_NUM = 'new_user_num_%s'; // 当日新增用户数
  20. protected const NEW_USER_RECHARGE_NUM = "new_user_recharge_num_%s"; // 当日新增户充值人数
  21. protected const NEW_USER_RECHARGE_TOTAL = "new_user_recharge_total_%s"; // 当日新增户充值金额
  22. protected const RANSE_NEW_USER_COUNT = "promotion:newUserCount:%s"; // 推广链接新用户统计
  23. /**
  24. *
  25. * name: getTodayData
  26. * @param int $accountId 账号id
  27. * @param int $type 账号类型 1 其他 2 投放公司 3 优化师
  28. * date 2023/06/20 10:20
  29. * @return array
  30. */
  31. public static function getTodayData($accountId, $type = 1)
  32. {
  33. $date = date("Y-m-d");
  34. $key = sprintf(self::PROMOTION_STATISTIC_RECORD_REDIS_KEY, $date);
  35. $new_user_recharge_total = self::getValue($key, sprintf(self::NEW_USER_RECHARGE_TOTAL, $accountId)); // 当日新增用户充值总额
  36. $new_user_recharge_num = self::getValue($key, sprintf(self::NEW_USER_RECHARGE_NUM, $accountId)); // 当日新增用户充值人数
  37. $new_user_num = self::getValue($key, sprintf(self::NEW_USER_NUM, $accountId)); // 当日新增用户人数
  38. [$recharge_coin_num, $recharge_vip_num] = self::getRechargeUserNum($accountId, $type);
  39. $data = [
  40. 'date' => $date,
  41. 'new_user_recharge_total' => $new_user_recharge_total ?: 0,
  42. 'new_user_recharge_num' => $new_user_recharge_num ?: 0,
  43. 'new_user_num' => $new_user_num ?: 0,
  44. 'recharge_coin_num' => $recharge_coin_num ?: 0,
  45. 'recharge_vip_num' => $recharge_vip_num ?: 0,
  46. ];
  47. if ($new_user_num > 0 && $new_user_recharge_num > 0) {
  48. $data['recharge_rate'] = sprintf("%.2f%s", ($new_user_recharge_num / $new_user_num) * 100, "%");
  49. } else {
  50. $data['recharge_rate'] = 0;
  51. $data['recharge_mean'] = 0;
  52. }
  53. if ($new_user_recharge_total > 0 || $new_user_recharge_num > 0) {
  54. $data['recharge_mean'] = sprintf('%.2f%s', ($new_user_recharge_total / $new_user_recharge_num), "%");
  55. } else {
  56. $data['recharge_mean'] = 0;
  57. }
  58. return $data;
  59. }
  60. /**
  61. * 获取redis值
  62. * name: getValue
  63. * @param $key
  64. * @param $field
  65. * @return mixed
  66. * date 2023/06/25 15:57
  67. */
  68. protected static function getValue($key, $field)
  69. {
  70. return Redis::hget($key, $field);
  71. }
  72. /**
  73. *
  74. * name: getTodayData
  75. * @param int $accountId 账号id
  76. * @param int $type 账号类型 1 其他 2 投放公司 3 优化师
  77. * date 2023/06/20 10:20
  78. * @return array
  79. */
  80. public static function getTodayHomeData(mixed $accountId, int $type)
  81. {
  82. $date = date("Y-m-d");
  83. $start = date("Y-m-d") . " 00:00:00";
  84. $end = date("Y-m-d") . " 23:59:59";
  85. if ($type == 1) {
  86. $new_user_num = DB::table('user_ranse_record_all')->where('date', $date)->count(); // 新增用户人数
  87. $info = DB::table('orders')->where('status', "<>", 'UNPAID')
  88. ->whereBetween("created_at", [$start, $end])
  89. ->whereBetween('ranse_created_at', [$start, $end])
  90. ->select(
  91. DB::raw("sum(if(status = 'unpaid', 0, price)) as recharge_total"), // 单日新增用户充值金额
  92. DB::raw("count(DISTINCT ranse_created_at,uid) as recharge_num") // 当日新增用户充值人数
  93. )->first();
  94. $new_user_recharge_total = $info->recharge_total ?: 0; // 新增用户充值总额
  95. $new_user_recharge_num = $info->recharge_num ?: 0; // 新增用户充值人数
  96. $info = DB::table('orders')->where('status', "<>", 'UNPAID')
  97. ->whereBetween("created_at", [$start, $end])
  98. ->whereBetween('ranse_created_at', [$start, $end])
  99. ->whereIn('order_type', ["COIN", "FIRST_COIN"])
  100. ->select(
  101. DB::raw("sum(if(status = 'unpaid', 0, price)) as recharge_total"), // 单日新增用户充值金额
  102. DB::raw("count(DISTINCT ranse_created_at,uid) as recharge_num") // 当日新增用户充值人数
  103. )->first(); // 普通充值金额
  104. $new_user_recharge_coin_total = $info->recharge_total ?: 0; // 新增用户普通充值总额
  105. $new_user_recharge_coin_num = $info->recharge_num ?: 0; // 新增用户普通充值总额
  106. $info = DB::table('orders')->where('status', "<>", 'UNPAID')
  107. ->whereBetween("created_at", [$start, $end])
  108. ->whereBetween('ranse_created_at', [$start, $end])
  109. ->whereNotIn('order_type', ["COIN", "FIRST_COIN"])
  110. ->select(
  111. DB::raw("sum(if(status = 'unpaid', 0, price)) as recharge_total"), // 单日新增用户充值金额
  112. DB::raw("count(DISTINCT ranse_created_at,uid) as recharge_num") // 当日新增用户充值人数
  113. )->first(); // 会员充值金额
  114. $new_user_recharge_vip_total = $info->recharge_total ?: 0; // 新增用户会员充值总额
  115. $new_user_recharge_vip_num = $info->recharge_num ?: 0; // 新增用户会员充值总额
  116. $info = DB::table('orders')->where('status', "<>", 'UNPAID')
  117. ->whereBetween("created_at", [$start, $end])
  118. ->select(
  119. DB::raw("sum(if(status = 'unpaid', 0, price)) as recharge_total"), // 单日新增用户充值金额
  120. DB::raw("count(DISTINCT ranse_created_at,uid) as recharge_num") // 当日新增用户充值人数
  121. )->first();
  122. $recharge_total = $info->recharge_total ?: 0; // 充值金额
  123. // 充值笔数
  124. $recharge_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  125. ->whereBetween("created_at", [$start, $end])->count();
  126. $recharge_coin_total = DB::table('orders')->where('status', "<>", 'UNPAID')
  127. ->whereBetween("created_at", [$start, $end])
  128. ->whereIn('order_type', ["COIN", "FIRST_COIN"])->sum('price'); // 普通充值金额
  129. $recharge_vip_total = DB::table('orders')->where('status', "<>", 'UNPAID')
  130. ->whereBetween("created_at", [$start, $end])
  131. ->whereNotIn('order_type', ["COIN", "FIRST_COIN"])->sum('price'); // 会员充值金额
  132. } else {
  133. $key = sprintf(self::PROMOTION_STATISTIC_RECORD_REDIS_KEY, $date);
  134. $new_user_recharge_total = self::getValue($key, sprintf(self::NEW_USER_RECHARGE_TOTAL, $accountId)); // 当日新增用户充值总额
  135. $new_user_recharge_num = self::getValue($key, sprintf(self::NEW_USER_RECHARGE_NUM, $accountId)); // 当日新增用户充值人数
  136. $new_user_num = self::getValue($key, sprintf(self::NEW_USER_NUM, $accountId)); // 当日新增用户人数
  137. if ($type == 2) {
  138. $where = ['puser_id' => $accountId];
  139. } else {
  140. $where = ['user_id' => $accountId];
  141. }
  142. $info = DB::table('orders')->where('status', "<>", 'UNPAID')
  143. ->where($where)
  144. ->whereBetween("created_at", [$start, $end])
  145. ->whereBetween('ranse_created_at', [$start, $end])
  146. ->whereIn('order_type', ["COIN", "FIRST_COIN"])->select(
  147. DB::raw("sum(if(status = 'unpaid', 0, price)) as recharge_total"), // 单日新增用户充值金额
  148. DB::raw("count(DISTINCT ranse_created_at,uid) as recharge_num") // 当日新增用户充值人数
  149. )->first(); // 普通充值金额
  150. $new_user_recharge_coin_total = $info->recharge_total ?: 0; // 新增用户普通充值总额
  151. $new_user_recharge_coin_num = $info->recharge_num ?: 0; // 新增用户普通充值总额
  152. $info = DB::table('orders')->where('status', "<>", 'UNPAID')
  153. ->where($where)
  154. ->whereBetween("created_at", [$start, $end])
  155. ->whereBetween('ranse_created_at', [$start, $end])
  156. ->whereNotIn('order_type', ["COIN", "FIRST_COIN"])
  157. ->select(
  158. DB::raw("sum(if(status = 'unpaid', 0, price)) as recharge_total"), // 单日新增用户充值金额
  159. DB::raw("count(DISTINCT ranse_created_at,uid) as recharge_num") // 当日新增用户充值人数
  160. )->first(); // 会员充值金额
  161. $new_user_recharge_vip_total = $info->recharge_total ?: 0; // 新增用户会员充值总额
  162. $new_user_recharge_vip_num = $info->recharge_num ?: 0; // 新增用户会员充值总额
  163. $info = DB::table('orders')->where('status', "<>", 'UNPAID')
  164. ->whereBetween("created_at", [$start, $end])
  165. ->where($where)
  166. ->select(
  167. DB::raw("sum(if(status = 'unpaid', 0, price)) as recharge_total"), // 单日新增用户充值金额
  168. DB::raw("count(DISTINCT ranse_created_at,uid) as recharge_num") // 当日新增用户充值人数
  169. )->first();
  170. $recharge_total = $info->recharge_total ?: 0; // 充值人数
  171. $recharge_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  172. ->whereBetween("created_at", [$start, $end])
  173. ->where($where)->count();
  174. $recharge_coin_total = DB::table('orders')->where('status', "<>", 'UNPAID')
  175. ->where($where)
  176. ->whereBetween("created_at", [$start, $end])
  177. ->whereIn('order_type', ["COIN", "FIRST_COIN"])->sum('price'); // 普通充值金额
  178. $recharge_vip_total = DB::table('orders')->where('status', "<>", 'UNPAID')
  179. ->where($where)
  180. ->whereBetween("created_at", [$start, $end])
  181. ->whereNotIn('order_type', ["COIN", "FIRST_COIN"])->sum('price'); // 会员充值金额
  182. }
  183. $data = [
  184. 'new_user_num' => $new_user_num, // 新增用户数
  185. 'new_user_recharge_num' => $new_user_recharge_num, // 新增用户充值人数
  186. 'new_user_recharge_coin_num' => $new_user_recharge_coin_num, // 新增用户普通充值人数
  187. 'new_user_recharge_vip_num' => $new_user_recharge_vip_num, // 新增用户vip充值人数
  188. 'new_user_recharge_total' => $new_user_recharge_total, // 新增用户充值金额
  189. 'new_user_recharge_vip_total' => $new_user_recharge_vip_total, // 新增用户普通充值金额
  190. 'new_user_recharge_coin_total' => $new_user_recharge_coin_total, // 新增用户vip充值金额
  191. 'recharge_total' => $recharge_total, // 充值金额
  192. 'recharge_coin_totall' => $recharge_coin_total, // 普通充值金额
  193. 'recharge_vip_total' => $recharge_vip_total, // VIP 充值金额
  194. 'recharge_num' => $recharge_num, // 充值笔数
  195. ];
  196. // 新增用户充值率
  197. $data['new_user_recharge_rate'] = $data['new_user_num'] > 0 && $data['new_user_recharge_num'] > 0 ? sprintf("%.2f%s",$data['new_user_recharge_num']/$data['new_user_num'],"%") : 0;
  198. // 新增用户人均充值
  199. $data['new_user_mean'] = $data['new_user_num'] > 0 && $data['new_user_recharge_total'] > 0 ? sprintf("%.2f",$data['new_user_recharge_total']/$data['new_user_num']) : 0;
  200. $data['recharge_mean'] = $data['recharge_total'] > 0 && $data['recharge_num'] > 0 ? sprintf("%.2f",$data['recharge_total']/$data['recharge_num'],"%") : 0; // 新增用户人均充值
  201. return $data;
  202. }
  203. /**
  204. * 保存redis的值
  205. * name: setValue
  206. * @param $key
  207. * @param $field
  208. * @param $value
  209. * date 2023/06/25 15:57
  210. */
  211. protected static function setValue($key, $field, $value)
  212. {
  213. Redis::hset($key, $field, $value);
  214. }
  215. /**
  216. * 充值人数查询
  217. * name: getRechargeUserNum
  218. * @param $accountId 账号id
  219. * @param $miniProgramId 小程序id
  220. * @param mixed $type 账号类型 2 投放公司 3 优化师
  221. * date 2023/06/20 10:18
  222. */
  223. private static function getRechargeUserNum($accountId, mixed $type): array
  224. {
  225. $start = date("Y-m-d") . " 00:00:00";
  226. $end = date("Y-m-d") . " 23:59:59";
  227. if ($type == 2) {
  228. // 投放公司
  229. $recharge_coin_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  230. ->where('puser_id', $accountId)->whereBetween("created_at", [$start, $end])
  231. ->whereBetween('ranse_created_at', [$start, $end])
  232. ->whereIn("order_type", ["COIN", "FIRST_COIN"])->groupBy('uid', 'ranse_created_at')->count();
  233. $recharge_vip_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  234. ->where('puser_id', $accountId)->whereBetween("created_at", [$start, $end])
  235. ->whereBetween('ranse_created_at', [$start, $end])
  236. ->whereNotIn("order_type", ["COIN", "FIRST_COIN"])->groupBy('uid', 'ranse_created_at')->count();
  237. } elseif ($type == 3) {
  238. // 优化师
  239. $recharge_coin_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  240. ->where('user_id', $accountId)->whereBetween("created_at", [$start, $end])
  241. ->whereBetween('ranse_created_at', [$start, $end])
  242. ->whereIn("order_type", ["COIN", "FIRST_COIN"])->groupBy('uid', 'ranse_created_at')->count();
  243. $recharge_vip_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  244. ->where('user_id', $accountId)->whereBetween("created_at", [$start, $end])
  245. ->whereBetween('ranse_created_at', [$start, $end])
  246. ->whereNotIn("order_type", ["COIN", "FIRST_COIN"])->groupBy('uid', 'ranse_created_at')->count();
  247. } else {
  248. // 其他暂不统计
  249. $recharge_coin_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  250. ->whereBetween("created_at", [$start, $end])
  251. ->whereBetween('ranse_created_at', [$start, $end])
  252. ->whereIn("order_type", ["COIN", "FIRST_COIN"])->groupBy('uid', 'ranse_created_at')->count();
  253. $recharge_vip_num = DB::table('orders')->where('status', "<>", 'UNPAID')
  254. ->whereBetween("created_at", [$start, $end])
  255. ->whereBetween('ranse_created_at', [$start, $end])
  256. ->whereNotIn("order_type", ["COIN", "FIRST_COIN"])->groupBy('uid', 'ranse_created_at')->count();
  257. }
  258. return [$recharge_coin_num, $recharge_vip_num];
  259. }
  260. /**
  261. *
  262. * name: getTodayData
  263. * @param int $accountId 账号id
  264. * @param mixed $type 账号类型 1 其他 2 投放公司 3 优化师
  265. */
  266. public static function historyStats(int $accountId, $type)
  267. {
  268. print_sql();
  269. $month = self::getStaticsData($accountId, date('Y-m-01'), date('Y-m-d', strtotime('yesterday')), $type);
  270. $lastMonth = self::getStaticsData($accountId, date('Y-m-01', strtotime(date('Y-m-01')) - 10), date('Y-m-d', strtotime(date('Y-m-01')) - 10), $type);
  271. $history = self::getHistoryData($accountId, $type);
  272. return ['month' => $month, 'lastMonth' => $lastMonth, 'history' => $history];
  273. }
  274. /**
  275. * 历史汇总
  276. * name: getMonthData
  277. * @param int $accountId 账号
  278. * @param mixed $type 角色类型 账号类型 1 其他 2 投放公司 3 优化师
  279. * @param mixed $minId 小程序id
  280. * date 2023/06/27 11:19
  281. */
  282. protected static function getHistoryData($accountId, $type, $minId = 0)
  283. {
  284. $date = date('Y-m-d', strtotime('yesterday'));
  285. $sql = TjOptimizerDayNewUser::where('date', $date);
  286. if ($type == 2) {
  287. $sql->where('puser_id', $accountId);
  288. } elseif ($type == 3) {
  289. $sql->where('puser_id', $accountId);
  290. }
  291. if ($minId) {
  292. $sql->where('miniprogram_id', $minId);
  293. }
  294. $info = $sql->select(
  295. DB::raw("sum(recharge_amount_total) as recharge_amount_total"), // 总充金额
  296. DB::raw("sum(recharge_user_total) as recharge_user_total"), // 累计充值人数
  297. )->first();
  298. return [
  299. 'recharge_amount_total' => $info->recharge_amount_total ?: 0,
  300. 'recharge_user_total' => $info->recharge_user_total ?: 0,
  301. ];
  302. }
  303. /**
  304. * 日期范围的统计
  305. * name: getMonthData
  306. * @param int $accountId 账号
  307. * @param mixed $type 角色类型 账号类型 1 其他 2 投放公司 3 优化师
  308. * @param mixed $minId 小程序id
  309. * date 2023/06/27 11:19
  310. */
  311. private static function getStaticsData($accountId, $start, $end, $type, $minId = 0)
  312. {
  313. $sql = TjOptimizerDayNewUser::where('date', '>=', $start)->where("date", "<=", $end);
  314. if ($type == 2) {
  315. $sql->where('puser_id', $accountId);
  316. } elseif ($type == 3) {
  317. $sql->where('puser_id', $accountId);
  318. }
  319. if ($minId) {
  320. $sql->where('miniprogram_id', $minId);
  321. }
  322. return self::handleStaticData($sql);
  323. }
  324. /**
  325. * 统计数据处理
  326. * name: handelStaticData
  327. * @param $sql
  328. * @return array
  329. * date 2023/06/27 14:51
  330. */
  331. protected static function handleStaticData($sql): array
  332. {
  333. $info = $sql->select(
  334. DB::raw("sum(new_user_recharge_total) as new_user_recharge_total"), // 充值人数
  335. DB::raw("sum(new_user_num) as new_user_num"), // 新增用户人数
  336. DB::raw("sum(new_user_recharge_num) as new_user_recharge_num"), // 充值人数
  337. DB::raw("sum(new_user_recharge_vip_num) as new_user_recharge_vip_num"), // VIP充值人数
  338. DB::raw("sum(new_user_recharge_coin_num) as new_user_recharge_coin_num") // 普通充值人数
  339. )->first();
  340. return [
  341. 'new_user_recharge_total' => $info->new_user_recharge_total ?: 0,
  342. 'new_user_num' => $info->new_user_num ?: 0,
  343. 'new_user_recharge_num' => $info->new_user_recharge_num ?: 0,
  344. 'new_user_recharge_vip_num' => $info->new_user_recharge_vip_num ?: 0,
  345. 'new_user_recharge_coin_num' => $info->new_user_recharge_coin_num ?: 0,
  346. ];
  347. }
  348. /**
  349. * 统计列表
  350. */
  351. public static function list($param)
  352. {
  353. $sql = self::getQuerySql($param)->select("tj_optimizer_day_new_users.*", 'users.username')->orderBy('date', 'desc')->orderBy('id', 'desc');
  354. $isAll = getProp($param, 'is_all');
  355. if ($isAll) {
  356. $list = $sql->get();
  357. } else {
  358. $list = $sql->paginate(getProp($param, 'limit', 15));
  359. }
  360. if ($list->isEmpty()) {
  361. return $list;
  362. }
  363. $companyIds = $list->pluck('puser_id')->unique()->toArray();
  364. $companys = DB::table('users')->whereIn('id', $companyIds)->get();
  365. foreach ($list as $value) {
  366. // 充值率
  367. $value->recharge_rate = $value->new_user_recharge_num > 0 && $value->new_user_num > 0 ? sprintf("%.2f%s", $value->new_user_recharge_num / $value->new_user_num, "%") : 0;
  368. // 人均充值
  369. $value->recharge_mean = $value->new_user_recharge_num > 0 && $value->new_user_recharge_total > 0 ? sprintf("%.2f%s", $value->new_user_recharge_total / $value->new_user_recharge_num, "%") : 0;
  370. $value->company_name = $companys->where('id', $value->puser_id)->value('username');
  371. }
  372. return $list;
  373. }
  374. // 列表数据统计
  375. public static function listStatistics($param): array
  376. {
  377. $sql = self::getQuerySql($param);
  378. return self::handleStaticData($sql);
  379. }
  380. private static function getQuerySql(array $param)
  381. {
  382. $sql = TjOptimizerDayNewUser::query()->leftJoin('users', 'users.id', "=", 'tj_optimizer_day_new_users.user_id');
  383. if (getProp($param, 'start_at')) {
  384. $sql->where('tj_optimizer_day_new_users.date', ">=", $param['start_at']);
  385. }
  386. if (getProp($param, 'end_at')) {
  387. $sql->where('tj_optimizer_day_new_users.date', "<=", $param['end_at']);
  388. }
  389. if (getProp($param, 'user_id')) {
  390. $sql->where('tj_optimizer_day_new_users.user_id', $param['user_id']);
  391. }
  392. if (getProp($param, 'puser_id')) {
  393. $sql->where('tj_optimizer_day_new_users.puser_id', $param['puser_id']);
  394. }
  395. if (getProp($param, 'miniprogram_id')) {
  396. $sql->where('tj_optimizer_day_new_users.miniprogram_id', $param['miniprogram_id']);
  397. }
  398. return $sql;
  399. }
  400. }