diff --git a/app/Http/Controllers/Admin/CityController.php b/app/Http/Controllers/Admin/CityController.php index 4b74717..b4afa1c 100644 --- a/app/Http/Controllers/Admin/CityController.php +++ b/app/Http/Controllers/Admin/CityController.php @@ -217,13 +217,34 @@ class CityController extends Controller ->toArray(); $usersCount = count(array_filter($userIds)); - // 予約待ち人数を取得(valid_flag = 1 かつ reserve_order が設定されているもの) - $waitingCount = DB::table('reserve') + // 予約待ち人数を取得 + // 条件:有効(valid_flag=1) かつ契約化されていない(contract_id IS NULL) + // キャンセル除外:reserve_cancel_flag が NULL または 0、かつ reserve_cancelday が NULL + $waitingQuery = DB::table('reserve') ->whereIn('park_id', $parkIds) ->where('valid_flag', 1) - ->whereNotNull('reserve_order') - ->where('reserve_order', '>', 0) - ->count(); + ->whereNull('contract_id'); + + // キャンセルフラグの有無をチェック(列が存在するかどうか) + try { + DB::table('reserve') + ->select(DB::raw('1')) + ->whereNotNull('reserve_cancel_flag') + ->limit(1) + ->first(); + + // 列が存在する場合、キャンセル除外条件を追加 + $waitingQuery = $waitingQuery + ->where(function ($q) { + $q->whereNull('reserve_cancel_flag') + ->orWhere('reserve_cancel_flag', 0); + }) + ->whereNull('reserve_cancelday'); + } catch (\Exception $e) { + // キャンセルフラグが未運用の場合は基本条件のみで計算 + } + + $waitingCount = $waitingQuery->count(); } $stats = [ diff --git a/app/Http/Controllers/Admin/InformationController.php b/app/Http/Controllers/Admin/InformationController.php index 6598892..a44c017 100644 --- a/app/Http/Controllers/Admin/InformationController.php +++ b/app/Http/Controllers/Admin/InformationController.php @@ -61,22 +61,68 @@ class InformationController extends Controller { // ダッシュボード統計情報を集計 - // 駐輪場の総収容台数 - $totalCapacity = DB::table('park') - ->sum('park_capacity') ?? 0; + // park_number テーブルから総容量を計算 + // park_standard(標準) + park_number(割当)+ park_limit(制限値)の合算 + $totalCapacity = DB::table('park_number') + ->selectRaw(' + COALESCE(SUM(park_standard), 0) as std_sum, + COALESCE(SUM(park_number), 0) as num_sum, + COALESCE(SUM(park_limit), 0) as limit_sum + ') + ->first(); - // 予約待ち人数(regular_contractで状態チェック) - $totalWaiting = DB::table('regular_contract') - ->whereIn('rc_status', [1]) // 待機中など - ->count(); + $totalCapacityValue = ($totalCapacity->std_sum ?? 0) + + ($totalCapacity->num_sum ?? 0) + + ($totalCapacity->limit_sum ?? 0); - // 利用率計算(使用中台数 / 総容量) - $utilizationRate = $totalCapacity > 0 - ? round((DB::table('park') - ->where('park_status', 1) - ->sum('park_capacity') ?? 0) / $totalCapacity * 100) + // 予約待ち人数(reserve テーブルから集計) + // 条件:有効(valid_flag=1) かつ契約化されていない(contract_id IS NULL) + // キャンセル除外:reserve_cancel_flag が NULL または 0、かつ reserve_cancelday が NULL + $reserveQuery = DB::table('reserve') + ->where('valid_flag', 1) + ->whereNull('contract_id'); + + // キャンセルフラグの有無をチェック(列が存在するかどうか) + try { + $testResult = DB::table('reserve') + ->select(DB::raw('1')) + ->whereNotNull('reserve_cancel_flag') + ->limit(1) + ->first(); + + // 列が存在する場合、キャンセル除外条件を追加 + $reserveQuery = $reserveQuery + ->where(function ($q) { + $q->whereNull('reserve_cancel_flag') + ->orWhere('reserve_cancel_flag', 0); + }) + ->whereNull('reserve_cancelday'); + } catch (\Exception $e) { + // キャンセルフラグが未運用の場合は基本条件のみで計算 + } + + $totalWaiting = $reserveQuery->count(); + + // 使用中台数(park_number の park_number が使用台数) + $totalUsed = DB::table('park_number') + ->sum('park_number') ?? 0; + + // 空き台数 = 総容量 - 使用中台数 + $totalVacant = max(0, $totalCapacityValue - $totalUsed); + + // 利用率計算(小数点以下切捨て) + $utilizationRate = $totalCapacityValue > 0 + ? (int) floor(($totalUsed / $totalCapacityValue) * 100) : 0; + // 予約待ち率(超過時のみ、超過なしは0%) + // 超過判定:待機人数 > 空き台数 + $totalWaitingRate = 0; + if ($totalCapacityValue > 0 && $totalWaiting > 0 && $totalWaiting > $totalVacant) { + // 超過分 / 総容量 * 100(分母チェック付き) + $totalWaitingRate = (int) floor((($totalWaiting - $totalVacant) / $totalCapacityValue) * 100); + } + $totalStats = [ 'total_cities' => DB::table('city')->count(), 'total_parks' => DB::table('park')->count(), @@ -87,11 +133,110 @@ class InformationController extends Controller ->whereDate('created_at', today()) ->count(), 'total_waiting' => $totalWaiting, - 'total_capacity' => $totalCapacity, + 'total_capacity' => $totalCapacityValue, 'total_utilization_rate' => $utilizationRate, + 'total_vacant_number' => $totalVacant, + 'total_waiting_rate' => $totalWaitingRate, ]; - return view('admin.information.dashboard', compact('totalStats')); + // 自治体別統計情報を作成 + $cityStats = []; + $cities = DB::table('city')->get(); + + foreach ($cities as $city) { + // その自治体に属する駐輪場 ID を取得 + $parkIds = DB::table('park') + ->where('city_id', $city->city_id) + ->pluck('park_id') + ->toArray(); + + // ① 駐輪場数 + $parksCount = count($parkIds); + + // ② 総収容台数(park_number テーブルの park_standard を合算) + $capacity = 0; + if (!empty($parkIds)) { + $capacityResult = DB::table('park_number') + ->whereIn('park_id', $parkIds) + ->sum('park_standard'); + $capacity = $capacityResult ?? 0; + } + + // ③ 契約台数(contract_cancel_flag = 0 かつ有効期間内) + $contractsCount = 0; + if (!empty($parkIds)) { + $contractsCount = DB::table('regular_contract') + ->whereIn('park_id', $parkIds) + ->where('contract_cancel_flag', 0) + ->where(function ($q) { + // 有効期間内:開始日 <= 今日 かつ 終了日 >= 今日 + $q->where('contract_periods', '<=', now()) + ->where('contract_periode', '>=', now()); + }) + ->count(); + } + + // ④ 利用率計算(小数点以下切捨て) + $utilizationRate = $capacity > 0 + ? (int) floor(($contractsCount / $capacity) * 100) + : 0; + + // ⑤ 空き台数 + $availableSpaces = max(0, $capacity - $contractsCount); + + // ⑥ 予約待ち人数(reserve テーブルで contract_id IS NULL かつ valid_flag = 1) + $waitingCount = 0; + if (!empty($parkIds)) { + $waitingQuery = DB::table('reserve') + ->whereIn('park_id', $parkIds) + ->where('valid_flag', 1) + ->whereNull('contract_id'); + + // キャンセルフラグの有無をチェック + try { + DB::table('reserve') + ->select(DB::raw('1')) + ->whereNotNull('reserve_cancel_flag') + ->limit(1) + ->first(); + + // 列が存在する場合、キャンセル除外条件を追加 + $waitingQuery = $waitingQuery + ->where(function ($q) { + $q->whereNull('reserve_cancel_flag') + ->orWhere('reserve_cancel_flag', 0); + }) + ->whereNull('reserve_cancelday'); + } catch (\Exception $e) { + // キャンセルフラグが未運用の場合は基本条件のみで計算 + } + + $waitingCount = $waitingQuery->count(); + } + + // ⑦ 利用者数(ユニークユーザー数) + $usersCount = 0; + if (!empty($parkIds)) { + $usersCount = DB::table('regular_contract') + ->whereIn('park_id', $parkIds) + ->distinct() + ->count('user_id'); + } + + // 配列に追加 + $cityStats[] = [ + 'city' => $city, + 'parks_count' => $parksCount, + 'contracts_count' => $contractsCount, + 'users_count' => $usersCount, + 'waiting_count' => $waitingCount, + 'capacity' => $capacity, + 'utilization_rate' => $utilizationRate, + 'available_spaces' => $availableSpaces, + ]; + } + + return view('admin.information.dashboard', compact('totalStats', 'cityStats')); } // ステータス一括更新(着手=2 / 対応完了=3) diff --git a/app/Http/Middleware/CheckCityAccess.php b/app/Http/Middleware/CheckCityAccess.php new file mode 100644 index 0000000..068283e --- /dev/null +++ b/app/Http/Middleware/CheckCityAccess.php @@ -0,0 +1,34 @@ +route('city_id'); + // $user = auth()->user(); + // if (!$user->canAccessCity($city_id)) { + // return abort(403, '指定された自治体へのアクセス権がありません。'); + // } + + return $next($request); + } +} diff --git a/resources/views/admin/CityMaster/dashboard.blade.php b/resources/views/admin/CityMaster/dashboard.blade.php index a99201c..1638fb8 100644 --- a/resources/views/admin/CityMaster/dashboard.blade.php +++ b/resources/views/admin/CityMaster/dashboard.blade.php @@ -89,7 +89,19 @@
総収容台数
空き台数
予約待ち率