224 lines
7.6 KiB
PHP
224 lines
7.6 KiB
PHP
<?php
|
||
|
||
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\admin\model\OrderReview;
|
||
use app\common\controller\Backend;
|
||
use PDOStatement;
|
||
use think\Collection;
|
||
use think\Exception;
|
||
use think\exception\DbException;
|
||
use think\Loader;
|
||
use think\Model;
|
||
use think\response\Json;
|
||
use function Symfony\Component\Clock\now;
|
||
|
||
/**
|
||
* 服务项目统计
|
||
*
|
||
* @icon fa fa-circle-o
|
||
*/
|
||
class Item extends Backend
|
||
{
|
||
|
||
|
||
protected $relationSearch = true;
|
||
|
||
public function _initialize()
|
||
{
|
||
parent::_initialize();
|
||
}
|
||
|
||
public function index()
|
||
{
|
||
return $this->fetch('index');
|
||
}
|
||
|
||
public function list()
|
||
{
|
||
$build = new Order();
|
||
|
||
$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]);
|
||
}
|
||
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 . '%');
|
||
}
|
||
|
||
|
||
$build->whereBetween('create_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', // 工人退款
|
||
])->group('item_title')
|
||
->order('count_num', 'desc');
|
||
// dd($total);
|
||
$res = $build->paginate();
|
||
$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']);
|
||
$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['cost_total'] = $cost_total;
|
||
// $re['id'] = $re['item_id'];
|
||
$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';
|
||
}
|
||
}
|
||
|
||
$res = $build->whereBetween('create_time', [$start, $end_at])
|
||
->where('status', Order::STATUS_FINISHED)
|
||
->field([
|
||
'item_title name', // 类型
|
||
'sum(total) total', // 营业额
|
||
'count(id) count', // 单量
|
||
'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;
|
||
}
|
||
|
||
$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'];
|
||
$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($performance / $total * 100, 2) : 0;
|
||
$profitRate[] = $total > 0 ? round(($total - $workerRefund) / $total * 100, 2) : 0;
|
||
$refundRate[] = $total > 0 ? round($refund / $total * 100, 2) : 0;
|
||
$monetizedValue[] = $total / $count;
|
||
}
|
||
|
||
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;
|
||
}
|
||
|
||
}
|