企微短剧业务系统

NewStatisticsService.php 62KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: shensong
  5. * Date: 2023/1/10
  6. * Time: 18:23
  7. */
  8. namespace App\Service;
  9. use App\Log;
  10. use App\Models\AdqUser;
  11. use App\Models\AuthorizeCorp;
  12. use App\Models\DjOrder;
  13. use App\Models\DjUser;
  14. use App\Models\DramaSeries;
  15. use App\Models\DramaUserRela;
  16. use App\Models\Es\AccountDataTrend;
  17. use App\Models\OfficialAccount;
  18. use App\Models\PlayletTrendStatistics;
  19. use App\Models\Report\CustomerServiceData;
  20. use App\Models\Report\DjCumulativeRecoveryData;
  21. use App\Models\Report\DjRegUserRangeReport;
  22. use App\Models\Report\NonReleaseRecovery;
  23. use App\Models\Report\OperateDayRetrieve;
  24. use App\Models\System\AdminManageCorp;
  25. use App\Models\System\Users;
  26. use App\Models\TencentAdAuth;
  27. use App\Models\TencentAdDailyReport;
  28. use App\RedisModel;
  29. use App\Service\Admin\AdminService;
  30. use App\Support\EmailQueue;
  31. class NewStatisticsService
  32. {
  33. # 运营数据统计
  34. public static function operateDayRetrieveByAccount($appId, $start, $end, $page, $pageSize, $dramaId, $sysGroupId
  35. , $adminId, $isSystemAdmin)
  36. {
  37. $today_date = date('Y-m-d');
  38. // 若选择截止日期大于今日,则将截止日期修改为今日
  39. if( !$end || $end>$today_date ){
  40. $end = $today_date;
  41. }
  42. #定义回收时段
  43. $retrievePart = array(); // 动态表头对应的默认回收数据
  44. $retrieveColumns = array(); // 动态表头
  45. $dmonth = $ddmonth = date('Y-m-01'); //当前月份
  46. $dymonth = date('Y-01-01', strtotime('-1 years'));//去年一月
  47. // 今年月份表头以及对应默认值格式化
  48. while($dmonth>=$dymonth){
  49. $retrievePart[$dmonth] = 0;
  50. $retrieveColumns[] = [
  51. 'name'=> intval( substr($dmonth, 2, 4) ) . '年' . intval( substr($dmonth, 5, 2) ).'月用户回收',
  52. 'column' => $dmonth
  53. ];
  54. $dmonth = date('Y-m-01', strtotime($dmonth.' -1 month'));
  55. }
  56. $lyear = $year = date('Y') - 2; // 去年
  57. while($year>='2021') {
  58. $retrievePart[$year] = 0; // 去年对应的默认回收数据
  59. $retrieveColumns[] = [
  60. 'name' => substr($year, 2, 2). '年用户回收',
  61. 'column' => $year
  62. ];
  63. $year = $year-1;
  64. }
  65. $retrievePart['other_pay_uv'] = 0;
  66. $retrievePart['other_pay_money'] = 0;
  67. $retrieveColumns[] = [
  68. 'name' => '非投放回收人数',
  69. 'column' => 'other_pay_uv'
  70. ];
  71. $retrieveColumns[] = [
  72. 'name' => '非投放回收金额',
  73. 'column' => 'other_pay_money'
  74. ];
  75. // 总回收表头字段及默认值
  76. $retrievePart['total_pay'] = 0;
  77. $retrieveColumns[] = [
  78. 'name' => '运营总回收',
  79. 'column' => 'total_pay'
  80. ];
  81. # 登录账号数据权限
  82. $mpAppIdList = OfficialAccount::getAccountMpAppIdList($adminId, $sysGroupId, $isSystemAdmin);
  83. if(empty($mpAppIdList)) {
  84. return [
  85. 'list' => [],
  86. 'total'=> 0,
  87. 'retrieveColumns' => $retrieveColumns
  88. ];
  89. }
  90. //短剧筛选
  91. if($dramaId){
  92. $dramaInfo = DramaUserRela::query()
  93. ->where('drama_id', $dramaId)
  94. ->where(function($query) use($appId, $mpAppIdList){
  95. if($appId) {
  96. $query->where('app_id', $appId);
  97. } else {
  98. $query->whereIn('app_id', $appId);
  99. }
  100. })
  101. ->where('sys_group_id', $sysGroupId)
  102. ->get();
  103. if( $dramaInfo->isEmpty() ){
  104. return [
  105. 'list' => [],
  106. 'total'=> 0,
  107. 'retrieveColumns' => $retrieveColumns
  108. ];
  109. }
  110. return NewStatisticsService::operateDayRetrieveDrama($dramaInfo, $start, $end, $retrievePart, $retrieveColumns
  111. , $page, $pageSize, $mpAppIdList);
  112. }
  113. if( !$start ){
  114. $start = date('Y-m-d', strtotime('-12 month'));
  115. }
  116. $total = (strtotime($end) - strtotime($start))/86400+1;
  117. $offset = ($page-1) * $pageSize;
  118. $npNum = $total<$pageSize ? $total : $pageSize;
  119. $pEnd = date('Y-m-d', strtotime($end .' -'.$offset.' day'));
  120. $pStart = date('Y-m-d', strtotime($pEnd .' -'.($npNum-1).' day'));
  121. if($pEnd<$start){
  122. return [
  123. 'list' => [],
  124. 'total'=> $total,
  125. 'retrieveColumns' => $retrieveColumns
  126. ];
  127. }
  128. if($pStart<$start){
  129. $pStart = $start;
  130. }
  131. $dataStat = self::getTrendData($pStart, $pEnd, $mpAppIdList, $sysGroupId, 1);
  132. $data = array();
  133. while($pStart<=$pEnd){
  134. if( isset($dataStat[$pEnd]) ){
  135. $data[] = $dataStat[$pEnd];
  136. } else {
  137. $retrieveInfo = $retrievePart;
  138. #查日报
  139. $cost = null;
  140. $fanNew = null;
  141. $dayReport = TencentAdDailyReport::query()
  142. ->where('ref_date', $pEnd)->whereIn('app_id', $mpAppIdList)
  143. ->selectRaw('sum(paid) as cost, sum(scan_follow_count) as fan_new')
  144. ->first();
  145. if( isset($dayReport->cost) ){
  146. $cost = round($dayReport->cost/100, 2);
  147. $fanNew = $dayReport->fan_new;
  148. }
  149. #查当日订单
  150. $orders = DjOrder::query()
  151. ->where('order_pay_time', '>=', strtotime($pEnd.' 00:00:00').'000')
  152. ->where('order_pay_time', '<=', strtotime($pEnd.' 23:59:59').'000' )
  153. ->where('enable', 1)
  154. ->where('pay_status', 1)
  155. ->where('is_ad_user', 1)
  156. ->where('order_type', 1)
  157. ->whereIn('bind_app_id', $mpAppIdList)
  158. ->where(function($query) use($sysGroupId, $mpAppIdList, $appId){
  159. if($appId) $query->where('bind_app_id', $appId);
  160. })
  161. ->select('mp_user_register_time', 'pay_money', 'external_userid')
  162. ->get();
  163. $otherOrders = DjOrder::query()
  164. ->selectRaw('count(distinct(openid)) as pay_uv, sum(pay_money) as pay_money')
  165. ->where('order_pay_time', '>=', strtotime($pEnd.' 00:00:00').'000')
  166. ->where('order_pay_time', '<=', strtotime($pEnd.' 23:59:59').'000' )
  167. ->where('enable', 1)
  168. ->where('pay_status', 1)
  169. ->where('is_ad_user', 0)
  170. ->where('order_type', 1)
  171. ->where(function($query) use($sysGroupId){
  172. if($sysGroupId) $query->where('sys_group_id', $sysGroupId);
  173. })->first();
  174. $newPayArr = [];
  175. $newPayMoney = 0;
  176. if( !$orders->isEmpty() ){
  177. foreach($orders as $order){
  178. $order->pay_money = round($order->pay_money/10000, 2);
  179. $pay_date = date('Y-m-d', substr($order->mp_user_register_time, 0, 10));
  180. if( $pay_date==$pEnd ){
  181. //新用户
  182. $newPayArr[] = $order->external_userid;
  183. $newPayMoney += $order->pay_money;
  184. if($pay_date>=$dymonth){
  185. //今年的
  186. $mon_key = substr($pay_date, 0, 7).'-01';
  187. $retrieveInfo[$mon_key] += $order->pay_money;
  188. } else {
  189. //往年
  190. if(isset($retrieveInfo[substr($pay_date,0,4)])){
  191. $retrieveInfo[substr($pay_date,0,4)] += $order->pay_money;
  192. }
  193. }
  194. } else {
  195. if($pay_date>=$dymonth){
  196. //今年的
  197. $mon_key = substr($pay_date, 0, 7).'-01';
  198. $retrieveInfo[$mon_key] += $order->pay_money;
  199. } else {
  200. //往年
  201. if(isset($retrieveInfo[substr($pay_date,0,4)])){
  202. $retrieveInfo[substr($pay_date,0,4)] += $order->pay_money;
  203. }
  204. }
  205. }
  206. if($pay_date<$ddmonth){
  207. $retrieveInfo['total_pay'] += $order->pay_money;
  208. }
  209. }
  210. $newPayMoney = round($newPayMoney, 2);
  211. $retrieveInfo = array_map(function($val){
  212. return round($val, 2);
  213. }, $retrieveInfo);
  214. }
  215. $newPayUc = count( array_unique($newPayArr) );
  216. $newRoi = $cost>0 ? round($newPayMoney/$cost, 2) : null;
  217. $new_cost = $newPayUc>0 ? round($cost/$newPayUc, 2) : null;
  218. $otherPayUv = isset($otherOrders->pay_uv) ? $otherOrders->pay_uv : null;
  219. $other_pay_money = isset($otherOrders->pay_money) ? round($otherOrders->pay_money/10000, 2) : null;
  220. $retrieveInfo['other_pay_uv'] = $otherPayUv;
  221. $retrieveInfo['other_pay_money'] = $other_pay_money;
  222. $data[] = [
  223. 'date' => $pEnd,
  224. 'cost' => $cost,
  225. 'fan_new' => $fanNew,
  226. 'new_pay_uc' => $newPayUc,
  227. 'new_pay_money' => $newPayMoney,
  228. 'new_roi' => $newRoi,
  229. 'new_cost' => $new_cost,
  230. 'retrieveInfo' => $retrieveInfo,
  231. ];
  232. }
  233. $pEnd = date('Y-m-d', strtotime($pEnd.' -1 day'));
  234. }
  235. return [
  236. 'list' => $data,
  237. 'total' => $total,
  238. 'retrieveColumns' => $retrieveColumns
  239. ];
  240. }
  241. public static function operateDayRetrieveAdqByAccount($start, $end, $page, $pageSize, $sysGroupId, $adminId
  242. , $isSystemAdmin)
  243. {
  244. $today_date = date('Y-m-d');
  245. // 若选择截止日期大于今日,则将截止日期修改为今日
  246. if( !$end || $end>$today_date ){
  247. $end = $today_date;
  248. }
  249. #定义回收时段
  250. $retrievePart = array(); // 动态表头对应的默认回收数据
  251. $retrieveColumns = array(); // 动态表头
  252. $dmonth = $ddmonth = date('Y-m-01'); //当前月份
  253. $dymonth = date('Y-01-01', strtotime('-1 year'));//当年一月
  254. // 今年月份表头以及对应默认值格式化
  255. while($dmonth>=$dymonth){
  256. $retrievePart[$dmonth] = 0;
  257. $retrieveColumns[] = [
  258. 'name'=> intval( substr($dmonth, 2, 4) ) . '年' . intval( substr($dmonth, 5, 2) ) . '月用户回收',
  259. 'column' => $dmonth
  260. ];
  261. $dmonth = date('Y-m-01', strtotime($dmonth.' -1 month'));
  262. }
  263. $lyear = $year = date('Y') - 2; // 去年
  264. while($year >= '2021') {
  265. $retrievePart[$year] = 0; // 去年对应的默认回收数据
  266. $retrieveColumns[] = [
  267. 'name' => substr($year, 2, 2). '年用户回收',
  268. 'column' => $year
  269. ];
  270. $year = $year-1;
  271. }
  272. $retrievePart['other_pay_uv'] = 0;
  273. $retrievePart['other_pay_money'] = 0;
  274. $retrieveColumns[] = [
  275. 'name' => '非投放回收人数',
  276. 'column' => 'other_pay_uv'
  277. ];
  278. $retrieveColumns[] = [
  279. 'name' => '非投放回收金额',
  280. 'column' => 'other_pay_money'
  281. ];
  282. // 总回收表头字段及默认值
  283. $retrievePart['total_pay'] = 0;
  284. $retrieveColumns[] = [
  285. 'name' => '运营总回收',
  286. 'column' => 'total_pay'
  287. ];
  288. $adqAccountIdList = PitcherService::adqAccountListForUser($adminId, $sysGroupId, $isSystemAdmin);
  289. if(empty($adqAccountIdList)) {
  290. return [
  291. 'list' => [],
  292. 'total'=> 0,
  293. 'retrieveColumns' => $retrieveColumns
  294. ];
  295. }
  296. if( !$start ){
  297. $start = date('Y-m-d', strtotime('-12 month'));
  298. }
  299. $total = (strtotime($end) - strtotime($start))/86400+1;
  300. $offset = ($page-1) * $pageSize;
  301. $npNum = $total<$pageSize ? $total : $pageSize;
  302. $pEnd = date('Y-m-d', strtotime($end .' -'.$offset.' day'));
  303. $pStart = date('Y-m-d', strtotime($pEnd .' -'.($npNum-1).' day'));
  304. if($pEnd<$start){
  305. return [
  306. 'list' => [],
  307. 'total'=> $total,
  308. 'retrieveColumns' => $retrieveColumns
  309. ];
  310. }
  311. if($pStart<$start){
  312. $pStart = $start;
  313. }
  314. $dataStat = self::getTrendData($pStart, $pEnd, $adqAccountIdList, $sysGroupId, 2);
  315. $data = array();
  316. while($pStart<=$pEnd){
  317. if( isset($dataStat[$pEnd]) ){
  318. $data[] = $dataStat[$pEnd];
  319. } else {
  320. $retrieveInfo = $retrievePart;
  321. #查日报
  322. $cost = null;
  323. $fanNew = null;
  324. $dayReport = TencentAdDailyReport::query()
  325. ->where('ref_date', $pEnd)
  326. ->where(function($query) use($sysGroupId, $adqAccountIdList){
  327. if(!empty($sysGroupId)) $query->whereIn('account_id', $adqAccountIdList);
  328. })
  329. ->selectRaw('sum(paid) as cost, sum(scan_follow_count) as fan_new')
  330. ->first();
  331. if( isset($dayReport->cost) ){
  332. $cost = round($dayReport->cost/100, 2);
  333. $fanNew = $dayReport->fan_new;
  334. }
  335. #查当日订单
  336. $orders = DjOrder::query()
  337. ->where('order_pay_time', '>=', strtotime($pEnd.' 00:00:00').'000')
  338. ->where('order_pay_time', '<=', strtotime($pEnd.' 23:59:59').'000' )
  339. ->where('enable', 1)->where('pay_status', 1)
  340. ->where('order_type', 2)->where('is_ad_user', 1)
  341. ->whereIn('adq_account_id', $adqAccountIdList)
  342. ->select('mp_user_register_time', 'pay_money', 'external_userid')
  343. ->get();
  344. $otherOrders = DjOrder::query()
  345. ->selectRaw('count(distinct(openid)) as pay_uv, sum(pay_money) as pay_money')
  346. ->where('order_pay_time', '>=', strtotime($pEnd.' 00:00:00').'000')
  347. ->where('order_pay_time', '<=', strtotime($pEnd.' 23:59:59').'000' )
  348. ->where('enable', 1)->where('pay_status', 1)->where('is_ad_user', 0)->where('order_type', 2)
  349. ->where('sys_group_id', $sysGroupId)->first();
  350. $newPayArr = [];
  351. $newPayMoney = 0;
  352. if( !$orders->isEmpty() ){
  353. foreach($orders as $order){
  354. $order->pay_money = round($order->pay_money/10000, 2);
  355. $pay_date = date('Y-m-d', substr($order->mp_user_register_time, 0, 10));
  356. if( $pay_date==$pEnd ){
  357. //新用户
  358. $newPayArr[] = $order->external_userid;
  359. $newPayMoney += $order->pay_money;
  360. if($pay_date>=$dymonth){
  361. //今年的
  362. $mon_key = substr($pay_date, 0, 7).'-01';
  363. $retrieveInfo[$mon_key] += $order->pay_money;
  364. } else {
  365. //往年
  366. if(isset($retrieveInfo[substr($pay_date,0,4)])){
  367. $retrieveInfo[substr($pay_date,0,4)] += $order->pay_money;
  368. }
  369. }
  370. } else {
  371. if($pay_date>=$dymonth){
  372. //今年的
  373. $mon_key = substr($pay_date, 0, 7).'-01';
  374. $retrieveInfo[$mon_key] += $order->pay_money;
  375. } else {
  376. //往年
  377. if(isset($retrieveInfo[substr($pay_date,0,4)])){
  378. $retrieveInfo[substr($pay_date,0,4)] += $order->pay_money;
  379. }
  380. }
  381. }
  382. if($pay_date<$ddmonth){
  383. $retrieveInfo['total_pay'] += $order->pay_money;
  384. }
  385. }
  386. $newPayMoney = round($newPayMoney, 2);
  387. $retrieveInfo = array_map(function($val){
  388. return round($val, 2);
  389. }, $retrieveInfo);
  390. }
  391. $newPayUc = count( array_unique($newPayArr) );
  392. $newRoi = $cost>0 ? round($newPayMoney/$cost, 2) : null;
  393. $new_cost = $newPayUc>0 ? round($cost/$newPayUc, 2) : null;
  394. $otherPayUv = isset($otherOrders->pay_uv) ? $otherOrders->pay_uv : null;
  395. $other_pay_money = isset($otherOrders->pay_money) ? round($otherOrders->pay_money/10000, 2) : null;
  396. $retrieveInfo['other_pay_uv'] = $otherPayUv;
  397. $retrieveInfo['other_pay_money'] = $other_pay_money;
  398. $data[] = [
  399. 'date' => $pEnd,
  400. 'cost' => $cost,
  401. 'fan_new' => $fanNew,
  402. 'new_pay_uc' => $newPayUc,
  403. 'new_pay_money' => $newPayMoney,
  404. 'new_roi' => $newRoi,
  405. 'new_cost' => $new_cost,
  406. 'retrieveInfo' => $retrieveInfo,
  407. ];
  408. }
  409. $pEnd = date('Y-m-d', strtotime($pEnd.' -1 day'));
  410. }
  411. return [
  412. 'list' => $data,
  413. 'total' => $total,
  414. 'retrieveColumns' => $retrieveColumns
  415. ];
  416. }
  417. public static function operateDayRetrieveDrama($drama_info, $start, $end, $retrievePart, $retrieveColumns, $page,
  418. $pageSize, $mpAppIdList)
  419. {
  420. $ddmonth = date('Y-m-01');//当前月份
  421. $dymonth = date('Y-01-01', strtotime('-1 year'));//当年一月
  422. $data = array();
  423. foreach($drama_info as $item){
  424. $app_id = $item->app_id;
  425. if($start){
  426. if($item->start_date<$start){
  427. $item->start_date = $start;
  428. }
  429. }
  430. if($end){
  431. if($item->end_date>$end){
  432. $item->end_date = $end;
  433. }
  434. }
  435. $sdate = $item->start_date;
  436. $edate = $item->end_date;
  437. while($edate>=$sdate){
  438. $retrieveInfo = $retrievePart;
  439. #查日报
  440. $cost = null;
  441. $fan_new = null;
  442. $dayReport = TencentAdDailyReport::query()
  443. ->where('ref_date', $edate)
  444. ->where(function($query) use($app_id){
  445. if($app_id) $query->where('app_id', $app_id);
  446. })
  447. ->selectRaw('sum(paid) as cost, sum(scan_follow_count) as fan_new')
  448. ->first();
  449. if( isset($dayReport->cost) ){
  450. $cost = round($dayReport->cost/100, 2);
  451. $fan_new = $dayReport->fan_new;
  452. }
  453. #查当日订单
  454. $orders = DjOrder::query()
  455. ->where('order_pay_time', '>=', strtotime($edate.' 00:00:00').'000')
  456. ->where('order_pay_time', '<=', strtotime($edate.' 23:59:59').'000' )
  457. ->where('enable', 1)
  458. ->where('pay_status', 1)
  459. ->where('is_ad_user', 1)
  460. ->where('order_type', 1)
  461. ->where(function($query) use($app_id){
  462. if($app_id) $query->where('bind_app_id', $app_id);
  463. })
  464. ->select('mp_user_register_time', 'pay_money', 'external_userid')
  465. ->get();
  466. $otherOrders = DjOrder::query()
  467. ->selectRaw('count(distinct(openid)) as pay_uv, sum(pay_money) as pay_money')
  468. ->where('order_pay_time', '>=', strtotime($edate.' 00:00:00').'000')
  469. ->where('order_pay_time', '<=', strtotime($edate.' 23:59:59').'000' )
  470. ->where('enable', 1)
  471. ->where('pay_status', 1)
  472. ->where('is_ad_user', 0)
  473. ->where('order_type', 1)
  474. ->where(function($query) use($app_id){
  475. if($app_id) $query->where('bind_app_id', $app_id);
  476. })->first();
  477. $new_pay_arr = [];
  478. $new_pay_money = 0;
  479. if( !$orders->isEmpty() ){
  480. foreach($orders as $order){
  481. $order->pay_money = round($order->pay_money/10000, 2);
  482. $pay_date = date('Y-m-d', substr($order->mp_user_register_time, 0, 10));
  483. if( $pay_date==$edate ){
  484. //新用户
  485. $new_pay_arr[] = $order->external_userid;
  486. $new_pay_money += $order->pay_money;
  487. if($pay_date>=$dymonth){
  488. //今年的
  489. $mon_key = substr($pay_date, 0, 7).'-01';
  490. $retrieveInfo[$mon_key] += $order->pay_money;
  491. } else {
  492. //往年
  493. if(isset($retrieveInfo[substr($pay_date,0,4)])){
  494. $retrieveInfo[substr($pay_date,0,4)] += $order->pay_money;
  495. }
  496. }
  497. } else {
  498. if($pay_date>=$dymonth){
  499. //今年的
  500. $mon_key = substr($pay_date, 0, 7).'-01';
  501. $retrieveInfo[$mon_key] += $order->pay_money;
  502. } else {
  503. //往年
  504. if(isset($retrieveInfo[substr($pay_date,0,4)])){
  505. $retrieveInfo[substr($pay_date,0,4)] += $order->pay_money;
  506. }
  507. }
  508. }
  509. if($pay_date<$ddmonth){
  510. $retrieveInfo['total_pay'] += $order->pay_money;
  511. }
  512. }
  513. $new_pay_money = round($new_pay_money, 2);
  514. $retrieveInfo = array_map(function($val){
  515. return round($val, 2);
  516. }, $retrieveInfo);
  517. }
  518. $new_pay_uc = count( array_unique($new_pay_arr) );
  519. $new_roi = $cost>0 ? round($new_pay_money/$cost, 2) : null;
  520. $new_cost = $new_pay_uc>0 ? round($cost/$new_pay_uc, 2) : null;
  521. $other_pay_uv = isset($otherOrders->pay_uv) ? $otherOrders->pay_uv : 0;
  522. $other_pay_money = isset($$otherOrders->pay_money) ? round($otherOrders->pay_money/10000, 2) : 0;
  523. $retrieveInfo['other_pay_uv'] = $other_pay_uv;
  524. $retrieveInfo['other_pay_money'] = $other_pay_money;
  525. if( isset($data[$edate]) ){
  526. $data[$edate]['cost'] += $cost;
  527. $data[$edate]['fan_new'] += $fan_new;
  528. $data[$edate]['new_pay_uc'] += $new_pay_uc;
  529. $data[$edate]['new_pay_money'] += $new_pay_money;
  530. foreach($retrieveInfo as $k=>$v){
  531. $data[$edate]['retrieveInfo'][$k] += $v;
  532. }
  533. } else {
  534. $data[$edate] = [
  535. 'date' => $edate,
  536. 'cost' => $cost,
  537. 'fan_new' => $fan_new,
  538. 'new_pay_uc' => $new_pay_uc,
  539. 'new_pay_money' => $new_pay_money,
  540. 'new_roi' => $new_roi,
  541. 'new_cost' => $new_cost,
  542. 'retrieveInfo' => $retrieveInfo,
  543. ];
  544. }
  545. $edate = date('Y-m-d', strtotime($edate.' -1 day'));
  546. }
  547. }
  548. if( !empty($data) ){
  549. krsort($data);
  550. foreach($data as $k=>&$v){
  551. $v['new_roi'] = $v['cost']>0 ? round($v['new_pay_money']/$v['cost'], 2) : null;
  552. $v['new_cost'] = $v['new_pay_uc']>0 ? round($v['cost']/$v['new_pay_uc'], 2) : null;
  553. }
  554. }
  555. $offset = ($page-1) * $pageSize;
  556. $total = count($data);
  557. $list = array_slice(array_values($data), $offset, $pageSize);
  558. return [
  559. 'list' => $list,
  560. 'total' => $total,
  561. 'retrieveColumns' => $retrieveColumns
  562. ];
  563. }
  564. public static function getTrendData($startDate, $endDate, $accountIdList, $sysGroupId, $adType)
  565. {
  566. # 统一将需要的离线数据查询出来
  567. $dataStat = OperateDayRetrieve::query()->selectRaw('expense_date as date, recovery_month, '
  568. .'sum(cost) as cost, sum(fan_new) as fan_new, sum(new_pay_money) as new_pay_money, sum(recovery_money)'
  569. .' as recovery_money')->whereIn('account_id', $accountIdList)->where('expense_date', '>=', $startDate)
  570. ->where('expense_date', '<=', $endDate)->where('enable', 1)->groupBy(['date', 'recovery_month'])->get();
  571. $nonReleaseRecovery = NonReleaseRecovery::query()->selectRaw('expense_date as date, pay_uv, pay_money')
  572. ->where('enable', 1)->where('expense_date', '>=', $startDate)->where('expense_date', '<=', $endDate)
  573. ->where('sys_group_id', $sysGroupId)->where('ad_type', (3-$adType))->get();
  574. $data = [];
  575. $date = $startDate;
  576. $year = date('Y') - 2; // 去年
  577. $retrievePart = [];
  578. while($year >= '2021') {
  579. $retrievePart[$year] = 0; // 去年对应的默认回收数据
  580. $year = $year-1;
  581. }
  582. if($endDate >= date('Y-m-d', strtotime('-1 days'))) {
  583. $endDate = date('Y-m-d', strtotime('-1 days'));
  584. }
  585. // 实时查询首日下单人数(因为涉及到多个投放账号之间的充值人数去重问题)
  586. $newPayUcList = DjOrder::query()->selectRaw("FROM_UNIXTIME(LEFT(mp_user_register_time,10),'%Y-%m-%d') "
  587. ."as expense_date, count(distinct(external_userid)) as uv")
  588. ->where('pay_status', 1)->where('enable', 1)
  589. ->where('is_ad_user', 1)->where('order_type', $adType)
  590. ->where('mp_user_register_time', '>=', strtotime($startDate.' 00:00:00').'000')
  591. ->where('mp_user_register_time', '<=', strtotime($endDate.' 23:59:59').'000' )
  592. ->where('order_pay_time', '>=', strtotime($startDate.' 00:00:00').'000')
  593. ->where('order_pay_time', '<=', strtotime($endDate.' 23:59:59').'000' )
  594. ->whereRaw("FROM_UNIXTIME(LEFT(mp_user_register_time,10),'%Y-%m-%d')=FROM_UNIXTIME(LEFT(order_pay_time,10),'%Y-%m-%d')")
  595. ->where(function ($query) use ($adType, $accountIdList) {
  596. if(1 == $adType) {
  597. $query->whereIn('bind_app_id', $accountIdList);
  598. } else {
  599. $query->whereIn('adq_account_id', $accountIdList);
  600. }
  601. })->groupBy('expense_date')->get();
  602. // 将所需要的数据按照日期处理成之前接口的格式,然后返回
  603. while($date <= $endDate) {
  604. $item = [];
  605. $item['date'] = $date;
  606. // 统计日期的成本,新粉数,新粉充值金额直接累加
  607. $item['cost'] = $dataStat->where('date', $date)->sum('cost');
  608. $item['fan_new'] = $dataStat->where('date', $date)->sum('fan_new');
  609. $item['new_pay_money'] = $dataStat->where('date', $date)->sum('new_pay_money');
  610. $newPayUc = $newPayUcList->where('expense_date', $date)->first();
  611. $item['new_pay_uc'] = isset($newPayUc->uv) ? round($newPayUc->uv) : 0;
  612. // 计算企微成本以及首日roi
  613. $item['new_cost'] = $item['new_pay_uc'] > 0 ? round($item['cost']/$item['new_pay_uc'], 2) : 0;
  614. $item['new_roi'] = $item['cost'] > 0 ? round($item['new_pay_money']/$item['cost'], 2) : 0;
  615. // 这里这样处理的原因是需要保持和之前接口返回的数据格式一致
  616. $retrieveInfo = [];
  617. $month = date('Y-01', strtotime('-1 year'));
  618. $endMonth = date('Y-m');
  619. // 统计近两年各个月份的回收金额,按月份放入一个字段中
  620. while($month<=$endMonth){
  621. $recoveryInfo = $dataStat->where('date', $date)->where('recovery_month', $month)
  622. ->first();
  623. $retrieveInfo[$month.'-01'] = isset($recoveryInfo->recovery_money) ? round($recoveryInfo->recovery_money, 2): 0;
  624. $month = date('Y-m', strtotime($month.'+1 month'));
  625. }
  626. foreach($retrievePart as $year => $payMoney) {
  627. // 统计去年的回收金额
  628. $retrieveInfo[$year] = $dataStat->where('recovery_month', '>=', $year.'-01')
  629. ->where('recovery_month', '<=', $year . '-12')->where('date', $date)
  630. ->sum('recovery_money');
  631. $retrieveInfo[$year] = round($retrieveInfo[$year], 2);
  632. }
  633. // 因为非投放回收金额无法归类到具体的投放账号,因此这里展示了所在公司账号在当天的回收金额以及人数
  634. $retrieveInfo['other_pay_uv'] = $nonReleaseRecovery->where('date', $date)->sum('pay_uv');
  635. $retrieveInfo['other_pay_money'] = $nonReleaseRecovery->where('date', $date)->sum('pay_money');
  636. $retrieveInfo['total_pay'] = $dataStat->where('date', $date)
  637. ->where('recovery_month', '<', date('Y-m'))->sum('recovery_money');
  638. # 数据格式化处理
  639. $retrieveInfo['other_pay_uv'] = round($retrieveInfo['other_pay_uv']);
  640. $retrieveInfo['other_pay_money'] = round($retrieveInfo['other_pay_money']);
  641. $retrieveInfo['total_pay'] = round($retrieveInfo['total_pay'], 2);
  642. $item['retrieveInfo'] = $retrieveInfo;
  643. $item['cost'] = round($item['cost'], 2);
  644. $item['fan_new'] = round($item['fan_new']);
  645. $item['new_pay_money'] = round($item['new_pay_money'], 2);
  646. $data[$date] = $item;
  647. $date = date('Y-m-d', strtotime($date . ' +1 days'));
  648. }
  649. return $data;
  650. }
  651. /* 数据循环统计 */
  652. public static function dataCycleListByAccount($params, $orderType, $page, $pageSize, $sortField, $sortType)
  653. {
  654. $requestData = [
  655. 'page' => $page,
  656. 'page_size' => $pageSize,
  657. 'sort_field' => $sortField,
  658. 'sort_type' => $sortType,
  659. 'params' => $params,
  660. 'order_type' => $orderType,
  661. ];
  662. $count = 0;
  663. $overview = [];
  664. $data = [];
  665. //补充头列表
  666. $head = [
  667. ['column' => 'date', 'name' => '用户注册时间', 'notes' => '', 'enable_to_sort' => true],
  668. ['column' => 'advertiser_cost', 'name' => '投放消耗', 'notes' => '', 'enable_to_sort' => true],
  669. ['column' => 'follow_uv', 'name' => '企微关注数', 'notes' => '', 'enable_to_sort' => true],
  670. ['column' => 'per_follow_cost', 'name' => '企微关注成本', 'notes' => '', 'enable_to_sort' => true],
  671. ['column' => 'first_order_cost', 'name' => '下单成本', 'notes' => '投放消耗/当日新增用户首单人数', 'enable_to_sort' => true],
  672. ['column' => 'first_order_cost_unique', 'name' => '下单成本(去重)', 'notes' => '投放消耗/当日新增用户首单人数(去重)', 'enable_to_sort' => false],
  673. ['column' => 'total_cvt_amt', 'name' => '总回收金额', 'notes' => '', 'enable_to_sort' => true],
  674. ['column' => 'total_roi', 'name' => '总回收', 'notes' => '总回收金额/投放消耗', 'enable_to_sort' => true],
  675. ];
  676. $overviewHead = $listHead = $head;
  677. foreach (DjRegUserRangeReport::count_range_days() as $day) {
  678. $listHead[] = ['column'=>'day'.$day.'_roi' , 'name' => 'day'.$day , 'notes' => '', 'enable_to_sort' => false];
  679. }
  680. // Log::logInfo('1', [getMillisecond()], 'time_test');
  681. try{
  682. // 1mp 2adq
  683. if(1 == $orderType) {
  684. $accountIdList = OfficialAccount::getAccountMpAppIdList($params['admin_id'], $params['sys_group_id'], $params['is_system_admin']);
  685. } else {
  686. $accountIdList = PitcherService::adqAccountListForUser($params['admin_id'], $params['sys_group_id'], $params['is_system_admin']);
  687. }
  688. // Log::logInfo('2', [getMillisecond()], 'time_test');
  689. if(empty($accountIdList)){
  690. $overview['head'] = $overviewHead;
  691. $overview['list'] = [];
  692. $data['head'] = $listHead;
  693. $data['list'] = [];
  694. return [0, $data, $overview];
  695. }
  696. if(isset($params['closing_date']) && $params['closing_date']) {
  697. if($params['closing_date'] < $params['end_date']) {
  698. $params['end_date'] = $params['closing_date'];
  699. }
  700. }
  701. list($list, $count) = DjRegUserRangeReport::getDataTrend($params, $sortField, $sortType, $page, $pageSize, $accountIdList);
  702. $list = $list->toArray();
  703. # 提取日期
  704. $dateList = array_column($list, 'date');
  705. $trendData = DjRegUserRangeReport::getTendData($accountIdList, $dateList);
  706. $trendData = array_column($trendData->toArray(), null, 'date');
  707. // Log::logInfo('3', [getMillisecond()], 'time_test');
  708. foreach ($list as $k=>$item){
  709. # 查询当日新增用户首单人数
  710. $firstDayPaidUserInfo = DjOrder::query()->selectRaw('count(distinct(external_userid)) as pay_user_unique')
  711. ->where('pay_status', 1)->where('enable', 1)->where('order_type', $orderType)
  712. ->whereBetween('order_pay_time',[
  713. strtotime($item['date'].' 00:00:00')*1000,
  714. strtotime($item['date'].' 23:59:59')*1000
  715. ])
  716. ->whereBetween('mp_user_register_time',[
  717. strtotime($item['date'].' 00:00:00')*1000,
  718. strtotime($item['date'].' 23:59:59')*1000
  719. ])
  720. ->where(function($query) use ($orderType, $accountIdList, $params) {
  721. if($params['plat_order_type']) $query->where('plat_order_type', $params['plat_order_type']);
  722. if(1 == $orderType) {
  723. $query->whereIn('bind_app_id', $accountIdList);
  724. } else {
  725. $query->whereIn('adq_account_id', $accountIdList);
  726. }
  727. })->first();
  728. $firstDayPaidUserUnique = $firstDayPaidUserInfo->pay_user_unique ?? 0;
  729. // Log::logInfo('4', [getMillisecond()], 'time_test');
  730. # 如果筛选了收益截止日期,则实时计算总回收金额以及回本率
  731. if($params['closing_date']) {
  732. $totalPay = DjOrder::query()->selectRaw('sum(pay_money) as money')
  733. ->where('pay_status', 1)->where('enable', 0)->where('order_type', $orderType)
  734. ->whereBetween('order_pay_time',[
  735. strtotime($item['date'].' 00:00:00')*1000,
  736. strtotime($params['closing_date'].' 23:59:59')*1000
  737. ])
  738. ->whereBetween('mp_user_register_time',[
  739. strtotime($item['date'].' 00:00:00')*1000,
  740. strtotime($item['date'].' 23:59:59')*1000
  741. ])
  742. ->where(function($query) use ($orderType, $accountIdList, $params) {
  743. if($params['plat_order_type']) $query->where('plat_order_type', $params['plat_order_type']);
  744. if(1 == $orderType) {
  745. $query->whereIn('bind_app_id', $accountIdList);
  746. } else {
  747. $query->whereIn('adq_account_id', $accountIdList);
  748. }
  749. })->first();
  750. $list[$k]['total_cvt_amt'] = $totalPay->money ?? 0;
  751. $list[$k]['total_roi'] = $item['advertiser_cost'] > 0 ? round($list[$k]['total_cvt_amt'] / $item['advertiser_cost'], 4) * 100 : 0;
  752. }
  753. # 数据格式化处理
  754. $list[$k]['advertiser_cost'] = round($list[$k]['advertiser_cost'], 2);
  755. $list[$k]['first_day_roi'] = empty($list[$k]['first_day_roi']) ? '0.00%' : round($list[$k]['first_day_roi'], 2).'%';
  756. $list[$k]['pay_user_unique'] = $firstDayPaidUserUnique;
  757. $list[$k]['first_order_cost_unique'] = $firstDayPaidUserUnique ?
  758. round($list[$k]['advertiser_cost'] / $firstDayPaidUserUnique, 2) : '0.00';
  759. $list[$k]['follow_uv'] = empty( $list[$k]['follow_uv'])? '0' : round($list[$k]['follow_uv']);
  760. $list[$k]['per_follow_cost'] = empty( $list[$k]['per_follow_cost'])? '0' : round($list[$k]['per_follow_cost'], 2);
  761. $list[$k]['total_roi'] = empty($list[$k]['total_roi']) ? '0.00%' : round($list[$k]['total_roi'], 2).'%';
  762. $list[$k]['first_order_cost'] = empty(round($list[$k]['advertiser_cost'])) || empty(round($list[$k]['first_order_ucnt'])) ?
  763. '0.00' :
  764. round($list[$k]['advertiser_cost']/$list[$k]['first_order_ucnt'],2);
  765. $list[$k]['total_cvt_amt'] = empty($list[$k]['total_cvt_amt']) ? '0.00' : $list[$k]['total_cvt_amt'];
  766. # 处理day1~day100的数据
  767. $advertiser_cost_amount = $list[$k]['advertiser_cost'];
  768. foreach (DjRegUserRangeReport::count_range_days() as $day) {
  769. // $day_cvt_amt = $list[$k]['day'.$day.'_cvt_amt'];
  770. $day_cvt_amt = $trendData[$item['date']]['day'.$day.'_cvt_amt'] ?? 0;
  771. if($params['closing_date']) {
  772. $searchEndDate = $params['closing_date'];
  773. } else {
  774. $searchEndDate = date('Y-m-d');
  775. }
  776. //补充ROI
  777. if(strtotime($item['date'])+($day-1)*86400 > strtotime($searchEndDate) ){ //大于当前时间,才是空字符串
  778. $list[$k]['day'.$day.'_roi'] = '';
  779. }elseif(round($day_cvt_amt)>0 && round($advertiser_cost_amount)>0){
  780. $list[$k]['day'.$day.'_roi'] = round($day_cvt_amt * 100 / $advertiser_cost_amount,2).'%';
  781. }else{
  782. $list[$k]['day'.$day.'_roi'] = '0.00%';
  783. }
  784. unset($list[$k]['day'.$day.'_cvt_amt']);
  785. }
  786. }
  787. // Log::logInfo('5', [getMillisecond()], 'time_test');
  788. $overviewList = self::dataCycleListOverview($params, $orderType, $accountIdList);
  789. // Log::logInfo('9', [getMillisecond()], 'time_test');
  790. $overview['list'] = $overviewList;
  791. $overview['head'] = $overviewHead;
  792. $data['list'] = $list;
  793. $data['head'] = $listHead;
  794. } catch (\Exception $exception) {
  795. Log::logError('NewStatisticsService.dataCycleList', [
  796. 'request_data' => $requestData,
  797. 'err_msg' => '数据循环统计接口发生异常',
  798. 'line' => $exception->getLine(),
  799. 'message' => $exception->getMessage(),
  800. 'trace' => $exception->getTraceAsString(),
  801. ], 'interface');
  802. EmailQueue::rPush('数据循环统计接口发生异常', json_encode([
  803. 'request_data' => $requestData,
  804. 'line' => $exception->getLine(),
  805. 'message' => $exception->getMessage(),
  806. 'trace' => $exception->getTraceAsString(),
  807. ]), ['song.shen@kuxuan-inc.com'], '猎羽');
  808. $overview['list'] = [];
  809. $overview['head'] = $overviewHead;
  810. $data['list'] = [];
  811. $data['head'] = $listHead;
  812. }
  813. return [$count, $data, $overview];
  814. }
  815. public static function dataCycleListOverview($params, $orderType, $accountIdList)
  816. {
  817. $data = ['date' => '汇总', 'advertiser_cost' => 0, 'follow_uv' => 0, 'per_follow_cost' => 0, 'first_order_cost' => 0,
  818. 'first_order_cost_unique' => 0, 'total_cvt_amt' => 0, 'total_roi' => '0.00%'];
  819. $list = DjRegUserRangeReport::getSummaryData($params, $accountIdList);
  820. if($list->isNotEmpty()) {
  821. $dateList = array_unique($list->pluck('date')->toArray());
  822. $minDate = min($dateList);
  823. $maxDate = max($dateList);
  824. // Log::logInfo('6', [getMillisecond()], 'time_test');
  825. $orderQuery = DjOrder::query()
  826. ->where('is_ad_user', 1)
  827. ->where('pay_status', 1);
  828. $orderQuery->whereBetween("order_pay_time",[
  829. strtotime("$minDate 00:00:00")*1000, //订单范围开始时间
  830. strtotime("$maxDate 23:59:59")*1000 //订单范围结束时间
  831. ])->whereBetween("mp_user_register_time",[
  832. strtotime("$minDate 00:00:00")*1000, //注册当日开始时间,毫秒
  833. strtotime("$maxDate 23:59:59")*1000 //注册当日结束时间,毫秒
  834. ])
  835. ->where('order_type', $orderType);
  836. if(!is_null($params['plat_order_type'])) {
  837. $orderQuery->where('plat_order_type', $params['plat_order_type']);
  838. }
  839. // 1mp 2adq
  840. if(1 == $orderType) {
  841. $orderQuery->whereIn("bind_app_id", $accountIdList);
  842. } else if (2 == $orderType) {
  843. $orderQuery->whereIn("adq_account_id", $accountIdList);
  844. }
  845. $orderQuery->whereRaw('FROM_UNIXTIME(LEFT(`mp_user_register_time`, 10), "%Y-%m-%d") = ' .
  846. 'FROM_UNIXTIME(LEFT(`order_pay_time`, 10), "%Y-%m-%d")');
  847. $first_order_ucnt_unique = $orderQuery->selectRaw('count(distinct(external_userid)) as count')->first()->count;
  848. // Log::logInfo('7', [getMillisecond()], 'time_test');
  849. $data['advertiser_cost'] = round($list->sum('advertiser_cost'), 2);
  850. $data['follow_uv'] = $list->sum('follow_uv');
  851. $data['per_follow_cost'] = ($data['follow_uv'] != 0) ? round($data['advertiser_cost'] / $data['follow_uv'], 2) : 0;
  852. $first_order_ucnt = $list->sum('first_order_ucnt');
  853. $data['first_order_cost'] = ($first_order_ucnt != 0) ? round($data['advertiser_cost'] / $first_order_ucnt, 2) : 0;
  854. $data['first_order_cost_unique'] = ($first_order_ucnt_unique != 0) ? round($data['advertiser_cost'] / $first_order_ucnt_unique, 2) : 0;
  855. $data['total_cvt_amt'] = round($list->sum('total_cvt_amt'), 2);
  856. $data['total_roi'] = ($data['advertiser_cost'] != 0) ? round($data['total_cvt_amt'] / $data['advertiser_cost'], 4) * 100 . '%' : '0.00%';
  857. // Log::logInfo('8', [getMillisecond()], 'time_test');
  858. }
  859. return $data;
  860. }
  861. public static function cumulativeRecoveryData($startDate, $endDate, $page, $pageSize, $isSystemAdmin, $adminId, $sysGroupId)
  862. {
  863. $todayDate = date('Y-m-d');
  864. // 若选择截止日期大于今日,则将截止日期修改为今日
  865. if( !$endDate || $endDate>$todayDate ){
  866. $endDate = $todayDate;
  867. }
  868. $dmonth = $ddmonth = date('Y-m-01'); //当前月份
  869. $dymonth = '2023-03-01';//当年一月
  870. $retrieveColumns = DjCumulativeRecoveryData::getReportTitle($dmonth, $dymonth);
  871. # 登录账号数据权限
  872. $appIdList = OfficialAccount::getSysGroupMpAppIdList($sysGroupId, 'cumulativeRecoveryData');
  873. if(empty($appIdList)) {
  874. return [
  875. 'list' => [],
  876. 'total'=> 0,
  877. 'retrieveColumns' => $retrieveColumns
  878. ];
  879. }
  880. if( !$startDate ){
  881. $startDate = date('Y-m-d', strtotime('-1 month'));
  882. }
  883. $total = (strtotime($endDate) - strtotime($startDate))/86400+1;
  884. $offset = ($page-1) * $pageSize;
  885. $npNum = $total<$pageSize ? $total : $pageSize;
  886. $pEnd = date('Y-m-d', strtotime($endDate .' -'.$offset.' day'));
  887. $pStart = date('Y-m-d', strtotime($pEnd .' -'.($npNum-1).' day'));
  888. if($pEnd<$startDate) {
  889. return [
  890. 'list' => [],
  891. 'total'=> $total,
  892. 'retrieveColumns' => $retrieveColumns
  893. ];
  894. }
  895. if($pStart<$startDate){
  896. $pStart = $startDate;
  897. }
  898. $data = DjCumulativeRecoveryData::getTrendData($pStart, $pEnd, $appIdList);
  899. return [
  900. 'list' => $data,
  901. 'total' => $total,
  902. 'retrieveColumns' => $retrieveColumns
  903. ];
  904. }
  905. public static function customerServiceDataTotal($params, $isSystemAdmin, $adminId, $sysGroupId)
  906. {
  907. $defaultResponse = [
  908. 'data' => [],
  909. 'columns' => CustomerServiceData::SUMMARY_TITLE,
  910. ];
  911. $corpStat = AuthorizeCorp::getAllCorpList();
  912. $flag = self::getSearchParams($isSystemAdmin, $sysGroupId, $adminId, $corpStat, $params);
  913. if(!$flag) {
  914. return $defaultResponse;
  915. }
  916. $res = CustomerServiceData::getUserListTotal($params);
  917. $defaultResponse['data'] = $res;
  918. return $defaultResponse;
  919. }
  920. public static function customerServiceData($params, $page, $pageSize, $isSystemAdmin, $adminId, $sysGroupId)
  921. {
  922. $defaultResponse = [
  923. 'list' => [],
  924. 'total' => 0,
  925. 'columns' => CustomerServiceData::TITLE,
  926. ];
  927. $corpStat = AuthorizeCorp::getAllCorpList();
  928. $flag = self::getSearchParams($isSystemAdmin, $sysGroupId, $adminId, $corpStat, $params);
  929. if(!$flag) {
  930. return $defaultResponse;
  931. }
  932. list($data, $total) = CustomerServiceData::getUserList($params, $page, $pageSize);
  933. # 提取查询结果中的客服ID
  934. $statUser = [];
  935. foreach ($data as $item) {
  936. $statUser[] = '("' . $item->corpid . '","' . $item->user_id . '")';
  937. }
  938. # 查询客服ID名称以及绑定的运营人员
  939. $operatorIdStat = AdqUser::search(['user_sql' => $statUser]);
  940. $userStat = DjUser::getUserBySearch(['user_sql' => $statUser]);
  941. $adminStat = Users::query()->where('group_admin_id', $sysGroupId)->get();
  942. foreach($data as &$item) {
  943. # 客服名称
  944. $userStatInfo = $userStat->where('corpid', $item->corpid)->where('user_id', $item->user_id)->first();
  945. $item->user_name = $userStatInfo->name ?? '';
  946. # 企微主体
  947. $corpStatInfo = $corpStat->where('corpid', $item->corpid)->first();
  948. $item->corp_name = $corpStatInfo->corp_name ?? '';
  949. # 运营人员
  950. $operatorIdInfo = $operatorIdStat->where('corpid', $item->corpid)->where('user_id', $item->user_id)->first();
  951. $operatorId = $operatorIdInfo->operator_id ?? 0;
  952. $operatorInfo = $adminStat->where('id', $operatorId)->first();
  953. $item->operator_name = $operatorInfo->name ?? '';
  954. $item->ref_date = substr($item->create_time, 0, 10);
  955. unset($item['create_time']);
  956. }
  957. return [
  958. 'list' => $data,
  959. 'total' => $total,
  960. 'columns' => CustomerServiceData::TITLE,
  961. ];
  962. }
  963. public static function getSearchParams($isSystemAdmin, $sysGroupId, $adminId, $corpStat, &$params) {
  964. # 当前登录用户数据权限
  965. $isSuperUser = AdminService::isSuperUser($isSystemAdmin, $sysGroupId, $adminId);
  966. if($isSuperUser) {
  967. $corp_id_list = AdminManageCorp::getSysGroupCorpList($sysGroupId);
  968. if(empty($corp_id_list)) {
  969. return false;
  970. }
  971. $corp_list = $corpStat->whereIn('id', $corp_id_list)->all();
  972. $params['corp_list'] = array_column($corp_list, 'corpid');
  973. } else {
  974. $params['operator_uid'] = $adminId;
  975. }
  976. $userSqlQuery = [];
  977. if(!empty($params['user_name']) || !empty($params['corp_list'])) {
  978. $userRes = DjUser::getUserBySearch([
  979. 'corpid' => $params['corp_id'],
  980. 'user_name' => $params['user_name'],
  981. 'corp_list' => $params['corp_list'] ?? null,
  982. ]);
  983. if($userRes->isEmpty()) {
  984. return false;
  985. }
  986. foreach($userRes as $userInfo) {
  987. $userSqlQuery[] = '("' . $userInfo->corpid . '","' . $userInfo->user_id . '")';
  988. }
  989. }
  990. $operatorSqlQuery = [];
  991. if(!empty($params['operator_uid'])) {
  992. $operatorRes = AdqUser::search([
  993. 'corpid' => $params['corp_id'],
  994. 'operator_id' => $params['operator_uid'],
  995. 'corp_list' => $params['corp_list'] ?? null,
  996. ]);
  997. if($operatorRes->isEmpty()) {
  998. return false;
  999. }
  1000. foreach($operatorRes as $operatorInfo) {
  1001. $operatorSqlQuery[] = '("' . $operatorInfo->corpid . '","' . $operatorInfo->user_id . '")';
  1002. }
  1003. }
  1004. if(!empty($params['user_name']) && !empty($params['operator_uid'])){
  1005. $userSqlArr = array_unique(array_intersect($userSqlQuery, $operatorSqlQuery));
  1006. $params['user_sql'] = $userSqlArr;
  1007. if(empty($params['user_sql'])) {
  1008. return false;
  1009. }
  1010. } else if (!empty($params['user_name']) && empty($params['operator_uid'])) {
  1011. $params['user_sql'] = $userSqlQuery;
  1012. } else if (!empty($params['operator_uid']) && empty($params['user_name'])) {
  1013. $params['user_sql'] = $operatorSqlQuery;
  1014. }
  1015. return true;
  1016. }
  1017. public static function throwPersonListFormat(&$list, $start, $end, $closingDate, $appId) {
  1018. $uids = $list->pluck('user_id');
  1019. $dramaids = $list->pluck('drama_id');
  1020. $accountIdList = $list->pluck('account_id')->toArray();
  1021. $accountIdList = array_filter($accountIdList);
  1022. $accounts = OfficialAccount::query()->pluck('mp_name', 'mp_app_id');
  1023. $users = Users::query()->whereIn('id', $uids)->pluck('name', 'id');
  1024. $playlets = DramaSeries::query()->whereIn('id', $dramaids)->pluck('name', 'id');
  1025. $relationList = AdqUser::getAppIdList($accountIdList);
  1026. $accountData = RedisModel::get(PlayletTrendStatistics::ACCOUNT_USER_LIST);
  1027. $accountData = !empty($accountData) ? json_decode($accountData, 1) : [];
  1028. # 查询投放账号账户余额
  1029. $accountFundsList = TencentAdAuth::query()->whereIn('account_id', $accountIdList)->select(['balance', 'account_id'])->get();
  1030. foreach($list as $key => $item){
  1031. #查对应时间信息
  1032. // if(!empty($item->disable_date)) $item->end_date = min($item->end_date, $item->disable_date);// 投手禁用日期与截止日期取最小
  1033. $item->start_date = max($item->start_date, $start);
  1034. $item->end_date = min($item->end_date, $end);// 截止日期与当前日期取最小
  1035. if($closingDate) {
  1036. $item->day3_end_date = (strtotime($item->end_date . '+2 days') > strtotime($closingDate)) ?
  1037. date('Y-m-d', strtotime($closingDate . '-2 days')) : $item->end_date;
  1038. $item->day7_end_date = (strtotime($item->end_date . '+6 days') > strtotime($closingDate)) ?
  1039. date('Y-m-d', strtotime($closingDate . '-6 days')) : $item->end_date;
  1040. } else {
  1041. $item->day3_end_date = (strtotime($item->end_date . '+2 days') > strtotime(date('Y-m-d'))) ?
  1042. date('Y-m-d', strtotime('-2 days')) : $item->end_date;
  1043. $item->day7_end_date = (strtotime($item->end_date . '+6 days') > strtotime(date('Y-m-d'))) ?
  1044. date('Y-m-d', strtotime('-6 days')) : $item->end_date;
  1045. }
  1046. if(!empty($item->app_id)){
  1047. $item->account_id = $item->app_id;
  1048. # 公众号
  1049. $item->account_name = $accounts->get($item->app_id) ?? null;
  1050. $item->official_account_name = [];
  1051. # 客服
  1052. $item->user_list = [];
  1053. # 余额
  1054. $item->balance = 0;
  1055. } else {
  1056. # 获取绑定信息
  1057. $bindInformation = PlayletTrendStatistics::getAccountBindInformation($item->account_id, $item->start_date, $item->end_date, $accounts);
  1058. # adq账号
  1059. $item->account_name = $item->account_id;
  1060. if(!empty($bindInformation['bind_app_list'])) {
  1061. $item->official_account_name = array_column($bindInformation['bind_app_list'], 'app_name');
  1062. $item->official_account_id = array_column($bindInformation['bind_app_list'], 'app_id');
  1063. } else {
  1064. $relationInfo = $relationList->where('account_id', $item->account_id)->first();
  1065. $officialAccountId = $relationInfo->app_id ?? null;
  1066. $official_account_name = $accounts->get($officialAccountId) ?? null;
  1067. $item->official_account_name = empty($official_account_name) ? [] : [$official_account_name];
  1068. $item->official_account_id = !empty($officialAccountId) ? [$officialAccountId] : [];
  1069. }
  1070. # 判断筛选公众号与当前公众号是否有交集
  1071. if(!empty($appId) && empty(array_intersect($item->official_account_id, $appId))) {
  1072. unset($list[$key]);
  1073. continue;
  1074. }
  1075. # 客服
  1076. if(!empty($bindInformation['bind_user_list'])) {
  1077. $item->user_list = $bindInformation['bind_user_list'];
  1078. } else {
  1079. $item->user_list = $accountData[$item->account_id] ?? [];
  1080. }
  1081. # 余额
  1082. $accountFundsInfo = $accountFundsList->where('account_id', $item->account_id)->first();
  1083. $item->balance = $accountFundsInfo->balance ?? 0;
  1084. }
  1085. $res = PlayletTrendStatistics::query()->where('playlet_id', $item->drama_id)
  1086. ->where('ref_date', '>=', $item->start_date)
  1087. ->where('ref_date', '<=', $item->end_date)
  1088. ->where('app_id', $item->account_id)
  1089. ->where('user_id', $item->user_id)
  1090. ->where('enable', 1)
  1091. ->selectRaw('sum(day_paid) as cost, sum(charge_total) as pay_money, sum(new_user_charge) '
  1092. .'as first_day_pay, sum(scan_follow_count) as scan_follow_total, sum(new_user_charge_uv) as new_pay_uc,'
  1093. .' sum(first_user_charge) as first_charge, sum(conversions_count) as conversions_count, '
  1094. .'sum(deep_conversions_count) as deep_conversions_count, sum(followers_number) as followers_number,'
  1095. .'sum(repeat_fans) as repeat_fans')
  1096. ->first();
  1097. # 3天倍率金额
  1098. if(!empty($item->day3_end_date)) {
  1099. $day3Charge = PlayletTrendStatistics::query()->where('playlet_id', $item->drama_id)
  1100. ->where('ref_date', '>=', $item->start_date)
  1101. ->where('ref_date', '<=', $item->day3_end_date)
  1102. ->where('app_id', $item->account_id)
  1103. ->where('user_id', $item->user_id)
  1104. ->where('enable', 1)
  1105. ->selectRaw('sum(new_user_charge) as day3_first_day_pay, sum(day3_charge) as day3_charge')
  1106. ->first();
  1107. } else {
  1108. $day3Charge = null;
  1109. }
  1110. # 7天倍率金额
  1111. if(!empty($item->day7_end_date)) {
  1112. $day7Charge = PlayletTrendStatistics::query()->where('playlet_id', $item->drama_id)
  1113. ->where('ref_date', '>=', $item->start_date)
  1114. ->where('ref_date', '<=', $item->day7_end_date)
  1115. ->where('app_id', $item->account_id)
  1116. ->where('user_id', $item->user_id)
  1117. ->where('enable', 1)
  1118. ->selectRaw('sum(new_user_charge) as day7_first_day_pay, sum(day7_charge) as day7_charge')
  1119. ->first();
  1120. } else {
  1121. $day7Charge = null;
  1122. }
  1123. $paramsData = [
  1124. 'account_id' => $item->account_id,
  1125. 'start_date' => $item->start_date,
  1126. 'end_date' => $item->end_date,
  1127. 'closing_date' => $closingDate
  1128. ];
  1129. if($closingDate) {
  1130. $chargeTotal = AccountDataTrend::getChargeTotal($paramsData);
  1131. $res->pay_money = round($chargeTotal/100, 2);
  1132. }
  1133. if( !isset($res->cost) ){
  1134. $item->cost = null;
  1135. $item->pay_money = null;
  1136. $item->first_day_roi = null;
  1137. $item->first_roi = null;
  1138. $item->profile = null;
  1139. $item->recall_rate = null;
  1140. $item->qw_cost = null;
  1141. $item->new_cost = null;
  1142. $item->scan_follow_total = null;
  1143. $item->three_days_rate = null;
  1144. $item->seven_days_rate = null;
  1145. $item->day3_charge = null;
  1146. $item->day7_charge = null;
  1147. $item->day3_first_day_pay = null;
  1148. $item->day7_first_day_pay = null;
  1149. $item->new_pay_uv = null;
  1150. $item->conversions_count = null;
  1151. $item->deep_conversions_count = null;
  1152. $item->followers_number = null;
  1153. $item->followers_cost = null;
  1154. $item->repeat_fans = null;
  1155. $item->repeat_rate = null;
  1156. } else {
  1157. // 累计消耗
  1158. $item->cost = round($res->cost, 2);
  1159. // 累计充值
  1160. $item->pay_money = round($res->pay_money, 2);
  1161. // 首日充值金额
  1162. $item->first_day_pay = round($res->first_day_pay, 2);
  1163. // 首日roi
  1164. $item->first_day_roi = $res->cost > 0 ? round($res->first_day_pay / $res->cost, 2) : null;
  1165. // 首单充值金额
  1166. $item->first_charge = round($res->first_charge, 2);
  1167. // 首单roi
  1168. $item->first_roi = $res->cost > 0 ? round($res->first_charge / $res->cost, 2) : null;
  1169. // 总毛利额
  1170. $item->profile = $res->pay_money - $res->cost;
  1171. // 回本率
  1172. $item->recall_rate = $res->cost > 0 ? round($res->pay_money / $res->cost * 100, 2) : null;
  1173. // 企微关注用户成本
  1174. $item->qw_cost = $res->scan_follow_total > 0 ? round($res->cost / $res->scan_follow_total, 2) : null;
  1175. // 企微加粉成本
  1176. $item->followers_cost = $res->followers_number > 0 ? round($res->cost / $res->followers_number, 2) : null;
  1177. // 实际下单人数(新用户下单人数)
  1178. $item->new_pay_uv = $res->new_pay_uc;
  1179. // 新用户下单成本
  1180. $item->new_cost = $res->new_pay_uc > 0 ? round($res->cost / $res->new_pay_uc, 2) : null;
  1181. // 企微关注数(企微粉丝人数)
  1182. $item->scan_follow_total = $res->scan_follow_total;
  1183. // 企微加粉人数
  1184. $item->followers_number = $res->followers_number;
  1185. // 回传下单人数(目标转化量)
  1186. $item->conversions_count = $res->conversions_count;
  1187. // 下单人数(深度目标转化量)
  1188. $item->deep_conversions_count = $res->deep_conversions_count;
  1189. // 复粉人数
  1190. $item->repeat_fans = $res->repeat_fans;
  1191. // 复粉率
  1192. $item->repeat_rate = $res->followers_number > 0 ? round($res->repeat_fans / $res->followers_number * 100, 2) : null;
  1193. // 3天倍率
  1194. $item->three_days_rate = isset($day3Charge->day3_first_day_pay) && $day3Charge->day3_first_day_pay > 0
  1195. && isset($day3Charge->day3_charge) ? round($day3Charge->day3_charge / $day3Charge->day3_first_day_pay, 2) : "0";
  1196. // 3天充值
  1197. $item->day3_charge = isset($day3Charge->day3_charge) ? round($day3Charge->day3_charge, 2) : 0;
  1198. // 3天首日充值
  1199. $item->day3_first_day_pay = isset($day3Charge->day3_first_day_pay) ? round($day3Charge->day3_first_day_pay, 2) : 0;
  1200. // 7天倍率
  1201. $item->seven_days_rate = isset($day7Charge->day7_first_day_pay) && $day7Charge->day7_first_day_pay > 0
  1202. && isset($day7Charge->day7_charge) ? round($day7Charge->day7_charge / $day7Charge->day7_first_day_pay, 2) : "0";
  1203. // 7天充值
  1204. $item->day7_charge = isset($day7Charge->day7_charge) ? round($day7Charge->day7_charge, 2) : 0;
  1205. // 7天首日充值
  1206. $item->day7_first_day_pay = isset($day7Charge->day7_first_day_pay) ? round($day7Charge->day7_first_day_pay, 2) : 0;
  1207. }
  1208. #投手
  1209. $item->user_name = $users->get($item->user_id) ?? null;
  1210. #剧集
  1211. $item->playletTitle = $playlets->get($item->drama_id) ?? null;
  1212. }
  1213. return ;
  1214. }
  1215. }