model = new Order(); } /** * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法 * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑 * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改 */ /** * 查看 * * @return string|Json * @throws \think\Exception * @throws DbException */ public function index() { //$this->chart(); //$today = now()->sub('')->format('Y-m-d' ); $today = now()->format('Y-m-01'); $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-01 00:00:00').' - '.now()->format('Y-m-d 23:59:59')); return $this->view->fetch(); } $filter = $this->request->param('filter'); $filter = json_decode($filter,true); $orderByData = [ 'sort' => $this->request->get('sort','dispatch_admin_id'), 'order' => $this->request->get('order','desc') ]; $filter['orderBy'] = $orderByData; if(!empty($filter['daterange'])){ $arr = explode(' - ',$filter['daterange']); if(trim($arr[0])){ $filter['start_time'] = trim($arr[0]); } if(trim($arr[1])){ $filter['end_time'] = trim($arr[1]); } } $list = $this->chart($filter,false); $result = array("total" => $list->total(), "rows" => $list->items()); return json($result); } public function chartData() { $filter = $this->request->post(); if(!empty($filter['daterange'])){ $arr = explode(' - ',$filter['daterange']); if(trim($arr[0])){ $filter['start_time'] = trim($arr[0]); } if(trim($arr[1])){ $filter['end_time'] = trim($arr[1]).' 23:59:59'; } } $data = $this->chart($filter,true); $newData = [ ['派单员','总业绩','转化率','利润率','变现值'] ]; foreach ($data as $datum){ $newData[] = [ $datum['admin_user'], $datum['performance'], $datum['trans_rate'], $datum['performance_rate'], $datum['cash_value'], ]; } return $newData; } //图表统计 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", $fields = [ 'dispatch_admin_id', // 使用 IFNULL 确保结果为 null 时返回 0 "IFNULL(COUNT(CASE WHEN status = 60 THEN 1 END), 0) AS finish_num", //完成数 "IFNULL(COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END), 0) AS count_num", //总订单数 (排除取消 和草稿) "IFNULL(COUNT(CASE WHEN status = 60 AND is_overtime = 1 THEN 1 END), 0) AS overtime_num", //超时数 "IFNULL(SUM(CASE WHEN status = 60 THEN total END), 0) AS total", //成效额 "IFNULL(SUM(CASE WHEN status = 60 THEN performance END), 0) AS performance", //业绩 "IFNULL(SUM(CASE WHEN status = 60 THEN (cost + material_cost) END), 0) AS cost_total", //总成本 "IFNULL(SUM(CASE WHEN status = 60 THEN (refund_amount + worker_refund_amount) END), 0) AS refund_total", //退款总数 "IFNULL(COUNT(CASE WHEN refund_amount > 0 OR worker_refund_amount > 0 THEN 1 END), 0) AS refund_count", //退款订单数量 "IFNULL(AVG(CASE WHEN status = 60 THEN UNIX_TIMESTAMP(dispatch_time) - UNIX_TIMESTAMP(create_time) END), 0) 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['orderBy'])){ $builder->order($filter['orderBy']['sort'],$filter['orderBy']['order']); } if(isset($filter['dispatch_admin_id'])){ $builder->whereIn('dispatch_admin_id',$filter['dispatch_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'; }*/ $time_field = 'audit_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); //超时率 $datum->overtime_rate = $this->_calc($datum->overtime_num,$datum->count_num,4,true); if(!empty($datum->dispatch_admin_id)){ $datum->admin_user = Admin::where('id',$datum->dispatch_admin_id)->value('nickname')??'系统'; }else{ $datum->admin_user = '系统'; } $datum->avg_time_diff = $this->_calc($datum->avg_time_diff,3600,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 int $scale * @return int|string */ private function _calc($a, $b, int $scale=4, $is_percent=false): int|string { $a = $a??0; $b = $b??0; $val = $b > 0 ? bcdiv($a,$b,$scale) : 0; if($is_percent){ return bcmul($val,100,2); } return $val; } }