ProductStatisticServices.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2016~2023 https://www.crmeb.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  8. // +----------------------------------------------------------------------
  9. // | Author: CRMEB Team <admin@crmeb.com>
  10. // +----------------------------------------------------------------------
  11. namespace app\services\statistic;
  12. use app\services\BaseServices;
  13. use app\services\order\StoreOrderRefundServices;
  14. use app\services\other\export\ExportServices;
  15. use app\services\order\StoreCartServices;
  16. use app\services\order\StoreOrderServices;
  17. use app\services\product\product\StoreProductLogServices;
  18. use app\services\product\product\StoreVisitServices;
  19. use app\services\user\UserBillServices;
  20. use crmeb\exceptions\AdminException;
  21. /**
  22. * Class ProductStatisticServices
  23. * @package app\services\statistic
  24. */
  25. class ProductStatisticServices extends BaseServices
  26. {
  27. /**
  28. * 商品基础
  29. * @param $where
  30. * @return array
  31. */
  32. public function getBasic($where)
  33. {
  34. $time = explode('-', $where['time']);
  35. if (count($time) != 2) throw new AdminException('请选择时间');
  36. //当前数据
  37. $now = $this->basicInfo($where, $time);
  38. //环比数据
  39. $dayNum = bcadd(bcdiv(bcsub(strtotime($time[1]), strtotime($time[0])), '86400'), '1');
  40. $lastTime = array(
  41. date("Y/m/d", strtotime("-$dayNum days", strtotime($time[0]))),
  42. date("Y/m/d", strtotime("-1 days", strtotime($time[0])))
  43. );
  44. $where['time'] = implode('-', $lastTime);
  45. $last = $this->basicInfo($where, $lastTime);
  46. //组合数据,计算环比
  47. $data = [];
  48. foreach ($now as $key => $item) {
  49. $data[$key]['num'] = $item;
  50. $num = $last[$key] > 0 ? $last[$key] : 1;
  51. $data[$key]['percent'] = bcmul((string)bcdiv((string)($item - $last[$key]), (string)$num, 4), 100, 2);
  52. }
  53. return $data;
  54. }
  55. /**
  56. * 商品基础数据
  57. * @param $where
  58. * @param $time
  59. * @return mixed
  60. */
  61. public function basicInfo($where, $time)
  62. {
  63. /** @var StoreVisitServices $storeVisit */
  64. $storeVisit = app()->make(StoreVisitServices::class);
  65. /** @var StoreCartServices $storeCart */
  66. $storeCart = app()->make(StoreCartServices::class);
  67. /** @var StoreOrderServices $storeOrder */
  68. $storeOrder = app()->make(StoreOrderServices::class);
  69. /** @var StoreProductLogServices $productLog */
  70. $productLog = app()->make(StoreProductLogServices::class);
  71. $data['browse'] = $productLog->count($where + ['type' => 'visit']);//商品浏览量
  72. $data['user'] = $productLog->getDistinctCount($where + ['type' => 'visit'], 'uid');//商品访客数
  73. $data['cart'] = $storeCart->getSum($where, 'cart_num');//加入购物车件数
  74. $data['order'] = $storeOrder->sum($where + ['pid' => 0], 'total_num', true);//下单件数
  75. $data['pay'] = $storeOrder->sum([
  76. ['paid', '=', 1],
  77. ['pay_time', '>=', strtotime($time[0])],
  78. ['pay_time', '<', strtotime($time[1]) + 86400],
  79. ['pid', '>=', 0]
  80. ], 'total_num');//支付件数
  81. $data['payPrice'] = $storeOrder->sum([
  82. ['paid', '=', 1],
  83. ['pay_time', '>=', strtotime($time[0])],
  84. ['pay_time', '<', strtotime($time[1]) + 86400],
  85. ['pid', '>=', 0]
  86. ], 'pay_price');//支付金额
  87. $data['cost'] = $storeOrder->sum([
  88. ['paid', '=', 1],
  89. ['pay_time', '>=', strtotime($time[0])],
  90. ['pay_time', '<', strtotime($time[1]) + 86400],
  91. ['pid', '>=', 0]
  92. ], 'cost');//成本金额
  93. $data['refundPrice'] = $storeOrder->sum($where + ['refund_status' => 2], 'pay_price', true);//退款金额
  94. $data['refund'] = $storeOrder->sum($where + ['refund_status' => 2], 'total_num', true);//退款件数
  95. $payPeople = $storeOrder->getDistinctCount($where + ['paid' => 1], 'uid');//成交用户数
  96. $data['payPercent'] = $data['user'] > 0 ? bcmul(bcdiv($payPeople, $data['user'], 4), 100, 2) : 0;//访问-付款转化率
  97. return $data;
  98. }
  99. /**
  100. * 商品趋势
  101. * @param $where
  102. * @param $excel
  103. * @return array
  104. */
  105. public function getTrend($where, $excel = false)
  106. {
  107. $time = explode('-', $where['time']);
  108. if (count($time) != 2) throw new AdminException(100100);
  109. $dayCount = bcadd(bcdiv(bcsub(strtotime($time[1]), strtotime($time[0])), '86400'), '1');
  110. $data = [];
  111. if ($dayCount == 1) {
  112. $data = $this->trend($time, 0, $excel);
  113. } elseif ($dayCount > 1 && $dayCount <= 31) {
  114. $data = $this->trend($time, 1, $excel);
  115. } elseif ($dayCount > 31 && $dayCount <= 92) {
  116. $data = $this->trend($time, 3, $excel);
  117. } elseif ($dayCount > 92) {
  118. $data = $this->trend($time, 30, $excel);
  119. }
  120. return $data;
  121. }
  122. /**
  123. * 商品趋势
  124. * @param $time
  125. * @param $num
  126. * @param $excel
  127. * @return array
  128. */
  129. public function trend($time, $num, $excel = false)
  130. {
  131. /** @var StoreOrderRefundServices $orderRefund */
  132. $orderRefund = app()->make(StoreOrderRefundServices::class);
  133. /** @var StoreOrderServices $storeOrder */
  134. $storeOrder = app()->make(StoreOrderServices::class);
  135. /** @var StoreCartServices $storeCart */
  136. $storeCart = app()->make(StoreCartServices::class);
  137. /** @var StoreProductLogServices $productLog */
  138. $productLog = app()->make(StoreProductLogServices::class);
  139. if ($num == 0) {
  140. $xAxis = ['00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23'];
  141. $timeType = '%H';
  142. } elseif ($num != 0) {
  143. $dt_start = strtotime($time[0]);
  144. $dt_end = strtotime($time[1]);
  145. while ($dt_start <= $dt_end) {
  146. if ($num == 30) {
  147. $xAxis[] = date('Y-m', $dt_start);
  148. $dt_start = strtotime("+1 month", $dt_start);
  149. $timeType = '%Y-%m';
  150. } else {
  151. $xAxis[] = date('m-d', $dt_start);
  152. $dt_start = strtotime("+$num day", $dt_start);
  153. $timeType = '%m-%d';
  154. }
  155. }
  156. }
  157. $browse = array_column($productLog->getProductTrend($time, $timeType, 'sum(visit_num)'), 'num', 'days');
  158. $user = array_column($productLog->getProductTrend($time, $timeType, 'count(distinct(uid))'), 'num', 'days');
  159. $pay = array_column($storeOrder->getProductTrend($time, $timeType, 'pay_time', 'sum(pay_price)'), 'num', 'days');
  160. $refund = array_column($orderRefund->getProductTrend($time, $timeType, 'refunded_time', 'sum(refunded_price)'), 'num', 'days');
  161. if ($excel) {
  162. $cart = array_column($storeCart->getProductTrend($time, $timeType, 'sum(cart_num)'), 'num', 'days');
  163. $order = array_column($storeOrder->getProductTrend($time, $timeType, 'add_time', 'sum(total_num)'), 'num', 'days');
  164. $payNum = array_column($storeOrder->getProductTrend($time, $timeType, 'pay_time', 'sum(total_num)'), 'num', 'days');
  165. $payCountNum = array_column($storeOrder->getProductTrend($time, $timeType, 'pay_time', 'count(distinct(uid))'), 'num', 'days');
  166. $cost = array_column($storeOrder->getProductTrend($time, $timeType, 'pay_time', 'sum(cost)'), 'num', 'days');
  167. $refundNum = array_column($orderRefund->getProductTrend($time, $timeType, 'refunded_time', 'sum(refund_num)'), 'num', 'days');
  168. $data = [];
  169. foreach ($xAxis as &$item) {
  170. if (isset($user[$item]) && isset($payCountNum[$item])) {
  171. $changes = bcmul(bcdiv((string)$payCountNum[$item], (string)$user[$item], 4), 100, 2);
  172. $changes = $changes > 100 ? 100 : $changes;
  173. } else {
  174. $changes = 0;
  175. }
  176. $data[] = [
  177. 'time' => $item,
  178. 'browse' => $browse[$item] ?? 0,
  179. 'user' => $user[$item] ?? 0,
  180. 'pay' => $pay[$item] ?? 0,
  181. 'refund' => $refund[$item] ?? 0,
  182. 'cart' => $cart[$item] ?? 0,
  183. 'order' => $order[$item] ?? 0,
  184. 'payNum' => $payNum[$item] ?? 0,
  185. 'cost' => $cost[$item] ?? 0,
  186. 'refundNum' => $refundNum[$item] ?? 0,
  187. 'changes' => $changes
  188. ];
  189. }
  190. /** @var ExportServices $exportService */
  191. $exportService = app()->make(ExportServices::class);
  192. $url = $exportService->productTrade($data);
  193. return compact('url');
  194. } else {
  195. $data = $series = [];
  196. foreach ($xAxis as $item) {
  197. $data['商品浏览量'][] = isset($browse[$item]) ? floatval($browse[$item]) : 0;
  198. $data['商品访客量'][] = isset($user[$item]) ? floatval($user[$item]) : 0;
  199. $data['支付金额'][] = isset($pay[$item]) ? floatval($pay[$item]) : 0;
  200. $data['退款金额'][] = isset($refund[$item]) ? floatval($refund[$item]) : 0;
  201. }
  202. foreach ($data as $key => $item) {
  203. if ($key == '商品浏览量' || $key == '商品访客量') {
  204. $series[] = [
  205. 'name' => $key,
  206. 'data' => $item,
  207. 'type' => 'line',
  208. 'smooth' => 'true',
  209. 'yAxisIndex' => 1,
  210. ];
  211. } else {
  212. $series[] = [
  213. 'name' => $key,
  214. 'data' => $item,
  215. 'type' => 'bar',
  216. ];
  217. }
  218. }
  219. return compact('xAxis', 'series');
  220. }
  221. }
  222. /**
  223. * 商品排行
  224. * @param $where
  225. * @return mixed
  226. */
  227. public function getProductRanking($where)
  228. {
  229. /** @var StoreProductLogServices $productLog */
  230. $productLog = app()->make(StoreProductLogServices::class);
  231. return $productLog->getRanking($where);
  232. }
  233. }