Report.php 21 KB

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