This commit is contained in:
parent
4137794126
commit
75bbec6f5a
@ -10,13 +10,13 @@ class PeriodicalController extends Controller
|
||||
// 画面
|
||||
public function list(Request $request)
|
||||
{
|
||||
// Bladeで使うカラム名(id, name)で取得
|
||||
$parks = DB::table('park')
|
||||
->select('park_id', 'park_name')
|
||||
->orderBy('park_name')
|
||||
$parks = DB::table('regular_contract')
|
||||
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
|
||||
->select('park.park_id', 'park.park_name')
|
||||
->distinct()
|
||||
->orderBy('park.park_name')
|
||||
->get();
|
||||
|
||||
// 必要なら選択中のpark_idも渡す
|
||||
$selectedParkId = $request->input('park_id', '');
|
||||
|
||||
return view('admin.periodical.list', compact('parks', 'selectedParkId'));
|
||||
@ -27,73 +27,365 @@ class PeriodicalController extends Controller
|
||||
{
|
||||
$parkId = $request->input('park_id');
|
||||
|
||||
// 契約状況
|
||||
$bicycleGeneral = DB::table('regular_contract')
|
||||
->where('park_id', $parkId)
|
||||
->where('user_categoryid', 1)
|
||||
->where('ptype_id', 1) // 1:自転車
|
||||
->where('contract_cancel_flag', 0)
|
||||
->count();
|
||||
$bicycleStudent = DB::table('regular_contract')
|
||||
->where('park_id', $parkId)
|
||||
->where('user_categoryid', 2)
|
||||
->where('ptype_id', 1)
|
||||
->where('contract_cancel_flag', 0)
|
||||
->count();
|
||||
// 原付・その他も同様に集計
|
||||
|
||||
$contractSummary = [
|
||||
[
|
||||
'type' => '自転車',
|
||||
'general_count' => $bicycleGeneral,
|
||||
'general_extra' => '',
|
||||
'student_count' => $bicycleStudent,
|
||||
'student_extra' => '',
|
||||
'use_total' => $bicycleGeneral + $bicycleStudent,
|
||||
'vacancy' => 8, // 例: 空き数
|
||||
'total' => $bicycleGeneral + $bicycleStudent + 8,
|
||||
'last' => [
|
||||
'reserve_date' => '2025/07/27',
|
||||
'contract_date' => '',
|
||||
],
|
||||
],
|
||||
// 原付・その他も同様に
|
||||
];
|
||||
|
||||
// 空き待ち状況
|
||||
$waitingSummary = [
|
||||
[
|
||||
'type' => '自転車',
|
||||
'general_count' => 28,
|
||||
'general_head' => '2023/03/08',
|
||||
'student_count' => 6,
|
||||
'student_head' => '2023/11/04',
|
||||
'total' => 34,
|
||||
],
|
||||
// 原付・その他も同様に
|
||||
];
|
||||
|
||||
// 更新状況
|
||||
$renewalSummary = [];
|
||||
for ($m = 1; $m <= 12; $m++) {
|
||||
$renewalSummary[] = [
|
||||
'month' => sprintf('%02d月', $m),
|
||||
'bicycle_general' => 0,
|
||||
'bicycle_student' => 0,
|
||||
'bicycle_total' => 0,
|
||||
'moped_general' => 0,
|
||||
'moped_student' => 0,
|
||||
'moped_total' => 0,
|
||||
'others_general' => 0,
|
||||
'others_student' => 0,
|
||||
'others_total' => 0,
|
||||
];
|
||||
if (empty($parkId)) {
|
||||
return response()->json([
|
||||
'contract_summary' => [],
|
||||
'waiting_summary' => [],
|
||||
'renewal_summary' => [],
|
||||
'debug_info' => ['message' => 'No park_id provided']
|
||||
]);
|
||||
}
|
||||
|
||||
// デバッグ情報を収集
|
||||
$debugInfo = [
|
||||
'park_id' => $parkId,
|
||||
'has_regular_type_id' => false,
|
||||
'contract_count' => 0,
|
||||
'waiting_count' => 0,
|
||||
'renewal_count' => 0
|
||||
];
|
||||
|
||||
|
||||
|
||||
// 契約状況を車種別に集計
|
||||
$contractData = [
|
||||
['psection_id' => 1, 'type' => '自転車'],
|
||||
['psection_id' => 2, 'type' => '原付'],
|
||||
['psection_id' => 0, 'type' => 'その他'] // その他は psection_id が1,2以外
|
||||
];
|
||||
|
||||
$contractSummary = [];
|
||||
$totalGeneral = 0;
|
||||
$totalStudent = 0;
|
||||
$totalUseTotal = 0;
|
||||
$totalVacancy = 0;
|
||||
$totalAll = 0;
|
||||
|
||||
foreach ($contractData as $vehicleType) {
|
||||
$query = DB::table('regular_contract as rc')
|
||||
->leftJoin('psection as ps', 'rc.psection_id', '=', 'ps.psection_id')
|
||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS general_count')
|
||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS student_count')
|
||||
->selectRaw('SUM(CASE WHEN rc.contract_cancel_flag = 0 THEN 1 ELSE 0 END) AS use_total')
|
||||
->selectRaw('SUM(CASE WHEN rc.contract_cancel_flag = 1 THEN 1 ELSE 0 END) AS vacancy')
|
||||
->selectRaw('COUNT(*) AS total')
|
||||
->where('rc.park_id', $parkId);
|
||||
|
||||
if ($vehicleType['psection_id'] === 0) {
|
||||
// その他:psection_id が 1,2 以外
|
||||
$query->whereNotIn('rc.psection_id', [1, 2]);
|
||||
} else {
|
||||
// 自転車または原付
|
||||
$query->where('rc.psection_id', $vehicleType['psection_id']);
|
||||
}
|
||||
|
||||
$result = $query->first();
|
||||
|
||||
$generalCount = (int) ($result->general_count ?? 0);
|
||||
$studentCount = (int) ($result->student_count ?? 0);
|
||||
$useTotal = (int) ($result->use_total ?? 0);
|
||||
$vacancy = (int) ($result->vacancy ?? 0);
|
||||
$total = (int) ($result->total ?? 0);
|
||||
|
||||
// 最古の予約日と契約日を取得
|
||||
$minReserveQuery = DB::table('regular_contract as rc2')
|
||||
->join('reserve as r2', 'rc2.contract_id', '=', 'r2.contract_id')
|
||||
->where('rc2.park_id', $parkId)
|
||||
->where('r2.valid_flag', 1)
|
||||
->where(function ($q) {
|
||||
$q->whereNull('r2.reserve_cancel_flag')->orWhere('r2.reserve_cancel_flag', 0);
|
||||
});
|
||||
|
||||
if ($vehicleType['psection_id'] === 0) {
|
||||
$minReserveQuery->whereNotIn('rc2.psection_id', [1, 2]);
|
||||
} else {
|
||||
$minReserveQuery->where('rc2.psection_id', $vehicleType['psection_id']);
|
||||
}
|
||||
|
||||
$minReserveDate = null;
|
||||
$minContractDate = null;
|
||||
|
||||
$reserveResult = $minReserveQuery->orderBy('r2.reserve_date', 'asc')->first(['r2.reserve_date']);
|
||||
if ($reserveResult) {
|
||||
$minReserveDate = date('Y/m/d', strtotime($reserveResult->reserve_date));
|
||||
}
|
||||
|
||||
$contractResult = $minReserveQuery->orderBy('r2.reserve_end', 'asc')->first(['r2.reserve_end']);
|
||||
if ($contractResult) {
|
||||
$minContractDate = date('Y/m/d', strtotime($contractResult->reserve_end));
|
||||
}
|
||||
|
||||
$contractSummary[] = [
|
||||
'type' => $vehicleType['type'],
|
||||
'general_count' => $generalCount,
|
||||
'general_extra' => '',
|
||||
'student_count' => $studentCount,
|
||||
'student_extra' => '',
|
||||
'use_total' => $useTotal,
|
||||
'vacancy' => $vacancy,
|
||||
'total' => $total,
|
||||
'last' => ['reserve_date' => $minReserveDate, 'contract_date' => $minContractDate],
|
||||
];
|
||||
|
||||
$totalGeneral += $generalCount;
|
||||
$totalStudent += $studentCount;
|
||||
$totalUseTotal += $useTotal;
|
||||
$totalVacancy += $vacancy;
|
||||
$totalAll += $total;
|
||||
}
|
||||
|
||||
// 合計行を追加
|
||||
$contractSummary[] = [
|
||||
'type' => '計',
|
||||
'general_count' => $totalGeneral,
|
||||
'general_extra' => '',
|
||||
'student_count' => $totalStudent,
|
||||
'student_extra' => '',
|
||||
'use_total' => $totalUseTotal,
|
||||
'vacancy' => $totalVacancy,
|
||||
'total' => $totalAll,
|
||||
'last' => ['reserve_date' => null, 'contract_date' => null],
|
||||
];
|
||||
|
||||
$debugInfo['contract_count'] = count($contractSummary);
|
||||
|
||||
// 空き待ち状況を車種別に集計
|
||||
$waitingData = [
|
||||
['psection_id' => 1, 'type' => '自転車'],
|
||||
['psection_id' => 2, 'type' => '原付'],
|
||||
['psection_id' => 0, 'type' => 'その他'] // その他は psection_id が1,2以外
|
||||
];
|
||||
|
||||
$waitingSummary = [];
|
||||
$totalGeneral = 0;
|
||||
$totalStudent = 0;
|
||||
$totalAll = 0;
|
||||
|
||||
foreach ($waitingData as $vehicleType) {
|
||||
$query = DB::table('regular_contract as rc')
|
||||
->join('reserve as r', 'rc.contract_id', '=', 'r.contract_id')
|
||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS general_count')
|
||||
->selectRaw('DATE_FORMAT(MIN(CASE WHEN rc.user_categoryid = 1 THEN r.reserve_date END), "%Y/%m/%d") AS general_first')
|
||||
->selectRaw('SUM(CASE WHEN rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS student_count')
|
||||
->selectRaw('DATE_FORMAT(MIN(CASE WHEN rc.user_categoryid = 2 THEN r.reserve_date END), "%Y/%m/%d") AS student_first')
|
||||
->selectRaw('COUNT(*) AS total')
|
||||
->where('rc.park_id', $parkId)
|
||||
->where('r.valid_flag', 1)
|
||||
->where(function ($q) {
|
||||
$q->whereNull('r.reserve_cancel_flag')->orWhere('r.reserve_cancel_flag', 0);
|
||||
});
|
||||
|
||||
if ($vehicleType['psection_id'] === 0) {
|
||||
// その他:psection_id が 1,2 以外
|
||||
$query->whereNotIn('rc.psection_id', [1, 2]);
|
||||
} else {
|
||||
// 自転車または原付
|
||||
$query->where('rc.psection_id', $vehicleType['psection_id']);
|
||||
}
|
||||
|
||||
$result = $query->first();
|
||||
|
||||
$generalCount = (int) ($result->general_count ?? 0);
|
||||
$studentCount = (int) ($result->student_count ?? 0);
|
||||
$typeTotal = $generalCount + $studentCount;
|
||||
|
||||
$waitingSummary[] = [
|
||||
'type' => $vehicleType['type'],
|
||||
'general_count' => $generalCount,
|
||||
'general_first' => $result->general_first ?? null,
|
||||
'student_count' => $studentCount,
|
||||
'student_first' => $result->student_first ?? null,
|
||||
'total' => $typeTotal,
|
||||
];
|
||||
|
||||
$totalGeneral += $generalCount;
|
||||
$totalStudent += $studentCount;
|
||||
$totalAll += $typeTotal;
|
||||
}
|
||||
|
||||
// 合計行を追加
|
||||
$waitingSummary[] = [
|
||||
'type' => '計',
|
||||
'general_count' => $totalGeneral,
|
||||
'general_first' => null,
|
||||
'student_count' => $totalStudent,
|
||||
'student_first' => null,
|
||||
'total' => $totalAll,
|
||||
];
|
||||
|
||||
$debugInfo['waiting_count'] = count($waitingSummary);
|
||||
|
||||
// まず期間タイプフィールドが存在するかチェック
|
||||
$hasRegularTypeId = false;
|
||||
try {
|
||||
$columns = DB::select('DESCRIBE regular_contract');
|
||||
foreach ($columns as $column) {
|
||||
if ($column->Field === 'regular_type_id') {
|
||||
$hasRegularTypeId = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// エラーの場合はデフォルトで false
|
||||
}
|
||||
|
||||
$debugInfo['has_regular_type_id'] = $hasRegularTypeId;
|
||||
|
||||
$renewalQuery = DB::table('regular_contract as rc')
|
||||
->join('reserve as r', 'rc.contract_id', '=', 'r.contract_id')
|
||||
->where('rc.park_id', $parkId)
|
||||
->whereNotNull('r.reserve_start')
|
||||
->where('r.valid_flag', 1)
|
||||
->selectRaw("DATE_FORMAT(r.reserve_start, '%Y-%m') AS month");
|
||||
|
||||
if ($hasRegularTypeId) {
|
||||
$renewalQuery->selectRaw('COALESCE(rc.regular_type_id, 1) AS period_type');
|
||||
} else {
|
||||
$renewalQuery->selectRaw('1 AS period_type'); // デフォルト値
|
||||
}
|
||||
|
||||
$renewalSummary = $renewalQuery
|
||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 1 AND rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS bicycle_general')
|
||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 1 AND rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS bicycle_student')
|
||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 2 AND rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS moped_general')
|
||||
->selectRaw('SUM(CASE WHEN rc.psection_id = 2 AND rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS moped_student')
|
||||
->selectRaw('SUM(CASE WHEN rc.psection_id NOT IN (1,2) AND rc.user_categoryid = 1 THEN 1 ELSE 0 END) AS other_general')
|
||||
->selectRaw('SUM(CASE WHEN rc.psection_id NOT IN (1,2) AND rc.user_categoryid = 2 THEN 1 ELSE 0 END) AS other_student')
|
||||
->groupBy(['month', 'period_type'])
|
||||
->orderBy('month')
|
||||
->orderBy('period_type')
|
||||
->limit(50)
|
||||
->get();
|
||||
|
||||
// 月別期間別データを構造化
|
||||
$structuredData = [];
|
||||
$periodLabels = [
|
||||
1 => '1ヶ月',
|
||||
2 => '2ヶ月',
|
||||
3 => '3ヶ月',
|
||||
6 => '6ヶ月',
|
||||
12 => '12ヶ月'
|
||||
];
|
||||
|
||||
// regular_type_id がない場合のデフォルト処理
|
||||
if (!$hasRegularTypeId) {
|
||||
// フィールドがない場合は、月ごとに「計」行のみ表示
|
||||
$monthlyTotals = [];
|
||||
foreach ($renewalSummary as $row) {
|
||||
$monthKey = $row->month;
|
||||
if (!isset($monthlyTotals[$monthKey])) {
|
||||
$monthlyTotals[$monthKey] = [
|
||||
'bicycle_general' => 0,
|
||||
'bicycle_student' => 0,
|
||||
'moped_general' => 0,
|
||||
'moped_student' => 0,
|
||||
'other_general' => 0,
|
||||
'other_student' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
$monthlyTotals[$monthKey]['bicycle_general'] += (int) $row->bicycle_general;
|
||||
$monthlyTotals[$monthKey]['bicycle_student'] += (int) $row->bicycle_student;
|
||||
$monthlyTotals[$monthKey]['moped_general'] += (int) $row->moped_general;
|
||||
$monthlyTotals[$monthKey]['moped_student'] += (int) $row->moped_student;
|
||||
$monthlyTotals[$monthKey]['other_general'] += (int) $row->other_general;
|
||||
$monthlyTotals[$monthKey]['other_student'] += (int) $row->other_student;
|
||||
}
|
||||
|
||||
foreach ($monthlyTotals as $monthKey => $totals) {
|
||||
$structuredData[$monthKey] = [
|
||||
'month' => $monthKey,
|
||||
'rows' => [[
|
||||
'label' => '計',
|
||||
'bicycle_general' => $totals['bicycle_general'],
|
||||
'bicycle_student' => $totals['bicycle_student'],
|
||||
'bicycle_total' => $totals['bicycle_general'] + $totals['bicycle_student'],
|
||||
'moped_general' => $totals['moped_general'],
|
||||
'moped_student' => $totals['moped_student'],
|
||||
'moped_total' => $totals['moped_general'] + $totals['moped_student'],
|
||||
'other_general' => $totals['other_general'],
|
||||
'other_student' => $totals['other_student'],
|
||||
'other_total' => $totals['other_general'] + $totals['other_student'],
|
||||
]]
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// regular_type_id がある場合の通常処理
|
||||
foreach ($renewalSummary as $row) {
|
||||
$monthKey = $row->month;
|
||||
$periodType = (int)$row->period_type;
|
||||
$periodLabel = $periodLabels[$periodType] ?? "{$periodType}ヶ月";
|
||||
|
||||
if (!isset($structuredData[$monthKey])) {
|
||||
$structuredData[$monthKey] = [
|
||||
'month' => $monthKey,
|
||||
'rows' => [],
|
||||
'totals' => [
|
||||
'bicycle_general' => 0,
|
||||
'bicycle_student' => 0,
|
||||
'moped_general' => 0,
|
||||
'moped_student' => 0,
|
||||
'other_general' => 0,
|
||||
'other_student' => 0,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
$bicycle_total = (int) $row->bicycle_general + (int) $row->bicycle_student;
|
||||
$moped_total = (int) $row->moped_general + (int) $row->moped_student;
|
||||
$other_total = (int) $row->other_general + (int) $row->other_student;
|
||||
|
||||
// 期間別データを追加
|
||||
$structuredData[$monthKey]['rows'][] = [
|
||||
'label' => $periodLabel,
|
||||
'bicycle_general' => (int) $row->bicycle_general,
|
||||
'bicycle_student' => (int) $row->bicycle_student,
|
||||
'bicycle_total' => $bicycle_total,
|
||||
'moped_general' => (int) $row->moped_general,
|
||||
'moped_student' => (int) $row->moped_student,
|
||||
'moped_total' => $moped_total,
|
||||
'other_general' => (int) $row->other_general,
|
||||
'other_student' => (int) $row->other_student,
|
||||
'other_total' => $other_total,
|
||||
];
|
||||
|
||||
// 月別合計を計算
|
||||
$structuredData[$monthKey]['totals']['bicycle_general'] += (int) $row->bicycle_general;
|
||||
$structuredData[$monthKey]['totals']['bicycle_student'] += (int) $row->bicycle_student;
|
||||
$structuredData[$monthKey]['totals']['moped_general'] += (int) $row->moped_general;
|
||||
$structuredData[$monthKey]['totals']['moped_student'] += (int) $row->moped_student;
|
||||
$structuredData[$monthKey]['totals']['other_general'] += (int) $row->other_general;
|
||||
$structuredData[$monthKey]['totals']['other_student'] += (int) $row->other_student;
|
||||
}
|
||||
|
||||
// 各月に計行を追加
|
||||
foreach ($structuredData as &$monthData) {
|
||||
$totals = $monthData['totals'];
|
||||
$monthData['rows'][] = [
|
||||
'label' => '計',
|
||||
'bicycle_general' => $totals['bicycle_general'],
|
||||
'bicycle_student' => $totals['bicycle_student'],
|
||||
'bicycle_total' => $totals['bicycle_general'] + $totals['bicycle_student'],
|
||||
'moped_general' => $totals['moped_general'],
|
||||
'moped_student' => $totals['moped_student'],
|
||||
'moped_total' => $totals['moped_general'] + $totals['moped_student'],
|
||||
'other_general' => $totals['other_general'],
|
||||
'other_student' => $totals['other_student'],
|
||||
'other_total' => $totals['other_general'] + $totals['other_student'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$renewalSummary = array_values($structuredData);
|
||||
|
||||
$debugInfo['renewal_count'] = count($renewalSummary);
|
||||
|
||||
return response()->json([
|
||||
'contract_summary' => $contractSummary,
|
||||
'waiting_summary' => $waitingSummary,
|
||||
'renewal_summary' => $renewalSummary,
|
||||
'waiting_summary' => $waitingSummary,
|
||||
'renewal_summary' => $renewalSummary,
|
||||
'debug_info' => $debugInfo
|
||||
]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@ -4,223 +4,243 @@
|
||||
|
||||
@section('content')
|
||||
<div class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-lg-6">
|
||||
<h1 class="m-0 text-dark">定期利用・契約状況</h1>
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<ol class="breadcrumb float-sm-right text-sm">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">ホーム</a></li>
|
||||
<li class="breadcrumb-item active">定期利用・契約状況</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6"><h1 class="m-0 text-dark">定期利用・契約状況</h1></div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right text-sm">
|
||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">ホーム</a></li>
|
||||
<li class="breadcrumb-item active">定期利用・契約状況</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
|
||||
{{-- 検索条件 --}}
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">
|
||||
<form id="filter-form" class="form-inline" onsubmit="return false;">
|
||||
<label class="mr-2">駐輪場:</label>
|
||||
<select name="park_id" id="park_id" class="form-control mr-3">
|
||||
<option value="">全て</option>
|
||||
@foreach($parks as $pk)
|
||||
<option value="{{ $pk->park_id }}" {{ (string) $pk->park_id === (string) ($selectedParkId ?? '') ? 'selected' : '' }}>
|
||||
{{ $pk->park_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</form>
|
||||
<small class="text-muted d-block mt-2">以下に記載以外の期間情報を参照したい場合は、マスタ管理>定期期間マスタ のCSV出力を利用してください。</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 契約状況 --}}
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<strong>契約状況</strong>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered mb-0 text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="align-middle">契約状況</th>
|
||||
<th colspan="2">一般</th>
|
||||
<th colspan="2">学生</th>
|
||||
<th rowspan="2" class="align-middle">利用計</th>
|
||||
<th rowspan="2" class="align-middle">空き</th>
|
||||
<th rowspan="2" class="align-middle">合計</th>
|
||||
<th colspan="2">直近契約</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>件数</th>
|
||||
<th><!-- 予備 --></th>
|
||||
<th>件数</th>
|
||||
<th><!-- 予備 --></th>
|
||||
<th>予約日</th>
|
||||
<th>契約日</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbl-contract-summary"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 空き待ち状況 --}}
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<strong>空き待ち状況</strong>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered mb-0 text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="align-middle">空き待ち状況</th>
|
||||
<th colspan="2">一般</th>
|
||||
<th colspan="2">学生</th>
|
||||
<th rowspan="2" class="align-middle">合計</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>件数</th>
|
||||
<th>先頭日</th>
|
||||
<th>件数</th>
|
||||
<th>先頭日</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbl-waiting-summary"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- 更新状況 --}}
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-light">
|
||||
<strong>更新状況</strong>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered mb-0 text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="align-middle" style="min-width:70px">月</th>
|
||||
<th colspan="3">自転車</th>
|
||||
<th colspan="3">原付</th>
|
||||
<th colspan="3">その他</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>一般</th>
|
||||
<th>学生</th>
|
||||
<th>計</th>
|
||||
<th>一般</th>
|
||||
<th>学生</th>
|
||||
<th>計</th>
|
||||
<th>一般</th>
|
||||
<th>学生</th>
|
||||
<th>計</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbl-renewal-summary"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="card card-body mb-3">
|
||||
<form class="form-inline" onsubmit="return false;">
|
||||
<label class="mr-2 mb-0">駐輪場:</label>
|
||||
<select name="park_id" id="park_id" class="form-control mr-3">
|
||||
<option value="">全て</option>
|
||||
@foreach ($parks as $p)
|
||||
<option value="{{ $p->park_id }}" {{ (string)$selectedParkId === (string)$p->park_id ? 'selected' : '' }}>
|
||||
{{ $p->park_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</form>
|
||||
<small class="text-muted d-block mt-2">
|
||||
以下に記載以外の期間情報を参照したい場合は、マスタ管理>定期期間マスタのCSV出力を利用してください。
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div id="stats-sections" style="display:none;">
|
||||
<div class="card mb-3">
|
||||
<div class="card-header p-2">契約状況</div>
|
||||
<div class="card-body p-2">
|
||||
<table class="table table-bordered mb-0 text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="align-middle">契約状況</th>
|
||||
<th rowspan="2" class="align-middle">一般</th>
|
||||
<th rowspan="2" class="align-middle">学生</th>
|
||||
<th rowspan="2" class="align-middle">利用計</th>
|
||||
<th rowspan="2" class="align-middle">空き</th>
|
||||
<th rowspan="2" class="align-middle">合計</th>
|
||||
<th colspan="2">直近契約</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>予約日</th>
|
||||
<th>契約日</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbl-contract-summary"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="card-header p-2">空き待ち状況</div>
|
||||
<div class="card-body p-2">
|
||||
<table class="table table-bordered mb-0 text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="align-middle">空き待ち状況</th>
|
||||
<th colspan="2">一般</th>
|
||||
<th colspan="2">学生</th>
|
||||
<th rowspan="2" class="align-middle">合計</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>件数</th>
|
||||
<th>先頭日</th>
|
||||
<th>件数</th>
|
||||
<th>先頭日</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbl-waiting-summary"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header p-2">更新状況</div>
|
||||
<div class="card-body p-2">
|
||||
<table class="table table-bordered mb-0 text-center">
|
||||
<thead>
|
||||
<tr>
|
||||
<th rowspan="2" class="align-middle" style="min-width:70px">月</th>
|
||||
<th rowspan="2" class="align-middle" style="min-width:60px">更新状況</th>
|
||||
<th colspan="3">自転車</th>
|
||||
<th colspan="3">原付</th>
|
||||
<th colspan="3">その他</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>一般</th><th>学生</th><th>計</th>
|
||||
<th>一般</th><th>学生</th><th>計</th>
|
||||
<th>一般</th><th>学生</th><th>計</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="tbl-renewal-summary"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
$(function () {
|
||||
loadStats();
|
||||
(function() {
|
||||
function $(sel){return document.querySelector(sel)}
|
||||
function $tb(id){return document.getElementById(id)}
|
||||
function escapeHtml(s){const d=document.createElement('div');d.textContent=(s??'');return d.innerHTML}
|
||||
function numberOrDash(v){const n=Number(v);return Number.isFinite(n)?n.toString():'-'}
|
||||
function formatDate(d){return d && d !== 'null' ? d : '-'}
|
||||
function formatMonth(m){
|
||||
if(!m || m === 'null') return '-';
|
||||
// YYYY-MM 形式を MM月 形式に変換
|
||||
const parts = m.split('-');
|
||||
if(parts.length === 2) {
|
||||
const monthNum = parseInt(parts[1], 10);
|
||||
return `${monthNum}月`;
|
||||
}
|
||||
return m.replace('-', '/');
|
||||
}
|
||||
|
||||
$('#park_id').on('change', function () {
|
||||
loadStats();
|
||||
const park = $('#park_id');
|
||||
const stats = $('#stats-sections');
|
||||
|
||||
park.addEventListener('change', loadStats);
|
||||
loadStats();
|
||||
|
||||
function loadStats(){
|
||||
const id = park.value;
|
||||
if(!id){ stats.style.display='none'; clearTables(); return; }
|
||||
|
||||
fetch("{{ route('periodical.listData') }}?park_id="+encodeURIComponent(id), {headers:{'Accept':'application/json'}})
|
||||
.then(r => r.ok ? r.json() : Promise.reject(r))
|
||||
.then(res => {
|
||||
stats.style.display='block';
|
||||
|
||||
// デバッグ情報があれば表示
|
||||
if(res.debug_info) {
|
||||
console.log('Debug info:', res.debug_info);
|
||||
}
|
||||
|
||||
renderContractSummary(res.contract_summary||[]);
|
||||
renderWaitingSummary(res.waiting_summary||[]);
|
||||
renderRenewalSummary(res.renewal_summary||[]);
|
||||
})
|
||||
.catch(err => {
|
||||
stats.style.display='none';
|
||||
clearTables();
|
||||
});
|
||||
}
|
||||
function clearTables(){
|
||||
['tbl-contract-summary','tbl-waiting-summary','tbl-renewal-summary'].forEach(id => $tb(id).innerHTML='');
|
||||
}
|
||||
|
||||
// 契約状況
|
||||
function renderContractSummary(list){
|
||||
const tb = $tb('tbl-contract-summary'); tb.innerHTML='';
|
||||
if(!Array.isArray(list)||!list.length){
|
||||
tb.innerHTML = noDataRow(8);
|
||||
return;
|
||||
}
|
||||
list.forEach(row=>{
|
||||
const rowClass = row.type === '計' ? ' class="font-weight-bold"' : '';
|
||||
tb.insertAdjacentHTML('beforeend', `
|
||||
<tr${rowClass}>
|
||||
<td>${escapeHtml(row.type)}</td>
|
||||
<td>${formatPair(row.general_count, row.general_extra)}</td>
|
||||
<td>${formatPair(row.student_count, row.student_extra)}</td>
|
||||
<td>${numberOrDash(row.use_total)}</td>
|
||||
<td>${numberOrDash(row.vacancy)}</td>
|
||||
<td>${numberOrDash(row.total)}</td>
|
||||
<td>${formatDate(row?.last?.reserve_date)}</td>
|
||||
<td>${formatDate(row?.last?.contract_date)}</td>
|
||||
</tr>`);
|
||||
});
|
||||
}
|
||||
function formatPair(c,e){
|
||||
const n = Number.isFinite(Number(c))?Number(c):0;
|
||||
const m = Number.isFinite(Number(e))?Number(e):0;
|
||||
return `${n}(${m})`;
|
||||
}
|
||||
|
||||
function loadStats() {
|
||||
$.ajax({
|
||||
url: "{{ route('periodical.listData') }}",
|
||||
type: 'GET',
|
||||
data: { park_id: $('#park_id').val() },
|
||||
success: function (res) {
|
||||
renderContractSummary(res.contract_summary || []);
|
||||
renderWaitingSummary(res.waiting_summary || []);
|
||||
renderRenewalSummary(res.renewal_summary || []);
|
||||
},
|
||||
error: function (xhr) {
|
||||
console.error(xhr.responseText || xhr.statusText);
|
||||
}
|
||||
});
|
||||
}
|
||||
// 空き待ち
|
||||
function renderWaitingSummary(list){
|
||||
const tb = $tb('tbl-waiting-summary'); tb.innerHTML='';
|
||||
if(!Array.isArray(list)||!list.length){ tb.innerHTML = noDataRow(6); return; }
|
||||
list.forEach(r=>{
|
||||
const rowClass = r.type === '計' ? ' class="font-weight-bold"' : '';
|
||||
tb.insertAdjacentHTML('beforeend', `
|
||||
<tr${rowClass}>
|
||||
<td>${escapeHtml(r.type)}</td>
|
||||
<td>${numberOrDash(r.general_count)}</td>
|
||||
<td>${formatDate(r.general_first)}</td>
|
||||
<td>${numberOrDash(r.student_count)}</td>
|
||||
<td>${formatDate(r.student_first)}</td>
|
||||
<td>${numberOrDash(r.total)}</td>
|
||||
</tr>`);
|
||||
});
|
||||
}
|
||||
|
||||
function nz(v) { return (v === null || v === undefined || v === '') ? '' : v; }
|
||||
|
||||
function renderContractSummary(rows) {
|
||||
const $tb = $('#tbl-contract-summary').empty();
|
||||
rows.forEach(r => {
|
||||
$tb.append(`
|
||||
<tr>
|
||||
<td class="text-left">${r.type}</td>
|
||||
<td>${nz(r.general_count)}</td>
|
||||
<td>${nz(r.general_extra)}</td>
|
||||
<td>${nz(r.student_count)}</td>
|
||||
<td>${nz(r.student_extra)}</td>
|
||||
<td>${nz(r.use_total)}</td>
|
||||
<td>${nz(r.vacancy)}</td>
|
||||
<td>${nz(r.total)}</td>
|
||||
<td>${r.last && r.last.reserve_date ? r.last.reserve_date : ''}</td>
|
||||
<td>${r.last && r.last.contract_date ? r.last.contract_date : ''}</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
function renderWaitingSummary(rows) {
|
||||
const $tb = $('#tbl-waiting-summary').empty();
|
||||
rows.forEach(r => {
|
||||
$tb.append(`
|
||||
<tr>
|
||||
<td class="text-left">${r.type}</td>
|
||||
<td>${nz(r.general_count)}</td>
|
||||
<td>${nz(r.general_head)}</td>
|
||||
<td>${nz(r.student_count)}</td>
|
||||
<td>${nz(r.student_head)}</td>
|
||||
<td>${nz(r.total)}</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
function renderRenewalSummary(rows) {
|
||||
const $tb = $('#tbl-renewal-summary').empty();
|
||||
rows.forEach(r => {
|
||||
$tb.append(`
|
||||
<tr>
|
||||
<td class="text-left">${r.month}</td>
|
||||
<td>${nz(r.bicycle_general)}</td>
|
||||
<td>${nz(r.bicycle_student)}</td>
|
||||
<td>${nz(r.bicycle_total)}</td>
|
||||
<td>${nz(r.moped_general)}</td>
|
||||
<td>${nz(r.moped_student)}</td>
|
||||
<td>${nz(r.moped_total)}</td>
|
||||
<td>${nz(r.others_general)}</td>
|
||||
<td>${nz(r.others_student)}</td>
|
||||
<td>${nz(r.others_total)}</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
}
|
||||
});
|
||||
// 更新状況(月ブロック形式)
|
||||
function renderRenewalSummary(blocks){
|
||||
const tb = $tb('tbl-renewal-summary'); tb.innerHTML='';
|
||||
if(!Array.isArray(blocks)||!blocks.length){ tb.innerHTML = noDataRow(11); return; }
|
||||
|
||||
// 新形式: [{month:'YYYY-MM', rows:[{label,...}]}]
|
||||
blocks.forEach(b=>{
|
||||
const rows = Array.isArray(b.rows)?b.rows:[];
|
||||
if(rows.length === 0) return;
|
||||
|
||||
rows.forEach((r,idx)=>{
|
||||
const monthCell = idx===0 ? `<td rowspan="${rows.length}" class="align-middle">${formatMonth(b.month)}</td>` : '';
|
||||
const rowClass = r.label === '計' ? ' class="font-weight-bold"' : '';
|
||||
tb.insertAdjacentHTML('beforeend', `
|
||||
<tr${rowClass}>
|
||||
${monthCell}
|
||||
<td>${escapeHtml(r.label)}</td>
|
||||
<td>${numberOrDash(r.bicycle_general)}</td>
|
||||
<td>${numberOrDash(r.bicycle_student)}</td>
|
||||
<td>${numberOrDash(r.bicycle_total)}</td>
|
||||
<td>${numberOrDash(r.moped_general)}</td>
|
||||
<td>${numberOrDash(r.moped_student)}</td>
|
||||
<td>${numberOrDash(r.moped_total)}</td>
|
||||
<td>${numberOrDash(r.other_general)}</td>
|
||||
<td>${numberOrDash(r.other_student)}</td>
|
||||
<td>${numberOrDash(r.other_total)}</td>
|
||||
</tr>`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function noDataRow(colspan){ return `<tr><td colspan="${colspan}">データがありません</td></tr>`; }
|
||||
})();
|
||||
</script>
|
||||
@endpush
|
||||
@endsection
|
||||
|
||||
Loading…
Reference in New Issue
Block a user