This commit is contained in:
parent
4137794126
commit
75bbec6f5a
@ -10,13 +10,13 @@ class PeriodicalController extends Controller
|
|||||||
// 画面
|
// 画面
|
||||||
public function list(Request $request)
|
public function list(Request $request)
|
||||||
{
|
{
|
||||||
// Bladeで使うカラム名(id, name)で取得
|
$parks = DB::table('regular_contract')
|
||||||
$parks = DB::table('park')
|
->join('park', 'regular_contract.park_id', '=', 'park.park_id')
|
||||||
->select('park_id', 'park_name')
|
->select('park.park_id', 'park.park_name')
|
||||||
->orderBy('park_name')
|
->distinct()
|
||||||
|
->orderBy('park.park_name')
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
// 必要なら選択中のpark_idも渡す
|
|
||||||
$selectedParkId = $request->input('park_id', '');
|
$selectedParkId = $request->input('park_id', '');
|
||||||
|
|
||||||
return view('admin.periodical.list', compact('parks', 'selectedParkId'));
|
return view('admin.periodical.list', compact('parks', 'selectedParkId'));
|
||||||
@ -27,73 +27,365 @@ class PeriodicalController extends Controller
|
|||||||
{
|
{
|
||||||
$parkId = $request->input('park_id');
|
$parkId = $request->input('park_id');
|
||||||
|
|
||||||
// 契約状況
|
if (empty($parkId)) {
|
||||||
$bicycleGeneral = DB::table('regular_contract')
|
return response()->json([
|
||||||
->where('park_id', $parkId)
|
'contract_summary' => [],
|
||||||
->where('user_categoryid', 1)
|
'waiting_summary' => [],
|
||||||
->where('ptype_id', 1) // 1:自転車
|
'renewal_summary' => [],
|
||||||
->where('contract_cancel_flag', 0)
|
'debug_info' => ['message' => 'No park_id provided']
|
||||||
->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,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// デバッグ情報を収集
|
||||||
|
$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([
|
return response()->json([
|
||||||
'contract_summary' => $contractSummary,
|
'contract_summary' => $contractSummary,
|
||||||
'waiting_summary' => $waitingSummary,
|
'waiting_summary' => $waitingSummary,
|
||||||
'renewal_summary' => $renewalSummary,
|
'renewal_summary' => $renewalSummary,
|
||||||
|
'debug_info' => $debugInfo
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
?>
|
||||||
@ -4,223 +4,243 @@
|
|||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="content-header">
|
<div class="content-header">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="row mb-2">
|
<div class="row mb-2">
|
||||||
<div class="col-lg-6">
|
<div class="col-sm-6"><h1 class="m-0 text-dark">定期利用・契約状況</h1></div>
|
||||||
<h1 class="m-0 text-dark">定期利用・契約状況</h1>
|
<div class="col-sm-6">
|
||||||
</div>
|
<ol class="breadcrumb float-sm-right text-sm">
|
||||||
<div class="col-lg-6">
|
<li class="breadcrumb-item"><a href="{{ route('home') }}">ホーム</a></li>
|
||||||
<ol class="breadcrumb float-sm-right text-sm">
|
<li class="breadcrumb-item active">定期利用・契約状況</li>
|
||||||
<li class="breadcrumb-item"><a href="{{ route('home') }}">ホーム</a></li>
|
</ol>
|
||||||
<li class="breadcrumb-item active">定期利用・契約状況</li>
|
</div>
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="content">
|
<section class="content">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
|
<div class="card card-body mb-3">
|
||||||
{{-- 検索条件 --}}
|
<form class="form-inline" onsubmit="return false;">
|
||||||
<div class="card mb-3">
|
<label class="mr-2 mb-0">駐輪場:</label>
|
||||||
<div class="card-body">
|
<select name="park_id" id="park_id" class="form-control mr-3">
|
||||||
<form id="filter-form" class="form-inline" onsubmit="return false;">
|
<option value="">全て</option>
|
||||||
<label class="mr-2">駐輪場:</label>
|
@foreach ($parks as $p)
|
||||||
<select name="park_id" id="park_id" class="form-control mr-3">
|
<option value="{{ $p->park_id }}" {{ (string)$selectedParkId === (string)$p->park_id ? 'selected' : '' }}>
|
||||||
<option value="">全て</option>
|
{{ $p->park_name }}
|
||||||
@foreach($parks as $pk)
|
</option>
|
||||||
<option value="{{ $pk->park_id }}" {{ (string) $pk->park_id === (string) ($selectedParkId ?? '') ? 'selected' : '' }}>
|
@endforeach
|
||||||
{{ $pk->park_name }}
|
</select>
|
||||||
</option>
|
</form>
|
||||||
@endforeach
|
<small class="text-muted d-block mt-2">
|
||||||
</select>
|
以下に記載以外の期間情報を参照したい場合は、マスタ管理>定期期間マスタのCSV出力を利用してください。
|
||||||
</form>
|
</small>
|
||||||
<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>
|
</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>
|
</section>
|
||||||
|
@endsection
|
||||||
|
|
||||||
@push('scripts')
|
@push('scripts')
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
(function() {
|
||||||
loadStats();
|
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 () {
|
const park = $('#park_id');
|
||||||
loadStats();
|
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({
|
function renderWaitingSummary(list){
|
||||||
url: "{{ route('periodical.listData') }}",
|
const tb = $tb('tbl-waiting-summary'); tb.innerHTML='';
|
||||||
type: 'GET',
|
if(!Array.isArray(list)||!list.length){ tb.innerHTML = noDataRow(6); return; }
|
||||||
data: { park_id: $('#park_id').val() },
|
list.forEach(r=>{
|
||||||
success: function (res) {
|
const rowClass = r.type === '計' ? ' class="font-weight-bold"' : '';
|
||||||
renderContractSummary(res.contract_summary || []);
|
tb.insertAdjacentHTML('beforeend', `
|
||||||
renderWaitingSummary(res.waiting_summary || []);
|
<tr${rowClass}>
|
||||||
renderRenewalSummary(res.renewal_summary || []);
|
<td>${escapeHtml(r.type)}</td>
|
||||||
},
|
<td>${numberOrDash(r.general_count)}</td>
|
||||||
error: function (xhr) {
|
<td>${formatDate(r.general_first)}</td>
|
||||||
console.error(xhr.responseText || xhr.statusText);
|
<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 renderRenewalSummary(blocks){
|
||||||
function renderContractSummary(rows) {
|
const tb = $tb('tbl-renewal-summary'); tb.innerHTML='';
|
||||||
const $tb = $('#tbl-contract-summary').empty();
|
if(!Array.isArray(blocks)||!blocks.length){ tb.innerHTML = noDataRow(11); return; }
|
||||||
rows.forEach(r => {
|
|
||||||
$tb.append(`
|
// 新形式: [{month:'YYYY-MM', rows:[{label,...}]}]
|
||||||
<tr>
|
blocks.forEach(b=>{
|
||||||
<td class="text-left">${r.type}</td>
|
const rows = Array.isArray(b.rows)?b.rows:[];
|
||||||
<td>${nz(r.general_count)}</td>
|
if(rows.length === 0) return;
|
||||||
<td>${nz(r.general_extra)}</td>
|
|
||||||
<td>${nz(r.student_count)}</td>
|
rows.forEach((r,idx)=>{
|
||||||
<td>${nz(r.student_extra)}</td>
|
const monthCell = idx===0 ? `<td rowspan="${rows.length}" class="align-middle">${formatMonth(b.month)}</td>` : '';
|
||||||
<td>${nz(r.use_total)}</td>
|
const rowClass = r.label === '計' ? ' class="font-weight-bold"' : '';
|
||||||
<td>${nz(r.vacancy)}</td>
|
tb.insertAdjacentHTML('beforeend', `
|
||||||
<td>${nz(r.total)}</td>
|
<tr${rowClass}>
|
||||||
<td>${r.last && r.last.reserve_date ? r.last.reserve_date : ''}</td>
|
${monthCell}
|
||||||
<td>${r.last && r.last.contract_date ? r.last.contract_date : ''}</td>
|
<td>${escapeHtml(r.label)}</td>
|
||||||
</tr>
|
<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>
|
||||||
function renderWaitingSummary(rows) {
|
<td>${numberOrDash(r.moped_total)}</td>
|
||||||
const $tb = $('#tbl-waiting-summary').empty();
|
<td>${numberOrDash(r.other_general)}</td>
|
||||||
rows.forEach(r => {
|
<td>${numberOrDash(r.other_student)}</td>
|
||||||
$tb.append(`
|
<td>${numberOrDash(r.other_total)}</td>
|
||||||
<tr>
|
</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 noDataRow(colspan){ return `<tr><td colspan="${colspan}">データがありません</td></tr>`; }
|
||||||
|
})();
|
||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
@endsection
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user