Report.php 23 KB

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