where('status', 1) ->field(['id', 'title', 'key_word', 'pid']) ->order('pid', 'asc') ->order('sort', 'desc') ->select(); $filtered = array_filter($sources, function ($item) { return $item['pid'] == 0; }); $pid_map = array_column($filtered, null, 'id'); $res = []; foreach ($sources as $item) { if ($item['pid'] != 0 && isset($pid_map[$item['pid']])) { $res [] = [ ...$item, 'ptitle' => $pid_map[$item['pid']]['title'] ]; } } /* $items = Db::name('item') ->where('status', 1) ->field(['id', 'title', 'key_word', 'pid']) ->order('pid', 'asc') ->order('sort', 'desc') ->select(); $tree = $this->buildTree($items); $formattedTree = $this->formatTree($tree); $this->items = $items; $this->itemsformattedTree = $formattedTree;*/ $items = \app\admin\model\Item::where('level',1)->field('id,title')->order('sort','desc')->select(); $this->view->assign("sources", $res); $this->view->assign("items", $items); } public function index() { $start = now()->modify('-7 days')->format('Y-m-d'); $end_at = now()->format('Y-m-d'); $default_daterange = $start . ' - ' . $end_at; return $this->fetch('index',[ 'default_daterange' => $default_daterange ]); } public function list() { $build = new Order(); [$where, $sort, $order, $offset, $limit] = $this->buildparams(); $start = now()->modify('-7 days')->format('Y-m-d'); $end_at = now()->format('Y-m-d 23:29:59'); $filter = request()->get('range',''); if (!empty($filter)){ $arr = explode(' - ', $filter); if (trim($arr[0])) { $start = trim($arr[0]). ' 00:00:00'; } if (trim($arr[1])) { $end_at = trim($arr[1]) . ' 23:29:59'; } } $area_id = request()->get('area_id'); if ($area_id) { $area_id = $this->trimSpecialZeros($area_id); $build->where('area_id', 'like', $area_id . '%'); } //来源 if(!empty(request()->get('source',null))){ $build->where('source',request()->get('source')); } if(!empty(request()->get('item_id',null))){ $item_id =request()->get('item_id'); $item_ids = $this->getItemsById($item_id); $item_ids [] = $item_id; $build->whereIn('item_id', $item_ids); } $build->whereBetween('audit_time', [$start, $end_at]) ->field([ 'item_title name', // 类型 'sum(total) total', // 营业额 'count(id) count_num', // 单量 'count(if(status=60,1,null)) finish_num', // 单量 'sum(performance) performance', // 收益 'sum(cost) cost', // 收益 'sum(material_cost) material_cost', // 收益 'sum(refund_amount) refund_amount', // 公司退款 'sum(worker_refund_amount) worker_refund_amount', // 工人退款 "IFNULL(AVG(CASE WHEN status > 10 THEN UNIX_TIMESTAMP(dispatch_time) - UNIX_TIMESTAMP(create_time) END), 0) AS avg_time_diff", //派单时效 ])->group('item_title') ->order('count_num', 'desc'); // dd($total); $res = $build->paginate($limit); $total = $res->total(); $ress = $res->items(); $data = []; // dd($res); foreach ($ress as $re) { $re = $re->toArray(); // dd($re); $cost_total = $re['cost'] + $re['material_cost']; $name = explode('/', $re['name']); $re['name'] = str_replace(' ', '', array_pop($name)); $re['performance_rate'] = $this->mydiv($re['performance'],$re['total']); $re['trans_rate'] = $this->mydiv($re['finish_num'],$re['count_num']); $re['cash_value'] = $this->mydiv($re['performance'],$re['count_num'],2,false); $re['total_avg'] = $this->mydiv($re['total'],$re['count_num'],2,false); $re['performance_avg'] = $this->mydiv($re['performance'],$re['finish_num'],2,false); $re['avg_time_diff'] = $this->mydiv($re['avg_time_diff'],3600,2,false); $re['cost_total'] = number_format($cost_total,2,'.',''); $data [] = $re; } return [ 'rows' => $data, 'total' => $total ]; } function trimSpecialZeros($str) { if (strlen($str) !== 6) { return $str; // 非6位字符串直接返回 } if (substr($str, -4) === "0000") { return substr($str, 0, 2); // 去掉后4位 } elseif (substr($str, -2) === "00") { return substr($str, 0, 4); // 去掉后2位 } return $str; // 不符合条件则原样返回 } public function chartData() { $build = new Order(); $start = now()->modify('-14 days')->format('Y-m-d'); $end_at = now()->format('Y-m-d 23:29:59'); $filter ['daterange'] = request()->post('daterange'); if (!empty($filter['daterange'])) { $arr = explode(' - ', $filter['daterange']); if (trim($arr[0])) { $start = trim($arr[0]); } if (trim($arr[1])) { $end_at = trim($arr[1]) . ' 23:29:59'; } } $build = $build ->whereBetween('create_time', [$start, $end_at]); //来源 if(!empty(request()->post('source',null))){ $build->where('source',request()->post('source')); } //城市 if(!empty(request()->post('area_id',null))){ $build->where('area_id','LIKE',request()->post('source').'%'); } if(!empty(request()->post('item_id',null))){ $item_id =request()->post('item_id'); $item_ids = $this->getItemsById($item_id); $item_ids [] = $item_id; $build->whereIn('item_id', $item_ids); } $res = $build->field([ 'item_title name', // 类型 'sum(total) total', // 营业额 'count(id) count', // 单量 'count(if(status=60,1,null)) finish_num', // 单量 'sum(performance) performance', // 收益 'sum(refund_amount) refund_amount', // 公司退款 'sum(worker_refund_amount) worker_refund_amount', // 工人退款 ])->group('item_title') ->order('count', 'desc')->select(); $data = []; foreach ($res as $re) { $re = $re->getData(); $name = explode('/', $re['name']); $re['name'] = str_replace(' ', '', array_pop($name)); $data [] = $re; } // dd($data); $xAxis = []; $totalPerformance = []; $conversionRate = []; // 假设转化率 = performance / total(或自定义逻辑) $profitRate = []; // 假设利润率 = (performance - worker_refund_amount) / performance $refundRate = []; // 假设退款率 = refund_amount / total $monetizedValue = []; // 假设变现值 = performance - refund_amount foreach ($data as $item) { $name = $item['name']; $total = (float)$item['total']; $finish_num = (int)$item['finish_num']; $performance = (float)$item['performance']; $refund = (float)($item['refund_amount'] + $item['worker_refund_amount']); $workerRefund = (float)$item['worker_refund_amount']; $count = max((int)$item['count'], 1); // 避免除以0 $xAxis[] = $name; $totalPerformance[] = $total; $conversionRate[] = $total > 0 ? round($finish_num / $count * 100, 2) : 0; $profitRate[] = $total > 0 ? round(($performance) / $total * 100, 2) : 0; $refundRate[] = $total > 0 ? round($refund / $total * 100, 2) : 0; $monetizedValue[] = round($total / $count, 2) ; } if ($totalPerformance){ $result = [ 'xAxis' => $xAxis, 'series' => [ ['name' => '总业绩(¥)', 'type' => 'bar', 'yAxisIndex' => 0, 'data' => $totalPerformance], ['name' => '转化率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => $conversionRate], ['name' => '利润率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => $profitRate], ['name' => '退款率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => $refundRate], ['name' => '变现值(¥)', 'type' => 'line', 'yAxisIndex' => 0, 'data' => $monetizedValue], ] ]; }else{ $result = [ 'xAxis' => ['无'], 'series' => [ ['name' => '总业绩(¥)', 'type' => 'bar', 'yAxisIndex' => 0, 'data' => [0]], ['name' => '转化率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => [0]], ['name' => '利润率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => [0]], ['name' => '退款率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => [0]], ['name' => '变现值(¥)', 'type' => 'line', 'yAxisIndex' => 0, 'data' => [0]], ] ]; } return $result; } private function mydiv($a, $b, int $scale = 4, $is_percent = true): int|string { $val = $b > 0 ? bcdiv($a, $b, $scale) : 0; if ($is_percent) { return bcmul($val, 100, 2); } return $val; } }