小说推广数据系统

PlayletDataStatistics.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <?php
  2. namespace App\Console\Commands;
  3. use App\Log;
  4. use App\Models\AccountPromoteConfig;
  5. use App\Models\AdsReport;
  6. use App\Models\PlayletConfig;
  7. use App\Models\PlayletStatisticsData;
  8. use App\Models\VpOrder;
  9. use App\Services\PlayletService;
  10. use Illuminate\Console\Command;
  11. class PlayletDataStatistics extends Command
  12. {
  13. protected $signature = 'PlayletDataStatistics';
  14. protected $description = '推手推广短剧离线数据统计';
  15. public function handle()
  16. {
  17. # 查询待处理的账号配置信息
  18. $accountConf = AccountPromoteConfig::where('enable', 1)->get();
  19. if(empty($accountConf)) {
  20. $this->infoMessage('暂无短剧推手配置信息');
  21. return false;
  22. }
  23. # 查询短剧信息
  24. $playletList = PlayletConfig::where('enable', 1)->get();
  25. if(empty($playletList)) {
  26. $this->infoMessage('暂无待处理的短剧信息');
  27. return false;
  28. }
  29. try {
  30. // 删除昨日离线数据,只保留当天的
  31. $yesterday = date('Y-m-d', strtotime('-1 day'));
  32. PlayletStatisticsData::where('created_date', $yesterday)->delete();
  33. $playletData = [];
  34. foreach ($accountConf as $conf) {
  35. $value = [];
  36. $date = date('Y-m-d');
  37. $value['start_date'] = $conf->start_date;
  38. $value['end_date'] = $conf->end_date > $date ? $date : $conf->end_date;
  39. $i = $value['start_date'];
  40. while($i<=$value['end_date']) {
  41. $key = $conf->playlet_id.'###'.$i;
  42. if(isset($playletData[$key])) {
  43. $playletData[$key]['app_list'][] = $conf->app_id;
  44. } else {
  45. $playletData[$key]['playlet_id'] = $conf->playlet_id;
  46. $playletData[$key]['subscribed_date'] = $i;
  47. $playletData[$key]['app_list'][] = $conf->app_id;
  48. }
  49. $i = date('Y-m-d', strtotime($i . ' +1 day'));
  50. }
  51. }
  52. if(empty($playletData)) {
  53. $this->infoMessage('短剧整理数据结果为空');
  54. return false;
  55. }
  56. # 获取推手-短剧对应日期的相关数据
  57. foreach ($playletData as $v) {
  58. # 获取本次待处理的短剧信息
  59. $playletId = isset($v['playlet_id']) ? $v['playlet_id'] : null;
  60. if(empty($playletId))
  61. continue;
  62. $playletInfo = $playletList->where('id', $playletId)->first();
  63. if(empty($playletInfo)) {
  64. continue;
  65. }
  66. $this->info('短剧编号【'.$playletId.'】');
  67. $this->info('短剧名称【'.$playletInfo->name.'】');
  68. $v['playlet_name'] = $playletInfo->name;
  69. $v['start_date'] = $v['end_date'] = $v['subscribed_date'];
  70. $v['first_day_roi'] = 0;
  71. $v['day_paid'] = 0;
  72. $v['charge_total'] = 0;
  73. $v['cost_cover_rate'] = 0;
  74. $v['fans_increase'] = 0;
  75. $v['new_user_cost'] = 0;
  76. $v['new_user_charge_uv'] = 0;
  77. $v['new_user_charge_pv'] = 0;
  78. $v['charge_user_cost'] = 0;
  79. $v['charge_data'] = '';
  80. $chargeData = [];
  81. $this->infoMessage('开始处理短剧:'.$playletInfo->name.'在'.$v['start_date'].'日的数据;');
  82. $res = $this->paymentTrendByDay($v['app_list'], $v['subscribed_date']);
  83. if(empty($res)) {
  84. $this->infoMessage(' 短剧:'.$playletInfo->name.'在'.$v['start_date'].'日的趋势数据为空');
  85. }
  86. if(empty($v['app_list'])) {
  87. $this->infoMessage(' 短剧:'.$playletInfo->name.'在'.$v['start_date'].'日的app_list数据为空');
  88. # 当天消耗
  89. $v['day_paid'] = 0;
  90. # 新增粉丝数
  91. $v['fans_increase'] = 0;
  92. } else {
  93. # 数据计算处理以及赋予默认值
  94. $adsReport = AdsReport::selectRaw('sum(paid) as paid, sum(scan_follow_count) as follow_uv')->whereIn('app_id', $v['app_list'])
  95. ->where('ref_date', $v['subscribed_date'])->first();
  96. # 当天消耗
  97. $v['day_paid'] = isset($adsReport->paid) ? $v['day_paid'] + $adsReport->paid / 100 : $v['day_paid'];
  98. # 新增粉丝数
  99. $v['fans_increase'] = isset($adsReport->follow_uv) ? $v['fans_increase'] + $adsReport->follow_uv : $v['fans_increase'];
  100. }
  101. foreach($res as $item) {
  102. # 当日新用户累计充值
  103. $v['charge_total'] = isset($item['charge_total']) ? $v['charge_total'] + $item['charge_total'] : $v['charge_total'];
  104. # 充值人数
  105. $v['new_user_charge_uv'] = isset($item['new_user_charge_uv']) ? $v['new_user_charge_uv'] + $item['new_user_charge_uv'] : $v['new_user_charge_uv'];
  106. # 充值次数
  107. $v['new_user_charge_pv'] = isset($item['new_user_charge_pv']) ? $v['new_user_charge_pv'] + $item['new_user_charge_pv'] : $v['new_user_charge_pv'];
  108. # 开始日志至之后的100天数据
  109. for ($i = 0; $i < PlayletService::DAYS; $i++) {
  110. if (isset($chargeData[$i])) {
  111. //已存在,累加
  112. $chargeData[$i]['day_charge'] = isset($item['chargeData'][$i]['day_charge']) ? $chargeData[$i]['day_charge'] + $item['chargeData'][$i]['day_charge'] : 0;
  113. $chargeData[$i]['charge_total'] = isset($item['chargeData'][$i]['charge_total']) ? $chargeData[$i]['charge_total'] + $item['chargeData'][$i]['charge_total'] : 0;
  114. $chargeData[$i]['day_paid'] = isset($item['chargeData'][$i]['day_paid']) ? $chargeData[$i]['day_paid'] + $item['chargeData'][$i]['day_paid'] : 0;
  115. } else {
  116. //不存在,赋值
  117. $chargeData[$i]['day_charge'] = isset($item['chargeData'][$i]['day_charge']) ? $item['chargeData'][$i]['day_charge'] : 0;
  118. $chargeData[$i]['charge_total'] = isset($item['chargeData'][$i]['charge_total']) ? $item['chargeData'][$i]['charge_total'] : 0;
  119. $chargeData[$i]['day_paid'] = isset($item['chargeData'][$i]['day_paid']) ? $item['chargeData'][$i]['day_paid'] : 0;
  120. }
  121. }
  122. }
  123. /*上面两项不在循环中累加的原因在于,循环中重点统计有新增粉丝的数据,循环中累加会丢失部分没有新粉数据日期的消耗*/
  124. # 首日ROI
  125. $v['first_day_roi'] = isset($chargeData[0]['day_paid']) && isset($chargeData[0]['day_charge']) && $chargeData[0]['day_paid'] != 0 ? ($chargeData[0]['day_charge'] / $chargeData[0]['day_paid']) : 0;
  126. # 回本率
  127. $v['cost_cover_rate'] = $v['day_paid'] != 0 ? ($v['charge_total'] / $v['day_paid']) : 0;
  128. # 新增粉丝成本
  129. $v['new_user_cost'] = $v['fans_increase'] != 0 ? ($v['day_paid'] / $v['fans_increase']) : 0;
  130. # 充值用户成本
  131. $v['charge_user_cost'] = $v['new_user_charge_uv'] != 0 ? ($v['day_paid'] / $v['new_user_charge_uv']) : 0;
  132. for ($i = 0; $i < PlayletService::DAYS; $i++) {
  133. $chargeData[$i]['day_charge'] = isset($chargeData[$i]['day_charge']) ? $chargeData[$i]['day_charge'] : 0;
  134. $chargeData[$i]['charge_total'] = isset($chargeData[$i]['charge_total']) ? $chargeData[$i]['charge_total'] : 0;
  135. $chargeData[$i]['day_paid'] = isset($chargeData[$i]['day_paid']) ? $chargeData[$i]['day_paid'] : 0;
  136. $chargeData[$i]['day_add'] = (isset($chargeData[$i]['day_paid']) && $chargeData[$i]['day_paid'] != 0) ? ($chargeData[$i]['day_charge'] / $chargeData[$i]['day_paid']) : 0;
  137. $chargeData[$i]['day_cover'] = (isset($chargeData[$i]['day_paid']) && $chargeData[$i]['day_paid'] != 0) ? ($chargeData[$i]['charge_total'] / $chargeData[$i]['day_paid']) : 0;
  138. $chargeData[$i]['day_times'] = isset($chargeData[$i]['day_paid']) && ($chargeData[$i]['day_paid'] * $v['first_day_roi']) != 0 ? ($chargeData[$i]['charge_total'] / ($chargeData[$i]['day_paid'] * $v['first_day_roi'])) : 0;
  139. }
  140. // }
  141. $v['charge_data'] = json_encode($chargeData);
  142. $this->insertData($v);
  143. unset($v);
  144. unset($chargeData);
  145. unset($res);
  146. }
  147. } catch (\Exception $e) {
  148. $this->infoMessage(' 异常###file:'.$e->getFile().';line:'.$e->getLine().';message:'.$e->getMessage());
  149. return false;
  150. }
  151. }
  152. /**
  153. * 账号在某天对应的付费趋势数据
  154. * */
  155. public static function paymentTrendByDay($appId, $date)
  156. {
  157. # 获取对应的公众号AppId
  158. if(is_array($appId)){
  159. $appIdList = $appId;
  160. } else {
  161. $appIdList = [$appId];
  162. }
  163. # 获取各日期对应的花费
  164. $paidList = AdsReport::getPaidData($appIdList, [$date]);
  165. $result = [];
  166. foreach($appIdList as $app_id){
  167. $trend = [];
  168. $fansData = self::subscribedFansData($app_id, $date, $date);
  169. $trend['fans_total'] = isset($fansData->fans_total) ? $fansData->fans_total : 0;
  170. $trend['charge_total'] = isset($fansData->charge_total) ? $fansData->charge_total / 10000 : 0;
  171. $trend['app_id'] = $app_id;
  172. # 当日消耗
  173. $paidInfo = $paidList->where('app_id', $app_id)
  174. ->where('ref_date', $date)
  175. ->first();
  176. $trend['day_paid'] = isset($paidInfo->paid) ? ($paidInfo->paid / 100) : 0;
  177. # 获取当日新用户充值情况
  178. $newUserCharge = VpOrder::getNewUserChargeFirstDay($date, $app_id);
  179. $trend['new_user_charge'] = isset($newUserCharge->new_user_charge) ? $newUserCharge->new_user_charge : 0;
  180. $trend['new_user_charge_uv'] = isset($newUserCharge->new_user_charge_uv) ? $newUserCharge->new_user_charge_uv : 0;
  181. $trend['new_user_charge_pv'] = isset($newUserCharge->new_user_charge_pv) ? $newUserCharge->new_user_charge_pv : 0;
  182. $trend['first_day_roi'] = $trend['day_paid'] != 0 ? (($trend['new_user_charge'] / 100) / $trend['day_paid']) : 0;
  183. // 充增回倍
  184. $trend['chargeData'] = PlayletService::chargeAfterSubscribed(
  185. $date, PlayletService::DAYS, $app_id, $trend['first_day_roi'], $trend['day_paid']
  186. );
  187. $result[] = $trend;
  188. }
  189. return $result;
  190. }
  191. private function insertData($playlet)
  192. {
  193. $insertData['start_date'] = $playlet['start_date'];
  194. $insertData['end_date'] = $playlet['end_date'];
  195. $insertData['playlet_name'] = $playlet['playlet_name'];
  196. $insertData['playlet_id'] = $playlet['playlet_id'];
  197. $insertData['first_day_roi'] = $playlet['first_day_roi'];
  198. $insertData['day_paid'] = $playlet['day_paid'];
  199. $insertData['charge_total'] = $playlet['charge_total'];
  200. $insertData['cost_cover_rate'] = $playlet['cost_cover_rate'];
  201. $insertData['fans_increase'] = $playlet['fans_increase'];
  202. $insertData['new_user_cost'] = $playlet['new_user_cost'];
  203. $insertData['new_user_charge_uv'] = $playlet['new_user_charge_uv'];
  204. $insertData['new_user_charge_pv'] = $playlet['new_user_charge_pv'];
  205. $insertData['charge_user_cost'] = $playlet['charge_user_cost'];
  206. $insertData['charge_data'] = $playlet['charge_data'];
  207. $insertData['created_date'] = date('Y-m-d');
  208. $row = PlayletStatisticsData::where('playlet_id', $insertData['playlet_id'])->where('created_date', $insertData['created_date'])
  209. ->where('start_date', $insertData['start_date'])->first();
  210. if($row) {
  211. # 更新
  212. $res = PlayletStatisticsData::where('playlet_id', $insertData['playlet_id'])->where('created_date', $insertData['created_date'])
  213. ->where('start_date', $insertData['start_date'])->update($insertData);
  214. if($res) {
  215. # 更新成功
  216. $this->infoMessage(' 处理短剧:'.$insertData['playlet_id'].'在'.$insertData['start_date'].'日的数据完成;处理结果:更新成功');
  217. } else {
  218. # 未有修改
  219. $this->infoMessage(' 处理短剧:'.$insertData['playlet_id'].'在'.$insertData['start_date'].'日的数据完成;处理结果:更新失败');
  220. }
  221. } else {
  222. # 插入
  223. $res = PlayletStatisticsData::insert($insertData);
  224. if($res) {
  225. # 新增成功
  226. $this->infoMessage(' 处理短剧:'.$insertData['playlet_id'].'在'.$insertData['start_date'].'日的数据完成;处理结果:更新成功');
  227. } else {
  228. # 新增失败
  229. $this->infoMessage(' 处理短剧:'.$insertData['playlet_id'].'在'.$insertData['start_date'].'日的数据完成;处理结果:更新失败');
  230. }
  231. }
  232. }
  233. /*
  234. * 获取账号指定日期新关注粉丝数据
  235. * */
  236. public static function subscribedFansData($appId, $startDate, $endDate)
  237. {
  238. # 获取公众号数据
  239. $data = VpOrder::selectRaw("DATE_FORMAT(mp_user_register_time, '%Y-%m-%d') as subscribed_date, count(openid) as fans_total, app_id, sum(pay_money) as charge_total")->where('enable', 1)
  240. ->where('app_id', $appId)
  241. ->where('mp_user_register_time', '>=', $startDate . ' 00:00:00')
  242. ->where('mp_user_register_time', '<=', $endDate . ' 23:59:59')
  243. ->where('pay_status', 1)
  244. ->first();
  245. return $data;
  246. }
  247. private function infoMessage($message)
  248. {
  249. $this->info(date('Y-m-d H:i:s') . ' ' .$message .' 内存占用:'.round(memory_get_usage()/1024/1024, 2).'MB'. "\r\n");
  250. }
  251. }