From bcf2a099df4bae2878f0a2f2e3f31b0d7d7ba9d0 Mon Sep 17 00:00:00 2001 From: gcd Date: Wed, 23 Apr 2025 22:17:20 +0800 Subject: [PATCH 01/22] =?UTF-8?q?feat:=20=E7=A7=BB=E9=99=A4=E5=A4=9A?= =?UTF-8?q?=E4=BD=99=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/common/controller/WorkerApi.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/common/controller/WorkerApi.php b/application/common/controller/WorkerApi.php index 939f90f..9ffb266 100644 --- a/application/common/controller/WorkerApi.php +++ b/application/common/controller/WorkerApi.php @@ -175,8 +175,8 @@ class WorkerApi extends BaseService 'time' => Request::instance()->server('REQUEST_TIME'), 'data' => $data, ]; - // 如果未设置类型则自动判断 - $type = $type ? $type : ($this->request->param(config('var_jsonp_handler')) ? 'jsonp' : $this->responseType); + // 如果未设置类型则使用默认类型判断 + $type = $type ? : $this->responseType; if (isset($header['statuscode'])) { $code = $header['statuscode']; From 7431a96291687fd526ae6871085e0f3e82e4608f Mon Sep 17 00:00:00 2001 From: gcd Date: Wed, 23 Apr 2025 22:55:19 +0800 Subject: [PATCH 02/22] =?UTF-8?q?fix:=20=E8=B0=83=E8=AF=95=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/worker/controller/Worker.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/application/worker/controller/Worker.php b/application/worker/controller/Worker.php index 5b42d65..c33688a 100644 --- a/application/worker/controller/Worker.php +++ b/application/worker/controller/Worker.php @@ -3,6 +3,7 @@ namespace app\worker\controller; use app\common\controller\WorkerApi; +use think\Request; class Worker extends WorkerApi { @@ -10,7 +11,6 @@ class Worker extends WorkerApi /** * 微信登录 - * @return void */ public function login() { @@ -25,6 +25,13 @@ class Worker extends WorkerApi //存在师傅id,直接登录 if ($workerVendor['worker_id']) { $this->workerLogin($workerVendor['worker_id']); + $result = [ + 'code' => 1, + 'msg' => '成功', + 'time' => Request::instance()->server('REQUEST_TIME'), + 'data' => $this->user, + ]; + return json($result); $this->success('登录成功', $this->user); } From eb91a7b9a30575bbc73e67c195a2642b9d0e00ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=9F=E5=B7=9D=E4=B8=9C?= Date: Thu, 24 Apr 2025 09:18:35 +0800 Subject: [PATCH 03/22] =?UTF-8?q?feat:=20=E5=88=A0=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/worker/controller/Worker.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/application/worker/controller/Worker.php b/application/worker/controller/Worker.php index c33688a..3ab5b39 100644 --- a/application/worker/controller/Worker.php +++ b/application/worker/controller/Worker.php @@ -3,7 +3,6 @@ namespace app\worker\controller; use app\common\controller\WorkerApi; -use think\Request; class Worker extends WorkerApi { @@ -25,13 +24,6 @@ class Worker extends WorkerApi //存在师傅id,直接登录 if ($workerVendor['worker_id']) { $this->workerLogin($workerVendor['worker_id']); - $result = [ - 'code' => 1, - 'msg' => '成功', - 'time' => Request::instance()->server('REQUEST_TIME'), - 'data' => $this->user, - ]; - return json($result); $this->success('登录成功', $this->user); } From 00a3f2bb2110c279760b83f29acdc1c38903e202 Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Thu, 24 Apr 2025 10:02:24 +0800 Subject: [PATCH 04/22] sth --- application/admin/controller/statistics/Dispatcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/admin/controller/statistics/Dispatcher.php b/application/admin/controller/statistics/Dispatcher.php index b756e2b..dc4b4a2 100644 --- a/application/admin/controller/statistics/Dispatcher.php +++ b/application/admin/controller/statistics/Dispatcher.php @@ -164,7 +164,7 @@ class Dispatcher extends Backend } if($getAll){ - $data = $builder->group('dispatch_admin_id')->select(); + $data = $builder->group('dispatch_admin_id')->limit(50)->select(); }else{ $data = $builder->group('dispatch_admin_id')->paginate(); } From 06715272c8cc40c7e6349abdf7a93f90d03aeb24 Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Thu, 24 Apr 2025 16:10:12 +0800 Subject: [PATCH 05/22] sth --- .../controller/statistics/Dispatcher.php | 9 ++-- application/config.php | 3 ++ .../js/backend/statistics/dispatcher.js | 41 ++++++++++++++----- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/application/admin/controller/statistics/Dispatcher.php b/application/admin/controller/statistics/Dispatcher.php index dc4b4a2..1793ac0 100644 --- a/application/admin/controller/statistics/Dispatcher.php +++ b/application/admin/controller/statistics/Dispatcher.php @@ -52,11 +52,14 @@ class Dispatcher extends Backend $today = now()->format('Y-m-d'); $today_end = now()->format('Y-m-d'); + //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { $this->assign('daterange',$today.' - '.$today_end); + $this->assignconfig('default_daterange',now()->format('Y-m-d 00:00:00').' - '.now()->format('Y-m-d 23:59:59')); + return $this->view->fetch(); } @@ -99,7 +102,7 @@ class Dispatcher extends Backend $newData = [ - ['派单员','总业绩(¥)','转化率(%)','利润率(%)','变现值'] + ['派单员','总业绩','转化率','利润率','变现值'] ]; foreach ($data as $datum){ $newData[] = [ @@ -127,7 +130,7 @@ class Dispatcher extends Backend "COUNT(CASE WHEN status = 60 THEN 1 END) AS finish_num", //完成数 "COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END) AS count_num", //总订单数 (排除取消 和草稿) "SUM(CASE WHEN status = 60 THEN total END) AS total", //成效额 - "SUM(CASE WHEN status = 60 THEN total END) AS performance", //业绩 + "SUM(CASE WHEN status = 60 THEN performance END) AS performance", //业绩 "SUM(CASE WHEN status = 60 THEN (cost + material_cost) END) AS cost_total", //总成本 @@ -189,7 +192,7 @@ class Dispatcher extends Backend }else{ $datum->admin_user = '系统'; } - $datum->avg_time_diff = $this->_calc($datum->avg_time_diff,3600,2); + $datum->avg_time_diff = $this->_calc($datum->avg_time_diff,3600*24,2); $datum->id = $datum->dispatch_admin_id; $newData[] = $datum->toArray(); diff --git a/application/config.php b/application/config.php index 826251f..a67f2e6 100755 --- a/application/config.php +++ b/application/config.php @@ -214,6 +214,9 @@ return [ // 是否自动开启 SESSION 'auto_start' => true, + //有效期 + 'expire' => 3600*24, + 'type' => 'redis', 'host' => Env::get('redis.redis_host'), // Redis 服务器地址 'port' => Env::get('redis.redis_port'), // Redis 端口 diff --git a/public/assets/js/backend/statistics/dispatcher.js b/public/assets/js/backend/statistics/dispatcher.js index 7af3b11..5c4bb02 100644 --- a/public/assets/js/backend/statistics/dispatcher.js +++ b/public/assets/js/backend/statistics/dispatcher.js @@ -29,7 +29,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t columns: [ [ //{field: 'id', title: __('Id')}, - {field: 'id', title: __('ID'),visible:false,operate: false}, + {field: 'id', title: __('ID'),visible:true,operate: false}, {field: 'admin_user', title: __('派单员'),operate: "LIKE"}, {field: 'count_num', title: __('总订单数'),operate: false}, {field: 'finish_num', title: __('完单数'),operate: false}, @@ -45,7 +45,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t {field: 'performance_avg', title: __('客单利润(¥)'), operate: false}, {field: 'total_avg', title: __('客单价(¥)'), operate: false}, - {field: 'avg_time_diff', title: __('派单时效(小时)'), operate: false}, + {field: 'avg_time_diff', title: __('派单时效(天)'), operate: false}, //{field: 'admin_user', title: __('派单员'),operate: "LIKE",visible:false}, //{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false}, @@ -57,7 +57,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t datetimeFormat: "YYYY-MM-DD", //defaultValue:today()+' - '+today(), data:'autocomplete="off" data-local={"format":"YYYY-MM-DD"}', - visible:false}, + visible:false, + defaultValue: Config.default_daterange + }, // {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} ] @@ -105,6 +107,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t // ] // } + const headers = response[0]; + const units = ['元', '%', '%', '']; // 如果你有单位可以一起拼接 + var barChart = Echarts.init(document.getElementById('bar-chart'), 'walden'); var option = { legend: {}, @@ -112,14 +117,30 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t dataset: { source: response }, - xAxis: { type: 'category' }, + xAxis: { + type: 'category', + axisLabel: { + show: true // 隐藏“系统” + }, + axisTick: { show: false }, + axisLine: { show: false } + }, yAxis: {}, - series: [ - { type: 'bar' }, - { type: 'bar' }, - { type: 'bar' }, - { type: 'bar' } - ] + series: headers.slice(1).map((title, i) => ({ + type: 'bar', + label: { + show: true, + position: 'top', + formatter: function (params) { + const value = params.value[i + 1]; // 因为第一列是“派单员” + const unit = units[i] || ''; + return `${value} ${unit}`; // 显示数值 + 单位 + } + }, + itemStyle: { + borderRadius: 4 + } + })) }; barChart.setOption(option); }, From 25c3dc4033ad39d2de57c953814b1f7f01466db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=9F=E5=B7=9D=E4=B8=9C?= Date: Thu, 24 Apr 2025 16:20:19 +0800 Subject: [PATCH 06/22] =?UTF-8?q?feat:=20=E7=94=A8=E6=88=B7=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE=E3=80=81=E9=9A=90=E7=A7=81=E6=94=BF=E7=AD=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/worker/controller/Common.php | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/application/worker/controller/Common.php b/application/worker/controller/Common.php index 1ffdfd5..cc64278 100644 --- a/application/worker/controller/Common.php +++ b/application/worker/controller/Common.php @@ -6,6 +6,8 @@ use app\common\controller\WorkerApi; class Common extends WorkerApi { + protected $noNeedLogin = ['config']; + public function ossParams() { $name = $this->request->post('name'); @@ -22,4 +24,24 @@ class Common extends WorkerApi $this->success('获取成功', $params); } + + public function config() + { + $res = [ + 'user_agreement' => $this->getUserAgreement(), + 'privacy_policy' => $this->getPrivacyPolicy(), + ]; + + $this->success('请求成功', $res); + } + + private function getUserAgreement(): string + { + return '超邦手用户服务协议

生效日期: 2025年3月3日

欢迎您使用“超邦手”小程序!本协议由四川亿灵匠网络科技有限公司(以下简称“我们”或“平台”)与您(以下简称“用户”)签订,适用于您在超邦手小程序上的所有活动。

一、服务内容

平台服务: 我们为维修师傅和用户提供信息匹配平台。用户可以在平台上发布维修需求,维修师傅可自由选择接单。

中介性质: 平台仅提供信息发布和撮合服务,不直接参与维修过程。

二、用户义务

真实信息: 用户须提供真实有效的信息进行注册,不得冒用他人身份。

遵守法律: 不得在平台上发布违法信息或从事不正当活动。

订单履约: 维修师傅须按约定完成服务,不得敷衍了事或拒绝履约。

三、费用与支付

支付方式: 用户在下单后通过平台支付维修费用。平台将向师傅支付相应服务费用。

平台抽佣: 平台会根据订单金额收取一定比例的佣金。

四、争议解决

协商处理: 用户与维修师傅之间发生争议,应优先协商解决。

平台介入: 无法协商一致的,可申请平台介入调解。

五、协议的修改与终止

修改: 我们有权根据实际情况对本协议进行修订,并通过平台公告的方式通知。

终止: 用户违反本协议的,我们有权终止服务。
'; + } + + private function getPrivacyPolicy(): string + { + return '超邦手隐私政策

生效日期: 2025年3月3日

我们深知个人信息对您的重要性,并承诺依法保护您的隐私。请您在使用“超邦手”小程序之前,仔细阅读本隐私政策。

一、我们如何收集和使用信息

基本信息: 在您注册账号时,我们会收集您的姓名、手机号等信息。

订单信息: 您在使用平台发布需求或接单时,我们会收集订单详情、地址等信息。

设备信息: 为保障您的账号安全,我们会收集设备型号、操作系统等信息。

二、信息的共享与转让

服务提供: 为促成交易的完成,平台会将必要信息共享给维修师傅。

法律要求: 在法律要求的情况下,我们可能向相关执法部门提供您的信息。

三、信息的存储和保护

存储期限: 您的个人信息将存储在符合安全标准的服务器中,保存期限不超过法律规定的时间。

安全保护: 我们采取严格的安全措施,防止您的信息被非法访问、使用或泄露。

四、您的权利

查询和更正: 您可以在小程序中访问、更正或删除您的个人信息。

撤回同意: 您有权撤回对我们收集和处理您信息的同意。

五、联系我们

如您对本隐私政策有任何疑问,可通过超邦手小程序的客服功能联系我们。

四川亿灵匠网络科技有限公司
'; + } } \ No newline at end of file From 9f9193a2c8690f2863ce56f369ea0c96d02d1ef7 Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Thu, 24 Apr 2025 16:58:38 +0800 Subject: [PATCH 07/22] sth --- .../admin/controller/aftersales/Aftersale.php | 22 +++++++++++++--- .../js/backend/statistics/dispatcher.js | 25 +++++++++++++++++-- 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/application/admin/controller/aftersales/Aftersale.php b/application/admin/controller/aftersales/Aftersale.php index ca244fe..7bf3b54 100644 --- a/application/admin/controller/aftersales/Aftersale.php +++ b/application/admin/controller/aftersales/Aftersale.php @@ -54,17 +54,29 @@ class Aftersale extends Backend $this->relationSearch = true; //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); + if ($this->request->isAjax()) { + + $from = $this->request->param('from',1); + $dispatch_admin_id = $this->request->param('dispatch_admin_id'); + //如果发送的来源是Selectpage,则转发到Selectpage if ($this->request->request('keyField')) { return $this->selectpage(); } list($where, $sort, $order, $offset, $limit) = $this->buildparams(); - $list = $this->model + $builder = $this->model ->with(['order']) - ->where($where) - ->order($sort, $order) + ->where($where); + + if($from == 2){ + //$builder->where('refund_amount','>',0); + //$builder->where('status','<>',-1); + $builder->where('fa_aftersale.dispatch_admin_id',$dispatch_admin_id ?: 0); + + } + $list = $builder->order($sort, $order) ->paginate($limit); foreach ($list as $row) { @@ -148,6 +160,10 @@ class Aftersale extends Backend unset($params['company_refund_amount']); unset($params['worker_refund_amount']); } + + $params['dispatch_admin_id'] = $order->dispatch_admin_id; + $params['dispatch_admin_user'] = $order->dispatch_admin_user; + $result = $this->model->allowField(true)->save($params); $order->aftersale_id = $this->model->id; $order->save(); diff --git a/public/assets/js/backend/statistics/dispatcher.js b/public/assets/js/backend/statistics/dispatcher.js index 5c4bb02..fa4824e 100644 --- a/public/assets/js/backend/statistics/dispatcher.js +++ b/public/assets/js/backend/statistics/dispatcher.js @@ -60,8 +60,24 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t visible:false, defaultValue: Config.default_daterange }, - - // {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + {field: 'operate', title: __('Operate'), table: table2, events: Table.api.events.operate, formatter: Table.api.formatter.operate, + buttons: [ + { + name: 'aftersales', + text:"售后列表", + title:"售后列表", + icon: 'fa fa-list', + url: function(row){ + return 'aftersales/aftersale/index?from=2&dispatch_admin_id='+row.id; + }, + extend: 'data-toggle="tooltip" data-container="body"', + classname: 'btn btn-xs btn-default btn-dialog', + visible:function(row){ + return true; + } + }, + ] + } ] ] }); @@ -207,6 +223,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t edit: function () { Controller.api.bindevent(); }, + + aftersales: function () { + Controller.api.bindevent(); + }, + api: { bindevent: function () { Form.api.bindevent($("form[role=form]")); From df587e31b56869bb40a4770d7fb7a040e46c8d61 Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Thu, 24 Apr 2025 17:03:12 +0800 Subject: [PATCH 08/22] sth --- application/admin/view/aftersales/aftersale/index.html | 4 ++-- public/assets/js/backend/aftersales/aftersale.js | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/application/admin/view/aftersales/aftersale/index.html b/application/admin/view/aftersales/aftersale/index.html index 6a3d3e8..d4c3045 100644 --- a/application/admin/view/aftersales/aftersale/index.html +++ b/application/admin/view/aftersales/aftersale/index.html @@ -22,14 +22,14 @@ {:__('Delete')} --> - diff --git a/public/assets/js/backend/aftersales/aftersale.js b/public/assets/js/backend/aftersales/aftersale.js index 6440d19..cb8fe61 100644 --- a/public/assets/js/backend/aftersales/aftersale.js +++ b/public/assets/js/backend/aftersales/aftersale.js @@ -53,6 +53,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin {field: 'images', title: __('Images'), operate: false, events: Table.api.events.image, formatter: Table.api.formatter.images}, {field: 'remark', title: __('Remark'), operate: false, table: table, class: 'autocontent', formatter: Table.api.formatter.content}, + {field: 'dispatch_admin_user', title: __('派单员'), operate: '='}, + //{field: 'admin_id', title: __('Admin_id')}, {field: 'admin_user', title: __('Admin_user'), operate: '='}, //{field: 'handle_admin_id', title: __('Handle_admin_id')}, From 82447b27ad1b1e198cf31884985dff47f15c71cc Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Fri, 25 Apr 2025 14:05:47 +0800 Subject: [PATCH 09/22] sth --- application/admin/controller/Order.php | 1 + .../admin/controller/orders/Dispatch.php | 1 + .../controller/statistics/Dispatcher.php | 51 +-- .../admin/controller/statistics/Worker.php | 191 +++++++++++ .../admin/lang/zh-cn/statistics/worker.php | 22 ++ application/admin/validate/Sworker.php | 27 ++ .../admin/view/statistics/dispatcher/add.html | 313 ------------------ .../view/statistics/dispatcher/edit.html | 313 ------------------ .../admin/view/statistics/worker/index.html | 26 ++ public/assets/js/backend/statistics/worker.js | 126 +++++++ 10 files changed, 405 insertions(+), 666 deletions(-) create mode 100644 application/admin/controller/statistics/Worker.php create mode 100644 application/admin/lang/zh-cn/statistics/worker.php create mode 100644 application/admin/validate/Sworker.php delete mode 100644 application/admin/view/statistics/dispatcher/add.html delete mode 100644 application/admin/view/statistics/dispatcher/edit.html create mode 100644 application/admin/view/statistics/worker/index.html create mode 100644 public/assets/js/backend/statistics/worker.js diff --git a/application/admin/controller/Order.php b/application/admin/controller/Order.php index 89567e2..8211365 100644 --- a/application/admin/controller/Order.php +++ b/application/admin/controller/Order.php @@ -390,6 +390,7 @@ class Order extends Backend $order->status = \app\admin\model\Order::STATUS_DISPATCHED; $order->dispatch_time = date('Y-m-d H:i:s'); // $order->dispatch_admin_id = $this->auth->id; + $order->worker_id = $worker_id; $order->save(); //日志 diff --git a/application/admin/controller/orders/Dispatch.php b/application/admin/controller/orders/Dispatch.php index 2e1cc12..1d7799b 100644 --- a/application/admin/controller/orders/Dispatch.php +++ b/application/admin/controller/orders/Dispatch.php @@ -155,6 +155,7 @@ class Dispatch extends Backend $order->status = Order::STATUS_DISPATCHED; $order->dispatch_time = date('Y-m-d H:i:s'); $order->dispatch_admin_id = $this->auth->id; + $order->worker_id = $worker->id; $order->save(); //order log diff --git a/application/admin/controller/statistics/Dispatcher.php b/application/admin/controller/statistics/Dispatcher.php index 1793ac0..447e51a 100644 --- a/application/admin/controller/statistics/Dispatcher.php +++ b/application/admin/controller/statistics/Dispatcher.php @@ -116,12 +116,12 @@ class Dispatcher extends Backend return $newData; } - //图表统计 - public function chart($filter,$getAll=false){ - - - + /** + * @throws DbException + */ + public function orderSubSql() + { $orderValid = implode(',',$this->model->tabStatus(Order::TAB_VALID)); //"COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END) AS ing_num", @@ -140,39 +140,9 @@ class Dispatcher extends Backend // "SUM(CASE WHEN status = 60 THEN (field1 + field2) END) AS performance", ]; - $builder = $this->model - ->field($fields); - //->where('dispatch_admin_id','>',0); + return $this->model->field($fields)->group('worker_id')->buildSql(); - if(!empty($filter['admin_id'])){ - $builder->where('dispatch_admin_id',$filter['admin_id']); - } - - if(!empty($filter['start_time']) && !empty($filter['end_time'])){ - $time_by = $filter['time_by'] ??1; - if($time_by == 1){ //按派单时间 - $time_field = 'dispatch_time'; - }else{ //按录单时间 - $time_field = 'create_time'; - } - $builder->whereBetween($time_field,[$filter['start_time'],$filter['end_time']]); - } - //城市 - if(!empty($filter['area_id'])){ - $builder->where('area_id',$filter['area_id']); - } - //项目 - if(!empty($filter['item_id'])){ - $builder->where('item_id',$filter['item_id']); - } - - if($getAll){ - $data = $builder->group('dispatch_admin_id')->limit(50)->select(); - }else{ - $data = $builder->group('dispatch_admin_id')->paginate(); - } - - $newData = []; + /* $newData = []; if(!empty($data)){ foreach ($data as &$datum){ @@ -203,7 +173,7 @@ class Dispatcher extends Backend return $newData; }else{ return $data; - } + }*/ //dump($newData);exit; } @@ -211,10 +181,11 @@ class Dispatcher extends Backend /** * @param $a * @param $b - * @param $scale + * @param int $scale * @return int|string */ - private function _calc($a,$b,$scale=4,$is_percent=false){ + private function _calc($a, $b, int $scale=4, $is_percent=false): int|string + { $val = $b > 0 ? bcdiv($a,$b,$scale) : 0; if($is_percent){ diff --git a/application/admin/controller/statistics/Worker.php b/application/admin/controller/statistics/Worker.php new file mode 100644 index 0000000..3c2097a --- /dev/null +++ b/application/admin/controller/statistics/Worker.php @@ -0,0 +1,191 @@ +model = new \app\admin\model\Worker(); + $this->OrderModel = new Order(); + $this->DispatchModel = new OrderDispatch(); + } + + + + /** + * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 + * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 + * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 + */ + + /** + * 查看 + * + * @return string|Json + * @throws Exception + * @throws DbException + */ + public function index() + { + //设置过滤方法 + $this->request->filter(['strip_tags', 'trim']); + if (false === $this->request->isAjax()) { + return $this->view->fetch(); + } + //如果发送的来源是 Selectpage,则转发到 Selectpage + if ($this->request->request('keyField')) { + return $this->selectpage(); + } + [$where, $sort, $order, $offset, $limit] = $this->buildparams(); + $list = $this->model + ->where($where) + ->order($sort, $order) + ->paginate($limit); + $result = ['total' => $list->total(), 'rows' => $list->items()]; + return json($result); + } + + + + + //图表统计 + public function chart($filter,$getAll=false){ + + + + + $orderValid = implode(',',$this->model->tabStatus(Order::TAB_VALID)); + + //"COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END) AS ing_num", + $fields = [ + 'dispatch_admin_id', + "COUNT(CASE WHEN status = 60 THEN 1 END) AS finish_num", //完成数 + "COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END) AS count_num", //总订单数 (排除取消 和草稿) + "SUM(CASE WHEN status = 60 THEN total END) AS total", //成效额 + "SUM(CASE WHEN status = 60 THEN performance END) AS performance", //业绩 + + "SUM(CASE WHEN status = 60 THEN (cost + material_cost) END) AS cost_total", //总成本 + + "SUM(CASE WHEN status = 60 THEN (refund_amount + worker_refund_amount) END) AS refund_total", //退款总数 + "COUNT(CASE WHEN refund_amount > 0 OR worker_refund_amount > 0 THEN 1 END) AS refund_count", //退款订单数量 + "AVG(CASE WHEN status > 10 THEN UNIX_TIMESTAMP(dispatch_time) - UNIX_TIMESTAMP(create_time) END) AS avg_time_diff", //派单时效 + // "SUM(CASE WHEN status = 60 THEN (field1 + field2) END) AS performance", + ]; + + $builder = $this->model + ->field($fields); + //->where('dispatch_admin_id','>',0); + + if(!empty($filter['admin_id'])){ + $builder->where('dispatch_admin_id',$filter['admin_id']); + } + + if(!empty($filter['start_time']) && !empty($filter['end_time'])){ + $time_by = $filter['time_by'] ??1; + if($time_by == 1){ //按派单时间 + $time_field = 'dispatch_time'; + }else{ //按录单时间 + $time_field = 'create_time'; + } + $builder->whereBetween($time_field,[$filter['start_time'],$filter['end_time']]); + } + //城市 + if(!empty($filter['area_id'])){ + $builder->where('area_id',$filter['area_id']); + } + //项目 + if(!empty($filter['item_id'])){ + $builder->where('item_id',$filter['item_id']); + } + + if($getAll){ + $data = $builder->group('dispatch_admin_id')->limit(50)->select(); + }else{ + $data = $builder->group('dispatch_admin_id')->paginate(); + } + + $newData = []; + + if(!empty($data)){ + foreach ($data as &$datum){ + //利润率 = 总业绩/总成效额 + $datum->performance_rate = $this->_calc($datum->performance,$datum->total,4,true); + //转化率 = 完单数 / 总订单数 + $datum->trans_rate = $this->_calc($datum->finish_num,$datum->count_num,4,true); + //变现值 = 总业绩 / 总订单数 + $datum->cash_value = $this->_calc($datum->performance,$datum->count_num,2); + //客单利润 = 总利润 / 完单数 + $datum->performance_avg = $this->_calc($datum->performance,$datum->finish_num,2); + //客单价 = 总成效额 / 完单数 + $datum->total_avg = $this->_calc($datum->total,$datum->finish_num,2); + + if(!empty($datum->dispatch_admin_id)){ + $datum->admin_user = Admin::where($datum->dispatch_admin_id)->value('nickname')??'系统'; + }else{ + $datum->admin_user = '系统'; + } + $datum->avg_time_diff = $this->_calc($datum->avg_time_diff,3600*24,2); + + $datum->id = $datum->dispatch_admin_id; + $newData[] = $datum->toArray(); + } + } + + if($getAll){ + return $newData; + }else{ + return $data; + } + //dump($newData);exit; + } + + + /** + * @param $a + * @param $b + * @param $scale + * @return int|string + */ + private function _calc($a,$b,$scale=4,$is_percent=false){ + $val = $b > 0 ? bcdiv($a,$b,$scale) : 0; + + if($is_percent){ + + return bcmul($val,100,2); + } + return $val; + } + + + +} diff --git a/application/admin/lang/zh-cn/statistics/worker.php b/application/admin/lang/zh-cn/statistics/worker.php new file mode 100644 index 0000000..b165c44 --- /dev/null +++ b/application/admin/lang/zh-cn/statistics/worker.php @@ -0,0 +1,22 @@ + 'ID', + 'Type' => '1 自营 2 非自营', + 'Name' => '师傅姓名', + 'Tel' => '师傅电话', + 'Status' => '师傅状态', + 'Status 1' => '激活', + 'Set status to 1' => '设为激活', + 'Status 0' => '冻结', + 'Set status to 0' => '设为冻结', + 'Area_id' => '所在地区', + 'Lng' => '经度', + 'Lat' => '纬度', + 'Location_update_time' => '位置更新时间', + 'Deposit_amount' => '保证金金额', + 'Star' => '信用(5星制)', + 'Create_time' => '创建时间', + 'Update_time' => '更新时间', + 'Deletetime' => '删除时间' +]; diff --git a/application/admin/validate/Sworker.php b/application/admin/validate/Sworker.php new file mode 100644 index 0000000..26fcc3c --- /dev/null +++ b/application/admin/validate/Sworker.php @@ -0,0 +1,27 @@ + [], + 'edit' => [], + ]; + +} diff --git a/application/admin/view/statistics/dispatcher/add.html b/application/admin/view/statistics/dispatcher/add.html deleted file mode 100644 index b49bd11..0000000 --- a/application/admin/view/statistics/dispatcher/add.html +++ /dev/null @@ -1,313 +0,0 @@ -
- -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
- {foreach name="statusList" item="vo"} - - {/foreach} -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
-
- -
- - -
- -
-
    -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - - - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    - -
    -
    -
    - -
    -
    - -
    - - -
    - -
    -
      -
      -
      - -
      diff --git a/application/admin/view/statistics/dispatcher/edit.html b/application/admin/view/statistics/dispatcher/edit.html deleted file mode 100644 index 6b3b94c..0000000 --- a/application/admin/view/statistics/dispatcher/edit.html +++ /dev/null @@ -1,313 +0,0 @@ -
      - -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      - {foreach name="statusList" item="vo"} - - {/foreach} -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      - -
      -
      -
      - -
      -
      - -
      - - -
      - -
      -
        -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - - - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        - -
        -
        -
        - -
        -
        - -
        - - -
        - -
        -
          -
          -
          - -
          diff --git a/application/admin/view/statistics/worker/index.html b/application/admin/view/statistics/worker/index.html new file mode 100644 index 0000000..e7f96ee --- /dev/null +++ b/application/admin/view/statistics/worker/index.html @@ -0,0 +1,26 @@ +
          + +
          + + + +
          + +
          +
          +
          +
          +
          + +
          + +
          +
          +
          + +
          +
          +
          diff --git a/public/assets/js/backend/statistics/worker.js b/public/assets/js/backend/statistics/worker.js new file mode 100644 index 0000000..0191615 --- /dev/null +++ b/public/assets/js/backend/statistics/worker.js @@ -0,0 +1,126 @@ +define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { + + var Controller = { + index: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + index_url: 'statistics/worker/index' + location.search, + add_url: 'statistics/worker/add', + edit_url: 'statistics/worker/edit', + del_url: 'statistics/worker/del', + multi_url: 'statistics/worker/multi', + import_url: 'statistics/worker/import', + table: 'worker', + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: $.fn.bootstrapTable.defaults.extend.index_url, + pk: 'id', + sortName: 'id', + fixedColumns: true, + fixedRightNumber: 1, + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'admin_id', title: __('Admin_id')}, + {field: 'type', title: __('Type')}, + {field: 'name', title: __('Name'), operate: 'LIKE'}, + {field: 'tel', title: __('Tel'), operate: 'LIKE'}, + {field: 'status', title: __('Status'), searchList: {"1":__('Status 1'),"0":__('Status 0')}, formatter: Table.api.formatter.status}, + {field: 'area_id', title: __('Area_id')}, + {field: 'lng', title: __('Lng'), operate:'BETWEEN'}, + {field: 'lat', title: __('Lat'), operate:'BETWEEN'}, + {field: 'location_update_time', title: __('Location_update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false}, + {field: 'deposit_amount', title: __('Deposit_amount'), operate:'BETWEEN'}, + {field: 'star', title: __('Star'), operate:'BETWEEN'}, + {field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false}, + {field: 'update_time', title: __('Update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false}, + {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + recyclebin: function () { + // 初始化表格参数配置 + Table.api.init({ + extend: { + 'dragsort_url': '' + } + }); + + var table = $("#table"); + + // 初始化表格 + table.bootstrapTable({ + url: 'statistics/worker/recyclebin' + location.search, + pk: 'id', + sortName: 'id', + columns: [ + [ + {checkbox: true}, + {field: 'id', title: __('Id')}, + {field: 'name', title: __('Name'), align: 'left'}, + { + field: 'deletetime', + title: __('Deletetime'), + operate: 'RANGE', + addclass: 'datetimerange', + formatter: Table.api.formatter.datetime + }, + { + field: 'operate', + width: '140px', + title: __('Operate'), + table: table, + events: Table.api.events.operate, + buttons: [ + { + name: 'Restore', + text: __('Restore'), + classname: 'btn btn-xs btn-info btn-ajax btn-restoreit', + icon: 'fa fa-rotate-left', + url: 'statistics/worker/restore', + refresh: true + }, + { + name: 'Destroy', + text: __('Destroy'), + classname: 'btn btn-xs btn-danger btn-ajax btn-destroyit', + icon: 'fa fa-times', + url: 'statistics/worker/destroy', + refresh: true + } + ], + formatter: Table.api.formatter.operate + } + ] + ] + }); + + // 为表格绑定事件 + Table.api.bindevent(table); + }, + + add: function () { + Controller.api.bindevent(); + }, + edit: function () { + Controller.api.bindevent(); + }, + api: { + bindevent: function () { + Form.api.bindevent($("form[role=form]")); + } + } + }; + return Controller; +}); From 0c2629f236051c7002a57aa4c92bd427ada8ec9d Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Fri, 25 Apr 2025 14:11:58 +0800 Subject: [PATCH 10/22] sth --- .../controller/statistics/Dispatcher.php | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/application/admin/controller/statistics/Dispatcher.php b/application/admin/controller/statistics/Dispatcher.php index 447e51a..9aefc63 100644 --- a/application/admin/controller/statistics/Dispatcher.php +++ b/application/admin/controller/statistics/Dispatcher.php @@ -19,14 +19,14 @@ class Dispatcher extends Backend /** * Staorder模型对象 - * @var \app\admin\model\Order + * @var Order */ protected $model = null; - public function _initialize() + public function _initialize(): void { parent::_initialize(); - $this->model = new \app\admin\model\Order(); + $this->model = new Order(); } @@ -116,12 +116,10 @@ class Dispatcher extends Backend return $newData; } - - /** - * @throws DbException - */ - public function orderSubSql() + //图表统计 + public function chart($filter,$getAll=false): \think\Collection|\think\Paginator|bool|array|string|\PDOStatement { + $orderValid = implode(',',$this->model->tabStatus(Order::TAB_VALID)); //"COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END) AS ing_num", @@ -140,9 +138,39 @@ class Dispatcher extends Backend // "SUM(CASE WHEN status = 60 THEN (field1 + field2) END) AS performance", ]; - return $this->model->field($fields)->group('worker_id')->buildSql(); + $builder = $this->model + ->field($fields); + //->where('dispatch_admin_id','>',0); - /* $newData = []; + if(!empty($filter['admin_id'])){ + $builder->where('dispatch_admin_id',$filter['admin_id']); + } + + if(!empty($filter['start_time']) && !empty($filter['end_time'])){ + $time_by = $filter['time_by'] ??1; + if($time_by == 1){ //按派单时间 + $time_field = 'dispatch_time'; + }else{ //按录单时间 + $time_field = 'create_time'; + } + $builder->whereBetween($time_field,[$filter['start_time'],$filter['end_time']]); + } + //城市 + if(!empty($filter['area_id'])){ + $builder->where('area_id',$filter['area_id']); + } + //项目 + if(!empty($filter['item_id'])){ + $builder->where('item_id',$filter['item_id']); + } + + if($getAll){ + $data = $builder->group('dispatch_admin_id')->limit(50)->select(); + }else{ + $data = $builder->group('dispatch_admin_id')->paginate(); + } + + $newData = []; if(!empty($data)){ foreach ($data as &$datum){ @@ -173,7 +201,7 @@ class Dispatcher extends Backend return $newData; }else{ return $data; - }*/ + } //dump($newData);exit; } From 78623550ba4c3ac9a598fa8735c03b5a161a221d Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Fri, 25 Apr 2025 16:22:05 +0800 Subject: [PATCH 11/22] sth --- .../admin/view/statistics/worker/index.html | 346 +++++++++++++++++- public/assets/js/backend/statistics/worker.js | 311 +++++++++++----- 2 files changed, 540 insertions(+), 117 deletions(-) diff --git a/application/admin/view/statistics/worker/index.html b/application/admin/view/statistics/worker/index.html index e7f96ee..b98bd73 100644 --- a/application/admin/view/statistics/worker/index.html +++ b/application/admin/view/statistics/worker/index.html @@ -1,26 +1,336 @@ + +
          -
          - - - + +
          -
          -
          -
          -
          -
          - -
          - -
          -
          -
          +
          +
          +
          +
          + + + +
          +
          +
          + +
          +
          + + + + + + + + + + + + + diff --git a/public/assets/js/backend/statistics/worker.js b/public/assets/js/backend/statistics/worker.js index 0191615..e46ac9c 100644 --- a/public/assets/js/backend/statistics/worker.js +++ b/public/assets/js/backend/statistics/worker.js @@ -1,113 +1,221 @@ -define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) { +define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-theme', 'template','addtabs','moment'], function ($, undefined, Backend, Table, Form,Echarts,undefined,Template,Datatable,Moment) { var Controller = { + index: function () { - // 初始化表格参数配置 - Table.api.init({ - extend: { - index_url: 'statistics/worker/index' + location.search, - add_url: 'statistics/worker/add', - edit_url: 'statistics/worker/edit', - del_url: 'statistics/worker/del', - multi_url: 'statistics/worker/multi', - import_url: 'statistics/worker/import', - table: 'worker', - } - }); + //绑定事件 + $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { + var $targetPanel = $($(this).attr("href")); + var tabVal = $(this).data('val'); - var table = $("#table"); + if (tabVal === 'second') { + // 当切换到“统计列表”时,自动刷新表格 + //$targetPanel.find(".btn-refresh").trigger("click"); + // 初始化表格参数配置 + Table.api.init(); + // 表格2 + var table2 = $("#table2"); + table2.bootstrapTable({ + url: 'statistics/worker/index' + location.search, + toolbar: '#toolbar1', + sortName: 'id', + search: false, + commonSearch:true, + visible: false, + showToggle: false, + showColumns: false, + showExport: true, + searchFormVisible:true, + columns: [ + [ + //{field: 'id', title: __('Id')}, + {field: 'id', title: __('ID'),visible:true,operate: false}, + {field: 'admin_user', title: __('派单员'),operate: "LIKE"}, + {field: 'count_num', title: __('总订单数'),operate: false}, + {field: 'finish_num', title: __('完单数'),operate: false}, + {field: 'total', title: __('成效额(¥)'), operate: false}, + {field: 'performance', title: __('总业绩(¥)'), operate: false}, + {field: 'cost_total', title: __('总成本(¥)'), operate: false}, + {field: 'refund_total', title: __('退款金额(¥)'), operate: false}, + {field: 'refund_count', title: __('退款单数'), operate: false}, - // 初始化表格 - table.bootstrapTable({ - url: $.fn.bootstrapTable.defaults.extend.index_url, - pk: 'id', - sortName: 'id', - fixedColumns: true, - fixedRightNumber: 1, - columns: [ - [ - {checkbox: true}, - {field: 'id', title: __('Id')}, - {field: 'admin_id', title: __('Admin_id')}, - {field: 'type', title: __('Type')}, - {field: 'name', title: __('Name'), operate: 'LIKE'}, - {field: 'tel', title: __('Tel'), operate: 'LIKE'}, - {field: 'status', title: __('Status'), searchList: {"1":__('Status 1'),"0":__('Status 0')}, formatter: Table.api.formatter.status}, - {field: 'area_id', title: __('Area_id')}, - {field: 'lng', title: __('Lng'), operate:'BETWEEN'}, - {field: 'lat', title: __('Lat'), operate:'BETWEEN'}, - {field: 'location_update_time', title: __('Location_update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false}, - {field: 'deposit_amount', title: __('Deposit_amount'), operate:'BETWEEN'}, - {field: 'star', title: __('Star'), operate:'BETWEEN'}, - {field: 'create_time', title: __('Create_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false}, - {field: 'update_time', title: __('Update_time'), operate:'RANGE', addclass:'datetimerange', autocomplete:false}, - {field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate} - ] - ] - }); + {field: 'performance_rate', title: __('利润率(%)'), operate: false}, + {field: 'trans_rate', title: __('转化率(%)'), operate: false}, + {field: 'cash_value', title: __('变现值'), operate: false}, + {field: 'performance_avg', title: __('客单利润(¥)'), operate: false}, + {field: 'total_avg', title: __('客单价(¥)'), operate: false}, - // 为表格绑定事件 - Table.api.bindevent(table); - }, - recyclebin: function () { - // 初始化表格参数配置 - Table.api.init({ - extend: { - 'dragsort_url': '' - } - }); + {field: 'avg_time_diff', title: __('派单时效(天)'), operate: false}, - var table = $("#table"); - - // 初始化表格 - table.bootstrapTable({ - url: 'statistics/worker/recyclebin' + location.search, - pk: 'id', - sortName: 'id', - columns: [ - [ - {checkbox: true}, - {field: 'id', title: __('Id')}, - {field: 'name', title: __('Name'), align: 'left'}, - { - field: 'deletetime', - title: __('Deletetime'), - operate: 'RANGE', - addclass: 'datetimerange', - formatter: Table.api.formatter.datetime - }, - { - field: 'operate', - width: '140px', - title: __('Operate'), - table: table, - events: Table.api.events.operate, - buttons: [ - { - name: 'Restore', - text: __('Restore'), - classname: 'btn btn-xs btn-info btn-ajax btn-restoreit', - icon: 'fa fa-rotate-left', - url: 'statistics/worker/restore', - refresh: true + //{field: 'admin_user', title: __('派单员'),operate: "LIKE",visible:false}, + //{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false}, + //{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false}, + {field: 'time_by', title: __('时间维度'), visible:false,searchList: {"1":__('录单时间'),"2":__('派单时间')},defaultValue:1, formatter: Table.api.formatter.normal}, + {field: 'daterange', title: __('时间筛选'), addclass:'datetimerange', + autocomplete:false, + operate: "RANGE", + datetimeFormat: "YYYY-MM-DD", + //defaultValue:today()+' - '+today(), + data:'autocomplete="off" data-local={"format":"YYYY-MM-DD"}', + visible:false, + defaultValue: Config.default_daterange }, - { - name: 'Destroy', - text: __('Destroy'), - classname: 'btn btn-xs btn-danger btn-ajax btn-destroyit', - icon: 'fa fa-times', - url: 'statistics/worker/destroy', - refresh: true + {field: 'operate', title: __('Operate'), table: table2, events: Table.api.events.operate, formatter: Table.api.formatter.operate, + buttons: [ + { + name: 'aftersales', + text:"售后列表", + title:"售后列表", + icon: 'fa fa-list', + url: function(row){ + return 'aftersales/aftersale/index?from=2&dispatch_admin_id='+row.id; + }, + extend: 'data-toggle="tooltip" data-container="body"', + classname: 'btn btn-xs btn-default btn-dialog', + visible:function(row){ + return true; + } + }, + ] } - ], - formatter: Table.api.formatter.operate - } - ] - ] + ] + ] + }); + // 为表格2绑定事件 + Table.api.bindevent(table2); + } + }); - // 为表格绑定事件 - Table.api.bindevent(table); + + + // 触发 tab 后发起 ajax 获取图表数据 + $('ul.nav-tabs li.active a[data-toggle="tab"]').on("shown.bs.tab", function () { + getChartData(); + }); + + + function getChartData(){ + return; + // 获取单选框选中的值 + var timeBy = $('input[name="filter[time_by]"]:checked').val(); + + // 获取日期范围值 + var daterange = $('#daterange').val(); + + // 构建查询参数 + var params = { + 'time_by': timeBy, + 'daterange': daterange + }; + + $.ajax({ + url: "statistics/dispatcher/chartData", // + type: "POST", + dataType: "json", + data:params, + success: function (response) { + // 数据结构 + // response = { + // source: [ + // ['产品销售', '2015', '2016', '2017'], + // ['风扇', 43.3, 85.8, 93.7], + // ... + // ] + // } + + const headers = response[0]; + const units = ['元', '%', '%', '']; // 如果你有单位可以一起拼接 + + var barChart = Echarts.init(document.getElementById('bar-chart'), 'walden'); + var option = { + legend: {}, + tooltip: {}, + dataset: { + source: response + }, + xAxis: { + type: 'category', + axisLabel: { + show: true // 隐藏“系统” + }, + axisTick: { show: false }, + axisLine: { show: false } + }, + yAxis: {}, + series: headers.slice(1).map((title, i) => ({ + type: 'bar', + label: { + show: true, + position: 'top', + formatter: function (params) { + const value = params.value[i + 1]; // 因为第一列是“派单员” + const unit = units[i] || ''; + return `${value} ${unit}`; // 显示数值 + 单位 + } + }, + itemStyle: { + borderRadius: 4 + } + })) + }; + barChart.setOption(option); + }, + error: function () { + console.error("图表数据加载失败"); + } + }); + } + + + + + var form = $("#chart-filter"); + var ranges = {}; + ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')]; + ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')]; + ranges[__('Last 7 Days')] = [Moment().subtract(6, 'days').startOf('day'), Moment().endOf('day')]; + ranges[__('Last 30 Days')] = [Moment().subtract(29, 'days').startOf('day'), Moment().endOf('day')]; + ranges[__('This Month')] = [Moment().startOf('month'), Moment().endOf('month')]; + ranges[__('Last Month')] = [Moment().subtract(1, 'month').startOf('month'), Moment().subtract(1, 'month').endOf('month')]; + ranges[__('今年')] = [Moment().startOf('year'), Moment().endOf('year')]; + var options = { + timePicker: false, + autoUpdateInput: false, + timePickerSeconds: true, + timePicker24Hour: true, + autoApply: true, + locale: { + format: 'YYYY-MM-DD', + customRangeLabel: __("Custom Range"), + applyLabel: __("Apply"), + cancelLabel: __("Clear"), + }, + ranges: ranges, + }; + var callback = function (start, end) { + $(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format)); + }; + require(['bootstrap-daterangepicker'], function () { + $(".datetimerange", form).each(function () { + $(this).on('apply.daterangepicker', function (ev, picker) { + callback.call(picker, picker.startDate, picker.endDate); + var label = picker.chosenLabel; + $(picker.element).data('label', label).trigger("change"); + }); + $(this).on('cancel.daterangepicker', function (ev, picker) { + $(this).val(''); + }); + $(this).daterangepicker($.extend({}, options), callback); + }); + }); + + // 手动触发一次激活 tab 的 shown.bs.tab + getChartData(); + // 绑定查询按钮的点击事件 + $('#filter-btn').on('click', function() { + getChartData(); + }); }, add: function () { @@ -116,6 +224,11 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefin edit: function () { Controller.api.bindevent(); }, + + aftersales: function () { + Controller.api.bindevent(); + }, + api: { bindevent: function () { Form.api.bindevent($("form[role=form]")); From b27654d765c702c1dcb948de06c76acaf2f194eb Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Fri, 25 Apr 2025 16:37:07 +0800 Subject: [PATCH 12/22] sth --- application/admin/controller/statistics/Worker.php | 5 +++++ application/admin/view/statistics/worker/index.html | 4 ++-- application/extra/map.php | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 application/extra/map.php diff --git a/application/admin/controller/statistics/Worker.php b/application/admin/controller/statistics/Worker.php index 3c2097a..afd5fc2 100644 --- a/application/admin/controller/statistics/Worker.php +++ b/application/admin/controller/statistics/Worker.php @@ -57,9 +57,14 @@ class Worker extends Backend */ public function index() { + + + //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { + $appkey = config('map.baidu_app_key'); + $this->assign('mapkey',$appkey); return $this->view->fetch(); } //如果发送的来源是 Selectpage,则转发到 Selectpage diff --git a/application/admin/view/statistics/worker/index.html b/application/admin/view/statistics/worker/index.html index b98bd73..b851d2d 100644 --- a/application/admin/view/statistics/worker/index.html +++ b/application/admin/view/statistics/worker/index.html @@ -255,7 +255,7 @@ - + diff --git a/application/extra/map.php b/application/extra/map.php new file mode 100644 index 0000000..4b37e7f --- /dev/null +++ b/application/extra/map.php @@ -0,0 +1,5 @@ + 'UQjHtbQQoDQRpAE5QLGFvC8exM6rcu69' +]; \ No newline at end of file From 2b8cb7150b841d6a1ced1af6e1543a045bb545fa Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Fri, 25 Apr 2025 16:55:00 +0800 Subject: [PATCH 13/22] sth --- application/common/command/CheckOrderDispatchCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/common/command/CheckOrderDispatchCommand.php b/application/common/command/CheckOrderDispatchCommand.php index 147c4de..702ba8d 100644 --- a/application/common/command/CheckOrderDispatchCommand.php +++ b/application/common/command/CheckOrderDispatchCommand.php @@ -29,7 +29,7 @@ class CheckOrderDispatchCommand extends Command //1修改为超时 $item->status = OrderDispatch::STATUS_OVERTIME; $item->save(); - $params = ['dispatch'=>$item,'remark'=>'系统自动处理,任务超时']; + $params = ['dispatch'=>$item,'remark'=>'系统自动检测,任务超时']; Hook::listen('order_dispatch_change',$params); } }); From bf418b8e3a59c1932425b67011e2a5f095a559d6 Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Fri, 25 Apr 2025 17:11:34 +0800 Subject: [PATCH 14/22] sth --- application/admin/common.php | 47 +++++++++++++++++++ .../admin/controller/workers/Worker.php | 13 +++++ 2 files changed, 60 insertions(+) diff --git a/application/admin/common.php b/application/admin/common.php index f3d1e99..4907228 100755 --- a/application/admin/common.php +++ b/application/admin/common.php @@ -194,4 +194,51 @@ if (!function_exists('build_heading')) { } return $result; } + + + + function getLocation($address){ + + + try { + // 百度地图 API 的 URL 和 API Key + $apiKey = config('map.baidu_app_key'); // 替换为您的 API Key + +// 构建请求 URL + $url = "http://api.map.baidu.com/geocoding/v3/?address=" . urlencode($address) . "&output=json&ak=" . $apiKey; + +// 使用 cURL 请求接口 + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $response = curl_exec($ch); + curl_close($ch); + +// 解析返回的 JSON 数据 + $data = json_decode($response, true); + +// 获取经纬度 + if ($data['status'] == 0) { + $latitude = $data['result']['location']['lat']; // 纬度 + $longitude = $data['result']['location']['lng']; // 经度 + + + return [ + 'lat' => $latitude, + 'lng' => $longitude, + ]; + } else { + return []; + //echo "地址解析失败: " . $data['msg'] . "\n"; + } + + }catch (Exception $exception){ + + return []; + } + + + + } + } diff --git a/application/admin/controller/workers/Worker.php b/application/admin/controller/workers/Worker.php index 27d11fd..fdbb5df 100644 --- a/application/admin/controller/workers/Worker.php +++ b/application/admin/controller/workers/Worker.php @@ -2,6 +2,7 @@ namespace app\admin\controller\workers; +use app\admin\model\Area; use app\admin\model\AuthGroup; use app\admin\model\Item; use app\admin\model\Order; @@ -158,6 +159,18 @@ class Worker extends Backend $this->model->validateFailException()->validate($validate); } $params['admin_id'] = $this->auth->id; + + if(!empty($params['area_id'])){ + + $area = Area::getByCode($params['area_id']); + if($area){ + $location = getLocation($area->merge_name); + if(!empty($location)){ + $params['lng'] = $location['lng']; + $params['lat'] = $location['lat']; + } + } + } $result = $this->model->allowField(true)->save($params); $item_map = model('item')->getAll(); $item_map = array_column($item_map, 'level', 'id'); From 4946ca452635abc13f6cdf9a97b072bb659f4b4f Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Sun, 27 Apr 2025 09:58:17 +0800 Subject: [PATCH 15/22] sth --- application/common/Logic/OrderLogic.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/application/common/Logic/OrderLogic.php b/application/common/Logic/OrderLogic.php index 8a379d6..4046a81 100644 --- a/application/common/Logic/OrderLogic.php +++ b/application/common/Logic/OrderLogic.php @@ -130,6 +130,8 @@ class OrderLogic if($nocancelOrder){ $order = Order::where('id',$dispatch->order_id)->where('status',Order::STATUS_DISPATCHED)->find(); + $order->worker_id = 0; + $order->save(); if(empty($order)){ throw new Exception('未找到关联订单'); } From df63a6c89f0ea155cb9507a40c46923389366448 Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Mon, 28 Apr 2025 10:22:20 +0800 Subject: [PATCH 16/22] sth --- .../admin/controller/statistics/Worker.php | 43 +++++++++++++++++-- .../admin/view/statistics/worker/index.html | 30 ++++++++----- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/application/admin/controller/statistics/Worker.php b/application/admin/controller/statistics/Worker.php index afd5fc2..43018db 100644 --- a/application/admin/controller/statistics/Worker.php +++ b/application/admin/controller/statistics/Worker.php @@ -3,6 +3,7 @@ namespace app\admin\controller\statistics; use app\admin\model\Admin; +use app\admin\model\Aftersale; use app\admin\model\Order; use app\admin\model\OrderDispatch; use app\common\controller\Backend; @@ -57,14 +58,50 @@ class Worker extends Backend */ public function index() { - - - //设置过滤方法 $this->request->filter(['strip_tags', 'trim']); if (false === $this->request->isAjax()) { $appkey = config('map.baidu_app_key'); $this->assign('mapkey',$appkey); + + $count = \app\admin\model\Worker::count(); + $active_count = \app\admin\model\Worker::where('location_update_time', '>=', date('Y-m-d H:i:s', strtotime('-30 days'))) + ->count(); + + $add_count_1 = \app\admin\model\Worker::where('create_time', '>=', date('Y-m-d')) + ->count(); + + $active_count_7 = \app\admin\model\Worker::where('create_time', '>=', date('Y-m-d H:i:s', strtotime('-7 days'))) + ->count(); + + $this->assign('count',$count); + $this->assign('active_count',$active_count); + $this->assign('add_count_1',$add_count_1); + $this->assign('add_count_7',$active_count_7); + + //待接单 + $todo_count = OrderDispatch::where('status',OrderDispatch::STATUS_TOGET)->count(); + //进行中 + $ing_count = OrderDispatch::whereIn('status',[OrderDispatch::STATUS_GOTIT,OrderDispatch::STATUS_PLANIT,OrderDispatch::STATUS_CLOCK])->count(); + //待验收 + $check_count = OrderDispatch::where('status',Order::STATUS_CHECKING)->count(); + //售后待处理 + $aftersale_count = Aftersale::where('status',1)->count(); + + $this->assign('todo_count',$todo_count); + $this->assign('ing_count',$ing_count); + $this->assign('check_count',$check_count); + $this->assign('aftersale_count',$aftersale_count); + + //师傅坐标 + $list = \app\admin\model\Worker::where('lng','>',0)->field(['lng','lat'])->select(); + $arr = []; + foreach ($list as $item){ + $arr[] = [ + $item->lng, $item->lat, + ]; + } + $this->assign('locationData',json_encode($arr)); return $this->view->fetch(); } //如果发送的来源是 Selectpage,则转发到 Selectpage diff --git a/application/admin/view/statistics/worker/index.html b/application/admin/view/statistics/worker/index.html index b851d2d..0b8cb66 100644 --- a/application/admin/view/statistics/worker/index.html +++ b/application/admin/view/statistics/worker/index.html @@ -189,7 +189,7 @@
          - 100/10 + {$count}/{$active_count} 师傅总数/活跃数
          @@ -199,8 +199,8 @@
          - 100 - 今日新增 + {$add_count_1}/{$add_count_7} + 今日新增/7天新增
          @@ -209,8 +209,8 @@
          - 100 - 师傅总数 + {$todo_count}/{$ing_count}/{$check_count} + 待接单/进行中/待验收
          @@ -219,12 +219,11 @@
          - 100 - 师傅总数 + {$aftersale_count} + 待处理售后
          - @@ -253,6 +252,10 @@ + diff --git a/public/assets/js/backend/statistics/worker.js b/public/assets/js/backend/statistics/worker.js index de557ec..dd48a05 100644 --- a/public/assets/js/backend/statistics/worker.js +++ b/public/assets/js/backend/statistics/worker.js @@ -54,6 +54,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t //{field: 'admin_user', title: __('派单员'),operate: "LIKE",visible:false}, //{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false}, //{field: 'city_name', title: __('城市'),operate: "LIKE",visible:false}, + + /*{field: 'area', title: __('城市'), searchList: function (column) { + return Template('sourcetpl', {}); + } + }, +*/ + {field: 'area.merge_name', title: __('地区'),operate: 'LIKE',visible:false}, + {field: 'daterange', title: __('时间筛选'), addclass:'datetimerange', autocomplete:false, operate: "RANGE", @@ -63,6 +71,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t visible:false, defaultValue: Config.default_daterange }, + {field: 'operate', title: __('Operate'), table: table2, events: Table.api.events.operate, formatter: Table.api.formatter.operate, buttons: [ { From d4aea44afc9ed31edd2f8a0a3d58dc2b7df43096 Mon Sep 17 00:00:00 2001 From: xman <1946321327@qq.com> Date: Mon, 28 Apr 2025 16:50:53 +0800 Subject: [PATCH 21/22] sth --- application/admin/controller/statistics/Worker.php | 4 +--- application/admin/model/Worker.php | 8 ++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/application/admin/controller/statistics/Worker.php b/application/admin/controller/statistics/Worker.php index 039725e..7407dd2 100644 --- a/application/admin/controller/statistics/Worker.php +++ b/application/admin/controller/statistics/Worker.php @@ -126,8 +126,6 @@ class Worker extends Backend if(trim($arr[1])){ $filter['end_time'] = trim($arr[1]); } - - } //派单表 @@ -139,7 +137,7 @@ class Worker extends Backend [$where, $sort, $order, $offset, $limit] = $this->buildparams(); $list = $this->model->alias('fa_worker') - ->with(['area']) + ->with(['area','items']) ->field([ 'fa_worker.*', 'IFNULL(a.dispatch_count, 0) AS dispatch_count', diff --git a/application/admin/model/Worker.php b/application/admin/model/Worker.php index 5078e8a..4d43be0 100644 --- a/application/admin/model/Worker.php +++ b/application/admin/model/Worker.php @@ -62,4 +62,12 @@ class Worker extends BaseModel } + + + // 定义通过中间表与 roles 表的一对多关系 + public function items() + { + return $this->hasManyThrough(Item::class, WorkerItem::class, 'worker_id', 'item_id', 'id', 'id'); + } + } From 51721c104af688586cd39819baf089fd5be8aac2 Mon Sep 17 00:00:00 2001 From: hant Date: Mon, 28 Apr 2025 22:22:21 +0800 Subject: [PATCH 22/22] ditu --- public/assets/js/addons.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/assets/js/addons.js b/public/assets/js/addons.js index f8a8cfa..177dd6d 100755 --- a/public/assets/js/addons.js +++ b/public/assets/js/addons.js @@ -12,9 +12,9 @@ define([], function () { var zoom_id = $(that).data("zoom-id") ? $(that).data("zoom-id") : ""; var lat = lat_id ? $("#" + lat_id).val() : ''; var lng = lng_id ? $("#" + lng_id).val() : ''; - var city_code = $("#area_id").val(); + var city_code = $("#c-city").val(); var zoom = zoom_id ? $("#" + zoom_id).val() : ''; - var url = "/addons/address/index/select?1=1"; + var url = "/addons/address/index/select?a=1"; url += (lat && lng) ? 'lat=' + lat + '&lng=' + lng + (input_id ? "&address=" + $("#" + input_id).val() : "") +(zoom ? "&zoom=" + zoom : "") : ''