102 lines
3.4 KiB
PHP
102 lines
3.4 KiB
PHP
<?php
|
||
|
||
namespace App\Services;
|
||
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Collection;
|
||
use App\Models\Park;
|
||
|
||
/**
|
||
* 利用率状況サービス
|
||
* - 旧 UsingStatusHelper の機能をサービスとして集約
|
||
* - 画面やAPIから本サービスを経由して取得する
|
||
*/
|
||
class UsingStatusService
|
||
{
|
||
/**
|
||
* 駐輪場別利用率統計を取得
|
||
*
|
||
* 取得元:
|
||
* - 限界収容台数: park_number.park_limit
|
||
* - 現在収容台数: park_number.park_number
|
||
* - 空き : park_number.park_limit - park_number.park_number
|
||
* - 利用率 : (現在収容台数 / 限界収容台数) * 100
|
||
*
|
||
* @param int|null $parkId 駐輪場ID(null の場合は全て)
|
||
* @return Collection
|
||
*/
|
||
public function getUtilizationStats(?int $parkId = null): Collection
|
||
{
|
||
// park_number に車種IDが ptype_id で入っている前提
|
||
// 異なる場合は 'pn.ptype_id' 部分を実テーブル定義に合わせて変更してください
|
||
$query = DB::table('park as p')
|
||
->join('park_number as pn', 'p.park_id', '=', 'pn.park_id')
|
||
->join('ptype as pt', 'pn.ptype_id', '=', 'pt.ptype_id')
|
||
->select([
|
||
'p.park_id',
|
||
'p.park_name',
|
||
'pt.ptype_id',
|
||
'pt.ptype_subject',
|
||
// 限界収容台数
|
||
'pn.park_limit',
|
||
// 現在収容台数
|
||
DB::raw('COALESCE(pn.park_number, 0) as current_count'),
|
||
// 空き = 収容上限 - 現在
|
||
DB::raw('GREATEST(0, COALESCE(pn.park_limit, 0) - COALESCE(pn.park_number, 0)) as available'),
|
||
// 利用率 = 現在 / 上限 * 100
|
||
DB::raw("CASE
|
||
WHEN COALESCE(pn.park_limit, 0) > 0
|
||
THEN ROUND((COALESCE(pn.park_number, 0) / pn.park_limit) * 100, 1)
|
||
ELSE 0
|
||
END as usage_rate"),
|
||
])
|
||
->where('p.park_close_flag', '!=', 1);
|
||
|
||
if (!empty($parkId)) {
|
||
$query->where('p.park_id', $parkId);
|
||
}
|
||
|
||
$results = $query
|
||
// 表示順:自転車 → 原付 → その他
|
||
->orderByRaw("CASE pt.ptype_subject WHEN '自転車' THEN 1 WHEN '原付' THEN 2 ELSE 3 END")
|
||
->orderBy('p.park_name')
|
||
->get();
|
||
|
||
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,
|
||
];
|
||
}
|
||
}
|
||
|
||
|