Report.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. <?php
  2. namespace app\admin\controller\shop;
  3. use app\admin\model\shop\Area;
  4. use app\common\controller\Backend;
  5. use app\admin\model\User;
  6. use app\admin\model\shop\SearchLog;
  7. use app\admin\model\shop\Goods;
  8. use app\admin\model\shop\Order;
  9. use app\admin\model\shop\OrderGoods;
  10. use app\admin\model\shop\OrderAftersales;
  11. use app\common\Enum\OrderEnum;
  12. use app\common\Enum\GoodsEnum;
  13. use think\Db;
  14. /**
  15. *
  16. */
  17. class Report extends Backend
  18. {
  19. /**
  20. * 查看
  21. */
  22. public function index()
  23. {
  24. try {
  25. \think\Db::execute("SET @@sql_mode='';");
  26. } catch (\Exception $e) {
  27. }
  28. //今日订单和会员
  29. $totalOrderAmount = round(Order::where('order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  30. ->where('pay_time', '>', 0)
  31. ->sum('pay_amount'), 2);
  32. $totalRefundAmount = round(OrderAftersales::where('status', 2)
  33. ->where('type', '<>', 3)
  34. ->sum('refund'), 2); //退款的
  35. $yesterdayOrderAmount = round(Order::where('order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  36. ->whereTime('pay_time', 'yesterday')
  37. ->sum('pay_amount'), 2);
  38. $yesterdayRefundAmount = round(OrderAftersales::where('status', 2)
  39. ->where('type', '<>', 3)
  40. ->whereTime('createtime', 'yesterday')
  41. ->sum('refund'), 2);
  42. $todayOrderAmount = round(Order::where('order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  43. ->whereTime('pay_time', 'today')
  44. ->sum('pay_amount'), 2);
  45. $todayRefundAmount = round(OrderAftersales::where('status', 2)
  46. ->where('type', '<>', 3)
  47. ->whereTime('createtime', 'today')
  48. ->sum('refund'), 2);
  49. $todayOrderRatio = $yesterdayOrderAmount > 0 ? ceil((($todayOrderAmount - $yesterdayOrderAmount) / $yesterdayOrderAmount) * 100) : ($todayOrderAmount > 0 ? 100 : 0);
  50. if ($this->request->isPost()) {
  51. $date = $this->request->post('date', '');
  52. list($orderSaleCategory, $orderSaleAmount, $orderSaleNums) = $this->getSaleOrderData($date);
  53. list($afterSaleCategory, $afterSaleAmount, $afterSaleNums) = $this->getSaleAfterData($date);
  54. $mapOrderList = $this->getMapSaleOrder($date);
  55. list($legendData, $seriesData) = $this->getCategoryOrder($date);
  56. $statistics = [
  57. 'orderSaleCategory' => $orderSaleCategory,
  58. 'orderSaleAmount' => $orderSaleAmount,
  59. 'orderSaleNums' => $orderSaleNums,
  60. 'afterSaleCategory' => $afterSaleCategory,
  61. 'afterSaleAmount' => $afterSaleAmount,
  62. 'afterSaleNums' => $afterSaleNums,
  63. 'totalOrderAmount' => $totalOrderAmount,
  64. 'todayOrderAmount' => $todayOrderAmount,
  65. 'yesterdayOrderAmount' => $yesterdayOrderAmount,
  66. 'todayOrderRatio' => $todayOrderRatio,
  67. "totalRefundAmount" => $totalRefundAmount,
  68. "yesterdayRefundAmount" => $yesterdayRefundAmount,
  69. "todayRefundAmount" => $todayRefundAmount,
  70. "totalProfitAmount" => round($totalOrderAmount - $totalRefundAmount, 2),
  71. "mapOrderList" => $mapOrderList,
  72. 'legendData' => $legendData,
  73. 'seriesData' => $seriesData
  74. ];
  75. $this->success('', '', $statistics);
  76. }
  77. $totalUser = User::count();
  78. $yesterdayUser = User::whereTime('jointime', 'yesterday')->count();
  79. $todayUser = User::whereTime('jointime', 'today')->count();
  80. $todayUserRatio = $yesterdayUser > 0 ? ceil((($todayUser - $yesterdayUser) / $yesterdayUser) * 100) : ($todayUser > 0 ? 100 : 0);
  81. //销售排行榜
  82. $todayPaidList = OrderGoods::alias('og')
  83. ->join('shop_order o', 'og.order_sn=o.order_sn')
  84. ->whereTime('o.pay_time', 'today')
  85. ->where('o.order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  86. ->where('o.pay_time', '>', 0)
  87. ->group('og.goods_id')
  88. ->field("COUNT(*) as nums,SUM(o.pay_amount) as amount,og.goods_id,og.goods_title as title")
  89. ->order("amount", "desc")
  90. ->limit(10)
  91. ->select();
  92. foreach ($todayPaidList as $index => $item) {
  93. $item->percent = $totalOrderAmount > 0 ? round(($item['amount'] / $totalOrderAmount) * 100, 2) : 0;
  94. }
  95. $weekPaidTotal = Order::where('order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])->where('pay_time', '>', 0)->whereTime('pay_time', 'week')->sum("pay_amount");
  96. $weekPaidList = OrderGoods::alias('og')
  97. ->join('shop_order o', 'og.order_sn=o.order_sn')
  98. ->whereTime('o.pay_time', 'week')
  99. ->where('o.order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  100. ->where('o.pay_time', '>', 0)
  101. ->group('og.goods_id')
  102. ->field("COUNT(*) as nums,SUM(o.pay_amount) as amount,og.goods_id,og.goods_title as title")
  103. ->order("amount", "desc")
  104. ->limit(10)
  105. ->select();
  106. foreach ($weekPaidList as $index => $item) {
  107. $item->percent = $weekPaidTotal > 0 ? round(($item['amount'] / $weekPaidTotal) * 100, 2) : 0;
  108. }
  109. $monthPaidTotal = Order::where('order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])->where('pay_time', '>', 0)->whereTime('pay_time', 'month')->sum("pay_amount");
  110. $monthPaidList = OrderGoods::alias('og')
  111. ->join('shop_order o', 'og.order_sn=o.order_sn')
  112. ->whereTime('o.pay_time', 'month')
  113. ->where('o.order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  114. ->where('o.pay_time', '>', 0)
  115. ->group('og.goods_id')
  116. ->field("COUNT(*) as nums,SUM(o.pay_amount) as amount,og.goods_id,og.goods_title as title")
  117. ->order("amount", "desc")
  118. ->limit(10)
  119. ->select();
  120. foreach ($monthPaidList as $index => $item) {
  121. $item->percent = $monthPaidTotal > 0 ? round(($item['amount'] / $monthPaidTotal) * 100, 2) : 0;
  122. }
  123. $this->view->assign("todayPaidList", $todayPaidList);
  124. $this->view->assign("weekPaidList", $weekPaidList);
  125. $this->view->assign("monthPaidList", $monthPaidList);
  126. $hotSearchList = SearchLog::order('nums desc')->limit(10)->select();
  127. $hotGoodsList = Goods::order('sales desc')->field('id,title,sales')->limit(10)->select();
  128. $comGoodsList = Goods::order('comments desc')->field('id,title,comments')->limit(10)->select();
  129. $this->view->assign("hotSearchList", $hotSearchList);
  130. $this->view->assign("hotGoodsList", $hotGoodsList);
  131. $this->view->assign("comGoodsList", $comGoodsList);
  132. $this->view->assign("totalOrderAmount", $totalOrderAmount);
  133. $this->view->assign("yesterdayOrderAmount", $yesterdayOrderAmount);
  134. $this->view->assign("todayOrderAmount", $todayOrderAmount);
  135. $this->view->assign("todayOrderRatio", $todayOrderRatio);
  136. $this->view->assign("totalRefundAmount", $totalRefundAmount);
  137. $this->view->assign("yesterdayRefundAmount", $yesterdayRefundAmount);
  138. $this->view->assign("todayRefundAmount", $todayRefundAmount);
  139. $this->view->assign("totalProfitAmount", $totalOrderAmount - $totalRefundAmount);
  140. $this->view->assign("totalUser", $totalUser);
  141. $this->view->assign("yesterdayUser", $yesterdayUser);
  142. $this->view->assign("todayUser", $todayUser);
  143. $this->view->assign("todayUserRatio", $todayUserRatio);
  144. //订单数和订单额统计
  145. list($orderSaleCategory, $orderSaleAmount, $orderSaleNums) = $this->getSaleOrderData();
  146. $this->assignconfig('orderSaleCategory', $orderSaleCategory);
  147. $this->assignconfig('orderSaleAmount', $orderSaleAmount);
  148. $this->assignconfig('orderSaleNums', $orderSaleNums);
  149. //退款数和订单额统计
  150. list($afterSaleCategory, $afterSaleAmount, $afterSaleNums) = $this->getSaleAfterData();
  151. $this->assignconfig('afterSaleCategory', $afterSaleCategory);
  152. $this->assignconfig('afterSaleAmount', $afterSaleAmount);
  153. $this->assignconfig('afterSaleNums', $afterSaleNums);
  154. $mapOrderList = $this->getMapSaleOrder();
  155. $this->assignconfig('mapOrderList', $mapOrderList);
  156. list($legendData, $seriesData) = $this->getCategoryOrder();
  157. $this->assignconfig('legendData', $legendData);
  158. $this->assignconfig('seriesData', $seriesData);
  159. return $this->view->fetch();
  160. }
  161. //按地区展示订单明细
  162. public function areas()
  163. {
  164. $id = $this->request->param('id');
  165. $name = $this->request->param('name');
  166. if ($this->request->isAjax()) {
  167. if (!$id && !$name) {
  168. $this->error('参数错误');
  169. }
  170. $date = $this->request->param('date');
  171. if ($date) {
  172. list($start, $end) = explode(' - ', $date);
  173. $starttime = strtotime($start);
  174. $endtime = strtotime($end);
  175. } else {
  176. $starttime = \fast\Date::unixtime('day', 0, 'begin');
  177. $endtime = \fast\Date::unixtime('day', 0, 'end');
  178. }
  179. $row = Area::get($id);
  180. if (empty($row)) {
  181. $row = Area::where('name', 'like', "{$name}%")->find();
  182. }
  183. if (empty($row)) {
  184. $this->error('地区记录未找到');
  185. }
  186. if (!in_array($row->level, [1, 2])) {
  187. $this->error('不支持查询地区范围');
  188. }
  189. $where = [];
  190. $group = 'city_id';
  191. if ($row->level == 1) {
  192. $where['oa.province_id'] = ['eq', $row->id];
  193. } else {
  194. $group = 'district_id';
  195. $where['oa.city_id'] = ['eq', $row->id];
  196. }
  197. $sql = Order::field('o.id,o.createtime,SUM(o.pay_amount) as amount,SUM(og.nums) as goods_nums,oa.city_id,oa.province_id,oa.district_id')
  198. ->where($where)
  199. ->where('o.createtime', 'between time', [$starttime, $endtime])
  200. ->where('o.order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  201. ->where('o.pay_time', '>', 0)
  202. ->alias('o')
  203. ->join('shop_order_goods og', 'o.order_sn=og.order_sn', 'LEFT')
  204. ->join('shop_order_address oa', 'o.id=oa.order_id', 'LEFT')
  205. ->group('o.id')
  206. ->fetchSql(true)
  207. ->select();
  208. $list = Db::query("SELECT d.*,count(*) nums,SUM(amount) AS amount,SUM(goods_nums) AS goods_nums FROM ({$sql}) AS d GROUP BY {$group}");
  209. $newList = [];
  210. $total = 0;
  211. foreach ($list as $res) {
  212. $newList[$res[$group]] = $res;
  213. $total = bcadd($total, $res['amount'], 2);
  214. }
  215. //组合
  216. $area = Area::field('id,name')->where('pid', $row->id)->select();
  217. $orderNums = $goodsNums = $orderMoney = $xAxis = [];
  218. $is_oblique = false;
  219. foreach ($area as $item) {
  220. if (isset($newList[$item['id']])) {
  221. $orderNums[] = $newList[$item['id']]['nums'];
  222. $goodsNums[] = $newList[$item['id']]['goods_nums'];
  223. $orderMoney[] = $newList[$item['id']]['amount'];
  224. $item->rate = $total == 0 ? 0 : round(($newList[$item['id']]['amount'] / $total) * 100, 2);
  225. } else {
  226. $orderNums[] = 0;
  227. $goodsNums[] = 0;
  228. $orderMoney[] = 0;
  229. $item->rate = 0;
  230. }
  231. $xAxis[] = $item['name'];
  232. if (mb_strlen($item['name']) > 4) {
  233. $is_oblique = true;
  234. };
  235. }
  236. if (!$is_oblique) {
  237. $xAxis = [];
  238. foreach ($area as $item) {
  239. $name = explode('市', $item['name']);
  240. $xAxis[] = $name[0];
  241. }
  242. }
  243. $this->success('获取成功', '', [
  244. 'xAxis' => $xAxis,
  245. 'is_oblique' => $is_oblique,
  246. 'orderNums' => $orderNums,
  247. 'goodsNums' => $goodsNums,
  248. 'orderMoney' => $orderMoney,
  249. 'rate' => array_column($area, 'rate'),
  250. 'name' => $row['name']
  251. ]);
  252. }
  253. $this->assignconfig('area', $id);
  254. return $this->view->fetch();
  255. }
  256. /**
  257. * 获取订单销量销售额统计数据
  258. */
  259. protected function getSaleOrderData($date = '')
  260. {
  261. if ($date) {
  262. list($start, $end) = explode(' - ', $date);
  263. $starttime = strtotime($start);
  264. $endtime = strtotime($end);
  265. } else {
  266. $starttime = \fast\Date::unixtime('day', 0, 'begin');
  267. $endtime = \fast\Date::unixtime('day', 0, 'end');
  268. }
  269. $totalseconds = $endtime - $starttime;
  270. $format = '%Y-%m-%d';
  271. if ($totalseconds > 86400 * 30 * 2) {
  272. $format = '%Y-%m';
  273. } else {
  274. if ($totalseconds > 86400) {
  275. $format = '%Y-%m-%d';
  276. } else {
  277. $format = '%H:00';
  278. }
  279. }
  280. $column = [];
  281. $orderList = Order::where('pay_time', 'between time', [$starttime, $endtime])
  282. ->where('order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  283. ->where('pay_time', '>', 0)
  284. ->field('pay_time, status, COUNT(*) AS nums, SUM(pay_amount) AS amount, MIN(pay_time) AS min_paytime, MAX(pay_time) AS max_paytime,
  285. DATE_FORMAT(FROM_UNIXTIME(pay_time), "' . $format . '") AS paydate')
  286. ->group('paydate')
  287. ->select();
  288. if ($totalseconds > 84600 * 30 * 2) {
  289. $starttime = strtotime('last month', $starttime);
  290. while (($starttime = strtotime('next month', $starttime)) <= $endtime) {
  291. $column[] = date('Y-m', $starttime);
  292. }
  293. } else {
  294. if ($totalseconds > 86400) {
  295. for ($time = $starttime; $time <= $endtime;) {
  296. $column[] = date("Y-m-d", $time);
  297. $time += 86400;
  298. }
  299. } else {
  300. for ($time = $starttime; $time <= $endtime;) {
  301. $column[] = date("H:00", $time);
  302. $time += 3600;
  303. }
  304. }
  305. }
  306. $orderSaleNums = $orderSaleAmount = array_fill_keys($column, 0);
  307. foreach ($orderList as $k => $v) {
  308. $orderSaleNums[$v['paydate']] = $v['nums'];
  309. $orderSaleAmount[$v['paydate']] = round($v['amount'], 2);
  310. }
  311. $orderSaleCategory = array_keys($orderSaleAmount);
  312. $orderSaleAmount = array_values($orderSaleAmount);
  313. $orderSaleNums = array_values($orderSaleNums);
  314. return [$orderSaleCategory, $orderSaleAmount, $orderSaleNums];
  315. }
  316. /**
  317. * 获取售后退款售额统计数据
  318. */
  319. protected function getSaleAfterData($date = '')
  320. {
  321. if ($date) {
  322. list($start, $end) = explode(' - ', $date);
  323. $starttime = strtotime($start);
  324. $endtime = strtotime($end);
  325. } else {
  326. $starttime = \fast\Date::unixtime('day', 0, 'begin');
  327. $endtime = \fast\Date::unixtime('day', 0, 'end');
  328. }
  329. $totalseconds = $endtime - $starttime;
  330. $format = '%Y-%m-%d';
  331. if ($totalseconds > 86400 * 30 * 2) {
  332. $format = '%Y-%m';
  333. } else {
  334. if ($totalseconds > 86400) {
  335. $format = '%Y-%m-%d';
  336. } else {
  337. $format = '%H:00';
  338. }
  339. }
  340. $afterList = OrderAftersales::where('createtime', 'between time', [$starttime, $endtime])
  341. ->where('status', 2)
  342. ->where('type', '<>', 3)
  343. ->field('createtime, status, COUNT(*) AS nums, SUM(refund) AS amount, MIN(createtime) AS min_paytime, MAX(createtime) AS max_paytime,
  344. DATE_FORMAT(FROM_UNIXTIME(createtime), "' . $format . '") AS paydate')
  345. ->group('paydate')
  346. ->select();
  347. if ($totalseconds > 84600 * 30 * 2) {
  348. $starttime = strtotime('last month', $starttime);
  349. while (($starttime = strtotime('next month', $starttime)) <= $endtime) {
  350. $column[] = date('Y-m', $starttime);
  351. }
  352. } else {
  353. if ($totalseconds > 86400) {
  354. for ($time = $starttime; $time <= $endtime;) {
  355. $column[] = date("Y-m-d", $time);
  356. $time += 86400;
  357. }
  358. } else {
  359. for ($time = $starttime; $time <= $endtime;) {
  360. $column[] = date("H:00", $time);
  361. $time += 3600;
  362. }
  363. }
  364. }
  365. $afterSaleNums = $afterSaleAmount = array_fill_keys($column, 0);
  366. foreach ($afterList as $k => $v) {
  367. $afterSaleNums[$v['paydate']] = $v['nums'];
  368. $afterSaleAmount[$v['paydate']] = round($v['amount'], 2);
  369. }
  370. $afterSaleCategory = array_keys($afterSaleAmount);
  371. $afterSaleAmount = array_values($afterSaleAmount);
  372. $afterSaleNums = array_values($afterSaleNums);
  373. return [$afterSaleCategory, $afterSaleAmount, $afterSaleNums];
  374. }
  375. //订单按省分布
  376. protected function getMapSaleOrder($date = '')
  377. {
  378. if ($date) {
  379. list($start, $end) = explode(' - ', $date);
  380. $starttime = strtotime($start);
  381. $endtime = strtotime($end);
  382. } else {
  383. $starttime = \fast\Date::unixtime('day', 0, 'begin');
  384. $endtime = \fast\Date::unixtime('day', 0, 'end');
  385. }
  386. $sql = Order::alias('o')
  387. ->where('o.createtime', 'between time', [$starttime, $endtime])
  388. ->where('o.order_status', 'IN', [OrderEnum::STATUS_PAY, OrderEnum::STATUS_SHIP, OrderEnum::STATUS_CONFIRM, OrderEnum::STATUS_AUTO_CONFIRM])
  389. ->where('o.pay_time', '>', 0)
  390. ->join('shop_order_goods og', 'og.order_sn=o.order_sn', 'LEFT')
  391. ->join('shop_order_address oa', 'o.id=oa.order_id', 'LEFT')
  392. ->field('o.createtime,SUM(o.pay_amount) as amount,SUM(og.nums) as goods_nums,oa.province_id')
  393. ->group('o.id')
  394. ->fetchSql(true)
  395. ->select();
  396. $mapOrderList = Db::query("SELECT d.*,count(*) nums,SUM(amount) AS amount,SUM(goods_nums) AS goods_nums FROM ({$sql}) AS d GROUP BY province_id");
  397. $newList = [];
  398. $total = 0;
  399. foreach ($mapOrderList as $item) {
  400. $newList[$item['province_id']] = $item;
  401. $total = bcadd($total, $item['amount'], 2);
  402. }
  403. $area = Area::field('id,name')->where('pid', 0)->select();
  404. $list = [];
  405. foreach ($area as $item) {
  406. $name = iconv_substr($item['name'], 0, 2);
  407. if (in_array($name, ['内蒙', '黑龙'])) {
  408. $name = iconv_substr($item['name'], 0, 3);
  409. }
  410. if (isset($newList[$item['id']])) {
  411. $list[] = [
  412. 'name' => $name,
  413. 'id' => $item['id'],
  414. 'value' => $newList[$item['id']]['nums'],
  415. 'amount' => $newList[$item['id']]['amount'],
  416. 'nums' => $newList[$item['id']]['goods_nums'],
  417. 'rate' => $total == 0 ? 0 : round(($newList[$item['id']]['amount'] / $total) * 100, 2)
  418. ];
  419. } else {
  420. $list[] = [
  421. 'name' => $name,
  422. 'id' => $item['id'],
  423. 'value' => 0,
  424. 'amount' => 0,
  425. 'rate' => 0
  426. ];
  427. }
  428. }
  429. $list[] = [
  430. 'name' => '南海诸岛',
  431. 'id' => 0,
  432. 'value' => 0,
  433. 'amount' => 0,
  434. 'rate' => 0
  435. ];
  436. return $list;
  437. }
  438. //订单按分类分布
  439. protected function getCategoryOrder($date = '')
  440. {
  441. if ($date) {
  442. list($start, $end) = explode(' - ', $date);
  443. $starttime = strtotime($start);
  444. $endtime = strtotime($end);
  445. } else {
  446. $starttime = \fast\Date::unixtime('day', 0, 'begin');
  447. $endtime = \fast\Date::unixtime('day', 0, 'end');
  448. }
  449. // 查询所有订单商品及其分类
  450. $orderGoodsList = \app\admin\model\shop\Order::where('o.createtime', 'between time', [$starttime, $endtime])
  451. ->where('o.order_status', 'IN', [
  452. \app\common\Enum\OrderEnum::STATUS_PAY,
  453. \app\common\Enum\OrderEnum::STATUS_SHIP,
  454. \app\common\Enum\OrderEnum::STATUS_CONFIRM,
  455. \app\common\Enum\OrderEnum::STATUS_AUTO_CONFIRM
  456. ])
  457. ->where('o.pay_time', '>', 0)
  458. ->alias('o')
  459. ->join('shop_order_goods og', 'o.order_sn=og.order_sn', 'LEFT')
  460. ->join('shop_goods g', 'og.goods_id=g.id', 'LEFT')
  461. ->field('og.nums, g.category_ids, o.pay_amount')
  462. ->select();
  463. $categoryStats = [];
  464. foreach ($orderGoodsList as $item) {
  465. if (empty($item['category_ids'])) continue;
  466. $categoryIds = explode(',', $item['category_ids']);
  467. foreach ($categoryIds as $cid) {
  468. $cid = trim($cid);
  469. if ($cid === '') continue;
  470. if (!isset($categoryStats[$cid])) {
  471. $categoryStats[$cid] = ['nums' => 0, 'amount' => 0];
  472. }
  473. $categoryStats[$cid]['nums'] += $item['nums'];
  474. $categoryStats[$cid]['amount'] += $item['pay_amount'];
  475. }
  476. }
  477. // 获取所有分类
  478. $category = \think\Db::name('shop_category')->field('id,name')->select();
  479. $legendData = [];
  480. $seriesData = [];
  481. foreach ($category as $item) {
  482. $cid = $item['id'];
  483. $legendData[] = $item['name'];
  484. $seriesData[] = [
  485. 'name' => $item['name'],
  486. 'value' => isset($categoryStats[$cid]) ? $categoryStats[$cid]['nums'] : 0
  487. ];
  488. }
  489. // 为空全部
  490. if (empty($legendData)) {
  491. $legendData = array_column($category ? $category->toArray() : [], 'name');
  492. foreach ($legendData as $item) {
  493. $seriesData[] = [
  494. 'name' => $item,
  495. 'value' => 0
  496. ];
  497. }
  498. }
  499. return [
  500. $legendData,
  501. $seriesData
  502. ];
  503. }
  504. }