diff --git a/app/Http/Controllers/Admin/ParkController.php b/app/Http/Controllers/Admin/ParkController.php index a21405e..8436999 100644 --- a/app/Http/Controllers/Admin/ParkController.php +++ b/app/Http/Controllers/Admin/ParkController.php @@ -1,275 +1,308 @@ leftJoin('city as c', 'p.city_id', '=', 'c.city_id') - ->select([ - 'p.*', - 'c.city_name', + public function __construct( + private readonly ParkService $parkService + ) { + } + + /** + * 一覧 + */ + public function index(ParkRequest $request) + { + $filters = $request->filters(); + + $parks = $this->parkService->paginate($filters, 20); + $cities = City::orderBy('city_id')->get(); + + $sort = $filters['sort'] ?? 'p.park_id'; + $sort_type = $filters['sort_type'] ?? 'asc'; + + return view('admin.parks.index', compact( + 'parks', + 'cities', + 'sort', + 'sort_type' + )); + } + + /** + * 新規(画面) + */ + public function create() + { + $cities = City::orderBy('city_id')->get(); + + return view('admin.parks.create', compact('cities')); + } + + /** + * 新規(登録) + */ + public function store(ParkRequest $request) + { + $operatorId = (int) (auth()->user()->ope_id ?? 1); + + $payload = $request->payload(); + + // 駐輪場五十音を設定 + $payload['park_syllabary'] = $this->toSyllabaryGroup( + $payload['park_ruby'] ?? null + ); + + // 駐輪場五十音を設定してから Service に渡す + $this->parkService->create( + $payload, + $operatorId + ); + + return redirect() + ->route('parks.index') + ->with('success', __('新規登録に完了しました。')); + } + + + /** + * 編集(画面) + */ + public function edit(int $id) + { + $record = $this->parkService->findOrFail($id); + $cities = City::orderBy('city_id')->get(); + + return view('admin.parks.edit', compact( + 'record', + 'cities' + )); + } + + + /** + * 編集(更新) + */ + public function update(ParkRequest $request, int $id) + { + $park = $this->parkService->findOrFail($id); + + $operatorId = (int) (auth()->user()->ope_id ?? 1); + + $payload = $request->payload(); + + // 駐輪場五十音を設定 + $payload['park_syllabary'] = $this->toSyllabaryGroup( + $payload['park_ruby'] ?? null); + + // 駐輪場五十音を設定してから Service に渡す + $this->parkService->update( + $park, $payload, $operatorId); + + $this->parkService->update( + $park, + $request->payload(), + $operatorId + ); + + return redirect() + ->route('parks.index') + ->with('success', __('更新に成功しました。')); + } + + + /** + * 削除(複数) + */ + public function destroy(Request $request) + { + $ids = (array) $request->input('pk', []); + + if (empty($ids)) { + return redirect() + ->route('parks.index') + ->with('error', __('削除するデータを選択してください。')); + } + + $ok = $this->parkService->deleteByIds($ids); + + return redirect() + ->route('parks.index') + ->with( + $ok ? 'success' : 'error', + $ok ? __('削除が完了しました。') : __('削除に失敗しました。') + ); + } + + /** + * CSV 出力 + */ + public function export(): StreamedResponse + { + $columns = [ + '駐輪場ID','市区','駐輪場名','駐輪場ふりがな','駐輪場五十音','住所', + '閉設フラグ','閉設日','残警告チェックフラグ','印字数','最新キープアライブ', + '更新オペレータID','更新期間開始日','更新期間開始時', + '更新期間終了日','更新期間終了時','駐輪開始期間', + 'リマインダー種別','リマインダー時間','契約後即利用許可', + '項目表示設定:性別','項目表示設定:生年月日','項目表示設定:防犯登録番号', + '二点間距離','駐車場座標(緯度)','駐車場座標(経度)','電話番号', + '駐輪場契約形態(定期)','駐輪場契約形態(一時利用)', + '車種制限','手続方法','支払方法', + '利用可能時間制限フラグ','利用可能時間(開始)','利用可能時間(終了)', + '常駐管理人フラグ','常駐時間(開始)','常駐時間(終了)', + '屋根フラグ','シール発行機フラグ','駐輪場利用方法', + '定期更新期間','空き待ち予約','特記事項','学生証確認種別', + '減免案内表示フラグ','減免対象年齢','減免案内表示開始月数','年跨ぎ', + ]; + + $rows = $this->parkService->exportRows(); + + return response()->streamDownload(function () use ($rows, $columns) { + $fp = fopen('php://output', 'w'); + + fwrite($fp, "\xEF\xBB\xBF"); + fputcsv($fp, $columns); + + foreach ($rows as $r) { + fputcsv($fp, [ + $r->park_id, + $r->city_id, + $r->park_name, + $r->park_ruby, + $r->park_syllabary, + $r->park_adrs, + $r->park_close_flag, + $r->park_day, + $r->alert_flag, + $r->print_number, + $r->keep_alive, + $r->operator_id, + $r->update_grace_period_start_date, + $r->update_grace_period_start_time, + $r->update_grace_period_end_date, + $r->update_grace_period_end_time, + $r->parking_start_grace_period, + $r->reminder_type, + $r->reminder_time, + $r->immediate_use_permit, + $r->gender_display_flag, + $r->bd_display_flag, + $r->securityreg_display_flag, + $r->distance_twopoints, + $r->park_latitude, + $r->park_longitude, + $r->park_tel, + $r->park_fixed_contract, + $r->park_temporary_contract, + $r->park_restriction, + $r->park_procedure, + $r->park_payment, + $r->park_available_time_flag, + $r->park_available_time_from, + $r->park_available_time_to, + $r->park_manager_flag, + $r->park_manager_resident_from, + $r->park_manager_resident_to, + $r->park_roof_flag, + $r->park_issuing_machine_flag, + $r->park_using_method, + $r->park_contract_renewal_term, + $r->park_reservation, + $r->park_reference, + $r->student_id_confirm_type, + $r->reduction_guide_display_flag, + $r->reduction_age, + $r->reduction_guide_display_start_month, + $r->overyear_flag, + ]); + } + + fclose($fp); + }, '駐輪場マスタ.csv', [ + 'Content-Type' => 'text/csv; charset=UTF-8', ]); - - if ($request->filled('park_name')) { - $query->where('p.park_name', 'like', '%' . $request->input('park_name') . '%'); - } - if ($request->filled('city_id')) { - $query->where('p.city_id', $request->input('city_id')); - } - if ($request->filled('sort')) { - $query->orderBy($request->input('sort'), $request->input('sort_type', 'asc')); - } else { - $query->orderBy('p.park_id', 'asc'); } - $parks = $query->paginate(20); - $cities = \DB::table('city')->orderBy('city_id')->get(); + /** + * 重複チェック(AJAX) + */ + public function checkDuplicate(Request $request) + { + $parkName = (string) $request->input('park_name', ''); + + if ($parkName === '') { + return response()->json(['duplicate' => false]); + } + + $dup = $this->parkService->checkDuplicateByName($parkName); + + if (!$dup) { + return response()->json(['duplicate' => false]); + } + + return response()->json([ + 'duplicate' => true, + 'park_id' => $dup->park_id, + 'park_name' => $dup->park_name, + ]); + } + + private function toSyllabaryGroup(?string $ruby): ?string + { + $ruby = trim((string) $ruby); + if ($ruby === '') { + return null; + } + + // 先取第1文字(UTF-8) + $first = mb_substr($ruby, 0, 1, 'UTF-8'); + + // 小书き/濁点などを正規化(必要最低限) + $map = [ + 'が'=>'か','ぎ'=>'き','ぐ'=>'く','げ'=>'け','ご'=>'こ', + 'ざ'=>'さ','じ'=>'し','ず'=>'す','ぜ'=>'せ','ぞ'=>'そ', + 'だ'=>'た','ぢ'=>'ち','づ'=>'つ','で'=>'て','ど'=>'と', + 'ば'=>'は','び'=>'ひ','ぶ'=>'ふ','べ'=>'へ','ぼ'=>'ほ', + 'ぱ'=>'は','ぴ'=>'ひ','ぷ'=>'ふ','ぺ'=>'へ','ぽ'=>'ほ', + 'ぁ'=>'あ','ぃ'=>'い','ぅ'=>'う','ぇ'=>'え','ぉ'=>'お', + 'ゃ'=>'や','ゅ'=>'ゆ','ょ'=>'よ','っ'=>'つ', + 'ゎ'=>'わ', + ]; + $first = $map[$first] ?? $first; + + // グループ判定(先頭文字で分類) + $groups = [ + 'あ' => ['あ','い','う','え','お'], + 'か' => ['か','き','く','け','こ'], + 'さ' => ['さ','し','す','せ','そ'], + 'た' => ['た','ち','つ','て','と'], + 'な' => ['な','に','ぬ','ね','の'], + 'は' => ['は','ひ','ふ','へ','ほ'], + 'ま' => ['ま','み','む','め','も'], + 'や' => ['や','ゆ','よ'], + 'ら' => ['ら','り','る','れ','ろ'], + 'わ' => ['わ','を','ん'], + ]; + + foreach ($groups as $head => $chars) { + if (in_array($first, $chars, true)) { + return $head; + } + } + + // ひらがな以外(空/英数など)は null + return null; + } - $sort = $request->input('sort', 'p.park_id'); - $sort_type = $request->input('sort_type', 'asc'); - return view('admin.parks.list', compact('parks', 'cities', 'sort', 'sort_type')); } - - public function add(Request $request) - { - $cities = \DB::table('city')->orderBy('city_id')->get(); - - if ($request->isMethod('post')) { - // バリデーション(必要な項目だけ例示) - $validated = $request->validate([ - 'city_id' => 'required|integer', - 'park_name' => 'required|string|max:255', - // 他の項目も必要に応じて追加 - ]); - - // 保存処理 - $park = new \App\Models\Park(); - $park->fill($validated); - $park->operator_id = auth()->user()->ope_id ?? 1; - $park->save(); - - return redirect()->route('parks')->with('success', '新規登録に完了しました。'); - } - - return view('admin.parks.add', [ - 'cities' => $cities, - ]); - } - - public function edit(Request $request, $pk, $view = '') - { - $park = Park::find($pk); - if (empty($pk) || empty($park)) { - abort('404'); - } - $data = $park->getAttributes(); - $dataList = $this->getDataDropList(); - $data = array_merge($data, $dataList); - if ($request->isMethod('POST') || $request->isMethod('PUT')) { - // ここをaddと同じバリデーションに変更 - $validated = $request->validate([ - 'city_id' => 'required|integer', - 'park_name' => 'required|string|max:255', - // 他の項目も必要に応じて追加 - ]); - - \DB::transaction(function () use ($validated, &$type, $park) { - $park->fill($validated); - $park->save(); - $type = true; - }); - $request->session()->flash('success', __('更新に成功しました')); - return redirect()->route('parks'); - } - if ($view != '') { - return view($view, $data); - } - return view('admin.parks.edit', [ - 'park' => $park, - 'cities' => $dataList['cities'] ?? [], - // 必要な他の変数もここで渡す - ]); - } - - public function delete(Request $request) - { - $arr_pk = $request->get('pk'); - if ($arr_pk) { - if (Park::destroy($arr_pk)) { - return redirect()->route('parks')->with('success', __("削除が完了しました。")); - } else { - return redirect()->route('parks')->with('error', __('削除に失敗しました。')); - } - } - return redirect()->route('parks')->with('error', __('削除するユーザーを選択してください。')); - } - - public function info(Request $request, $id) - { - return $this->edit($request, $id, 'admin.parks.info'); - } - - public function getDataDropList() - { - $data['cities'] = City::orderBy('city_id')->get(); - return $data; - } - - - -public function export(Request $request) -{ - $columns = [ - '駐輪場ID', '市区', '駐輪場名', '駐輪場ふりがな', '駐輪場五十音', '住所', - '閉設フラグ', '閉設日', '残警告チェックフラグ', '印字数', '最新キープアライブ', - '更新オペレータID', '更新期間開始日', '更新期間開始時', '更新期間終了日', '更新期間終了時', - '駐輪開始期間', 'リマインダー種別', 'リマインダー時間', '契約後即利用許可', - '項目表示設定:性別', '項目表示設定:生年月日', '項目表示設定:防犯登録番号', - '二点間距離', '駐車場座標(緯度)', '駐車場座標(経度)', '電話番号', - '駐輪場契約形態(定期)', '駐輪場契約形態(一時利用)', '車種制限', '手続方法', '支払方法', - '利用可能時間制限フラグ', '利用可能時間(開始)', '利用可能時間(終了)', - '常駐管理人フラグ', '常駐時間(開始)', '常駐時間(終了)', - '屋根フラグ', 'シール発行機フラグ', '駐輪場利用方法', '定期更新期間', - '空き待ち予約', '特記事項', '学生証確認種別', - '減免案内表示フラグ', '減免対象年齢', '減免案内表示開始月数', '年跨ぎ' - ]; - - $dataExport = DB::table('park as p') - ->select([ - 'p.park_id', 'p.city_id', 'p.park_name', 'p.park_ruby', 'p.park_syllabary', 'p.park_adrs', - 'p.park_close_flag', 'p.park_day', 'p.alert_flag', 'p.print_number', 'p.keep_alive', - 'p.operator_id', 'p.update_grace_period_start_date', 'p.update_grace_period_start_time', - 'p.update_grace_period_end_date', 'p.update_grace_period_end_time', - 'p.parking_start_grace_period', 'p.reminder_type', 'p.reminder_time', 'p.immediate_use_permit', - 'p.gender_display_flag', 'p.bd_display_flag', 'p.securityreg_display_flag', - 'p.distance_twopoints', 'p.park_latitude', 'p.park_longitude', 'p.park_tel', - 'p.park_fixed_contract', 'p.park_temporary_contract', 'p.park_restriction', - 'p.park_procedure', 'p.park_payment', - 'p.park_available_time_flag', 'p.park_available_time_from', 'p.park_available_time_to', - 'p.park_manager_flag', 'p.park_manager_resident_from', 'p.park_manager_resident_to', - 'p.park_roof_flag', 'p.park_issuing_machine_flag', 'p.park_using_method', - 'p.park_contract_renewal_term', 'p.park_reservation', 'p.park_reference', - 'p.student_id_confirm_type', 'p.reduction_guide_display_flag', 'p.reduction_age', - 'p.reduction_guide_display_start_month', 'p.overyear_flag' - ]) - ->orderBy('p.park_id', 'asc') - ->get(); - - $response = new StreamedResponse(function () use ($dataExport, $columns) { - $stream = fopen('php://output', 'w'); - // Excel兼容 BOM - fwrite($stream, chr(0xEF) . chr(0xBB) . chr(0xBF)); - fputcsv($stream, $columns); - - foreach ($dataExport as $item) { - fputcsv($stream, [ - $item->park_id, $item->city_id, $item->park_name, $item->park_ruby, $item->park_syllabary, $item->park_adrs, - $item->park_close_flag, $item->park_day, $item->alert_flag, $item->print_number, $item->keep_alive, - $item->operator_id, $item->update_grace_period_start_date, $item->update_grace_period_start_time, - $item->update_grace_period_end_date, $item->update_grace_period_end_time, - $item->parking_start_grace_period, $item->reminder_type, $item->reminder_time, $item->immediate_use_permit, - $item->gender_display_flag, $item->bd_display_flag, $item->securityreg_display_flag, - $item->distance_twopoints, $item->park_latitude, $item->park_longitude, $item->park_tel, - $item->park_fixed_contract, $item->park_temporary_contract, $item->park_restriction, - $item->park_procedure, $item->park_payment, - $item->park_available_time_flag, $item->park_available_time_from, $item->park_available_time_to, - $item->park_manager_flag, $item->park_manager_resident_from, $item->park_manager_resident_to, - $item->park_roof_flag, $item->park_issuing_machine_flag, $item->park_using_method, - $item->park_contract_renewal_term, $item->park_reservation, $item->park_reference, - $item->student_id_confirm_type, $item->reduction_guide_display_flag, $item->reduction_age, - $item->reduction_guide_display_start_month, $item->overyear_flag - ]); - } - - fclose($stream); - }); - - $response->headers->set('Content-Type', 'text/csv; charset=UTF-8'); - $response->headers->set('Content-Disposition', 'attachment; filename="駐輪場マスタ.csv"'); - $response->headers->set('Cache-Control', 'no-store, no-cache'); - - return $response; -} - - public function import(Request $request) - { - $file = $request->file('file'); - if (!empty($file)) { - $data = Utils::csvToArray($file); - $type = 1; - $msg = ''; - $record = 0; - DB::beginTransaction(); - try { - Park::query()->delete(); - $col = 13; - foreach ($data as $key => $items) { - $record = $key + 2; - if (count($items) == $col) { - $row = new Park(); - $row->park_id = $items[0]; - $row->city_id = $items[1]; - $row->park_name = $items[3]; - $row->park_ruby = $items[4]; - $row->park_syllabary = $items[5]; - $row->park_adrs = $items[6]; - $row->park_close_flag = $items[7]; - $row->park_day = $items[9]; - $row->alert_flag = $items[10]; - $row->print_number = $items[11]; - $row->keep_alive = $items[12]; - if (!$row->save()) { - $type = 0; - $msg = '行:record型が一致しません。'; - break; - } - } else { - $type = 0; - $msg = '行:record列数が一致しません。'; - break; - } - } - } catch (\Exception $e) { - $msg = '行:record型が一致しません。'; - $type = 0; - } - if ($type) { - DB::commit(); - return redirect()->route('parks')->with('success', __('輸入成功')); - } else { - DB::rollBack(); - return redirect()->route('parks')->with('error', __($msg, ['record' => $record])); - } - } else { - return redirect()->route('parks')->with('error', __('あなたはcsvファイルを選択していません。')); - } - } - - public function checkDuplicate(\Illuminate\Http\Request $request) - { - $parkName = $request->input('park_name'); - $duplicate = Park::where('park_name', $parkName)->first(); - if ($duplicate) { - return response()->json([ - 'duplicate' => true, - 'park_id' => $duplicate->park_id, - 'park_name' => $duplicate->park_name, - ]); - } - return response()->json(['duplicate' => false]); - } -} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/ReservesController.php b/app/Http/Controllers/Admin/ReservesController.php index 96c237e..74df6ff 100644 --- a/app/Http/Controllers/Admin/ReservesController.php +++ b/app/Http/Controllers/Admin/ReservesController.php @@ -1,469 +1,118 @@ input('sort', 'reserve_id'); - $sortType = strtolower($request->input('sort_type', 'asc')) === 'desc' ? 'desc' : 'asc'; + $result = $this->reserveService->paginate($request->payload()); - // ── 絞り込み(必要最低限:利用者/駐輪場/期間)────────────────── - $userId = trim((string) $request->input('user_id', '')); - $parkId = trim((string) $request->input('park_id', '')); - $fromDt = $request->input('reserve_date_from', ''); - $toDt = $request->input('reserve_date_to', ''); - $keyword = trim((string) $request->input('keyword', '')); // 利用者名かな など - $validFlag = trim((string) $request->input('valid_flag', '')); - $mailSentFrom = $request->input('mail_sent_from', ''); - $mailSentTo = $request->input('mail_sent_to', ''); + return view('admin.reserves.index', $result); + } - $priceUnion = DB::query()->fromSub(function ($sub) { - $sub->from('price_a') - ->select('price_parkplaceid', 'prine_name') - ->unionAll( - DB::table('price_b')->select('price_parkplaceid', 'prine_name') - ); - }, 'price_union'); + /** + * 新規(画面) + * Why: プルダウン等の初期表示データ取得は Service に寄せる。 + */ + public function create(): View + { + $form = $this->reserveService->getCreateForm(); - // ── クエリ構築 ──────────────────────────────────────────────── - $q = DB::table('reserve as r') - ->leftJoin('user as u', 'u.user_id', '=', 'r.user_id') - ->leftJoin('park as p', 'p.park_id', '=', 'r.park_id') - ->leftJoin('psection as ps', 'ps.psection_id', '=', 'r.psection_id') - ->leftJoin('ptype as pt', 'pt.ptype_id', '=', 'r.ptype_id') - ->leftJoin('usertype as t', 't.user_categoryid', '=', 'r.user_categoryid') - ->leftJoinSub($priceUnion, 'price_union', function ($join) { - $join->on('price_union.price_parkplaceid', '=', 'r.price_parkplaceid'); - }) - ->select([ - 'r.reserve_id', - 'r.contract_id', - 'r.contract_created_at', - 'r.user_id', - 'r.park_id', - 'r.price_parkplaceid', - 'r.psection_id', - 'r.reserve_date', - 'r.reserve_start', - 'r.reserve_end', - 'r.reserve_reduction', - 'r.reserve_auto_remind', - 'r.reserve_manual_remind', - DB::raw('r.`800m_flag` as flag_800m'), - 'r.reserve_cancelday', - 'r.valid_flag', - 'r.reserve_manual', - 'r.reserve_notice', - 'r.sent_date', - 'r.reserve_order', - 'r.valid_flag', - 'r.ope_id', - 'r.user_categoryid', - DB::raw('u.user_name as user_name'), - DB::raw('u.user_phonetic as user_phonetic'), - DB::raw('u.user_mobile as user_mobile'), - DB::raw('p.park_name as park_name'), - DB::raw('pt.ptype_subject as ptype_subject'), - DB::raw('ps.psection_subject as psection_subject'), - DB::raw('price_union.price_parkplaceid as display_price_parkplaceid'), - DB::raw('price_union.prine_name as display_prine_name'), - DB::raw('t.usertype_subject1 as usertype_subject1'), - DB::raw('t.usertype_subject2 as usertype_subject2'), - DB::raw('t.usertype_subject3 as usertype_subject3'), - ]); + return view('admin.reserves.create', [ + 'record' => null, - if ($userId !== '') - $q->where('r.user_id', 'like', "%{$userId}%"); - if ($parkId !== '') - $q->where('r.park_id', '=', (int) $parkId); + // Blade: ($userTypes ?? []) as $id => $label 형태로 사용 + 'userTypes' => $form['userTypeOptions'] ?? [], - if ($fromDt) - $q->whereDate('r.reserve_date', '>=', $fromDt); - if ($toDt) - $q->whereDate('r.reserve_date', '<=', $toDt); + // Blade: ($parks ?? []) as $id => $label + 'parks' => $form['parkOptions'] ?? [], - if ($keyword !== '') { - $q->where(function ($w) use ($keyword) { - $w->where('u.user_name', 'like', "%{$keyword}%") - ->orWhere('u.user_phonetic', 'like', "%{$keyword}%"); - }); - } - if (in_array($validFlag, ['0', '1'], true)) { - $q->where('r.valid_flag', '=', (int) $validFlag); - } - if ($mailSentFrom !== null && $mailSentFrom !== '') { - $q->where('r.sent_date', '>=', $mailSentFrom); - } - if ($mailSentTo !== null && $mailSentTo !== '') { - $q->where('r.sent_date', '<=', $mailSentTo); - } + // Blade: ($prices ?? []) as $id => $label (prine_name 표시) + 'prices' => $form['priceOptions'] ?? [], - // ソート許可カラム(JOIN 先も含む) - $sortable = [ - 'reserve_id', - 'contract_id', - 'contract_created_at', - 'user_categoryid', - 'user_id', - 'reserve_date', - 'park_price_name', - 'price_parkplaceid', - 'psection_subject', - 'ptype_subject', - 'park_name', - 'reserve_reduction', - 'reserve_auto_remind', - 'reserve_manual_remind', - 'flag_800m', - 'reserve_cancelday', - 'valid_flag', - 'sent_date', - 'reserve_manual', - 'reserve_notice', - 'reserve_order', - ]; - if (!in_array($sort, $sortable, true)) { - $sort = 'reserve_id'; - } + // Blade: ($psections ?? []) as $id => $label + 'psections' => $form['psectionOptions'] ?? [], - $sortMap = [ - 'reserve_id' => DB::raw('r.reserve_id'), - 'contract_id' => DB::raw('r.contract_id'), - 'contract_created_at' => DB::raw('r.contract_created_at'), - 'user_categoryid' => DB::raw('r.user_categoryid'), - 'user_id' => DB::raw('r.user_id'), - 'reserve_date' => DB::raw('r.reserve_date'), - 'park_price_name' => DB::raw('price_union.prine_name'), - 'price_parkplaceid' => DB::raw('r.price_parkplaceid'), - 'psection_subject' => DB::raw('ps.psection_subject'), - 'ptype_subject' => DB::raw('pt.ptype_subject'), - 'park_name' => DB::raw('p.park_name'), - 'reserve_reduction' => DB::raw('r.reserve_reduction'), - 'reserve_auto_remind' => DB::raw('r.reserve_auto_remind'), - 'reserve_manual_remind' => DB::raw('r.reserve_manual_remind'), - 'flag_800m' => DB::raw('r.`800m_flag`'), - 'reserve_cancelday' => DB::raw('r.reserve_cancelday'), - 'valid_flag' => DB::raw('r.valid_flag'), - 'sent_date' => DB::raw('r.sent_date'), - 'reserve_manual' => DB::raw('r.reserve_manual'), - 'reserve_notice' => DB::raw('r.reserve_notice'), - 'reserve_order' => DB::raw('r.reserve_order'), - ]; - $sortColumn = $sortMap[$sort] ?? DB::raw('r.reserve_id'); - $q->orderBy($sortColumn, $sortType); + // Blade: ($ptypes ?? []) as $id => $label + 'ptypes' => $form['ptypeOptions'] ?? [], + ]); + } - $parkOptions = Park::query() - ->orderBy('park_id', 'asc') - ->pluck('park_name', 'park_id') - ->toArray(); + /** + * 新規(登録) + */ + public function store(ReserveRequest $request): RedirectResponse + { + $this->reserveService->create($request->payload()); - $list = $q->paginate(50); + return redirect() + ->route('reserves.index') + ->with('success', __('登録を完了しました。')); + } - $placeIds = $list->getCollection() - ->pluck('price_parkplaceid') - ->filter() - ->unique() - ->values() - ->all(); + /** + * 編集(画面) + */ + public function edit(int $reserveId): View + { + $form = $this->reserveService->getEditForm($reserveId); - if (!empty($placeIds)) { - $priceNamesA = PriceA::query() - ->whereIn('price_parkplaceid', $placeIds) - ->pluck('prine_name', 'price_parkplaceid') - ->toArray(); + return view('admin.reserves.edit', [ + 'record' => $form['row'], - $priceNamesB = PriceB::query() - ->whereIn('price_parkplaceid', $placeIds) - ->pluck('prine_name', 'price_parkplaceid') - ->toArray(); + 'userTypes' => $form['userTypeOptions'] ?? [], + 'parks' => $form['parkOptions'] ?? [], + 'prices' => $form['priceOptions'] ?? [], + 'psections' => $form['psectionOptions'] ?? [], + 'ptypes' => $form['ptypeOptions'] ?? [], + ]); + } - // 駐輪場所名のマッピング(price_b で上書き) - $priceNames = array_replace($priceNamesA, $priceNamesB); - $list->setCollection( - $list->getCollection()->map(function ($row) use ($priceNames) { - $id = $row->price_parkplaceid ?? null; - $row->display_prine_name = ($id !== null && array_key_exists($id, $priceNames)) - ? $priceNames[$id] - : null; - return $row; - }) + + /** + * 編集(更新) + */ + public function update(ReserveRequest $request, int $reserveId): RedirectResponse + { + $this->reserveService->update($reserveId, $request->payload()); + + return redirect() + ->route('reserves.index') + ->with('success', __('更新を完了しました。')); + } + + /** + * 削除(複数削除 pk[]) + */ + public function destroy(ReserveRequest $request): RedirectResponse + { + $payload = $request->payload(); + $deleted = $this->reserveService->deleteMany($payload['ids'] ?? []); + + return redirect() + ->route('reserves.index') + ->with( + $deleted > 0 ? 'success' : 'warning', + $deleted > 0 ? __(':count 件を削除しました。', ['count' => $deleted]) : __('削除対象がありません。') ); - } - - return view('admin.reserves.list', [ - 'list' => $list, - 'sort' => $sort, - 'sort_type' => $sortType, - // 入力保持 - 'user_id' => $userId, - 'park_id' => $parkId, - 'reserve_date_from' => $fromDt, - 'reserve_date_to' => $toDt, - 'keyword' => $keyword, - 'valid_flag' => $validFlag, - 'mail_sent_from' => $mailSentFrom, - 'mail_sent_to' => $mailSentTo, - 'parkOptions' => $parkOptions, - ]); } - - /** - * 予約追加(GET: 画面表示 / POST: 登録) - */ - public function add(Request $request) - { - if ($request->isMethod('get')) { - $userTypes = DB::table('usertype') - ->orderBy('user_categoryid', 'asc') - ->get([ - 'user_categoryid', - 'usertype_subject1', - 'usertype_subject2', - 'usertype_subject3', - ]) - ->map(function ($row) { - $labels = array_filter([ - $row->usertype_subject1, - $row->usertype_subject2, - $row->usertype_subject3, - ], fn ($v) => $v !== null && $v !== ''); - $row->display_name = $labels ? implode('/', $labels) : ''; - return $row; - }); - - $parks = Park::query() - ->orderBy('park_id', 'asc') - ->get(['park_id', 'park_name']); - - $priceA = PriceA::query() - ->select('price_parkplaceid', 'prine_name') - ->get(); - $priceB = PriceB::query() - ->select('price_parkplaceid', 'prine_name') - ->get(); - $priceOptions = $priceA->merge($priceB) - ->sortBy('price_parkplaceid', SORT_NATURAL) - ->unique('price_parkplaceid') - ->values(); - - return view('admin.reserves.add', [ - 'userTypes' => $userTypes, - 'parks' => $parks, - 'priceOptions' => $priceOptions, - ]); - } - - // 予約の最低限バリデーション(必要に応じて追加) - $v = Validator::make($request->all(), [ - 'user_id' => ['required', 'integer'], - 'park_id' => ['required', 'integer'], - 'reserve_date' => ['nullable', 'date'], - 'reserve_start' => ['nullable', 'date'], - 'reserve_end' => ['nullable', 'date'], - ], [], [ - 'user_id' => '利用者ID', - 'park_id' => '駐輪場ID', - ]); - - if ($v->fails()) { - return back()->withErrors($v)->withInput(); - } - - $now = now(); - $opeId = optional(Auth::user())->ope_id; - - $nextReserveId = DB::transaction(function () { - $currentMax = DB::table('reserve')->max('reserve_id'); - return $currentMax ? $currentMax + 1 : 1; - }); - - DB::table('reserve')->insert([ - 'reserve_id' => $nextReserveId, - 'user_id' => (int) $request->input('user_id'), - 'park_id' => (int) $request->input('park_id'), - 'contract_id' => $request->input('contract_id'), - 'price_parkplaceid' => $request->input('price_parkplaceid'), - 'psection_id' => $request->input('psection_id'), - 'reserve_date' => $request->input('reserve_date'), - 'reserve_start' => $now, - 'reserve_end' => $now, - 'valid_flag' => $request->input('valid_flag'), - 'ope_id' => $opeId, - 'created_at' => $now, - 'updated_at' => $now, - ]); - - return redirect()->route('reserves')->with('success', '予約を登録しました。'); - } - - /** - * 予約削除 - */ - public function delete(Request $request) - { - - $normalizeIds = function ($raw) { - - if (is_string($raw)) { - $raw = explode(',', $raw); - } - if (is_array($raw) && count($raw) === 1 && is_string($raw[0]) && str_contains($raw[0], ',')) { - $raw = explode(',', $raw[0]); - } - $ids = array_map('intval', (array) $raw); - $ids = array_values(array_unique(array_filter($ids, fn($v) => $v > 0))); - return $ids; - }; - - if ($request->isMethod('get')) { - - $ids = $normalizeIds($request->input('ids', [])); - - $rows = []; - if ($ids) { - $rows = DB::table('reserve as r') - ->leftJoin('user as u', 'u.user_id', '=', 'r.user_id') - ->leftJoin('park as p', 'p.park_id', '=', 'r.park_id') - ->whereIn('r.reserve_id', $ids) - ->select('r.*', 'u.user_name', 'p.park_name') - ->get(); - } - return view('admin.reserves.delete', compact('rows', 'ids')); - } - - - if ($request->post('confirmed')) { - $ids = $normalizeIds($request->input('ids', [])); - if ($ids) { - $deleted = DB::table('reserve')->whereIn('reserve_id', $ids)->delete(); - return redirect()->route('reserves')->with( - $deleted ? 'success' : 'warning', - $deleted ? "{$deleted} 件を削除しました。" : '対象が見つかりませんでした。' - ); - } - } - - return redirect()->route('reserves')->with('warning', '削除対象がありません。'); - } - - - public function edit(Request $request, $reserve_id) - { - $id = (int) $reserve_id; - - // 取得レコード(無ければ404) - $row = DB::table('reserve')->where('reserve_id', $id)->first(); - if (!$row) { - abort(404); - } - - // POST: 更新処理(※reserveテーブルに確実にある列だけ更新) - if ($request->isMethod('post')) { - $v = Validator::make($request->all(), [ - 'user_id' => ['required', 'integer'], - 'park_id' => ['required', 'integer'], - 'reserve_date' => ['nullable', 'date'], - 'reserve_start' => ['nullable', 'date'], - 'reserve_end' => ['nullable', 'date'], - ], [], [ - 'user_id' => '利用者ID', - 'park_id' => '駐輪場ID', - ]); - - if ($v->fails()) { - return back()->withErrors($v)->withInput(); - } - - $data = [ - 'contract_id' => $request->input('contract_id'), - 'user_id' => (int) $request->input('user_id'), - 'park_id' => (int) $request->input('park_id'), - 'price_parkplaceid' => $request->input('price_parkplaceid'), - 'psection_id' => $request->input('psection_id'), - 'reserve_date' => $request->input('reserve_date'), - 'reserve_start' => $request->input('reserve_start'), - 'reserve_end' => $request->input('reserve_end'), - 'valid_flag' => $request->input('valid_flag'), - 'ope_id' => $request->input('ope_id'), - 'updated_at' => now(), - ]; - DB::table('reserve')->where('reserve_id', $id)->update($data); - - return redirect()->route('reserves')->with('success', '予約を更新しました。'); - } - - // GET: 編集画面表示用の各種プルダウン(存在するテーブルだけ読む) - $userOptions = DB::table('user') - ->orderBy('user_id', 'asc') - ->limit(5000) - ->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id') - ->toArray(); - - $parkOptions = DB::table('park') - ->orderBy('park_id', 'asc') - ->pluck('park_name', 'park_id') - ->toArray(); - - $userTypeOptions = Schema::hasTable('usertype') - ? DB::table('usertype')->orderBy('user_categoryid') - ->pluck('print_name', 'user_categoryid')->toArray() - : []; - - $parkplaceOptions = Schema::hasTable('price_parkplace') - ? DB::table('price_parkplace')->orderBy('price_parkplaceid') - ->pluck('price_parkplaceid', 'price_parkplaceid')->toArray() - : []; - - $psectionOptions = Schema::hasTable('psection') - ? DB::table('psection')->orderBy('psection_id') - ->pluck( - Schema::hasColumn('psection', 'psection_name') ? 'psection_name' : 'psection_id', - 'psection_id' - )->toArray() - : []; - - $ptypeOptions = Schema::hasTable('ptype') - ? DB::table('ptype')->orderBy('ptype_id') - ->pluck( - Schema::hasColumn('ptype', 'ptype_name') ? 'ptype_name' : 'ptype_id', - 'ptype_id' - )->toArray() - : []; - - - return view('admin.reserves.edit', compact( - 'row', - 'userOptions', - 'parkOptions', - 'userTypeOptions', - 'parkplaceOptions', - 'psectionOptions', - 'ptypeOptions' - )); - } - } diff --git a/app/Http/Controllers/Admin/UsertypeController.php b/app/Http/Controllers/Admin/UsertypeController.php index f075eff..e39a0fd 100644 --- a/app/Http/Controllers/Admin/UsertypeController.php +++ b/app/Http/Controllers/Admin/UsertypeController.php @@ -2,20 +2,22 @@ namespace App\Http\Controllers\Admin; +use App\Http\Controllers\Controller; use App\Http\Requests\UsertypeRequest; use App\Models\Usertype; -use App\Utils; -use Illuminate\Support\Facades\DB; +use App\Services\UsertypeService; use Illuminate\Http\Request; -use App\Http\Controllers\Controller; -use Illuminate\Support\Facades\Validator; -use Response; class UsertypeController extends Controller { - public function list(Request $request) + public function __construct( + private readonly UsertypeService $service + ) {} + + public function index(Request $request) { - $sort = $request->input('sort', 'user_categoryid'); + // sort の許可値チェック + $sort = $request->query('sort', 'user_categoryid'); $allowSort = [ 'user_categoryid', 'sort_order', @@ -28,315 +30,86 @@ class UsertypeController extends Controller $sort = 'user_categoryid'; } - $sortType = strtolower($request->input('sort_type', 'asc')); + $sortType = strtolower($request->query('sort_type', 'asc')); if (!in_array($sortType, ['asc', 'desc'], true)) { $sortType = 'asc'; } - $action = $request->input('action'); - if ($action === 'unlink') { - $request->merge([ - 'filter_sort_order' => '', - 'filter_usertype_subject1' => '', - 'filter_usertype_subject2' => '', - 'filter_usertype_subject3' => '', - 'page' => 1, - ]); - } + $list = $this->service->paginateList( + $request->query('filter_sort_order'), + $request->query('filter_usertype_subject1'), + $request->query('filter_usertype_subject2'), + $request->query('filter_usertype_subject3'), + $sort, + $sortType + ); - $inputs = [ - 'isMethodPost' => $request->isMethod('post') ? 1 : 0, - 'isExport' => 0, - 'sort' => $sort, - 'sort_type' => $sortType, - 'page' => (int) $request->get('page', 1), - 'action' => $action, - ]; - - $filters = [ - 'filter_sort_order' => $request->input('filter_sort_order', ''), - 'filter_usertype_subject1'=> $request->input('filter_usertype_subject1', ''), - 'filter_usertype_subject2'=> $request->input('filter_usertype_subject2', ''), - 'filter_usertype_subject3'=> $request->input('filter_usertype_subject3', ''), - ]; - - $searchParams = array_merge($inputs, $filters); - - $viewData = $searchParams; - $viewData['list'] = Usertype::search($searchParams); - - if ($viewData['list']->total() > 0 && $viewData['page'] > $viewData['list']->lastPage()) { - return redirect()->route('usertypes'); - } - - return view('admin.usertypes.list', $viewData); - } - - public function add(Request $request) - { - // 画面に戻すための初期値 - $viewData = [ - 'sort_order' => old('sort_order', ''), - 'usertype_subject1' => old('usertype_subject1', ''), - 'usertype_subject2' => old('usertype_subject2', ''), - 'usertype_subject3' => old('usertype_subject3', ''), - 'print_name' => old('print_name', ''), - 'usertype_money' => old('usertype_money', ''), - 'usertype_remarks' => old('usertype_remarks', ''), - 'isEdit' => 0, - 'isInfo' => 0, - ]; - - if ($request->isMethod('post')) { - // 入力値をまとめる - $inputs = [ - 'sort_order' => $request->input('sort_order'), - 'usertype_subject1' => $request->input('usertype_subject1'), - 'usertype_subject2' => $request->input('usertype_subject2'), - 'usertype_subject3' => $request->input('usertype_subject3'), - 'print_name' => $request->input('print_name'), - 'usertype_money' => $request->input('usertype_money'), - 'usertype_remarks' => $request->input('usertype_remarks'), - ]; - - // バリデーションルール(最小限) - $rules = [ - 'sort_order' => 'required|integer', - 'usertype_subject1' => 'required|string|max:10', - 'usertype_subject2' => 'required|string|max:10', - 'usertype_subject3' => 'nullable|string|max:10', - 'print_name' => 'nullable|string|max:20', - 'usertype_money' => 'nullable|string|max:10', - 'usertype_remarks' => 'nullable|string|max:85', - ]; - - - $messages = [ - 'sort_order.required' => 'ソートオーダーは必須です。', - 'sort_order.integer' => 'ソートオーダーは数値で入力してください。', - - 'usertype_subject1.required' => '分類名1は必須です。', - 'usertype_subject2.required' => '分類名2は必須です。', - - // 'print_name.required' => '印字名は必須です。', - ]; - - $validator = Validator::make($inputs, $rules, $messages); - - if ($validator->fails()) { - return back()->withErrors($validator)->withInput(); - } - - // 登録処理 - $ok = false; - \DB::transaction(function () use ($inputs, &$ok) { - $new = new Usertype(); - $new->fill($inputs); - $ok = $new->save(); - }); - - if ($ok) { - return redirect()->route('usertypes')->with('success', '登録が完了しました。'); - } - return back()->with('error', '登録に失敗しました。')->withInput(); - } - - // GET: 画面表示 - return view('admin.usertypes.add', $viewData); - } - - - public function edit(Request $request, $id) - { - $record = Usertype::findOrFail($id); - - $data = [ - 'record' => $record, - 'isEdit' => true, - 'isInfo' => false, - ]; - - if (method_exists($this, 'getDataDropList')) { - $data = array_merge($data, $this->getDataDropList()); - } - - // POST:更新処理 - if ($request->isMethod('POST')) { - - $rules = [ - 'sort_order' => 'required|integer', - 'usertype_subject1' => 'required|string|max:10', - 'usertype_subject2' => 'required|string|max:10', - 'usertype_subject3' => 'nullable|string|max:10', - 'print_name' => 'nullable|string|max:20', - 'usertype_money' => 'nullable|string|max:10', - 'usertype_remarks' => 'nullable|string|max:85', - ]; - - - $messages = [ - 'sort_order.required' => 'ソートオーダーは必須です。', - 'sort_order.integer' => 'ソートオーダーは数値で入力してください。', - - 'usertype_subject1.required' => '分類名1は必須です。', - 'usertype_subject2.required' => '分類名2は必須です。', - 'usertype_subject3.required' => '分類名3は必須です。', - - ]; - - - $validator = Validator::make($request->all(), $rules, $messages); - - if ($validator->fails()) { - return back()->withErrors($validator)->withInput(); - } - - \DB::transaction(function () use ($request, $record) { - $record->fill([ - 'sort_order' => $request->sort_order, - 'usertype_subject1' => $request->usertype_subject1, - 'usertype_subject2' => $request->usertype_subject2, - 'usertype_subject3' => $request->usertype_subject3, - 'print_name' => $request->print_name, - 'usertype_money' => $request->usertype_money, - 'usertype_remarks' => $request->usertype_remarks, - ]); - $record->save(); - }); - - return redirect()->route('usertypes')->with('success', '更新が完了しました。'); - } - - // GET:画面表示 - return view('admin.usertypes.edit', $data); - } - - - public function delete(Request $request) - { - // pk[] が無ければ ids[] を見る(両対応) - $arr_pk = $request->input('pk'); - if (empty($arr_pk)) { - $arr_pk = $request->input('ids', []); - } - if (!is_array($arr_pk)) { - $arr_pk = [$arr_pk]; - } - if (empty($arr_pk)) { - return redirect()->route('usertypes')->with('error', '削除対象を1件以上選択してください。'); - } - - if (Usertype::deleteByPk($arr_pk)) { - return redirect()->route('usertypes')->with('success', '削除が完了しました。'); - } - return redirect()->route('usertypes')->with('error', '削除に失敗しました。'); - } - - - public function info(Request $request, $id) - { - return $this->edit($request, $id, 'admin.usertypes.info'); - } - - public function getDataDropList() - { - $data = []; - return $data; - } - - public function export(Request $request) - { - // ファイル名 - $filename = '利用者分類マスタ_' . now()->format('YmdHis') . '.csv'; - - // 検索条件(一覧と同じ) - $inputs = [ - 'isMethodPost' => 0, - 'isExport' => 1, - 'sort' => $request->input('sort', ''), - 'sort_type' => $request->input('sort_type', ''), - 'filter_sort_order' => $request->input('filter_sort_order', ''), - 'filter_usertype_subject1' => $request->input('filter_usertype_subject1', ''), - 'filter_usertype_subject2' => $request->input('filter_usertype_subject2', ''), - 'filter_usertype_subject3' => $request->input('filter_usertype_subject3', ''), - ]; - - $dataExport = Usertype::search($inputs); - - return response()->streamDownload(function () use ($dataExport) { - - // Excel用 UTF-8 BOM - echo "\xEF\xBB\xBF"; - - // ヘッダー行 - echo "利用者分類ID,ソートオーダー,分類名1,分類名2,分類名3,適用料率,備考\n"; - - // データ行 - foreach ($dataExport as $item) { - echo implode(',', [ - $item->user_categoryid, - $item->sort_order, - $item->usertype_subject1, - $item->usertype_subject2, - $item->usertype_subject3, - $item->usertype_money, - $item->usertype_remarks, - ]) . "\n"; - } - - }, $filename, [ - 'Content-Type' => 'text/csv; charset=UTF-8', + return view('admin.usertypes.index', [ + 'list' => $list, + 'sort' => $sort, + 'sort_type' => $sortType, + 'filter_sort_order' => $request->query('filter_sort_order', ''), + 'filter_usertype_subject1' => $request->query('filter_usertype_subject1', ''), + 'filter_usertype_subject2' => $request->query('filter_usertype_subject2', ''), + 'filter_usertype_subject3' => $request->query('filter_usertype_subject3', ''), ]); } - public function import(Request $request) + public function create() { - $file = $request->file('file'); - if (!empty($file)) { - $data = Utils::csvToArray($file); - $type = 1; - $msg = ''; - $record = 0; - DB::beginTransaction(); - try { - Usertype::query()->delete(); - $col = 4; - foreach ($data as $key => $items) { - $record = $key + 2; - if (count($items) == $col) { - $row = new Usertype(); - $row->user_categoryid = $items[0]; - $row->print_name = $items[1]; - $row->usertype_money = $items[2]; - $row->usertype_remarks = $items[3]; - if (!$row->save()) { - $type = 0; - $msg = '行:record型が一致しません。'; - break; - } - } else { - $type = 0; - $msg = '行:record列数が一致しません。'; - break; - } - } - } catch (\Exception $e) { - dd($e); - $msg = '行:record型が一致しません。'; - $type = 0; - } - if ($type) { - DB::commit(); - return redirect()->route('usertypes')->with('success', __('輸入成功')); - } else { - DB::rollBack(); - return redirect()->route('usertypes')->with('error', __($msg, ['record' => $record])); - } - } else { - return redirect()->route('usertypes')->with('error', __('あなたはcsvファイルを選択していません。')); - } + return view('admin.usertypes.create', [ + 'isEdit' => false, + ]); } + public function store(UsertypeRequest $request) + { + $this->service->create($request->validated()); -} \ No newline at end of file + return redirect() + ->route('usertypes.index') + ->with('success', '登録が完了しました。'); + } + + public function edit(int $id) + { + $record = Usertype::query()->findOrFail($id); + + return view('admin.usertypes.edit', [ + 'record' => $record, + 'isEdit' => true, + ]); + } + + public function update(UsertypeRequest $request, int $id) + { + $record = Usertype::query()->findOrFail($id); + + $this->service->update($record, $request->validated()); + + return redirect() + ->route('usertypes.index') + ->with('success', '更新が完了しました。'); + } + + public function destroy(Request $request) + { + $ids = $request->input('pk', []); + if (!is_array($ids)) { + $ids = [$ids]; + } + + if ($ids === []) { + return redirect() + ->route('usertypes.index') + ->with('error', '削除対象を1件以上選択してください。'); + } + + Usertype::query()->whereIn('user_categoryid', $ids)->delete(); + + return redirect() + ->route('usertypes.index') + ->with('success', '削除が完了しました。'); + } +} diff --git a/app/Http/Requests/CityRequest.php b/app/Http/Requests/CityRequest.php index 073beb5..1d127da 100644 --- a/app/Http/Requests/CityRequest.php +++ b/app/Http/Requests/CityRequest.php @@ -14,11 +14,31 @@ final class CityRequest extends FormRequest public function rules(): array { - return [ - 'city_name' => ['required', 'string', 'max:20', 'regex:/^[^ -~。-゚]+$/u'], - 'print_layout' => ['required', 'string', 'max:255', 'regex:/^[A-Za-z0-9]+$/'], - 'city_remarks' => ['nullable', 'string', 'max:255'], + // 市区名:全角文字列 / 必須 / 1〜20文字 + 'city_name' => [ + 'required', + 'string', + 'min:1', + 'max:20', + 'regex:/^[^ -~。-゚]+$/u', + ], + + // 印字レイアウトファイル:半角英数字 / 必須 / 1〜255文字 + 'print_layout' => [ + 'required', + 'string', + 'min:1', + 'max:255', + 'regex:/^[A-Za-z0-9]+$/', + ], + + // 備考:任意文字列 / 最大255 + 'city_remarks' => [ + 'nullable', + 'string', + 'max:255', + ], ]; } diff --git a/app/Http/Requests/ParkRequest.php b/app/Http/Requests/ParkRequest.php new file mode 100644 index 0000000..b11ad7f --- /dev/null +++ b/app/Http/Requests/ParkRequest.php @@ -0,0 +1,132 @@ +isMethod('post') || $this->isMethod('put')) { + return [ + // 必須 + 'city_id' => ['required', 'integer'], + 'park_name' => ['required', 'string', 'max:255'], + + // 文字系 + 'park_ruby' => ['nullable', 'string', 'max:255'], + 'park_syllabary' => ['nullable', 'string', 'max:3'], + 'park_adrs' => ['nullable', 'string', 'max:255'], + 'price_memo' => ['nullable', 'string', 'max:1000'], + + // フラグ / 種別系(integer想定) + 'park_close_flag' => ['nullable', 'integer'], + 'inverse_use_flag1' => ['nullable', 'integer'], // 逆利用フラグ(一覧) + 'inverse_use_flag2' => ['nullable', 'integer'], // 逆利用フラグ(学生) + 'parking_regulations_flag' => ['nullable', 'integer'], // 駐輪規定フラグ + 'alert_flag' => ['nullable', 'integer'], // 残警告チェックフラグ + 'immediate_use_perm' => ['nullable', 'integer'], // 契約後即利用許可 + 'gender_display_flag' => ['nullable', 'integer'], // 項目表示設定:性別 + 'bd_display_flag' => ['nullable', 'integer'], // 項目表示設定:生年月日 + 'securityreg_display_flag' => ['nullable', 'integer'], // 項目表示設定:防犯登録番号 + 'park_fixed_contract' => ['nullable', 'integer'], // 駐輪場契約形態(定期) + 'park_temporary_contract' => ['nullable', 'integer'], // 駐輪場契約形態(一時利用) + 'park_available_time_flag' => ['nullable', 'integer'], // 利用可能時間制限フラグ + 'park_manager_flag' => ['nullable', 'integer'], // 常駐管理人フラグ + 'park_roof_flag' => ['nullable', 'integer'], // 屋根フラグ + 'park_issuing_machine_flag' => ['nullable', 'integer'], // シール発行機フラグ + 'reduction_guide_display_flag' => ['nullable', 'integer'], // 減免案内表示フラグ + 'overyear_flag' => ['nullable', 'integer'], // 年跨ぎ + + // 数値系 + 'print_number' => ['nullable', 'integer'], // 印字数 + 'distance_twopoints' => ['nullable', 'integer'], // 二点間距離 + 'reduction_age' => ['nullable', 'integer'], // 減免対象年齢 + 'reduction_guide_display_start_month' => ['nullable', 'integer'], // 減免案内表示開始月数 + + // 日付/時刻系(date/time/datetime) + 'park_day' => ['nullable', 'date'], // 閉設日 + 'keep_alive' => ['nullable', 'date'], // 最新キープアライブ + 'update_grace_period_start_date' => ['nullable', 'integer', 'between:1,31'], // 更新期間開始日 + 'update_grace_period_start_time' => ['nullable', 'date_format:H:i'], // 更新期間開始時 + 'update_grace_period_end_date' => ['nullable', 'integer', 'between:1,31'], // 更新期間終了日 + 'update_grace_period_end_time' => ['nullable', 'date_format:H:i'], // 更新期間終了時 + 'parking_start_grace_period' => ['nullable', 'integer', 'between:1,31'], // 駐輪開始猶予期間 + + 'reminder_type' => ['nullable', 'integer'], // リマインダー種別 + 'reminder_time' => ['nullable', 'date_format:H:i'], // リマインダー時間 + 'park_available_time_from' => ['nullable', 'date_format:H:i'], // 利用可能時間(開始) + 'park_available_time_to' => ['nullable', 'date_format:H:i'], // 利用可能時間(終了) + 'park_manager_resident_from' => ['nullable', 'date_format:H:i'], // 常駐時間(開始) + 'park_manager_resident_to' => ['nullable', 'date_format:H:i'], // 常駐時間(終了) + + // 緯度/経度/電話など + 'park_latitude' => ['nullable', 'string', 'max:50'], // 駐車場座標(緯度) + 'park_longitude' => ['nullable', 'string', 'max:50'], // 駐車場座標(経度) + 'park_tel' => ['nullable', 'string', 'max:50'], // 電話番号 + + // 備考/自由入力 + 'park_restriction' => ['nullable', 'string', 'max:50'], // 車種制限 + 'park_procedure' => ['nullable', 'string', 'max:50'], // 手続方法 + 'park_payment' => ['nullable', 'string', 'max:100'], // 支払方法 + 'park_using_method' => ['nullable', 'string', 'max:1000'], // 駐輪場利用方法 + 'park_contract_renewal_term' => ['nullable', 'string', 'max:255'], // 定期更新期間 + 'park_reservation' => ['nullable', 'string', 'max:255'], // 空き待ち予約 + 'park_reference' => ['nullable', 'string', 'max:1000'], // 特記事項 + 'student_id_confirmation_type' => ['nullable', 'string', 'max:255'], // 学生証確認種別 + ]; + } + + return []; + } + + // + protected function prepareForValidation(): void + { + foreach ([ + 'park_available_time_from', + 'park_available_time_to', + 'park_manager_resident_from', + 'park_manager_resident_to', + 'update_grace_period_start_time', + 'update_grace_period_end_time', + 'reminder_time', + + ] as $key) { + if ($this->filled($key)) { + $v = (string) $this->input($key); + $this->merge([$key => substr($v, 0, 5)]); // HH:MM로 통일 + } + } + } + /** + * add / edit payload + */ + public function payload(): array + { + return $this->validated(); + } + + public function filters(): array + { + return [ + 'park_name' => $this->input('park_name'), + 'city_id' => $this->input('city_id'), + 'sort' => $this->input('sort'), + 'sort_type' => $this->input('sort_type', 'asc'), + ]; + } + + +} diff --git a/app/Http/Requests/ReserveRequest.php b/app/Http/Requests/ReserveRequest.php new file mode 100644 index 0000000..d1381e7 --- /dev/null +++ b/app/Http/Requests/ReserveRequest.php @@ -0,0 +1,160 @@ +routeAction(); + + if ($action === 'index') { + return [ + 'sort' => ['nullable', 'string'], + 'sort_type' => ['nullable', 'in:asc,desc'], + 'user_id' => ['nullable', 'string'], + 'park_id' => ['nullable', 'integer'], + 'reserve_date_from' => ['nullable', 'date'], + 'reserve_date_to' => ['nullable', 'date'], + 'keyword' => ['nullable', 'string'], + 'valid_flag' => ['nullable', 'in:0,1'], + ]; + } + + if ($action === 'destroy') { + return [ + 'ids' => ['required'], + ]; + } + + if ($action === 'store') { + return [ + 'user_id' => ['required', 'integer'], + 'park_id' => ['required', 'integer'], + 'contract_id' => ['nullable', 'string'], + 'price_parkplaceid' => ['nullable', 'integer'], + 'psection_id' => ['nullable', 'integer'], + 'reserve_date' => ['nullable', 'date'], + 'valid_flag' => ['nullable', 'in:0,1'], + ]; + } + + if ($action === 'update') { + return [ + 'user_id' => ['required', 'integer'], + 'park_id' => ['required', 'integer'], + 'contract_id' => ['nullable', 'string'], + 'price_parkplaceid' => ['nullable', 'integer'], + 'psection_id' => ['nullable', 'integer'], + 'reserve_date' => ['nullable', 'date'], + 'reserve_start' => ['nullable', 'date'], + 'reserve_end' => ['nullable', 'date'], + 'valid_flag' => ['nullable', 'in:0,1'], + 'ope_id' => ['nullable', 'integer'], + ]; + } + + // create/edit 등 “画面表示だけ” 는 검증 불필요 + return []; + } + + /** + * Why: Controller/Service 에서 공통으로 쓰는 입력 정규화. + */ + public function payload(): array + { + $action = $this->routeAction(); + + if ($action === 'index') { + return [ + 'sort' => (string) $this->input('sort', 'reserve_id'), + 'sortType' => (string) $this->input('sort_type', 'asc'), + 'userId' => trim((string) $this->input('user_id', '')), + 'parkId' => $this->filled('park_id') ? (int) $this->input('park_id') : null, + 'fromDt' => $this->input('reserve_date_from'), + 'toDt' => $this->input('reserve_date_to'), + 'keyword' => trim((string) $this->input('keyword', '')), + 'validFlag' => $this->filled('valid_flag') ? (string) $this->input('valid_flag') : null, + ]; + } + + if ($action === 'destroy') { + return [ + 'ids' => $this->normalizeIds($this->input('ids')), + ]; + } + + if ($action === 'store' || $action === 'update') { + return [ + 'contractId' => $this->input('contract_id'), + 'userCategoryId' => $this->filled('user_categoryid') ? (int) $this->input('user_categoryid') : null, + 'contractCreatedAt' => $this->input('contract_created_at'), + + 'userId' => (int) $this->input('user_id'), + 'parkId' => (int) $this->input('park_id'), + + 'priceParkplaceId' => $this->filled('price_parkplaceid') ? (int) $this->input('price_parkplaceid') : null, + 'psectionId' => $this->filled('psection_id') ? (int) $this->input('psection_id') : null, + 'ptypeId' => $this->filled('ptype_id') ? (int) $this->input('ptype_id') : null, + + 'reserveDate' => $this->input('reserve_date'), + 'reserveStart' => $this->input('reserve_start'), + 'reserveEnd' => $this->input('reserve_end'), + + 'reserveReduction' => $this->input('reserve_reduction'), + 'reserveAutoRemind' => $this->input('reserve_auto_remind'), + 'reserveManualRemind' => $this->input('reserve_manual_remind'), + + 'flag800m' => $this->filled('800m_flag') ? (int) $this->input('800m_flag') : null, + 'reserveCancelday' => $this->input('reserve_cancelday'), + + 'validFlag' => $this->filled('valid_flag') ? (int) $this->input('valid_flag') : null, + + 'reserveManual' => $this->filled('reserve_manual') ? (int) $this->input('reserve_manual') : null, + 'reserveNotice' => $this->input('reserve_notice'), + + 'sentDate' => $this->input('sent_date'), + 'reserveOrder' => $this->filled('reserve_order') ? (int) $this->input('reserve_order') : null, + + 'reserveType' => $this->filled('reserve_type') ? (int) $this->input('reserve_type') : null, + + 'opeId' => $this->filled('ope_id') ? (int) $this->input('ope_id') : null, + ]; + } + + + return []; + } + + private function routeAction(): string + { + // routes: reserves.index / reserves.store / reserves.update / reserves.destroy ... + $name = (string) $this->route()?->getName(); + if ($name === '') { + return ''; + } + + $parts = explode('.', $name); + return (string) end($parts); + } + + private function normalizeIds(mixed $raw): array + { + if (is_string($raw)) { + $raw = explode(',', $raw); + } + + if (is_array($raw) && count($raw) === 1 && is_string($raw[0]) && str_contains($raw[0], ',')) { + $raw = explode(',', $raw[0]); + } + + $ids = array_map('intval', (array) $raw); + $ids = array_values(array_unique(array_filter($ids, static fn (int $v): bool => $v > 0))); + + return $ids; + } +} diff --git a/app/Http/Requests/UsertypeRequest.php b/app/Http/Requests/UsertypeRequest.php new file mode 100644 index 0000000..be7bf60 --- /dev/null +++ b/app/Http/Requests/UsertypeRequest.php @@ -0,0 +1,91 @@ + [ + 'required', + 'integer', + ], + + // 分類名1:文字列 / 必須 / 最大10文字 + 'usertype_subject1' => [ + 'required', + 'string', + 'min:1', + 'max:10', + ], + + // 分類名2:文字列 / 必須 / 最大10文字 + 'usertype_subject2' => [ + 'required', + 'string', + 'min:1', + 'max:10', + ], + + // 分類名3:文字列 / 任意 / 最大10文字 + 'usertype_subject3' => [ + 'nullable', + 'string', + 'max:10', + ], + + // 印字名:文字列 / 任意 / 最大20文字 + 'print_name' => [ + 'nullable', + 'string', + 'max:20', + ], + + // 適用料率:文字列 / 任意 / 最大10文字 + 'usertype_money' => [ + 'nullable', + 'string', + 'max:10', + ], + + // 備考:文字列 / 任意 / 最大85文字 + 'usertype_remarks' => [ + 'nullable', + 'string', + 'max:85', + ], + ]; + } + + public function messages(): array + { + return [ + 'sort_order.required' => 'ソートオーダーは必須です。', + 'sort_order.integer' => 'ソートオーダーは数値で入力してください。', + + 'usertype_subject1.required' => '分類名1は必須です。', + 'usertype_subject1.max' => '分類名1は10文字以内で入力してください。', + + 'usertype_subject2.required' => '分類名2は必須です。', + 'usertype_subject2.max' => '分類名2は10文字以内で入力してください。', + + 'usertype_subject3.max' => '分類名3は10文字以内で入力してください。', + + 'print_name.max' => '印字名は20文字以内で入力してください。', + + 'usertype_money.max' => '適用料率は10文字以内で入力してください。', + + 'usertype_remarks.max' => '備考は85文字以内で入力してください。', + ]; + } +} diff --git a/app/Models/Park.php b/app/Models/Park.php index 2e2507e..f17c0a3 100644 --- a/app/Models/Park.php +++ b/app/Models/Park.php @@ -28,45 +28,55 @@ class Park extends Model 'alert_flag', // 残警告チェックフラグ 'print_number', // 印字数 'keep_alive', // 最新キープアライブ - 'renew_start_date', // 更新期間開始日 - 'renew_start_time', // 更新期間開始時 - 'renew_end_date', // 更新期間終了日 - 'renew_end_time', // 更新期間終了時 - 'parking_start_period', // 駐輪開始期間 - 'reminder_type', // リマインダー種別 - 'reminder_time', // リマインダー時間 - 'immediate_use_after_contract', // 契約後即利用許可 - 'display_gender', // 項目表示設定:性別 - 'display_birthday', // 項目表示設定:生年月日 - 'display_security_registration_number', // 項目表示設定:防犯登録番号 - 'distance_between_two_points', // 二点間距離 - 'latitude', // 駐車場座標(緯度) - 'longitude', // 駐車場座標(経度) - 'phone_number', // 電話番号 - 'contract_type_regular', // 駐輪場契約形態(定期) - 'contract_type_temporary', // 駐輪場契約形態(一時利用) - 'vehicle_type_limit', // 車種制限 - 'procedure_method', // 手続方法 - 'payment_method', // 支払方法 - 'usage_time_limit_flag', // 利用可能時間制限フラグ - 'usage_time_start', // 利用可能時間(開始) - 'usage_time_end', // 利用可能時間(終了) - 'resident_manager_flag', // 常駐管理人フラグ - 'resident_time_start', // 常駐時間(開始) - 'resident_time_end', // 常駐時間(終了) - 'roof_flag', // 屋根フラグ - 'seal_issuing_machine_flag', // シール発行機フラグ - 'usage_method', // 駐輪場利用方法 - 'periodic_update_period', // 定期更新期間 - 'waiting_reservation', // 空き待ち予約 - 'special_notes', // 特記事項 - 'student_id_confirmation_type', // 学生証確認種別 - 'reduction_guide_display_flag', // 減免案内表示フラグ - 'reduction_target_age', // 減免対象年齢 - 'reduction_guide_display_start_month', // 減免案内表示開始月数 - 'cross_year', // 年跨ぎ - 'reverse_use_general', // 逆利用一般 - 'reverse_use_student' // 逆利用学生 + + 'update_grace_period_start_date', // 更新期間開始日 + 'update_grace_period_start_time', // 更新期間開始時 + 'update_grace_period_end_date', // 更新期間終了日 + 'update_grace_period_end_time', // 更新期間終了時 + 'parking_start_grace_period', // 駐輪開始猶予期間 + + 'reminder_type', // リマインダー種別 + 'reminder_time', // リマインダー時間 + 'immediate_use_permit', // 契約後即利用許可 + 'gender_display_flag', // 項目表示設定:性別 + 'bd_display_flag', // 項目表示設定:生年月日 + 'securityreg_display_flag', // 項目表示設定:防犯登録番号 + 'distance_twopoints', // 二点間距離 + + 'park_latitude', // 駐車場座標(緯度) + 'park_longitude', // 駐車場座標(経度) + 'park_tel', // 電話番号 + 'park_fixed_contract', // 駐輪場契約形態(定期) + 'park_temporary_contract', // 駐輪場契約形態(一時利用) + 'park_restriction', // 車種制限 + 'park_procedure', // 手続方法 + 'park_payment', // 支払方法 + + 'park_available_time_flag', // 利用可能時間制限フラグ + 'park_available_time_from', // 利用可能時間(開始) + 'park_available_time_to', // 利用可能時間(終了) + 'park_manager_flag', // 常駐管理人フラグ + 'park_manager_resident_from', // 常駐時間(開始) + 'park_manager_resident_to', // 常駐時間(終了) + 'park_roof_flag', // 屋根フラグ + + 'park_issuing_machine_flag', // シール発行機フラグ + 'park_using_method', // 駐輪場利用方法 + 'park_contract_renewal_term', // 定期更新期間 + + 'park_reservation', // 空き待ち予約 + 'park_reference', // 特記事項 + 'student_id_confirmation_type', // 学生証確認種別 + + 'reduction_guide_display_flag', // 減免案内表示フラグ + 'reduction_age', // 減免対象年齢 + + 'reduction_guide_display_start_month', // 減免案内表示開始月数 + 'overyear_flag', // 年跨ぎ + 'inverse_use_flag1', // 逆利用一般 + 'inverse_use_flag2', // 逆利用学生 + 'parking_regulations_flag' // 駐輪規定フラグ + ]; public static function search($inputs) diff --git a/app/Services/ParkService.php b/app/Services/ParkService.php new file mode 100644 index 0000000..4fb6710 --- /dev/null +++ b/app/Services/ParkService.php @@ -0,0 +1,199 @@ +leftJoin('city as c', 'p.city_id', '=', 'c.city_id') + ->select([ + 'p.*', + 'c.city_name', + ]); + + if (!empty($filters['park_name'])) { + $query->where('p.park_name', 'like', '%' . (string) $filters['park_name'] . '%'); + } + + if (!empty($filters['city_id'])) { + $query->where('p.city_id', (int) $filters['city_id']); + } + + $sort = (string) ($filters['sort'] ?? ''); + $sortType = (string) ($filters['sort_type'] ?? 'asc'); + + if ($sort === '') { + $sort = 'p.park_id'; + } + + $allowedSorts = [ + 'p.park_id', + 'p.park_name', + 'p.city_id', + 'p.updated_at', + 'c.city_name', + ]; + + if (!in_array($sort, $allowedSorts, true)) { + $sort = 'p.park_id'; + } + + if (!in_array($sortType, ['asc', 'desc'], true)) { + $sortType = 'asc'; + } + + $query->orderBy($sort, $sortType); + + return $query->paginate($perPage)->appends([ + 'park_name' => $filters['park_name'] ?? null, + 'city_id' => $filters['city_id'] ?? null, + 'sort' => $sort, + 'sort_type' => $sortType, + ]); + } + + public function findOrFail(int $parkId): Park + { + $park = Park::find($parkId); + + if (!$park) { + throw new ModelNotFoundException(); + } + + return $park; + } + + public function create(array $payload, int $operatorId): Park + { + return DB::transaction(function () use ($payload, $operatorId) { + $park = new Park(); + $park->fill($payload); + $park->operator_id = $operatorId; + $park->save(); + + return $park; + }); + } + + public function update(Park $park, array $payload, int $operatorId): Park + { + return DB::transaction(function () use ($park, $payload, $operatorId) { + $park->fill($payload); + $park->operator_id = $operatorId; + $park->save(); + + return $park; + }); + } + + public function deleteByIds(array $ids): bool + { + return (bool) Park::destroy($ids); + } + + public function exportRows(): Collection + { + return DB::table('park as p') + ->select([ + 'p.park_id', + 'p.city_id', + 'p.park_name', + 'p.park_ruby', + 'p.park_syllabary', + 'p.park_adrs', + 'p.park_close_flag', + 'p.park_day', + 'p.alert_flag', + 'p.print_number', + 'p.keep_alive', + 'p.operator_id', + 'p.update_grace_period_start_date', + 'p.update_grace_period_start_time', + 'p.update_grace_period_end_date', + 'p.update_grace_period_end_time', + 'p.parking_start_grace_period', + 'p.reminder_type', + 'p.reminder_time', + 'p.immediate_use_permit', + 'p.gender_display_flag', + 'p.bd_display_flag', + 'p.securityreg_display_flag', + 'p.distance_twopoints', + 'p.park_latitude', + 'p.park_longitude', + 'p.park_tel', + 'p.park_fixed_contract', + 'p.park_temporary_contract', + 'p.park_restriction', + 'p.park_procedure', + 'p.park_payment', + 'p.park_available_time_flag', + 'p.park_available_time_from', + 'p.park_available_time_to', + 'p.park_manager_flag', + 'p.park_manager_resident_from', + 'p.park_manager_resident_to', + 'p.park_roof_flag', + 'p.park_issuing_machine_flag', + 'p.park_using_method', + 'p.park_contract_renewal_term', + 'p.park_reservation', + 'p.park_reference', + 'p.student_id_confirm_type', + 'p.reduction_guide_display_flag', + 'p.reduction_age', + 'p.reduction_guide_display_start_month', + 'p.overyear_flag', + ]) + ->orderBy('p.park_id', 'asc') + ->get(); + } + + public function importCsv(UploadedFile $file): void + { + $data = \App\Utils::csvToArray($file); + + DB::transaction(function () use ($data) { + Park::query()->delete(); + + $expectedCols = 13; + + foreach ($data as $index => $items) { + if (count($items) !== $expectedCols) { + throw new \RuntimeException('列数が一致しません。line=' . ($index + 2)); + } + + $row = new Park(); + $row->park_id = $items[0]; + $row->city_id = $items[1]; + $row->park_name = $items[3]; + $row->park_ruby = $items[4]; + $row->park_syllabary = $items[5]; + $row->park_adrs = $items[6]; + $row->park_close_flag = $items[7]; + $row->park_day = $items[9]; + $row->alert_flag = $items[10]; + $row->print_number = $items[11]; + $row->keep_alive = $items[12]; + + $row->save(); + } + }); + } + + public function checkDuplicateByName(string $parkName): ?Park + { + return Park::where('park_name', $parkName)->first(); + } +} diff --git a/app/Services/ReserveService.php b/app/Services/ReserveService.php new file mode 100644 index 0000000..5ecad94 --- /dev/null +++ b/app/Services/ReserveService.php @@ -0,0 +1,510 @@ +normalizeSort((string) $payload['sort'], $this->sortableKeys()); + $sortType = $this->normalizeSortType((string) $payload['sortType']); + + $q = $this->baseQuery(); + + $this->applyFilters($q, $payload); + $this->applySort($q, $sort, $sortType); + + $parkOptions = Park::query() + ->orderBy('park_id', 'asc') + ->pluck('park_name', 'park_id') + ->toArray(); + + $list = $q->paginate(50); + + $this->attachPriceNames($list); + + return [ + 'list' => $list, + 'sort' => $sort, + 'sort_type' => $sortType, + + 'user_id' => (string) $payload['userId'], + 'park_id' => $payload['parkId'], + 'reserve_date_from' => $payload['fromDt'], + 'reserve_date_to' => $payload['toDt'], + 'keyword' => (string) $payload['keyword'], + 'valid_flag' => $payload['validFlag'], + + 'parkOptions' => $parkOptions, + ]; + } + + /** + * 新規画面用のプルダウンなど。 + */ + public function getFormOptions(): array + { + $userTypes = DB::table('usertype') + ->orderBy('user_categoryid', 'asc') + ->get([ + 'user_categoryid', + 'usertype_subject1', + 'usertype_subject2', + 'usertype_subject3', + ]) + ->map(function (object $row): object { + $labels = array_filter([ + $row->usertype_subject1, + $row->usertype_subject2, + $row->usertype_subject3, + ], static fn ($v): bool => $v !== null && $v !== ''); + + $row->display_name = $labels ? implode('/', $labels) : ''; + return $row; + }); + + $parks = Park::query() + ->orderBy('park_id', 'asc') + ->get(['park_id', 'park_name']); + + $priceOptions = $this->getUnifiedPriceOptions(); + + return [ + 'userTypes' => $userTypes, + 'parks' => $parks, + 'priceOptions' => $priceOptions, + ]; + } + + /** + * 新規画面用:プルダウン等 + */ + public function getCreateForm(): array + { + $userOptions = DB::table('user') + ->orderBy('user_id', 'asc') + ->limit(5000) + ->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id') + ->toArray(); + + $parkOptions = DB::table('park') + ->orderBy('park_id', 'asc') + ->pluck('park_name', 'park_id') + ->toArray(); + + $userTypeOptions = DB::table('usertype') + ->orderBy('user_categoryid') + ->select([ + 'user_categoryid', + DB::raw(" + COALESCE( + NULLIF(TRIM(CONCAT_WS('/', + NULLIF(TRIM(usertype_subject1), ''), + NULLIF(TRIM(usertype_subject2), ''), + NULLIF(TRIM(usertype_subject3), '') + )), ''), + print_name + ) AS label + ") + ]) + ->pluck('label', 'user_categoryid') + ->toArray(); + + $priceOptions = Schema::hasTable('price') + ? DB::table('price') + ->orderBy('price_parkplaceid') + ->pluck('prine_name', 'price_parkplaceid') + ->toArray() + : []; + + $psectionOptions = Schema::hasTable('psection') + ? DB::table('psection') + ->orderBy('psection_id') + ->pluck( + Schema::hasColumn('psection', 'psection_subject') ? 'psection_subject' : 'psection_id', + 'psection_id' + ) + ->toArray() + : []; + + $ptypeOptions = Schema::hasTable('ptype') + ? DB::table('ptype') + ->orderBy('ptype_id') + ->pluck( + Schema::hasColumn('ptype', 'ptype_subject') ? 'ptype_subject' : 'ptype_id', + 'ptype_id' + ) + ->toArray() + : []; + + return [ + 'userOptions' => $userOptions, + 'parkOptions' => $parkOptions, + 'userTypeOptions' => $userTypeOptions, + 'priceOptions' => $priceOptions, + 'psectionOptions' => $psectionOptions, + 'ptypeOptions' => $ptypeOptions, + ]; + } + + + /** + * 編集画面用:対象レコード+プルダウン + */ + public function getEditForm(int $reserveId): array + { + $row = DB::table('reserve')->where('reserve_id', $reserveId)->first(); + if ($row === null) { + abort(404); + } + + $userOptions = DB::table('user') + ->orderBy('user_id', 'asc') + ->limit(5000) + ->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id') + ->toArray(); + + $parkOptions = DB::table('park') + ->orderBy('park_id', 'asc') + ->pluck('park_name', 'park_id') + ->toArray(); + + $userTypeOptions = DB::table('usertype') + ->orderBy('user_categoryid') + ->select([ + 'user_categoryid', + DB::raw(" + COALESCE( + NULLIF(TRIM(CONCAT_WS('/', + NULLIF(TRIM(usertype_subject1), ''), + NULLIF(TRIM(usertype_subject2), ''), + NULLIF(TRIM(usertype_subject3), '') + )), ''), + print_name + ) AS label + ") + ]) + ->pluck('label', 'user_categoryid') + ->toArray(); + + $priceOptions = Schema::hasTable('price') + ? DB::table('price') + ->orderBy('price_parkplaceid') + ->pluck('prine_name', 'price_parkplaceid') + ->toArray() + : []; + + $psectionOptions = Schema::hasTable('psection') + ? DB::table('psection') + ->orderBy('psection_id') + ->pluck( + Schema::hasColumn('psection', 'psection_subject') ? 'psection_subject' : 'psection_id', + 'psection_id' + ) + ->toArray() + : []; + $ptypeOptions = Schema::hasTable('ptype') + ? DB::table('ptype') + ->orderBy('ptype_id') + ->pluck( + Schema::hasColumn('ptype', 'ptype_subject') ? 'ptype_subject' : 'ptype_id', + 'ptype_id' + ) + ->toArray() + : []; + + return [ + 'row' => $row, + 'userOptions' => $userOptions, + 'parkOptions' => $parkOptions, + 'userTypeOptions' => $userTypeOptions, + 'priceOptions' => $priceOptions, + 'psectionOptions' => $psectionOptions, + 'ptypeOptions' => $ptypeOptions, + + ]; + } + + /** + * 更新 + */ + public function update(int $reserveId, array $payload): void + { + $exists = DB::table('reserve')->where('reserve_id', $reserveId)->exists(); + if (!$exists) { + abort(404); + } + + $data = [ + 'user_categoryid' => $payload['userCategoryId'], + 'contract_id' => $payload['contractId'], + 'contract_created_at' => $payload['contractCreatedAt'], + + 'user_id' => $payload['userId'], + 'park_id' => $payload['parkId'], + 'price_parkplaceid' => $payload['priceParkplaceId'], + 'psection_id' => $payload['psectionId'], + 'ptype_id' => $payload['ptypeId'], + 'reserve_date' => $payload['reserveDate'], + 'reserve_start' => $payload['reserveStart'], + 'reserve_end' => $payload['reserveEnd'], + 'valid_flag' => $payload['validFlag'], + 'reserve_reduction' => $payload['reserveReduction'], + 'reserve_auto_remind' => $payload['reserveAutoRemind'], + 'reserve_manual_remind' => $payload['reserveManualRemind'], + '800m_flag' => $payload['flag800m'], + 'reserve_cancelday' => $payload['reserveCancelday'], + 'reserve_manual' => $payload['reserveManual'], + 'reserve_notice' => $payload['reserveNotice'], + 'reserve_type' => $payload['reserveType'], + 'sent_date' => $payload['sentDate'], + 'reserve_order' => $payload['reserveOrder'], + + 'ope_id' => $payload['opeId'], + 'updated_at' => now(), + ]; + + DB::table('reserve') + ->where('reserve_id', $reserveId) + ->update($data); + } + + /** + * 複数削除 + * + * @return int 削除件数 + */ + public function deleteMany(array $ids): int + { + if ($ids === []) { + return 0; + } + + return (int) DB::table('reserve') + ->whereIn('reserve_id', $ids) + ->delete(); + } + + private function baseQuery(): Builder + { + return DB::table('reserve as r') + ->leftJoin('user as u', 'u.user_id', '=', 'r.user_id') + ->leftJoin('park as p', 'p.park_id', '=', 'r.park_id') + ->leftJoin('psection as ps', 'ps.psection_id', '=', 'r.psection_id') + ->leftJoin('ptype as pt', 'pt.ptype_id', '=', 'r.ptype_id') + ->leftJoin('usertype as t', 't.user_categoryid', '=', 'r.user_categoryid') + ->select([ + 'r.reserve_id', + 'r.contract_id', + 'r.contract_created_at', + 'r.user_categoryid', + 'r.user_id', + 'r.park_id', + 'r.price_parkplaceid', + 'r.psection_id', + 'r.ptype_id', + 'r.reserve_date', + + 'r.reserve_reduction', + 'r.reserve_auto_remind', + 'r.reserve_manual_remind', + DB::raw('r.`800m_flag` as flag_800m'), + 'r.reserve_cancelday', + 'r.valid_flag', + 'r.ope_id', + 'r.reserve_manual', + 'r.reserve_notice', + 'r.sent_date', + 'r.reserve_order', + 'r.reserve_type', + + DB::raw('u.user_name as user_name'), + DB::raw('p.park_name as park_name'), + DB::raw('ps.psection_subject as psection_subject'), + DB::raw('pt.ptype_subject as ptype_subject'), + + DB::raw('t.usertype_subject1 as usertype_subject1'), + DB::raw('t.usertype_subject2 as usertype_subject2'), + DB::raw('t.usertype_subject3 as usertype_subject3'), + ]); + } + + + + private function applyFilters(Builder $q, array $payload): void + { + if ($payload['userId'] !== '') { + $q->where('r.user_id', 'like', '%' . $payload['userId'] . '%'); + } + + if ($payload['parkId'] !== null) { + $q->where('r.park_id', '=', $payload['parkId']); + } + + if (!empty($payload['fromDt'])) { + $q->whereDate('r.reserve_date', '>=', $payload['fromDt']); + } + + if (!empty($payload['toDt'])) { + $q->whereDate('r.reserve_date', '<=', $payload['toDt']); + } + + if ($payload['keyword'] !== '') { + $keyword = $payload['keyword']; + + $q->where(function (Builder $w) use ($keyword): void { + $w->where('u.user_name', 'like', '%' . $keyword . '%') + ->orWhere('u.user_phonetic', 'like', '%' . $keyword . '%'); + }); + } + + if (in_array($payload['validFlag'], ['0', '1'], true)) { + $q->where('r.valid_flag', '=', (int) $payload['validFlag']); + } + } + + private function applySort(Builder $q, string $sort, string $sortType): void + { + $sortMap = [ + 'reserve_id' => DB::raw('r.reserve_id'), + 'contract_id' => DB::raw('r.contract_id'), + 'contract_created_at' => DB::raw('r.contract_created_at'), // + 'user_categoryid' => DB::raw('r.user_categoryid'), + 'user_id' => DB::raw('r.user_id'), + 'reserve_date' => DB::raw('r.reserve_date'), + + 'park_name' => DB::raw('p.park_name'), + 'price_parkplaceid' => DB::raw('r.price_parkplaceid'), + + 'psection_subject' => DB::raw('ps.psection_subject'), + 'ptype_subject' => DB::raw('pt.ptype_subject'), + + 'reserve_reduction' => DB::raw('r.reserve_reduction'), + 'reserve_auto_remind' => DB::raw('r.reserve_auto_remind'), + 'reserve_manual_remind' => DB::raw('r.reserve_manual_remind'), + + 'flag_800m' => DB::raw('r.`800m_flag`'), // + 'reserve_cancelday' => DB::raw('r.reserve_cancelday'), + 'valid_flag' => DB::raw('r.valid_flag'), + + 'sent_date' => DB::raw('r.sent_date'), + 'reserve_manual' => DB::raw('r.reserve_manual'), + 'reserve_notice' => DB::raw('r.reserve_notice'), + 'reserve_order' => DB::raw('r.reserve_order'), + + 'reserve_type' => DB::raw('r.reserve_type'), // + ]; + + if (!isset($sortMap[$sort])) { + return; + } + + $q->orderBy($sortMap[$sort], $sortType); + } + + + private function sortableKeys(): array + { + return [ + 'reserve_id', + 'contract_id', + 'contract_created_at', + 'user_categoryid', + 'user_id', + 'reserve_date', + + 'park_name', + 'price_parkplaceid', + + 'psection_subject', + 'ptype_subject', + + 'reserve_reduction', + 'reserve_auto_remind', + 'reserve_manual_remind', + + 'flag_800m', + 'reserve_cancelday', + 'valid_flag', + + 'sent_date', + 'reserve_manual', + 'reserve_notice', + 'reserve_order', + + 'reserve_type', + ]; + } + + + private function normalizeSort(string $sort, array $sortable): string + { + return in_array($sort, $sortable, true) ? $sort : 'reserve_id'; + } + + private function normalizeSortType(string $sortType): string + { + $sortType = strtolower($sortType); + return $sortType === 'desc' ? 'desc' : 'asc'; + } + + private function attachPriceNames(LengthAwarePaginator $list): void + { + $placeIds = $list->getCollection() + ->pluck('price_parkplaceid') + ->filter() + ->unique() + ->values() + ->all(); + + if ($placeIds === []) { + return; + } + + $priceNames = Price::query() + ->whereIn('price_parkplaceid', $placeIds) + ->pluck('prine_name', 'price_parkplaceid') + ->toArray(); + + $list->setCollection( + $list->getCollection()->map(function (object $row) use ($priceNames): object { + $id = $row->price_parkplaceid ?? null; + + $row->display_prine_name = ($id !== null && array_key_exists($id, $priceNames)) + ? $priceNames[$id] + : null; + + return $row; + }) + ); + } + + + private function getUnifiedPriceOptions() + { + return Price::query() + ->select('price_parkplaceid', 'prine_name') + ->get() + ->sortBy('price_parkplaceid', SORT_NATURAL) + ->unique('price_parkplaceid') + ->values(); + } + +} diff --git a/app/Services/UsertypeService.php b/app/Services/UsertypeService.php new file mode 100644 index 0000000..632f1a1 --- /dev/null +++ b/app/Services/UsertypeService.php @@ -0,0 +1,70 @@ +where('sort_order', $sortOrder); + } + + if ($subject1 !== null && $subject1 !== '') { + $query->where('usertype_subject1', 'like', '%' . $subject1 . '%'); + } + + if ($subject2 !== null && $subject2 !== '') { + $query->where('usertype_subject2', 'like', '%' . $subject2 . '%'); + } + + if ($subject3 !== null && $subject3 !== '') { + $query->where('usertype_subject3', 'like', '%' . $subject3 . '%'); + } + + $query->orderBy($sort, $sortType); + + return $query->paginate(Utils::item_per_page); + } + + public function create(array $validated): Usertype + { + return Usertype::create($this->payload($validated)); + } + + public function update(Usertype $usertype, array $validated): Usertype + { + $usertype->fill($this->payload($validated)); + $usertype->save(); + + return $usertype; + } + + private function payload(array $validated): array + { + return [ + 'sort_order' => $validated['sort_order'], + 'usertype_subject1' => $validated['usertype_subject1'], + 'usertype_subject2' => $validated['usertype_subject2'], + 'usertype_subject3' => $validated['usertype_subject3'] ?? null, + 'print_name' => $validated['print_name'] ?? null, + 'usertype_money' => $validated['usertype_money'] ?? null, + 'usertype_remarks' => $validated['usertype_remarks'] ?? null, + ]; + } +} diff --git a/resources/views/admin/opes/list.blade.php b/resources/views/admin/opes/list.blade.php index 7a43886..6522cb9 100644 --- a/resources/views/admin/opes/list.blade.php +++ b/resources/views/admin/opes/list.blade.php @@ -11,7 +11,6 @@
-
- | + + | ++ 駐輪場ID + | + ++ 市区 + | + ++ 駐輪場名 + | + ++ 駐輪場ふりがな + | + ++ 駐輪場五十音 + | + +住所 | +閉設状態 | +閉設日 | +価格メモ | +残警告チェックフラグ | +印字数 | +最新キープアライブ | + +更新期間開始日 | +更新期間開始時 | +更新期間終了日 | +更新期間終了時 | +駐輪開始期間 | + +リマインダー種別 | +リマインダー時間 | +契約後即利用許可 | +項目表示設定:性別 | +項目表示設定:生年月日 | +項目表示設定:防犯登録番号 | + +二点間距離 | +駐車場座標(緯度) | +駐車場座標(経度) | +電話番号 | + +駐輪場契約形態(定期) | +駐輪場契約形態(一時利用) | +車種制限 | +手続方法 | +支払方法 | +利用時間制限フラグ | +利用可能時間(開始) | +利用可能時間(終了) | + +常駐管理人フラグ | + +常駐時間(開始) | +常駐時間(終了) | +屋根フラグ | +シール機フラグ | +駐輪場利用方法 | +定期更新期間 | +空き待ち予約 | +特記事項 | + +学生証確認種別 | +減免案内表示フラグ | +減免対象年齢 | +減免案内表示開始月数 | +年跨ぎ | +
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
+
+
+
+ 編集
+
+
+ |
+
+ {{ $park->park_id }} | +{{ $park->city_name ?? '' }} | +{{ $park->park_name ?? '' }} | +{{ $park->park_ruby ?? '' }} | +{{ $park->park_syllabary ?? '' }} | +{{ $park->park_adrs ?? '' }} | +{{ ($park->park_close_flag ?? 0) == 1 ? '閉設' : '営業中' }} | +{{ $park->park_day ?? '' }} | +{{ $park->price_memo ?? '' }} | + +{{ $park->alert_flag ?? '' }} | +{{ $park->print_number ?? '' }} | +{{ $park->keep_alive ?? '' }} | +{{ $park->update_grace_period_start_date ?? '' }} | +{{ substr($park->update_grace_period_start_time ?? '', 0, 5) }} | +{{ $park->update_grace_period_end_date ?? '' }} | +{{ substr($park->update_grace_period_end_time ?? '', 0, 5) }} | + +{{ $park->parking_start_grace_period ?? '' }} | + ++ @switch($park->reminder_type ?? '') + @case(0) 毎日 @break + @case(1) 1日おき @break + @case(2) 2日おき @break + @default 未設定 + @endswitch + | + +{{ $park->reminder_time ?? '' }} | +{{ ($park->immediate_use_permit ?? 0) ? '許可する' : '許可しない' }} | +{{ ($park->gender_display_flag ?? 0) ? '表示する' : '表示しない' }} | +{{ ($park->bd_display_flag ?? 0) ? '表示する' : '表示しない' }} | +{{ ($park->securityreg_display_flag ?? 0) ? '表示する' : '表示しない' }} | +{{ $park->distance_twopoints ?? '' }} | +{{ $park->park_latitude ?? '' }} | +{{ $park->park_longitude ?? '' }} | +{{ $park->park_tel ?? '' }} | + +{{ ($park->park_fixed_contract ?? 0) ? '定期利用可' : '定期利用不可' }} | +{{ ($park->park_temporary_contract ?? 0) ? '一時利用可' : '一時利用不可' }} | +{{ $park->park_restriction ?? '' }} | +{{ $park->park_procedure ?? '' }} | +{{ $park->park_payment ?? '' }} | +{{ ($park->park_available_time_flag ?? 0) ? '制限あり' : '制限なし' }} | +{{ substr($park->park_available_time_from ?? '', 0, 5) }} | +{{ substr($park->park_available_time_to ?? '', 0, 5) }} | +{{ ($park->park_manager_flag ?? 0) ? '常駐' : '非常駐' }} | +{{ substr($park->park_manager_resident_from ?? '', 0, 5) }} | +{{ substr($park->park_manager_resident_to ?? '', 0, 5) }} | +{{ ($park->park_roof_flag ?? 0) ? '屋根あり' : '屋根なし' }} | +{{ ($park->park_issuing_machine_flag ?? 0) ? 'あり' : 'なし' }} | +{{ $park->park_using_method ?? '' }} | +{{ $park->park_contract_renewal_term ?? '' }} | +{{ $park->park_reservation ?? '' }} | +{{ $park->park_reference ?? '' }} | + ++ @switch($park->student_id_confirm_type ?? '') + @case('none') 確認しない @break + @case('year') 年1回 @break + @case('reissue') 再発行時 @break + @default 未設定 + @endswitch + | + +{{ ($park->reduction_guide_display_flag ?? 0) ? '表示する' : '表示しない' }} | +{{ $park->reduction_age ?? '' }} | +{{ $park->reduction_guide_display_start_month ?? '' }} | +{{ ($park->overyear_flag ?? 0) ? 'あり' : 'なし' }} | +
| - | 駐輪場ID | -市区 | -駐輪場名 | -駐輪場ふりがな | -駐輪場五十音 | -住所 | -閉設フラグ | -閉設日 | -残警告チェックフラグ | -印字数 | -最新キープアライブ | -更新オペレータID | -更新期間開始日 | -更新期間開始時 | -更新期間終了日 | -更新期間終了時 | -駐輪開始期間 | -リマインダー種別 | -リマインダー時間 | -契約後即利用許可 | -項目表示設定:性別 | -項目表示設定:生年月日 | -項目表示設定:防犯登録番号 | -二点間距離 | -駐車場座標(緯度) | -駐車場座標(経度) | -電話番号 | -駐輪場契約形態(定期) | -駐輪場契約形態(一時利用) | -車種制限 | -手続方法 | -支払方法 | -利用可能時間制限フラグ | -利用可能時間(開始) | -利用可能時間(終了) | -常駐管理人フラグ | -常駐時間(開始) | -常駐時間(終了) | -屋根フラグ | -シール発行機フラグ | -駐輪場利用方法 | -定期更新期間 | -空き待ち予約 | -特記事項 | -学生証確認種別 | -減免案内表示フラグ | -減免対象年齢 | -減免案内表示開始月数 | -年跨ぎ | -
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| - - 編集 - | -{{ $park->park_id }} | -{{ $park->city_name }} | -{{ $park->park_name }} | -{{ $park->park_ruby }} | -{{ $park->park_syllabary }} | -{{ $park->park_adrs }} | -- - @if($park->park_close_flag == 1) - 閉設 - @else - 営業中 - @endif - - | -{{ $park->park_day }} | -{{ $park->alert_flag }} | -{{ $park->print_number }} | -{{ $park->keep_alive }} | -{{ $park->operator_id ?? '' }} | - -{{ $park->update_grace_period_start_date }} | -{{ $park->update_grace_period_start_time }} | -{{ $park->update_grace_period_end_date }} | -{{ $park->update_grace_period_end_time }} | -{{ $park->parking_start_grace_period }} | -- @if($park->reminder_type === 0) - 毎日 - @elseif($park->reminder_type === 1) - 1日おき - @elseif($park->reminder_type === 2) - 2日おき - @else - 未設定 - @endif - | -{{ $park->reminder_time }} | -{{ $park->immediate_use_permit == 1 ? '許可する' : '許可しない' }} | -{{ $park->gender_display_flag == 1 ? '表示する' : '表示しない' }} | -{{ $park->bd_display_flag == 1 ? '表示する' : '表示しない' }} | -{{ $park->securityreg_display_flag == 1 ? '表示する' : '表示しない' }} | -{{ $park->distance_twopoints }} | -{{ $park->park_latitude }} | -{{ $park->park_longitude }} | -{{ $park->park_tel }} | -{{ $park->park_fixed_contract == 1 ? '定期利用可' : '定期利用不可' }} | -{{ $park->park_temporary_contract == 1 ? '一時利用可' : '一時利用不可' }} | -{{ $park->park_restriction }} | -{{ $park->park_procedure }} | -{{ $park->park_payment }} | -{{ $park->park_available_time_flag }} | -{{ $park->park_available_time_from }} | -{{ $park->park_available_time_to }} | -{{ $park->park_manager_flag }} | -{{ $park->park_manager_resident_from }} | -{{ $park->park_manager_resident_to }} | -{{ $park->park_roof_flag }} | -{{ $park->park_issuing_machine_flag }} | -{{ $park->park_using_method }} | -{{ $park->park_contract_renewal_term }} | -{{ $park->park_reservation }} | -{{ $park->park_reference }} | -{{ $park->student_id_confirm_type }} | -{{ $park->reduction_guide_display_flag }} | -{{ $park->reduction_age }} | -{{ $park->reduction_guide_display_start_month }} | -{{ $park->overyear_flag }} | -
| 予約ID | -定期契約ID | -利用者名 | -駐輪場 | -予約日時 | -
|---|---|---|---|---|
| {{ $r->reserve_id }} | -{{ $r->contract_id ?? '' }} | -{{ $r->user_name ?? '' }} | -{{ $r->park_name ?? '' }} | - {{-- ※ 実テーブル列名に合わせて reserve_date を使用 --}} -{{ $r->reserve_date ?? '' }} | -
- 削除対象ID: - @foreach($collectedIds as $id) - {{ $id }} - @endforeach -
- @else -削除対象が取得できませんでした。
- @endif -+ ※この画面のデータは通常変更する必要はありません。 +
+| + + | + ++ 定期予約ID + | + ++ 定期契約ID + | + ++ 定期契約日時 + | + ++ 利用者分類ID + | + ++ 利用者ID + | + ++ 予約日時 + | + ++ 駐輪場ID + | + ++ 駐輪場所ID + | + ++ 車種区分ID + | + ++ 駐輪分類ID + | + ++ 減免措置 + | + ++ 自動リマインド日 + | + ++ 手動リマインド日 + | + ++ 800M以内フラグ + | + ++ 解約日 + | + ++ 有効フラグ + | + ++ メール送信日時 + | + ++ 手動通知 + | + ++ 手動通知方法 + | + ++ 空き待ち順 + | + + {{-- ★追加:予約区分 --}} ++ 予約区分 + | +
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
+
+
+
+ 編集
+
+
+ |
+
+ {{ $item->reserve_id }} | {{-- 定期予約ID --}} +{{ $item->contract_id ?? '' }} | {{-- 定期契約ID --}} +{{ $item->contract_created_at ?? '' }} | {{-- 定期契約日時 --}} + +{{ $item->user_categoryid ?? '' }} | {{-- 利用者分類ID --}} +{{ trim(($item->user_id ?? '') . ' ' . ($item->user_name ?? '')) }} | {{-- 利用者ID --}} +{{ $item->reserve_date ?? '' }} | {{-- 予約日時 --}} + +{{ $item->park_name ?? '' }} | {{-- 駐輪場ID --}} +{{ $item->display_prine_name ?? '' }} | {{-- 駐輪場所ID --}} +{{ $item->psection_subject ?? '' }} | {{-- 車種区分ID --}} +{{ $item->ptype_subject ?? '' }} | {{-- 駐輪分類ID --}} + ++ @if((string)($item->reserve_reduction ?? '') === '1') + あり + @elseif((string)($item->reserve_reduction ?? '') === '0') + なし + @else + {{ $item->reserve_reduction ?? '' }} + @endif + | {{-- 減免措置 --}} + +{{ $item->reserve_auto_remind ?? '' }} | {{-- 自動リマインド日 --}} +{{ $item->reserve_manual_remind ?? '' }} | {{-- 手動リマインド日 --}} + ++ @if((string)($item->flag_800m ?? '') === '1') + ○ + @elseif((string)($item->flag_800m ?? '') === '0') + × + @else + {{ $item->flag_800m ?? '' }} + @endif + | {{-- 800M以内フラグ --}} + +{{ $item->reserve_cancelday ?? '' }} | {{-- 解約日 --}} + ++ @if((string)($item->valid_flag ?? '') === '1') + 有効 + @elseif((string)($item->valid_flag ?? '') === '0') + 無効 + @else + {{ $item->valid_flag ?? '' }} + @endif + | {{-- 有効フラグ --}} + +{{ $item->sent_date ?? '' }} | {{-- メール送信日時 --}} + ++ @if((string)($item->reserve_manual ?? '') === '1') + 手動 + @elseif((string)($item->reserve_manual ?? '') === '0') + 自動 + @else + {{ $item->reserve_manual ?? '' }} + @endif + | {{-- 手動通知 --}} + ++ @if((string)($item->reserve_notice ?? '') === 'tel') + 電話 + @elseif((string)($item->reserve_notice ?? '') === 'post') + 郵送 + @else + {{ $item->reserve_notice ?? '' }} + @endif + | {{-- 手動通知方法 --}} + +{{ $item->reserve_order ?? '' }} | {{-- 空き待ち順 --}} + ++ @if((string)($item->reserve_type ?? '') === '1') + 仮予約 + @elseif((string)($item->reserve_type ?? '') === '0') + 通常予約 + @else + {{ $item->reserve_type ?? '' }} + @endif + | {{-- ★予約区分 --}} + +
※この画面では予約情報の検索・一括削除が行えます。
-| - - - | -定期予約ID {!! $renderSortIcon() !!} | -定期契約ID {!! $renderSortIcon() !!} | -定期契約日時 {!! $renderSortIcon() !!} | -利用者分類ID {!! $renderSortIcon() !!} | -利用者ID {!! $renderSortIcon() !!} | -予約日時 {!! $renderSortIcon() !!} | -駐輪場ID {!! $renderSortIcon() !!} | -駐輪場所ID {!! $renderSortIcon() !!} | -車種区分ID {!! $renderSortIcon() !!} | -駐輪分類ID {!! $renderSortIcon() !!} | -減免措置 {!! $renderSortIcon() !!} | -自動リマインド日 {!! $renderSortIcon() !!} | -手動リマインド日 {!! $renderSortIcon() !!} | -800M以内フラグ {!! $renderSortIcon() !!} | -解約日 {!! $renderSortIcon() !!} | -有効フラグ {!! $renderSortIcon() !!} | -メール送信日時 {!! $renderSortIcon() !!} | -手動通知 {!! $renderSortIcon() !!} | -手動通知方法 {!! $renderSortIcon() !!} | -空き待ち順 {!! $renderSortIcon() !!} | -
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
-
-
- 編集
-
- |
-
- {{-- データ列(存在しないカラムは空文字で安全に表示) --}}
- {{ $row->reserve_id }} | {{-- 定期予約ID --}} -{{ $row->contract_id ?? '' }} | {{-- 定期契約ID --}} -{{ $row->contract_created_at ?? '' }} | {{-- 定期契約日時 --}} -- @php - $subjects = array_values(array_filter([ - $row->usertype_subject1 ?? '', - $row->usertype_subject2 ?? '', - $row->usertype_subject3 ?? '', - ], fn($value) => $value !== '')); - @endphp - {{ $subjects ? implode('/', $subjects) : '' }} - | {{-- 利用者分類ID(分類名1/2/3 表示) --}} -{{ trim(($row->user_id ?? '') . ' ' . ($row->user_name ?? '')) }} | {{-- 利用者ID(ID 名字) --}} -{{ $row->reserve_date ?? '' }} | {{-- 予約日時 --}} -{{ trim($row->park_name ?? '') }} | {{-- 駐輪場ID --}} -{{ $row->display_prine_name ?? '' }} | {{-- 駐輪場所ID --}} -{{ $row->psection_subject ?? '' }} | {{-- 車種区分ID:区分名を表示 --}} -{{ $row->ptype_subject ?? '' }} | {{-- 駐輪分類ID:ptype_subject 表示 --}} -{{ $row->reserve_reduction ?? '' }} | {{-- 減免措置 --}} -{{ $row->reserve_auto_remind ?? '' }} | {{-- 自動リマインド日 --}} -{{ $row->reserve_manual_remind ?? '' }} | {{-- 手動リマインド日 --}} -{{ $row->flag_800m ?? '' }} | {{-- 800M以内フラグ --}} -{{ $row->reserve_cancelday ?? '' }} | {{-- 解約日 --}} -- @if((string)$row->valid_flag === '1') - 有効 - @elseif((string)$row->valid_flag === '0') - 無効 - @else - {{ $row->valid_flag ?? '' }} - @endif - | {{-- 有効フラグ --}} -{{ $row->sent_date ?? '' }} | {{-- メール送信日時 --}} -{{ $row->reserve_manual ?? '' }} | {{-- 手動通知 --}} -{{ $row->reserve_notice ?? '' }} | {{-- 手動通知方法 --}} -{{ $row->reserve_order ?? '' }} | {{-- 空き待ち順 --}} -