diff --git a/app/Http/Controllers/Admin/HomeController.php b/app/Http/Controllers/Admin/HomeController.php index 266d1fb..cc90e72 100644 --- a/app/Http/Controllers/Admin/HomeController.php +++ b/app/Http/Controllers/Admin/HomeController.php @@ -136,12 +136,18 @@ class HomeController extends CommonController $list = []; foreach ($productItem as $item) { foreach ($factor as $factor_item) { + // 修复:使用 MySQL 5.7 的 JSON 函数进行精确查询,防止SQL注入 + $factorItemId = (int) $factor_item->id; $total = OrderItems::where('product_item_id', $item->id) - ->whereRaw("factors like '%\"factor_item_id\": $factor_item->id%'") + ->whereRaw("JSON_SEARCH(factors, 'one', ?, NULL, '$[*].factor_item_id') IS NOT NULL", [$factorItemId]) ->sum('total'); - $list [] = [ - 'name' => $item->price + $factor_item->price . '元/天', - 'total_price' => $item->price + $factor_item->price, + + // 修复:明确计算价格总和,避免运算符优先级问题 + $totalPrice = (float) $item->price + (float) $factor_item->price; + + $list[] = [ + 'name' => $totalPrice . '元/天', + 'total_price' => $totalPrice, 'product_item_id' => $item->id, 'factor_item_id' => $factor_item->id, 'total' => $total, diff --git a/app/Http/Controllers/Admin/StatisticsController.php b/app/Http/Controllers/Admin/StatisticsController.php index 3363608..8fd33dd 100755 --- a/app/Http/Controllers/Admin/StatisticsController.php +++ b/app/Http/Controllers/Admin/StatisticsController.php @@ -21,6 +21,7 @@ use App\Models\Orders; use App\Models\Paramedic; use App\Models\Product; use App\Models\ProductItems; +use App\Models\ProductParamedicLevel; use App\Models\Project; use App\Models\Recharge; use App\Models\Refund; @@ -94,17 +95,29 @@ class StatisticsController extends CommonController $query->where("project_id", $project_id); })->pluck("paramedic_id")->toArray(); $query->where("project_id", $project_id)->orWhereIn("id", $order_item_paramedic_ids); - })->with(["orderItems" => function ($query) use ($month, $project_id) { - $query->whereRaw("(DATE_FORMAT(`service_date`,'%Y-%m') = '{$month}' or DATE_FORMAT(`paid_at`,'%Y-%m') = '{$month}')") - ->where("total", ">", 0) - ->whereHas("order", function ($query) use ($project_id) { - $query->where("project_id", $project_id); - }) - ->with(["order", "product", "productItem", "productParamedicLevel", "paramedic" => function ($query) { - $query->withoutGlobalScope(AdminProjectScope::class); - }, "bed", "room", "building", "area"]) - ->orderBy("id"); - }])->get(); + })->with([ + "orderItems" => function ($query) use ($month, $project_id) { + $query->whereRaw("(DATE_FORMAT(`service_date`,'%Y-%m') = '{$month}' or DATE_FORMAT(`paid_at`,'%Y-%m') = '{$month}')") + ->where("total", ">", 0) + ->whereHas("order", function ($query) use ($project_id) { + $query->where("project_id", $project_id); + }) + ->with([ + "order", + "product", + "productItem", + "productParamedicLevel", + "paramedic" => function ($query) { + $query->withoutGlobalScope(AdminProjectScope::class); + }, + "bed", + "room", + "building", + "area" + ]) + ->orderBy("id"); + } + ])->get(); $allItems = collect(); foreach ($paramedics as $paramedic) { @@ -209,8 +222,10 @@ class StatisticsController extends CommonController $factors = json_decode($orderItem->factors, true); $parent_factors = json_decode($orderItem->order->factors, true); - if (!in_array("所在科室", collect($factors)->pluck("factor_name")->toArray()) - && in_array("所在科室", collect($parent_factors)->pluck("factor_name")->toArray())) { + if ( + !in_array("所在科室", collect($factors)->pluck("factor_name")->toArray()) + && in_array("所在科室", collect($parent_factors)->pluck("factor_name")->toArray()) + ) { $add = collect($parent_factors)->keyBy("factor_name")["所在科室"]; $factors[] = $add; $orderItem->update([ @@ -338,16 +353,16 @@ class StatisticsController extends CommonController "patients" => function ($query) use ($before_datetime) { $query->whereRaw("UNIX_TIMESTAMP(`created_at`) <= {$before_datetime}")->orderBy("id", "desc"); }, -// "oneBalance" => function ($query) use ($before_datetime) { + // "oneBalance" => function ($query) use ($before_datetime) { // $query->whereRaw("UNIX_TIMESTAMP(`created_at`) <= {$before_datetime}")->orderBy("id", "desc"); // } ]) -// ->whereHas("oneBalance", function ($query) use ($before_datetime) { + // ->whereHas("oneBalance", function ($query) use ($before_datetime) { // $query->whereRaw("UNIX_TIMESTAMP(`created_at`) <= {$before_datetime}")->where("balance", ">", 0)->orderBy("id", "desc"); // }) ->whereHas("orders", function ($query) use ($before_datetime, $project_id) { $query -// ->whereRaw("UNIX_TIMESTAMP(`created_at`) <= {$before_datetime}") + // ->whereRaw("UNIX_TIMESTAMP(`created_at`) <= {$before_datetime}") ->where("project_id", $project_id); }) ->get(); @@ -459,27 +474,81 @@ class StatisticsController extends CommonController })->paginate(40); $data->appends($request->all())->render(); - $product = Product::where('project_id', $project_id)->first(); - $productItem = ProductItems::where('product_id', $product->id)->get(); - $factor = FactorItems::where('factor_id', $product->statistic_factor_id)->get(); + // ===== 重构:先从 OrderItems 获取真实价格数据,生成列,然后再统计每个病区的数据 ===== + // 1. 获取当前分页中所有病区的床位 ID + $areaIds = collect($data->items())->pluck('id'); + $beds = Bed::whereIn('area_id', $areaIds)->get(); + $bedsByArea = $beds->groupBy('area_id'); + $allBedIds = $beds->pluck('id'); + + // 2. 获取这些床位在当月的所有真实子订单(仅统计 total > 0,且属于当前项目) + $orderItems = OrderItems::whereIn('bed_id', $allBedIds) + ->where('total', '>', 0) + ->where('paid_at', 'like', '%' . $month . '%') + ->whereHas('order', function ($query) use ($project_id) { + $query->where('project_id', $project_id); + }) + ->get(); + + // 3. 按「真实价格」去重生成表头列(xx元/天),并取一条样本数据上的因子名称作为小字说明 + // 使用 groupBy('total'),避免闭包分组可能导致的 array_key_exists 问题 + $columns = $orderItems + ->groupBy('total') + ->map(function ($group, $total) { + /** @var OrderItems $sample */ + $sample = $group->first(); + $price = (float) $total; + + $factor_item_name = ''; + if ($sample && $sample->factors) { + $factors = json_decode($sample->factors, true) ?: []; + if (!empty($factors)) { + // 取第一条因子作为说明文本(前端展示不变:价格 + 小字) + $factor_item_name = $factors[0]['factor_item_name'] ?? ''; + } + } + + return [ + 'price' => $price, + 'name' => $price . '元/天', + 'factor_item_name' => $factor_item_name, + ]; + }) + ->sortBy('price') + ->values() + ->toArray(); + + // 4. 按病区 + 列价格 统计每个病区在每个价格档位上的总金额 $sumOrderTotal = 0; foreach ($data as $item) { - // 获取所有床位id - $bedIds = Bed::where('area_id', $item->id)->pluck('id'); - // 总和 - $item->order_total = OrderItems::whereIn('product_item_id', $productItem->pluck('id')) - ->whereIn("bed_id", $bedIds) - ->where('paid_at', 'like', '%' . $month . '%') - ->sum('total'); + // 当前病区所有床位 ID + $bedIds = $bedsByArea->get($item->id, collect())->pluck('id'); + + // 当前病区相关的所有子订单 + $areaOrderItems = $orderItems->whereIn('bed_id', $bedIds->all()); + + // 病区总收入 + $item->order_total = $areaOrderItems->sum('total'); $sumOrderTotal += $item->order_total; - // 子项 - $item->lies = $this->getLies($bedIds, $productItem, $factor, $month); - } - // 获取所有列 - $lie = []; - if (isset($data[0]->lies)) { - $lie = array_column($data[0]->lies, 'name'); + + // 子项:按表头列(价格)统计该病区在各价格档位上的总金额 + $lies = []; + foreach ($columns as $col) { + $price = (float) $col['price']; + $colTotal = $areaOrderItems->where('total', $price)->sum('total'); + + $lies[] = [ + 'name' => $col['name'], + 'factor_item_name' => $col['factor_item_name'], + 'total_price' => $price, + 'total' => $colTotal, + ]; + } + $item->lies = $lies; } + + // 表头列:使用上面生成的真实价格列(包含价格和 factor_item 名称) + $lie = $columns; $months = $this->_getMonths(); return view($this->bladePath . ".huli", compact("sumOrderTotal", "data", "month", "lie", "projects", "project_id")); @@ -491,16 +560,33 @@ class StatisticsController extends CommonController public function getLies($bedIds, $productItem, $factor, $month) { $list = []; + + // 修复:如果床位ID为空,直接返回空数组,避免 whereIn 空数组导致的SQL错误 + if (empty($bedIds)) { + return $list; + } + foreach ($productItem as $item) { foreach ($factor as $factor_item) { - $total = OrderItems::where('product_item_id', $item->id) + $query = OrderItems::where('product_item_id', $item->id) ->whereIn("bed_id", $bedIds) - ->whereRaw("factors like '%\"factor_item_id\": $factor_item->id%'") - ->where('paid_at', 'like', '%' . $month . '%') - ->sum('total'); - $list [] = [ - 'name' => $item->price + $factor_item->price . '元/天', - 'total_price' => $item->price + $factor_item->price, + ->where('paid_at', 'like', '%' . $month . '%'); + + // 使用 MySQL 5.7 的 JSON_SEARCH 精确匹配包含指定 factor_item_id 的子订单 + $factorItemId = (int) $factor_item->id; + $query->whereRaw("JSON_SEARCH(factors, 'one', ?, NULL, '$[*].factor_item_id') IS NOT NULL", [$factorItemId]); + + // 1)列对应的真实总收入:该因子 + 产品子项 + 病区 + 月份 下所有子订单的 total 之和 + $total = (float) $query->sum('total'); + + // 2)表头展示的价格:按“公式”计算,保证不是 0(近似真实下单价) + // 价格 = 产品子项基础价 + 因子价格 + $totalPrice = (float) $item->price + (float) $factor_item->price; + + $list[] = [ + 'name' => $totalPrice . '元/天', + 'factor_item_name' => $factor_item->name ?? '', + 'total_price' => $totalPrice, 'product_item_id' => $item->id, 'factor_item_id' => $factor_item->id, 'total' => $total diff --git a/public/.well-known/acme-challenge/XuhBUEvx2PXOhnrLb2lfM2is3XbaBhBOXl8SMmUHv0s b/public/.well-known/acme-challenge/XuhBUEvx2PXOhnrLb2lfM2is3XbaBhBOXl8SMmUHv0s new file mode 100644 index 0000000..5f96af7 --- /dev/null +++ b/public/.well-known/acme-challenge/XuhBUEvx2PXOhnrLb2lfM2is3XbaBhBOXl8SMmUHv0s @@ -0,0 +1 @@ +XuhBUEvx2PXOhnrLb2lfM2is3XbaBhBOXl8SMmUHv0s.5-N8Ip449Q-0w2bLgJMR9BQtRA8QQojBMyN7wrETK2I \ No newline at end of file diff --git a/public/1_18.apk b/public/1_18.apk new file mode 100755 index 0000000..9be2924 Binary files /dev/null and b/public/1_18.apk differ diff --git a/resources/views/admin/statistics/huli.blade.php b/resources/views/admin/statistics/huli.blade.php index 199c7f3..a8a74e7 100644 --- a/resources/views/admin/statistics/huli.blade.php +++ b/resources/views/admin/statistics/huli.blade.php @@ -7,11 +7,10 @@