This commit is contained in:
parent
3188276fe5
commit
592c12c152
@ -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 = [
|
||||
|
||||
@ -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)
|
||||
|
||||
34
app/Http/Middleware/CheckCityAccess.php
Normal file
34
app/Http/Middleware/CheckCityAccess.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
class CheckCityAccess
|
||||
{
|
||||
/**
|
||||
* 自治体へのアクセス権限を確認するミドルウェア
|
||||
*
|
||||
* 将来的に以下の権限判定を追加予定:
|
||||
* - ユーザーが指定自治体にアクセス権があるか確認
|
||||
* - 権限がない場合は 403 Forbidden を返す
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
// 現在の処理:権限判定なしで通す
|
||||
// TODO: 将来的に以下の権限判定ロジックを追加
|
||||
// $city_id = $request->route('city_id');
|
||||
// $user = auth()->user();
|
||||
// if (!$user->canAccessCity($city_id)) {
|
||||
// return abort(403, '指定された自治体へのアクセス権がありません。');
|
||||
// }
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
}
|
||||
@ -89,7 +89,19 @@
|
||||
<div class="col-lg-3 col-6">
|
||||
<div class="small-box bg-purple">
|
||||
<div class="inner">
|
||||
<h3>{{ number_format($parks->sum('park_capacity') ?? 0) }}</h3>
|
||||
@php
|
||||
// park_number テーブルから指定駐輪場群の容量を集計
|
||||
$parkIds = $parks->pluck('park_id')->toArray();
|
||||
$parkNumberCapacity = 0;
|
||||
if (!empty($parkIds)) {
|
||||
$parkNumberData = \Illuminate\Support\Facades\DB::table('park_number')
|
||||
->whereIn('park_id', $parkIds)
|
||||
->selectRaw('COALESCE(SUM(park_standard), 0) + COALESCE(SUM(park_number), 0) + COALESCE(SUM(park_limit), 0) as total')
|
||||
->first();
|
||||
$parkNumberCapacity = $parkNumberData->total ?? 0;
|
||||
}
|
||||
@endphp
|
||||
<h3>{{ number_format($parkNumberCapacity) }}</h3>
|
||||
<p>総収容台数</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
@ -105,7 +117,7 @@
|
||||
<div class="small-box bg-teal">
|
||||
<div class="inner">
|
||||
@php
|
||||
$totalCapacity = $parks->sum('park_capacity') ?? 0;
|
||||
$totalCapacity = $parkNumberCapacity;
|
||||
$utilizationRate = $totalCapacity > 0 ? round(($stats['contracts_count'] / $totalCapacity) * 100, 1) : 0;
|
||||
@endphp
|
||||
<h3>{{ $utilizationRate }}%</h3>
|
||||
@ -123,7 +135,7 @@
|
||||
<div class="col-lg-3 col-6">
|
||||
<div class="small-box bg-secondary">
|
||||
<div class="inner">
|
||||
<h3>{{ number_format($totalCapacity - $stats['contracts_count']) }}</h3>
|
||||
<h3>{{ number_format(max(0, $totalCapacity - $stats['contracts_count'])) }}</h3>
|
||||
<p>空き台数</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
@ -139,7 +151,13 @@
|
||||
<div class="small-box bg-navy">
|
||||
<div class="inner">
|
||||
@php
|
||||
$waitingRate = $stats['contracts_count'] > 0 ? round(($stats['waiting_count'] / $stats['contracts_count']) * 100, 1) : 0;
|
||||
// 待機超過分 / 総容量で予約待ち率を計算(超過なしは0%)
|
||||
// 分母チェック付き:総容量 > 0 の場合のみ計算
|
||||
$totalVacant = max(0, $totalCapacity - $stats['contracts_count']);
|
||||
$waitingRate = 0;
|
||||
if ($totalCapacity > 0 && $stats['waiting_count'] > 0 && $stats['waiting_count'] > $totalVacant) {
|
||||
$waitingRate = (int) floor((($stats['waiting_count'] - $totalVacant) / $totalCapacity) * 100);
|
||||
}
|
||||
@endphp
|
||||
<h3>{{ $waitingRate }}%</h3>
|
||||
<p>予約待ち率</p>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user