100, // 自転車 2 => 50, // 原付 3 => 30, // その他 ]; $query = DB::table('park as p') ->leftJoin('price_a as pr', 'p.park_id', '=', 'pr.park_id') ->leftJoin('ptype as pt', 'pr.price_ptypeid', '=', 'pt.ptype_id') ->leftJoin('regular_contract as rc', function ($join) { $join->on('pr.price_parkplaceid', '=', 'rc.price_parkplaceid') ->where('rc.contract_cancel_flag', '=', 0); }) ->select([ 'p.park_id', 'p.park_name', 'pt.ptype_id', 'pt.ptype_subject', DB::raw('COUNT(rc.contract_id) as current_count'), ]) ->whereNotNull('pr.price_parkplaceid') ->whereNotNull('pt.ptype_id') ->where('p.park_close_flag', '!=', 1); if ($parkId) { $query->where('p.park_id', $parkId); } $results = $query ->groupBy(['p.park_id', 'p.park_name', 'pt.ptype_id', 'pt.ptype_subject']) ->orderBy('p.park_name') ->orderBy('pt.ptype_subject') ->get(); // 後計算で容量・空き・利用率を付与 foreach ($results as $result) { $capacity = $defaultCapacity[$result->ptype_id] ?? 50; $result->park_limit = $capacity; $result->available = $capacity - $result->current_count; $result->usage_rate = $capacity > 0 ? round(($result->current_count / $capacity * 100), 1) : 0; } return $results; } /** * 駐輪場一覧を取得(選択用) */ public function getParkList(): Collection { return Park::select('park_id', 'park_name') ->where('park_close_flag', '!=', 1) ->orderBy('park_name') ->get(); } /** * 合計行の計算 * * @param Collection $stats * @return array{total_limit:int,total_current:int,total_available:int,total_usage_rate:float} */ public function calculateTotals(Collection $stats): array { $totalLimit = (int) $stats->sum('park_limit'); $totalCurrent = (int) $stats->sum('current_count'); $totalAvailable = $totalLimit - $totalCurrent; $totalUsageRate = $totalLimit > 0 ? round(($totalCurrent / $totalLimit * 100), 1) : 0.0; return [ 'total_limit' => $totalLimit, 'total_current' => $totalCurrent, 'total_available' => $totalAvailable, 'total_usage_rate' => $totalUsageRate, ]; } }