diff --git a/application/admin/controller/Orderplan.php b/application/admin/controller/Orderplan.php index 4c22078..ba2d728 100644 --- a/application/admin/controller/Orderplan.php +++ b/application/admin/controller/Orderplan.php @@ -3,8 +3,10 @@ namespace app\admin\controller; use app\admin\addresmart\Address; +use app\admin\model\Abnormal; use app\admin\model\AuthGroupAccess; use app\admin\model\order\Invoice; +use app\admin\model\OrderAbnormal; use app\admin\model\OrderDispatch; use app\admin\model\Worker; use app\admin\model\WorkerItem; @@ -41,16 +43,246 @@ class Orderplan extends Backend parent::_initialize(); $this->model = new \app\admin\model\Order; - - //$this->view->assign("collectList", $this->model->getCollectList()); - //$this->view->assign("dispatchTypeList", $this->model->getDispatchTypeList()); } - public function dashboard(){ + public function dashboard() + { return $this->fetch('orderplan/index'); } + public function data() + { + $top = $this->getTopTotal(); + $lines = $this->getLine(); + $pie = $this->getPie(); + $this->success(data: [ + 'top' => $top, + 'lines' => $lines, + 'pie' => $pie, + ]); + } + + private function getTopTotal() + { + $build = new \app\admin\model\Order(); + + $build->field([ + 'sum(total) total', + 'count(id) count', + 'sum(performance) performance' + ])->limit(1); + + $res = $this->buildDate($build)->select(); + + $res = $res[0] ?? false; + $worker = Worker::where('status', 1)->count(); + if ($res) { + return [ + 'total' => $res->total, + 'count' => $res->count, + 'performance' => $res->performance, + 'worker' => $worker, + ]; + } + + return [ + 'total' => 0, + 'count' => 0, + 'performance' => 0, + 'worker' => 0, + ]; + } + + private function getLine() + { + $build = new \app\admin\model\Order(); + $start = now()->modify('-14 days')->format('Y-m-d'); + $end_at = now()->format('Y-m-d'); + $build->field([ + 'DATE(create_time) day', + 'sum(total) total', + 'count(id) count', + 'sum(performance) performance' + ])->group(' DATE(create_time)'); + + $res = $this->buildDate($build)->select(); + $data = []; + foreach ($res as $re) { + $re = $re->getData(); + $data [] = $re; + } + return $this->prepareEchartsBarData($data, $start, $end_at); + } + + private function getPie() + { + $build = new OrderAbnormal(); + $res = $this->buildDate($build) + ->field([ + 'abnormal_title name', + 'count(id) value', + ]) + ->group('abnormal_title') + ->select(); + $data = []; + foreach ($res as $re) { + $re = $re->getData(); + $data [] = $re; + } + $out ['cancel'] = $data; + + + + $build = new \app\admin\model\Order(); + $res = $this->buildDate($build) + ->field([ + 'item_title name', + 'count(id) value', + ]) + ->group('item_title') + ->select(); + $data = []; + foreach ($res as $re) { + $re = $re->getData(); + $name = explode('/',$re['name']); + $re['name'] = str_replace(' ', '' ,array_pop($name)); + $data [] = $re; + } + $out ['item'] = $data; + + $build = new \app\admin\model\Order(); + $res = $this->buildDate($build) + ->field([ + 'SUBSTRING(area_id, 1, 2) AS name', + 'count(id) value', + ]) + ->group('name') + ->select(); + $data = []; + foreach ($res as $re) { + $re = $re->getData(); + $re['name'] = $this->getProvinceByCode($re['name']); + $data [] = $re; + } + $out ['area'] = $data; + + $build = new \app\admin\model\Order(); + $res = $this->buildDate($build) + ->field([ + 'source_shop AS name', + 'count(id) value', + ]) + ->group('name') + ->select(); + $data = []; + foreach ($res as $re) { + $re = $re->getData(); + $data [] = $re; + } + $out ['source'] = $data; + + + return $out; + } + + + private function buildDate($build) + { + $start = now()->modify('-14 days')->format('Y-m-d'); + $end_at = now()->format('Y-m-d'); + + $build->where('create_time', 'between', [$start, $end_at]); + return $build; + } + + private function prepareEchartsBarData(array $data, string $startDate, string $endDate): array + { + // 将原始数据用日期作为键索引 + $indexed = []; + foreach ($data as $item) { + $indexed[$item['day']] = $item; + } + + $start = strtotime($startDate); + $end = strtotime($endDate); + + $xAxis = []; + $series_total = []; + $series_count = []; + $series_performance = []; + $rate = []; + + for ($date = $start; $date <= $end; $date += 86400) { + $day = date('Y-m-d', $date); + $xAxis[] = $day; + + $total = isset($indexed[$day]) ? (float)$indexed[$day]['total'] : 0; + $count = isset($indexed[$day]) ? (int)$indexed[$day]['count'] : 0; + $performance = isset($indexed[$day]) ? (float)$indexed[$day]['performance'] : 0; + + $series_total[] = $total; + $series_count[] = $count; + $series_performance[] = $performance; + $rate[] = $total ? number_format($performance / $total * 100, 2) : '0'; + } + + return [ + 'xAxis' => $xAxis, + 'series' => [ + 'total' => $series_total, + 'count' => $series_count, + 'performance' => $series_performance, + 'rate' => $rate, + ], + ]; + } + + + function getProvinceByCode($code) { + // 省级行政区域编码对应数组 + $provinces = [ + 11 => '北京', + 12 => '天津', + 13 => '河北', + 14 => '山西', + 15 => '内蒙古', + 21 => '辽宁', + 22 => '吉林', + 23 => '黑龙江', + 31 => '上海', + 32 => '江苏', + 33 => '浙江', + 34 => '安徽', + 35 => '福建', + 36 => '江西', + 37 => '山东', + 41 => '河南', + 42 => '湖北', + 43 => '湖南', + 44 => '广东', + 45 => '广西', + 46 => '海南', + 50 => '重庆', + 51 => '四川', + 52 => '贵州', + 53 => '云南', + 54 => '西藏', + 61 => '陕西', + 62 => '甘肃', + 63 => '青海', + 64 => '宁夏', + 65 => '新疆', + 71 => '台湾', + 81 => '香港', + 82 => '澳门' + ]; + + // 如果提供的代码存在于数组中,返回对应的省名称,否则返回未知 + return isset($provinces[$code]) ? $provinces[$code] : '未知'; + } + + } diff --git a/application/admin/view/orderplan/index.html b/application/admin/view/orderplan/index.html index cc916c8..1a730f4 100644 --- a/application/admin/view/orderplan/index.html +++ b/application/admin/view/orderplan/index.html @@ -26,7 +26,7 @@ 订单量
- 1,240 + loading
@@ -39,7 +39,7 @@ 总业绩
- 1,240 + loading
@@ -52,7 +52,7 @@ 师傅总数
- 1,240 + loading
diff --git a/public/assets/js/backend/orderplan.js b/public/assets/js/backend/orderplan.js index f10d39b..7d0fc59 100644 --- a/public/assets/js/backend/orderplan.js +++ b/public/assets/js/backend/orderplan.js @@ -2,13 +2,20 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th var Controller = { dashboard: function () { + Fast.api.ajax({ + url: 'orderplan/data', + }, function (data, ret) { + Controller.echarts.top(data.top); + Controller.echarts.money_line(data.lines); + Controller.echarts.cancel_order_pie(data.pie.cancel); + Controller.echarts.item_pie(data.pie.item); + Controller.echarts.area_pie(data.pie.area); + Controller.echarts.source_pie(data.pie.source); + }); Controller.api.bindevent(); - Controller.echarts.item_pie(); - Controller.echarts.area_pie(); - Controller.echarts.source_pie(); Controller.echarts.cancel_order_pie(); - Controller.echarts.money_line(); + console.log(123); }, @@ -24,13 +31,26 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th } }, echarts: { - item_pie: function(){ + top: function(data){ + let map = [ + 'count','performance','worker' + ]; + $('.myplan-num').each(function(index) { + if (index === 1){ + $(this).html('¥' + data[map[index]]); + }else { + $(this).html(data[map[index]]); + + } + }); + }, + item_pie: function(data){ // 基本的饼图配置 var myChart = echarts.init(document.getElementById('item_pie')); var option = { title: { - text: '取消订单类型', + text: '订单项目类型', subtext: '', left: 'right' }, @@ -49,7 +69,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th legend: { orient: 'vertical', left: 'left', - data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'] + data: data.map(item => item.name) }, series: [ { @@ -57,13 +77,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th type: 'pie', radius: '50%', center: ['50%', '60%'], - data: [ - { value: 335, name: '直接访问' }, - { value: 310, name: '邮件营销' }, - { value: 234, name: '联盟广告' }, - { value: 135, name: '视频广告' }, - { value: 1548, name: '搜索引擎' } - ], + data: data, emphasis: { itemStyle: { shadowBlur: 10, @@ -82,13 +96,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th myChart.resize(); }); }, - area_pie: function(){ + area_pie: function(data){ // 基本的饼图配置 var myChart = echarts.init(document.getElementById('area_pie')); var option = { title: { - text: '取消订单类型', + text: '订单区域', subtext: '', left: 'right' }, @@ -96,11 +110,6 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, - legend: { - orient: 'vertical', - left: 'left', - data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'] - }, color: [ "#18d1b1", "#3fb1e3", @@ -109,19 +118,18 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th "#c4ebad", "#96dee8" ], + legend: { + orient: 'vertical', + left: 'left', + data: data.map(item => item.name) + }, series: [ { - name: '访问来源', + name: '订单区域', type: 'pie', radius: '50%', center: ['50%', '60%'], - data: [ - { value: 335, name: '直接访问' }, - { value: 310, name: '邮件营销' }, - { value: 234, name: '联盟广告' }, - { value: 135, name: '视频广告' }, - { value: 1548, name: '搜索引擎' } - ], + data: data, emphasis: { itemStyle: { shadowBlur: 10, @@ -140,13 +148,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th myChart.resize(); }); }, - source_pie: function(){ + source_pie: function(data){ // 基本的饼图配置 var myChart = echarts.init(document.getElementById('source_pie')); var option = { title: { - text: '订单地区', + text: '来源店铺', subtext: '', left: 'right' }, @@ -165,21 +173,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th legend: { orient: 'vertical', left: 'left', - data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'] + data: data.map(item => item.name) }, series: [ { - name: '访问来源', + name: '来源店铺', type: 'pie', radius: '50%', center: ['50%', '60%'], - data: [ - { value: 335, name: '直接访问' }, - { value: 310, name: '邮件营销' }, - { value: 234, name: '联盟广告' }, - { value: 135, name: '视频广告' }, - { value: 1548, name: '搜索引擎' } - ], + data: data, emphasis: { itemStyle: { shadowBlur: 10, @@ -198,13 +200,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th myChart.resize(); }); }, - cancel_order_pie: function(){ + cancel_order_pie: function(data){ // 基本的饼图配置 var myChart = echarts.init(document.getElementById('cancel_order_pie')); var option = { title: { - text: '订单来源', + text: '异常订单占比', subtext: '', left: 'right' }, @@ -223,7 +225,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th legend: { orient: 'vertical', left: 'left', - data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎'] + data: data.map(item => item.name) }, series: [ { @@ -231,13 +233,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th type: 'pie', radius: '50%', center: ['50%', '60%'], - data: [ - { value: 335, name: '直接访问' }, - { value: 310, name: '邮件营销' }, - { value: 234, name: '联盟广告' }, - { value: 135, name: '视频广告' }, - { value: 1548, name: '搜索引擎' } - ], + data: data, emphasis: { itemStyle: { shadowBlur: 10, @@ -256,7 +252,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th myChart.resize(); }); }, - money_line: function (){ + money_line: function (data){ var myChart = echarts.init(document.getElementById('money_line')); var option = { @@ -283,13 +279,13 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th "#96dee8" ], legend: { - data: ['柱状图1', '柱状图2', '折线图'], + data: ['订单量', '营销额', '收益','收益率'], left: 'left' }, xAxis: [ { type: 'category', - data: ['1月', '2月', '3月', '4月', '5月', '6月'], + data: data.xAxis, axisPointer: { type: 'shadow' } @@ -298,41 +294,51 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts','echarts-th yAxis: [ { type: 'value', - name: '柱状图数值', + name: '金额', position: 'left' }, { type: 'value', - name: '折线图数值', + name: '单量/百分比', position: 'right', min: 0, // 设置右侧y轴的最小值 - max: 1 // 设置右侧y轴的最大值 + max: 100 // 设置右侧y轴的最大值 } ], series: [ { - name: '柱状图1', + name: '订单量', type: 'bar', - data: [120, 132, 101, 134, 90, 230], + data: data.series.count, + emphasis: { + focus: 'series' + }, + yAxisIndex: 1, + barGap: '10%' // 调整柱状图1与柱状图2之间的间距 + }, + { + name: '营销额', + type: 'bar', + data: data.series.total, emphasis: { focus: 'series' }, barGap: '10%' // 调整柱状图1与柱状图2之间的间距 }, { - name: '柱状图2', + name: '收益', type: 'bar', - data: [220, 182, 191, 234, 290, 330], + data: data.series.performance, emphasis: { focus: 'series' }, barGap: '10%' // 调整柱状图1与柱状图2之间的间距 }, { - name: '折线图', + name: '收益率', type: 'line', yAxisIndex: 1, - data: [0.2, 0.3, 0.4, 0.6, 0.5, 0.8], + data: data.series.rate, smooth: true, lineStyle: { color: '#ff6600'