This commit is contained in:
parent
3188276fe5
commit
592c12c152
@ -217,13 +217,34 @@ class CityController extends Controller
|
|||||||
->toArray();
|
->toArray();
|
||||||
$usersCount = count(array_filter($userIds));
|
$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)
|
->whereIn('park_id', $parkIds)
|
||||||
->where('valid_flag', 1)
|
->where('valid_flag', 1)
|
||||||
->whereNotNull('reserve_order')
|
->whereNull('contract_id');
|
||||||
->where('reserve_order', '>', 0)
|
|
||||||
->count();
|
// キャンセルフラグの有無をチェック(列が存在するかどうか)
|
||||||
|
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 = [
|
$stats = [
|
||||||
|
|||||||
@ -61,22 +61,68 @@ class InformationController extends Controller
|
|||||||
{
|
{
|
||||||
// ダッシュボード統計情報を集計
|
// ダッシュボード統計情報を集計
|
||||||
|
|
||||||
// 駐輪場の総収容台数
|
// park_number テーブルから総容量を計算
|
||||||
$totalCapacity = DB::table('park')
|
// park_standard(標準) + park_number(割当)+ park_limit(制限値)の合算
|
||||||
->sum('park_capacity') ?? 0;
|
$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で状態チェック)
|
$totalCapacityValue = ($totalCapacity->std_sum ?? 0) +
|
||||||
$totalWaiting = DB::table('regular_contract')
|
($totalCapacity->num_sum ?? 0) +
|
||||||
->whereIn('rc_status', [1]) // 待機中など
|
($totalCapacity->limit_sum ?? 0);
|
||||||
->count();
|
|
||||||
|
|
||||||
// 利用率計算(使用中台数 / 総容量)
|
// 予約待ち人数(reserve テーブルから集計)
|
||||||
$utilizationRate = $totalCapacity > 0
|
// 条件:有効(valid_flag=1) かつ契約化されていない(contract_id IS NULL)
|
||||||
? round((DB::table('park')
|
// キャンセル除外:reserve_cancel_flag が NULL または 0、かつ reserve_cancelday が NULL
|
||||||
->where('park_status', 1)
|
$reserveQuery = DB::table('reserve')
|
||||||
->sum('park_capacity') ?? 0) / $totalCapacity * 100)
|
->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;
|
||||||
|
|
||||||
|
// 予約待ち率(超過時のみ、超過なしは0%)
|
||||||
|
// 超過判定:待機人数 > 空き台数
|
||||||
|
$totalWaitingRate = 0;
|
||||||
|
if ($totalCapacityValue > 0 && $totalWaiting > 0 && $totalWaiting > $totalVacant) {
|
||||||
|
// 超過分 / 総容量 * 100(分母チェック付き)
|
||||||
|
$totalWaitingRate = (int) floor((($totalWaiting - $totalVacant) / $totalCapacityValue) * 100);
|
||||||
|
}
|
||||||
|
|
||||||
$totalStats = [
|
$totalStats = [
|
||||||
'total_cities' => DB::table('city')->count(),
|
'total_cities' => DB::table('city')->count(),
|
||||||
'total_parks' => DB::table('park')->count(),
|
'total_parks' => DB::table('park')->count(),
|
||||||
@ -87,11 +133,110 @@ class InformationController extends Controller
|
|||||||
->whereDate('created_at', today())
|
->whereDate('created_at', today())
|
||||||
->count(),
|
->count(),
|
||||||
'total_waiting' => $totalWaiting,
|
'total_waiting' => $totalWaiting,
|
||||||
'total_capacity' => $totalCapacity,
|
'total_capacity' => $totalCapacityValue,
|
||||||
'total_utilization_rate' => $utilizationRate,
|
'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)
|
// ステータス一括更新(着手=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="col-lg-3 col-6">
|
||||||
<div class="small-box bg-purple">
|
<div class="small-box bg-purple">
|
||||||
<div class="inner">
|
<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>
|
<p>総収容台数</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
@ -105,7 +117,7 @@
|
|||||||
<div class="small-box bg-teal">
|
<div class="small-box bg-teal">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
@php
|
@php
|
||||||
$totalCapacity = $parks->sum('park_capacity') ?? 0;
|
$totalCapacity = $parkNumberCapacity;
|
||||||
$utilizationRate = $totalCapacity > 0 ? round(($stats['contracts_count'] / $totalCapacity) * 100, 1) : 0;
|
$utilizationRate = $totalCapacity > 0 ? round(($stats['contracts_count'] / $totalCapacity) * 100, 1) : 0;
|
||||||
@endphp
|
@endphp
|
||||||
<h3>{{ $utilizationRate }}%</h3>
|
<h3>{{ $utilizationRate }}%</h3>
|
||||||
@ -123,7 +135,7 @@
|
|||||||
<div class="col-lg-3 col-6">
|
<div class="col-lg-3 col-6">
|
||||||
<div class="small-box bg-secondary">
|
<div class="small-box bg-secondary">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
<h3>{{ number_format($totalCapacity - $stats['contracts_count']) }}</h3>
|
<h3>{{ number_format(max(0, $totalCapacity - $stats['contracts_count'])) }}</h3>
|
||||||
<p>空き台数</p>
|
<p>空き台数</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
@ -139,7 +151,13 @@
|
|||||||
<div class="small-box bg-navy">
|
<div class="small-box bg-navy">
|
||||||
<div class="inner">
|
<div class="inner">
|
||||||
@php
|
@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
|
@endphp
|
||||||
<h3>{{ $waitingRate }}%</h3>
|
<h3>{{ $waitingRate }}%</h3>
|
||||||
<p>予約待ち率</p>
|
<p>予約待ち率</p>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user