diff --git a/.env b/.env index 5ebf6e4..1b72b13 100644 --- a/.env +++ b/.env @@ -3,7 +3,6 @@ APP_ENV=local APP_KEY=base64:ejLwJbt2bEXY9emPUmsurG+X1hzkjTxQQvq2/FO14RY= APP_DEBUG=true APP_URL=https://krgm.so-manager-dev.com/ - APP_LOCALE=ja APP_FALLBACK_LOCALE=ja APP_FAKER_LOCALE=ja_JP diff --git a/.gitea/workflows/deploy-preview.yml b/.gitea/workflows/deploy-preview.yml new file mode 100644 index 0000000..ecd1f6f --- /dev/null +++ b/.gitea/workflows/deploy-preview.yml @@ -0,0 +1,20 @@ +name: Deploy preview (main_ou) + +on: + push: + branches: ["main_ou"] + workflow_dispatch: + +concurrency: + group: deploy-main_ou + cancel-in-progress: true + +jobs: + deploy: + runs-on: ["native"] + steps: + - uses: actions/checkout@v4 + - name: Deploy to preview (main_ou) + env: + BRANCH: main_ou + run: /usr/local/bin/deploy_branch_simple.sh \ No newline at end of file diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml deleted file mode 100644 index 976e13c..0000000 --- a/.gitea/workflows/deploy.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Deploy krgm (auto) - -on: - push: - branches: [ "main" ] - workflow_dispatch: - -jobs: - deploy: - runs-on: [ "native" ] - steps: - - uses: actions/checkout@v4 - - name: Deploy to server - run: /usr/local/bin/deploy_krgm.sh \ No newline at end of file diff --git a/app/AppModel.php b/app/AppModel.php new file mode 100644 index 0000000..d13a543 --- /dev/null +++ b/app/AppModel.php @@ -0,0 +1,10 @@ + $request->isMethod('post'), + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + 'page' => $request->get('page', 1), + ]; + + $query = City::query(); + + if ($request->filled('city_name')) { + $query->where('city_name', 'like', '%' . $request->input('city_name') . '%'); + } + + if (!empty($inputs['sort'])) { + $query->orderBy($inputs['sort'], $inputs['sort_type'] ?? 'asc'); + } + + $inputs['list'] = $query->paginate(20); + + if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) { + return redirect()->route('city'); + } + + return view('admin.CityMaster.list', $inputs); + } + + public function add(Request $request) + { + $inputs = [ + 'city_name' => '', + 'print_layout' => '', + 'city_user' => '', + 'city_remarks' => '', + ]; + + if ($request->isMethod('POST')) { + $rules = [ + 'city_name' => 'required|string|max:255', + ]; + $validator = Validator::make($request->all(), $rules); + + $inputs = array_merge($inputs, $request->all()); + + if (!$validator->fails()) { + $maxId = DB::table('city')->max('city_id'); + $newCityId = $maxId ? $maxId + 1 : 1; + + $city = new City(); + $city->city_id = $newCityId; + $city->fill($request->only([ + 'city_name', + 'print_layout', + 'city_user', + 'city_remarks', + ])); + + if ($city->save()) { + $request->session()->flash('success', __('登録に成功しました')); + return redirect()->route('city'); + } else { + $request->session()->flash('error', __('登録に失敗しました')); + } + } else { + $inputs['errorMsg'] = $validator->errors()->all(); + } + } + + return view('admin.CityMaster.add', $inputs); + } + + public function edit(Request $request, $pk, $view = '') + { + $city = City::find($pk); + if (!$city) { + abort(404); + } + + if ($request->isMethod('POST')) { + $rules = [ + 'city_name' => 'required|string|max:255', + ]; + $validator = Validator::make($request->all(), $rules); + + if (!$validator->fails()) { + $city->fill($request->only([ + 'city_name', + 'print_layout', + 'city_user', + 'city_remarks', + ])); + + if ($city->save()) { + $request->session()->flash('success', __('更新に成功しました')); + return redirect()->route('city'); + } else { + $request->session()->flash('error', __('更新に失敗しました')); + } + } else { + return view('admin.CityMaster.edit', [ + 'city' => $city, + 'errorMsg' => $validator->errors()->all(), + ]); + } + } + + return view($view ?: 'admin.CityMaster.edit', [ + 'city' => $city, + ]); + } + + public function info(Request $request, $pk) + { + return $this->edit($request, $pk, 'CityMaster.info'); + } + + public function delete(Request $request) + { + $arr_pk = $request->get('pk'); + if ($arr_pk && City::destroy($arr_pk)) { + return redirect()->route('city')->with('success', __("削除が完了しました。")); + } else { + return redirect()->route('city')->with('error', __('削除に失敗しました。')); + } + } +} diff --git a/app/Http/Controllers/Admin/ContractorController.php b/app/Http/Controllers/Admin/ContractorController.php new file mode 100644 index 0000000..eaf43bf --- /dev/null +++ b/app/Http/Controllers/Admin/ContractorController.php @@ -0,0 +1,115 @@ +select([ + 'rc.contract_id', + 'rc.contract_qr_id', + 'rc.user_id', + 'rc.user_categoryid', + 'rc.park_id', + 'rc.contract_created_at', + 'rc.contract_periods', + 'rc.contract_periode', + 'rc.tag_qr_flag', + 'rc.contract_flag', + 'rc.contract_cancel_flag', + 'rc.contract_payment_day', + 'rc.contract_money', + 'rc.billing_amount', + 'rc.contract_permission', + 'rc.contract_manual', + 'rc.contract_notice', + 'p.park_name', + 'u.user_name', + 'u.user_phonetic', + 'u.user_mobile', + 'u.user_homephone', + 'u.user_primemail', + 'u.user_gender', + 'u.user_birthdate', + 'u.user_regident_zip', + 'u.user_regident_pre', + 'u.user_regident_city', + 'u.user_regident_add', + 'u.user_relate_zip', + 'u.user_relate_pre', + 'u.user_relate_city', + 'u.user_relate_add', + 'u.user_graduate', + 'u.user_workplace', + 'u.user_school', + 'u.user_remarks', + // 他に必要なカラムもここに追加 + ]) + ->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id') + ->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id'); + + // 検索条件例 + if ($request->filled('contract_id')) { + $q->where('rc.contract_id', $request->input('contract_id')); + } + if ($request->filled('name')) { + $q->where('u.user_name', 'like', '%' . $request->input('name') . '%'); + } + + // タグ・QR(完全一致、空白なら絞り込まない) + if ($request->filled('tag_qr_flag') && $request->input('tag_qr_flag') !== '') { + $q->where('rc.tag_qr_flag', $request->input('tag_qr_flag')); + } + + // ソート処理 + $sort = $request->input('sort', 'rc.contract_id'); + $sortType = $request->input('sort_type', 'desc'); + // カラム名のバリデーション(必要に応じて拡張) + $allowSorts = ['rc.contract_id']; + if (!in_array($sort, $allowSorts)) { + $sort = 'rc.contract_id'; + } + $sortType = ($sortType === 'asc') ? 'asc' : 'desc'; + + $rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString(); + + return view('admin.contractor.list', compact('rows', 'sort', 'sortType')); + } + + /** + * 詳細表示 + */ + public function info($id) + { + $contract = DB::table('regular_contract as rc') + ->select([ + 'rc.*', + 'p.park_name', + 'u.user_name', + 'u.user_phonetic', + 'u.user_mobile', + 'u.user_homephone', + 'u.user_primemail', + 'u.user_gender', + 'u.user_birthdate', + 'u.user_regident_city', + ]) + ->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id') + ->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id') + ->where('rc.contract_id', $id) + ->first(); + + if (!$contract) { abort(404); } + + return view('admin.contractor.info', compact('contract')); + } +} diff --git a/app/Http/Controllers/Admin/ContractorListController.php b/app/Http/Controllers/Admin/ContractorListController.php new file mode 100644 index 0000000..2b5f27f --- /dev/null +++ b/app/Http/Controllers/Admin/ContractorListController.php @@ -0,0 +1,116 @@ +select([ + 'rc.contract_id', + 'rc.contract_qr_id', + 'rc.user_id', + 'rc.user_categoryid', + 'rc.park_id', + 'rc.contract_created_at', + 'rc.contract_periods', + 'rc.contract_periode', + 'rc.tag_qr_flag', + 'rc.contract_flag', + 'rc.contract_cancel_flag', + 'rc.contract_payment_day', + 'rc.contract_money', + 'rc.billing_amount', + 'rc.contract_permission', + 'rc.contract_manual', + 'rc.contract_notice', + 'p.park_name', + // userテーブルの正しいカラム名 + 'u.user_name', + 'u.user_phonetic', + 'u.user_mobile', + 'u.user_homephone', + 'u.user_primemail', + 'u.user_gender', + 'u.user_birthdate', + 'u.user_regident_zip', + 'u.user_regident_pre', + 'u.user_regident_city', + 'u.user_regident_add', + 'u.user_relate_zip', + 'u.user_relate_pre', + 'u.user_relate_city', + 'u.user_relate_add', + 'u.user_graduate', + 'u.user_workplace', + 'u.user_school', + 'u.user_remarks', + // 他に必要なカラムもここに追加 + ]) + ->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id') + ->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id'); + + // 検索条件例 + if ($request->filled('contract_id')) { + $q->where('rc.contract_id', $request->input('contract_id')); + } + if ($request->filled('name')) { + $q->where('u.user_name', 'like', '%' . $request->input('name') . '%'); + } + + // タグ・QR(完全一致、空白なら絞り込まない) + if ($request->filled('tag_qr_flag') && $request->input('tag_qr_flag') !== '') { + $q->where('rc.tag_qr_flag', $request->input('tag_qr_flag')); + } + + // ソート処理 + $sort = $request->input('sort', 'rc.contract_id'); + $sortType = $request->input('sort_type', 'desc'); + // カラム名のバリデーション(必要に応じて拡張) + $allowSorts = ['rc.contract_id']; + if (!in_array($sort, $allowSorts)) { + $sort = 'rc.contract_id'; + } + $sortType = ($sortType === 'asc') ? 'asc' : 'desc'; + + $rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString(); + + return view('admin.contractor_list.list', compact('rows', 'sort', 'sortType')); + } + + /** + * 詳細表示 + */ + public function info($id) + { + $contract = DB::table('regular_contract as rc') + ->select([ + 'rc.*', + 'p.park_name', + 'u.user_name', + 'u.user_phonetic', + 'u.user_mobile', + 'u.user_homephone', + 'u.user_primemail', + 'u.user_gender', + 'u.user_birthdate', + 'u.user_regident_city', + ]) + ->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id') + ->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id') + ->where('rc.contract_id', $id) + ->first(); + + if (!$contract) { abort(404); } + + return view('admin.contractor.info', compact('contract')); + } +} diff --git a/app/Http/Controllers/Admin/NewsController.php b/app/Http/Controllers/Admin/NewsController.php new file mode 100644 index 0000000..6af4b4e --- /dev/null +++ b/app/Http/Controllers/Admin/NewsController.php @@ -0,0 +1,192 @@ +user(); + return $u->ope_id ?? $u->id ?? null; + } + + /** + * 一覧表示(GET/POST) + * 検索条件:kw(本文/URL 部分一致)、mode、open_datetime 範囲(from/to) + */ + public function list(Request $request) + { + // 一覧用クエリ(表示に必要な列のみ) + $q = DB::table($this->table)->select([ + "{$this->pk} as id", + 'news', + 'mode', + 'open_datetime', + 'link_url', + 'image1_filename', + 'image2_filename', + 'created_at', + 'updated_at', + ]); + + // キーワード検索(本文/リンクURL) + if ($kw = trim((string)$request->input('kw', ''))) { + $q->where(function($w) use ($kw) { + $w->where('news','like',"%{$kw}%") + ->orWhere('link_url','like',"%{$kw}%"); + }); + } + + // 表示モードで絞り込み(0:非表示 / 1:公開 / 2:下書き など) + if ($request->filled('mode')) { + $q->where('mode', (int)$request->input('mode')); + } + + // 公開日時の範囲指定 + if ($request->filled('from')) { $q->where('open_datetime','>=',$request->input('from')); } + if ($request->filled('to')) { $q->where('open_datetime','<=',$request->input('to')); } + + // 並び順:公開日時の降順 → 主キー降順 + $rows = $q->orderByDesc('open_datetime') + ->orderByDesc($this->pk) + ->paginate(20) + ->withQueryString(); + + return view('admin.news.list', compact('rows')); + } + + /** + * 新規作成(GET:フォーム表示 / POST:登録処理) + */ + public function add(Request $request) + { + if ($request->isMethod('post')) { + // 入力チェック + $v = $request->validate([ + 'news' => 'required|string', + 'open_datetime' => 'nullable|date_format:Y-m-d H:i:s', + 'link_url' => 'nullable|string|max:255', + 'image1_filename' => 'nullable|string|max:255', + 'image2_filename' => 'nullable|string|max:255', + 'mode' => 'required|integer|min:0|max:9', + ]); + + // 登録 + $now = now(); + DB::table($this->table)->insert([ + 'news' => $v['news'], + 'open_datetime' => $v['open_datetime'] ?? null, + 'link_url' => $v['link_url'] ?? null, + 'image1_filename' => $v['image1_filename'] ?? null, + 'image2_filename' => $v['image2_filename'] ?? null, + 'mode' => $v['mode'], + 'created_at' => $now, + 'updated_at' => $now, + 'operator_id' => $this->currentOperatorId(), + ]); + + return redirect()->route('news')->with('success','ニュースを登録しました。'); + } + + // フォーム表示 + return view('admin.news.add'); + } + + /** + * 編集(GET:フォーム表示 / POST:更新処理) + * @param int $id ニュースID + */ + public function edit($id, Request $request) + { + // 対象データ取得 + $news = DB::table($this->table)->where($this->pk, $id)->first(); + if (!$news) { abort(404); } + + if ($request->isMethod('post')) { + // 入力チェック + $v = $request->validate([ + 'news' => 'required|string', + 'open_datetime' => 'nullable|date_format:Y-m-d H:i:s', + 'link_url' => 'nullable|string|max:255', + 'image1_filename' => 'nullable|string|max:255', + 'image2_filename' => 'nullable|string|max:255', + 'mode' => 'required|integer|min:0|max:9', + ]); + + // 更新 + DB::table($this->table)->where($this->pk, $id)->update([ + 'news' => $v['news'], + 'open_datetime' => $v['open_datetime'] ?? null, + 'link_url' => $v['link_url'] ?? null, + 'image1_filename' => $v['image1_filename'] ?? null, + 'image2_filename' => $v['image2_filename'] ?? null, + 'mode' => $v['mode'], + 'updated_at' => now(), + 'operator_id' => $this->currentOperatorId(), + ]); + + return redirect()->route('news_edit', ['id'=>$id])->with('success','更新しました。'); + } + + // フォーム表示 + return view('admin.news.edit', compact('news')); + } + + /** + * 詳細表示 + * @param int $id ニュースID + */ + public function info($id) + { + // 詳細用に必要な列を選択 + $news = DB::table($this->table) + ->select([ + "{$this->pk} as id", + 'news','mode','open_datetime','link_url', + 'image1_filename','image2_filename', + 'created_at','updated_at','operator_id', + ])->where($this->pk, $id)->first(); + + if (!$news) { abort(404); } + + return view('admin.news.info', compact('news')); + } + + /** + * 削除(単体 id または 複数 ids[] に対応) + */ + public function delete(Request $request) + { + // 削除対象IDの取得(単体 or 複数) + $ids = $request->input('ids'); + if (!$ids) { + $id = (int)$request->input('id'); + if ($id > 0) { $ids = [$id]; } + } + + // バリデーション:削除対象未選択 + if (!is_array($ids) || empty($ids)) { + return back()->with('error', '削除対象が選択されていません。'); + } + + // 削除実行 + DB::table($this->table)->whereIn($this->pk, $ids)->delete(); + + return back()->with('success','削除しました。'); + } +} diff --git a/app/Http/Controllers/Admin/ParkController.php b/app/Http/Controllers/Admin/ParkController.php new file mode 100644 index 0000000..7a175fb --- /dev/null +++ b/app/Http/Controllers/Admin/ParkController.php @@ -0,0 +1,266 @@ +leftJoin('city as c', 'p.city_id', '=', 'c.city_id') + ->select([ + 'p.park_id', + 'c.city_name', + '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', + ]); + + 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(); + + return view('admin.parks.list', compact('parks', 'cities')); + } + + 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->save(); + + return redirect()->route('parks')->with('success', '登録しました'); + } + + return view('admin.parks.add', [ + 'cities' => $cities, + ]); + } + + public function edit(Request $request, $pk, $view = '') + { + $park = Park::getByPk($pk); + if (empty($pk) || empty($park)) { + abort('404'); + } + $data = $park->getAttributes(); + $dataList = $this->getDataDropList(); + $data = array_merge($data, $dataList); + if ($request->isMethod('POST')) { + // ここを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::deleteByPk($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) + { + + $headers = array( + "Content-type" => "text/csv;charset=UTF-8", + 'Content-Encoding: UTF-8', + "Content-Disposition" => "attachment; filename=file.csv", + "Pragma" => "no-cache", + "Cache-Control" => "must-revalidate, post-check=0, pre-check=0", + "Expires" => "0" + ); + $inputs = [ + 'isMethodPost' => 0, + 'isExport' => 1, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + + ]; + + $dataExport = Park::search($inputs); + $columns = array( + __('駐輪場ID '),// 0 + __('市区ID'),// 1 + __('市区'),// 2 + __('駐輪場名'),// 3 + __('駐輪場ふりがな'),// 4 + __('駐輪場五十音'),// 5 + __('住所'),// 6 + __('閉設フラグ'),// 7 + __('閉設フラグ'),// 8 + __('閉設日'),// 9 + __('残警告チェックフラグ'),// 10 + __('印字数'),// 11 + __('最新キープアライブ')// 12 + ); + $filename = "駐輪場マスタ.csv"; + $file = fopen($filename, 'w+'); + fputcsv($file, $columns); + foreach ($dataExport as $items) { + fputcsv( + $file, + array( + $items->park_id,// 0 + $items->city_id,// 1 + !empty($items->getCity()) ? $items->getCity()->city_name : "",// 2 + $items->park_name, // 3 + $items->park_ruby, // 4 + $items->park_syllabary, // 5 + $items->park_adrs, // 6 + $items->park_close_flag,// 7 + $items->getParkCloseFlagDisplay(),// 8 + $items->park_day,// 9 + $items->alert_flag,// 10 + $items->print_number,// 11 + $items->keep_alive// 12 + ) + ); + } + fclose($file); + return Response::download($filename, $filename, $headers); + } + + 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/PeriodicalController.php b/app/Http/Controllers/Admin/PeriodicalController.php new file mode 100644 index 0000000..37b81e5 --- /dev/null +++ b/app/Http/Controllers/Admin/PeriodicalController.php @@ -0,0 +1,99 @@ +select('park_id', 'park_name') + ->orderBy('park_name') + ->get(); + + // 必要なら選択中のpark_idも渡す + $selectedParkId = $request->input('park_id', ''); + + return view('admin.periodical.list', compact('parks', 'selectedParkId')); + } + + // 画面上の3つの統計用データ + public function listData(Request $request) + { + $parkId = $request->input('park_id'); + + // 契約状況 + $bicycleGeneral = DB::table('regular_contract') + ->where('park_id', $parkId) + ->where('user_categoryid', 1) + ->where('ptype_id', 1) // 1:自転車 + ->where('contract_cancel_flag', 0) + ->count(); + $bicycleStudent = DB::table('regular_contract') + ->where('park_id', $parkId) + ->where('user_categoryid', 2) + ->where('ptype_id', 1) + ->where('contract_cancel_flag', 0) + ->count(); + // 原付・その他も同様に集計 + + $contractSummary = [ + [ + 'type' => '自転車', + 'general_count' => $bicycleGeneral, + 'general_extra' => '', + 'student_count' => $bicycleStudent, + 'student_extra' => '', + 'use_total' => $bicycleGeneral + $bicycleStudent, + 'vacancy' => 8, // 例: 空き数 + 'total' => $bicycleGeneral + $bicycleStudent + 8, + 'last' => [ + 'reserve_date' => '2025/07/27', + 'contract_date' => '', + ], + ], + // 原付・その他も同様に + ]; + + // 空き待ち状況 + $waitingSummary = [ + [ + 'type' => '自転車', + 'general_count' => 28, + 'general_head' => '2023/03/08', + 'student_count' => 6, + 'student_head' => '2023/11/04', + 'total' => 34, + ], + // 原付・その他も同様に + ]; + + // 更新状況 + $renewalSummary = []; + for ($m = 1; $m <= 12; $m++) { + $renewalSummary[] = [ + 'month' => sprintf('%02d月', $m), + 'bicycle_general' => 0, + 'bicycle_student' => 0, + 'bicycle_total' => 0, + 'moped_general' => 0, + 'moped_student' => 0, + 'moped_total' => 0, + 'others_general' => 0, + 'others_student' => 0, + 'others_total' => 0, + ]; + } + + return response()->json([ + 'contract_summary' => $contractSummary, + 'waiting_summary' => $waitingSummary, + 'renewal_summary' => $renewalSummary, + ]); + } +} diff --git a/app/Http/Controllers/Admin/PplaceController.php b/app/Http/Controllers/Admin/PplaceController.php new file mode 100644 index 0000000..7134d41 --- /dev/null +++ b/app/Http/Controllers/Admin/PplaceController.php @@ -0,0 +1,175 @@ + 0, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + 'page' => $request->get('page', 1), + ]; + + $inputs['list'] = Pplace::search($inputs); + + if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) { + return redirect()->route('pplace'); + } + + return view('admin.Pplace.list', $inputs); + } + + public function add(Request $request) + { + $inputs = [ + 'pplace_number' => $request->input('pplace_number'), + 'pplace_remarks' => $request->input('pplace_remarks'), + 'operator_id' => $request->input('operator_id'), + ]; + + $inputs['operators'] = Ope::getList(); // + + if ($request->isMethod('POST')) { + $validator = Validator::make($inputs, [ + 'pplace_number' => 'required|string|max:255', + 'pplace_remarks' => 'nullable|string|max:255', + 'operator_id' => 'nullable|integer', + ]); + + if (!$validator->fails()) { + DB::transaction(function () use ($inputs) { + $pplace = new Pplace(); + $pplace->fill($inputs); + $pplace->save(); + }); + return redirect()->route('pplace')->with('success', '登録成功'); + } else { + $inputs['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + + return view('admin.Pplace.add', $inputs); + } + + public function edit(Request $request, $id, $view = '') + { + + $record = Pplace::find($id); + + if (!$record) abort(404); + + $data = $record->toArray(); + $data['operators'] = Ope::getList(); + + + if ($request->isMethod('POST')) { + $inputs = $request->all(); + $validator = Validator::make($inputs, [ + 'pplace_number' => 'required|string|max:255', + 'pplace_remarks' => 'nullable|string|max:255', + 'operator_id' => 'nullable|integer', + ]); + + $data = array_merge($data, $inputs); + + if (!$validator->fails()) { + DB::transaction(function () use ($record, $inputs) { + $record->fill($inputs); + $record->save(); + }); + return redirect()->route('pplace')->with('success', '更新成功'); + } else { + $data['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + + return view($view ?: 'admin.Pplace.edit', $data); + } + + public function info(Request $request, $id) + { + return $this->edit($request, $id, 'admin.Pplace.info'); + } + + public function delete(Request $request) + { + $pk = $request->get('pk'); + if ($pk && Pplace::destroy($pk)) { + return redirect()->route('pplace')->with('success', '削除成功'); + } + return redirect()->route('pplace')->with('error', '削除失敗'); + } + + public function export() + { + $headers = [ + "Content-type" => "text/csv;charset=UTF-8", + "Content-Disposition" => "attachment; filename=Pplace.csv", + ]; + + $data = Pplace::all(); + $columns = ['ID', '番号', '備考', 'オペレータID']; + + $filename = "Pplace.csv"; + $file = fopen($filename, 'w+'); + fputcsv($file, $columns); + + foreach ($data as $item) { + fputcsv($file, [ + $item->pplace_id, + $item->pplace_number, + $item->pplace_remarks, + $item->operator_id, + ]); + } + + fclose($file); + return Response::download($filename, $filename, $headers); + } + + public function import(Request $request) + { + $file = $request->file('file'); + if (!$file) { + return redirect()->route('pplace')->with('error', 'CSVファイルを選択してください'); + } + + $data = \App\Utils::csvToArray($file); + $record = 0; + + DB::beginTransaction(); + try { + foreach ($data as $key => $row) { + $record = $key + 2; + if (count($row) < 3) throw new \Exception('列数が不正です'); + + Pplace::create([ + 'pplace_number' => $row[0], + 'pplace_remarks' => $row[1], + 'operator_id' => $row[2], + ]); + } + DB::commit(); + return redirect()->route('pplace')->with('success', 'インポート成功'); + } catch (\Exception $e) { + DB::rollBack(); + return redirect()->route('pplace')->with('error', "行 {$record} : " . $e->getMessage()); + } + } + + private function __buildErrorMessasges($validator) + { + return implode("\n", $validator->errors()->all()); + } +} diff --git a/app/Http/Controllers/Admin/PriceController.php b/app/Http/Controllers/Admin/PriceController.php new file mode 100644 index 0000000..81f9cc1 --- /dev/null +++ b/app/Http/Controllers/Admin/PriceController.php @@ -0,0 +1,259 @@ + 0, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + 'page' => $request->get('page', 1), + + ]; + $inputs['list'] = Price::search($inputs); + if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) { + return redirect()->route('prices'); + } + return view('admin.prices.list', $inputs); + } + + public function add(Request $request) + { + $inputs = [ + 'prine_name' => $request->input('prine_name'), // 商品名 + 'price_month' => $request->input('price_month',''), // 期間 + 'park_id' => $request->input('park_name'), // 駐輪場 + 'psection_id' => $request->input('psection_subject'), // 車種区分 + 'price_ptypeid' => $request->input('ptype_subject'), // 駐輪分類 + 'user_categoryid' => $request->input('user_category_name'), // 利用者分類 + 'pplace_id' => $request->input('pplace_id'), // 駐車車室 + 'price' => $request->input('price'), // 駐輪料金(税込) + ]; + + $dataList = $this->getDataDropList(); + $inputs = array_merge($inputs, $dataList); + if ($request->isMethod('POST')) { + $type = false; + $validation = new PriceRequest(); + $rules = $validation->rules(); + $validator = Validator::make($request->all(), $rules, $validation->messages()); + if (!$validator->fails()) { + \DB::transaction(function () use ($inputs, &$type) { + $new = new Price(); + $new->fill($inputs); + if( $new->save()){ + $type = true; + } + + }); + if ($type) { + $request->session()->flash('success', __('新しい成功を創造する。')); + return redirect()->route('prices'); + } else { + $request->session()->flash('error', __('新しい作成に失敗しました')); + } + }else { + $inputs['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + + return view('admin.prices.add', $inputs); + } + + public function edit(Request $request, $pk ,$view=''){ + $price = Price::getByPk($pk); + if (empty($pk) || empty($price)) { + abort('404'); + } + $data = $price->getAttributes(); + $dataList = $this->getDataDropList(); + $data = array_merge($data, $dataList); + if ($request->isMethod('POST')) { + $type = false; + $validation = new PriceRequest(); + $rules = $validation->rules(); + $validator = Validator::make($request->all(), $rules, $validation->messages()); + $requestAll = $request->all(); + $requestAll['price_ptypeid]'] = $request->input('ptype_subject'); + $requestAll['user_categoryid'] = $request->input('user_category_name'); // 利用者分類 + $requestAll['psection_id'] = $request->input('psection_subject'); + $requestAll['park_id'] = $request->input('park_name'); + $data = array_merge($data, $requestAll); + if (!$validator->fails()) { + \DB::transaction(function () use ($data, &$type,$price) { + $price->fill($data); + $price->save(); + $type = true; + }); + if ($type) { + $request->session()->flash('success', __('更新に成功しました')); + return redirect()->route('prices'); + } else { + $request->session()->flash('error', __('更新に失敗しました')); + } + }else { + $data['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + if ($view != '') { + return view($view, $data); + } + return view('admin.prices.edit', $data); + } + + public function delete(Request $request) + { + $arr_pk = $request->get('pk'); + if ($arr_pk) { + if (Price::deleteByPk($arr_pk)) { + return redirect()->route('prices')->with('success', __("削除成功。")); + } else { + return redirect()->route('prices')->with('error', __('削除に失敗しました。')); + } + } + return redirect()->route('prices')->with('error', __('削除するユーザーを選択してください。')); + } + + public function export(Request $request) + { + + $headers = array( + "Content-type" => "text/csv;charset=UTF-8", + 'Content-Encoding: UTF-8', + "Content-Disposition" => "attachment; filename=file.csv", + "Pragma" => "no-cache", + "Cache-Control" => "must-revalidate, post-check=0, pre-check=0", + "Expires" => "0" + ); + $inputs = [ + 'isMethodPost' => 0, + 'isExport' => 1, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + + ]; + + $dataExport = Price::search($inputs); + $columns = array( + __('駐車場所ID'),// 0 + __('商品名'),// 1 + __('期間'),// 2 + __('駐輪場ID'),// 3 + __('駐輪場名'),// 3 + __('車種区分ID'),// 5 + __('車種区分'),// 6 + __('駐輪分類ID'),// 7 + __('駐輪分類'),// 8 + __('利用者分類ID'),// 9 + __('利用者分類'),// 10 + __('駐車車室ID'),//11 + __('駐輪料金(税込)'),// 12 + ); + $filename = "駐輪場所、料金マスタ.csv"; + $file = fopen($filename, 'w+'); + fputcsv($file, $columns); + foreach ($dataExport as $items) { + fputcsv($file, array( + $items->price_parkplaceid,// 0 + $items->prine_name, // 1 + $items->price_month, // 2 + $items->park_id, // 3 + !empty($items->getPark())? $items->getPark()->park_name:'' ,// 4 + $items->psection_id, // 5 + !empty($items->getPSection())? $items->getPSection()->psection_subject:'',// 6 + $items->price_ptypeid, // 7 + !empty($items->getPType())? $items->getPType()->ptype_subject:'' ,// 8 + $items->user_categoryid, //9 + !empty($items->getUserType())? $items->getUserType()->print_name:'' ,//10 + $items->pplace_id,// 11 + $items->price, // 12 + )); + } + fclose($file); + return Response::download($filename, $filename, $headers); + } + + public function import(Request $request) + { + $file = $request->file('file'); + if(!empty($file)){ + $data = Utils::csvToArray($file); + $type = 1; + $msg = ''; + $record = 0; + DB::beginTransaction(); + try { + Price::query()->delete(); + $col = 13; + foreach ($data as $key => $items) { + $record = $key + 2; + if (count($items) == $col) { + $row = new Price(); + $row->price_parkplaceid = $items[0]; + $row->prine_name = $items[1]; + $row->price_month = $items[2]; + $row->park_id = $items[3]; + $row->psection_id = $items[5]; + $row->price_ptypeid = $items[7]; + $row->user_categoryid = $items[9]; + $row->pplace_id = $items[11]; + $row->price = $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('prices')->with('success', __('輸入成功')); + } else { + DB::rollBack(); + return redirect()->route('prices')->with('error', __($msg, ['record' => $record])); + } + } else { + return redirect()->route('prices')->with('error', __('あなたはcsvファイルを選択していません。')); + } + } + + public function info(Request $request, $id) + { + return $this->edit($request, $id, 'admin.prices.info'); + } + + public function getDataDropList() + { + $data['parks'] = Park::getList() ; + $data['psections'] = Psection::getList() ; + $data['ptypes'] = Ptype::getList() ; + $data['userTypes'] = Usertype::getList() ; + return $data; + } + + +} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/PriceListController.php b/app/Http/Controllers/Admin/PriceListController.php new file mode 100644 index 0000000..9c180de --- /dev/null +++ b/app/Http/Controllers/Admin/PriceListController.php @@ -0,0 +1,144 @@ +get(); + $parkId = $request->input('park_id', ''); + + $masterList = [ + [ + 'name' => 'マスターA', + 'status' => '利用中', + 'groups' => [], + ], + [ + 'name' => 'マスターB', + 'status' => '待作中', + 'groups' => [], + ], + ]; + + if ($parkId) { + // parkとprice_aをJOIN + $aRows = \DB::table('price_a') + ->join('park', 'park.park_id', '=', 'price_a.park_id') + ->where('price_a.park_id', $parkId) + ->select('price_a.*') // 必要ならpark.*も + ->get(); + + $aGrouped = $this->groupPriceRows($aRows); + + $masterList[0]['groups'] = $aGrouped; + // マスターBも同様に取得・整形する場合はここに追加 + } + + return view('admin.PriceList.list', [ + 'parkList' => $parkList, + 'parkId' => $parkId, + 'masterList' => $masterList, + ]); + } + + /** + * 料金データを「駐輪分類ID-ユーザ分類ID-駐輪場ID」でグループ化 + */ + private function groupPriceRows($rows) + { + $result = []; + foreach ($rows as $row) { + // グループキーは分類ID+ユーザ分類ID+駐輪場ID + $key = $row->price_ptypeid . '-' . $row->user_categoryid . '-' . $row->park_id; + + if (!isset($result[$key])) { + $result[$key] = [ + 'id' => $row->price_parkplaceid, + 'classification' => $row->price_ptypeid, + 'room_number' => '', // 必要ならpplace_id等をセット + 'category1' => $row->prine_name ?? '', + 'category2' => '', + 'category3' => '', + 'bike_1m' => '', + 'bike_2m' => '', + 'bike_3m' => '', + 'bike_6m' => '', + 'bike_12m' => '', + // 必要なら原付・自動二輪も同様に追加 + ]; + } + + // 月数ごとに金額をセット + if ($row->price_month == 1) { + $result[$key]['bike_1m'] = $row->price; + } elseif ($row->price_month == 2) { + $result[$key]['bike_2m'] = $row->price; + } elseif ($row->price_month == 3) { + $result[$key]['bike_3m'] = $row->price; + } elseif ($row->price_month == 6) { + $result[$key]['bike_6m'] = $row->price; + } elseif ($row->price_month == 12) { + $result[$key]['bike_12m'] = $row->price; + } + } + return array_values($result); + } + + public function update(Request $request) + { + foreach ($request->input('rows', []) as $row) { + $id = $row['id'] ?? null; + if (!$id) continue; + + // 更新対象の月リスト + $months = [ + 'bike_1m' => 1, + 'bike_2m' => 2, + 'bike_3m' => 3, + 'bike_6m' => 6, + 'bike_12m' => 12, + ]; + + foreach ($months as $field => $month) { + if (isset($row[$field])) { + // price_aから該当レコードを取得 + $item = \App\Models\PriceA::where('price_parkplaceid', $id) + ->where('price_month', $month) + ->first(); + if ($item) { + $item->price = $row[$field]; + $item->save(); + } + } + } + // 原付・自動二輪も同様に必要なら追加 + } + return back()->with('success', '金額を更新しました'); + } + + public function insert(Request $request) + { + // 例:bike_2m(2ヶ月)だけ新規追加する場合 + if ($request->filled('bike_2m')) { + $row = new \App\Models\PriceA(); + $row->park_id = $request->input('park_id'); // 必要に応じて + $row->price = $request->input('bike_2m'); + $row->price_month = 2; + // 他の必要なカラムもセット + $row->save(); + } + // 他の月も同様に必要なら追加 + return back()->with('success', '金額を追加しました'); + } +} diff --git a/app/Http/Controllers/Admin/PsectionController.php b/app/Http/Controllers/Admin/PsectionController.php new file mode 100644 index 0000000..9351d2a --- /dev/null +++ b/app/Http/Controllers/Admin/PsectionController.php @@ -0,0 +1,73 @@ +input('sort', 'psection_id'); + $sort_type = $request->input('sort_type', 'asc'); + + $query = Psection::query(); + if (in_array($sort, ['psection_id', 'psection_subject'])) { + $query->orderBy($sort, $sort_type); + } + + $list = $query->get(); + + return view('admin.psection.list', compact('list', 'sort', 'sort_type')); + } + + // 新規追加 + public function add(Request $request) + { + if ($request->isMethod('post')) { + $validated = $request->validate([ + 'psection_id' => 'required|integer|unique:psection,psection_id', + 'psection_subject' => 'required|string|max:255', + ]); + Psection::create($validated); + return redirect()->route('psection')->with('success', '車種区分を追加しました'); + } + return view('admin.psection.add'); + } + + // 編集 + public function edit(Request $request, $id) + { + $psection = Psection::findOrFail($id); + if ($request->isMethod('post')) { + $validated = $request->validate([ + 'psection_subject' => 'required|string|max:255', + ]); + $psection->update($validated); + return redirect()->route('psection')->with('success', '車種区分を更新しました'); + } + return view('admin.psection.edit', compact('psection')); + } + + // 詳細(info) + public function info(Request $request, $id) + { + $psection = Psection::findOrFail($id); + return view('admin.psection.info', compact('psection')); + } + + // 削除 + public function delete(Request $request) + { + $ids = $request->input('pk', []); + if (!empty($ids)) { + Psection::whereIn('psection_id', $ids)->delete(); + return redirect()->route('psection')->with('success', '削除しました'); + } + return redirect()->route('psection')->with('error', '削除対象を選択してください'); + } +} diff --git a/app/Http/Controllers/Admin/PtypeController.php b/app/Http/Controllers/Admin/PtypeController.php new file mode 100644 index 0000000..39d88c3 --- /dev/null +++ b/app/Http/Controllers/Admin/PtypeController.php @@ -0,0 +1,230 @@ + 0, + 'isExport' => 0, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + 'page' => $request->get('page', 1), + + ]; + $inputs['isMethodPost'] = $request->isMethod('post'); + $inputs['list'] = Ptype::search($inputs); + if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) { + return redirect()->route('ptypes'); + } + return view('admin.ptypes.list', $inputs); + } + + public function add(Request $request) + { + $inputs = [ + //TODO 駐輪分類ID not found in database specs + 'ptype_subject' => $request->input('ptype_subject'), // 駐輪分類名 + 'ptype_remarks' => $request->input('ptype_remarks'), // 備考 + ]; + + if ($request->isMethod('POST')) { + $rules = [ + 'ptype_subject' => 'required|string|max:255', + 'ptype_sort' => 'nullable|integer', + 'ptype_remarks' => 'nullable|string|max:255', + ]; + $messages = [ + 'ptype_subject.required' => '駐輪分類名は必須です。', + ]; + $validator = Validator::make($request->all(), $rules, $messages); + if (!$validator->fails()) { + \DB::transaction(function () use ($inputs, &$type) { + $new = new Ptype(); + $new->fill($inputs); + if ($new->save()) { + $type = true; + } + + }); + if ($type) { + $request->session()->flash('success', __('データ新規作成しました。')); + return redirect()->route('ptypes'); + } else { + $request->session()->flash('error', __('新規作成に失敗しました')); + } + } else { + $inputs['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + + return view('admin.ptypes.add', $inputs); + } + + public function edit(Request $request, $pk, $view = '') + { + $ptype = Ptype::getByPk($pk); + if (empty($pk) || empty($ptype)) { + abort('404'); + } + $data = $ptype->getAttributes(); + $dataList = $this->getDataDropList(); + $data = array_merge($data, $dataList); + if ($request->isMethod('POST')) { + $type = false; + // ここを修正 + $rules = [ + 'ptype_subject' => 'required|string|max:255', + 'ptype_sort' => 'nullable|integer', + 'ptype_remarks' => 'nullable|string|max:255', + ]; + $messages = [ + 'ptype_subject.required' => '駐輪分類名は必須です。', + ]; + $validator = Validator::make($request->all(), $rules, $messages); + $requestAll = $request->all(); + $data = array_merge($data, $requestAll); + if (!$validator->fails()) { + \DB::transaction(function () use ($data, &$type, $ptype) { + $ptype->fill($data); + $ptype->save(); + $type = true; + }); + if ($type) { + $request->session()->flash('success', __('更新に成功しました')); + return redirect()->route('ptypes'); + } else { + $request->session()->flash('error', __('更新に失敗しました')); + } + } else { + $data['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + if ($view != '') { + return view($view, $data); + } + return view('admin.ptypes.edit', $data); + } + + public function delete(Request $request) + { + $arr_pk = $request->get('pk'); + if ($arr_pk) { + if (Ptype::deleteByPk($arr_pk)) { + return redirect()->route('ptypes')->with('success', __("削除が完了しました。")); + } else { + return redirect()->route('ptypes')->with('error', __('削除に失敗しました。')); + } + } + return redirect()->route('ptypes')->with('error', __('削除するデータを選択してください。')); + } + + + public function info(Request $request, $id) + { + return $this->edit($request, $id, 'admin.ptypes.info'); + } + + public function getDataDropList() + { + $data = []; + return $data; + } + + public function export(Request $request) + { + + $headers = array( + "Content-type" => "text/csv;charset=UTF-8", + 'Content-Encoding: UTF-8', + "Content-Disposition" => "attachment; filename=file.csv", + "Pragma" => "no-cache", + "Cache-Control" => "must-revalidate, post-check=0, pre-check=0", + "Expires" => "0" + ); + $inputs = [ + 'isMethodPost' => 0, + 'isExport' => 1, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + + ]; + + $dataExport = Ptype::search($inputs); + $columns = array( + __('駐輪分類ID'), + __('駐輪分類名'), + __('備考'), + ); + $filename = "駐輪分類マスタ.csv"; + $file = fopen($filename, 'w+'); + fputcsv($file, $columns); + foreach ($dataExport as $items) { + fputcsv($file, array( + $items->ptype_id, + $items->ptype_subject, + $items->ptype_remarks, + )); + } + fclose($file); + return Response::download($filename, $filename, $headers); + } + + public function import(Request $request) + { + $file = $request->file('file'); + if (!empty($file)) { + $data = Utils::csvToArray($file); + $type = 1; + $msg = ''; + $record = 0; + DB::beginTransaction(); + try { + Ptype::query()->delete(); + $col = 3; + foreach ($data as $key => $items) { + $record = $key + 2; + if (count($items) == $col) { + $row = new Ptype(); + $row->ptype_id = $items[0]; + $row->ptype_subject = $items[1]; + $row->ptype_remarks = $items[2]; + 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('ptypes')->with('success', __('輸入成功')); + } else { + DB::rollBack(); + return redirect()->route('ptypes')->with('error', __($msg, ['record' => $record])); + } + } else { + return redirect()->route('ptypes')->with('error', __('あなたはcsvファイルを選択していません。')); + } + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/RegularContractController.php b/app/Http/Controllers/Admin/RegularContractController.php new file mode 100644 index 0000000..17a5a55 --- /dev/null +++ b/app/Http/Controllers/Admin/RegularContractController.php @@ -0,0 +1,528 @@ +input('sort', 'contract_id'); + $sortType = strtolower($request->input('sort_type', 'desc')) === 'asc' ? 'asc' : 'desc'; + + // ===== 絞り込み(テキスト系)===== + // フォームの name 属性と完全一致させる&既定値は空文字にして Blade が未定義にならないようにする + $contract_qr_id = trim((string) $request->input('contract_qr_id', '')); + $user_id = trim((string) $request->input('user_id', '')); + $park_id = trim((string) $request->input('park_id', '')); + $user_phonetic = trim((string) $request->input('user_phonetic', '')); // フリガナ + $phone = trim((string) $request->input('phone', '')); // 電話(携帯/自宅) + $email = trim((string) $request->input('email', '')); // メール + $usertype_name_kw = trim((string) $request->input('usertype_name', '')); // 利用者分類名 + $park_name_kw = trim((string) $request->input('park_name', '')); // 駐輪場名 + + // ===== 絞り込み(日付範囲)===== + $reserve_from = $request->input('reserve_date_from', ''); + $reserve_to = $request->input('reserve_date_to', ''); + $created_from = $request->input('contract_created_from', ''); + $created_to = $request->input('contract_created_to', ''); + $updated_from = $request->input('contract_updated_from', ''); + $updated_to = $request->input('contract_updated_to', ''); + $canceled_from = $request->input('contract_canceled_from', ''); + $canceled_to = $request->input('contract_canceled_to', ''); + + // ===== 列挙(全て/0/1)===== + $contract_flag = $request->input('contract_flag', ''); + $contract_permission = $request->input('contract_permission', ''); + $tag_qr_flag = $request->input('tag_qr_flag', ''); + $update_flag = $request->input('update_flag', ''); + $contract_cancel_flag = $request->input('contract_cancel_flag', ''); + + // ===== クエリ(結合込み)===== + $q = DB::table('regular_contract as rc') + ->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id') + ->leftJoin('usertype as t', 't.user_categoryid', '=', 'rc.user_categoryid') + ->leftJoin('park as p', 'p.park_id', '=', 'rc.park_id') + ->select([ + // rc + 'rc.contract_id', + 'rc.contract_qr_id', + 'rc.user_id', + 'rc.user_categoryid', + 'rc.reserve_id', + 'rc.park_id', + 'rc.price_parkplaceid', + 'rc.user_securitynum', + 'rc.reserve_date', + 'rc.contract_reserve', + 'rc.contract_created_at', + 'rc.contract_updated_at', + 'rc.contract_cancelday', + 'rc.contract_flag', + 'rc.contract_permission', + 'rc.contract_cancel_flag', + 'rc.tag_qr_flag', + 'rc.update_flag', + 'rc.park_position', + 'rc.ope_id', + // user + 'u.user_name', + 'u.user_phonetic', + 'u.user_mobile', + 'u.user_homephone', + 'u.user_primemail', + // usertype & park + DB::raw('t.print_name as usertype_name'), + DB::raw('p.park_name as park_name'), + ]); + + // ===== LIKE / キーワード ===== + if ($contract_qr_id !== '') { + $q->where('rc.contract_qr_id', 'like', "%{$contract_qr_id}%"); + } + if ($user_id !== '') { + $q->where('rc.user_id', 'like', "%{$user_id}%"); + } + if ($park_id !== '') { + $q->where('rc.park_id', 'like', "%{$park_id}%"); + } + if ($user_phonetic !== '') { + $q->where('u.user_phonetic', 'like', "%{$user_phonetic}%"); + } + if ($email !== '') { + $q->where('u.user_primemail', 'like', "%{$email}%"); + } + if ($usertype_name_kw !== '') { + $q->where('t.print_name', 'like', "%{$usertype_name_kw}%"); + } + if ($park_name_kw !== '') { + $q->where('p.park_name', 'like', "%{$park_name_kw}%"); + } + if ($phone !== '') { + $q->where(function ($w) use ($phone) { + $w->where('u.user_mobile', 'like', "%{$phone}%") + ->orWhere('u.user_homephone', 'like', "%{$phone}%"); + }); + } + + // ===== 日付範囲 ===== + if ($reserve_from) { + $q->whereDate('rc.reserve_date', '>=', $reserve_from); + } + if ($reserve_to) { + $q->whereDate('rc.reserve_date', '<=', $reserve_to); + } + if ($created_from) { + $q->whereDate('rc.contract_created_at', '>=', $created_from); + } + if ($created_to) { + $q->whereDate('rc.contract_created_at', '<=', $created_to); + } + if ($updated_from) { + $q->whereDate('rc.contract_updated_at', '>=', $updated_from); + } + if ($updated_to) { + $q->whereDate('rc.contract_updated_at', '<=', $updated_to); + } + if ($canceled_from) { + $q->whereDate('rc.contract_cancelday', '>=', $canceled_from); + } + if ($canceled_to) { + $q->whereDate('rc.contract_cancelday', '<=', $canceled_to); + } + + // ===== 列挙フィルタ ===== + if ($contract_flag !== '') { + $q->where('rc.contract_flag', (int) $contract_flag); + } + if ($contract_permission !== '') { + $q->where('rc.contract_permission', (int) $contract_permission); + } + if ($tag_qr_flag !== '') { + $q->where('rc.tag_qr_flag', (int) $tag_qr_flag); + } + if ($update_flag !== '') { + $q->where('rc.update_flag', (int) $update_flag); + } + if ($contract_cancel_flag !== '') { + $q->where('rc.contract_cancel_flag', (int) $contract_cancel_flag); + } + + // ===== ソート(仮想列は結合側にマッピング)===== + $sortable = [ + 'contract_id', + 'contract_qr_id', + 'user_id', + 'user_categoryid', + 'reserve_id', + 'park_id', + 'price_parkplaceid', + 'user_securitynum', + 'reserve_date', + 'contract_reserve', + 'contract_created_at', + 'contract_updated_at', + 'contract_cancelday', + 'contract_flag', + 'contract_permission', + 'contract_cancel_flag', + 'tag_qr_flag', + 'update_flag', + 'park_position', + 'ope_id', + // 結合先の見出し列 + 'user_name', + 'user_phonetic', + 'user_mobile', + 'user_homephone', + 'user_primemail', + 'usertype_name', + 'park_name', + ]; + if (!in_array($sort, $sortable, true)) { + $sort = 'contract_id'; + } + $sortMap = [ + 'user_name' => 'u.user_name', + 'user_phonetic' => 'u.user_phonetic', + 'user_mobile' => 'u.user_mobile', + 'user_homephone' => 'u.user_homephone', + 'user_primemail' => 'u.user_primemail', + 'usertype_name' => 't.print_name', + 'park_name' => 'p.park_name', + ]; + $sortColumn = $sortMap[$sort] ?? ('rc.' . $sort); + + $list = $q->orderBy($sortColumn, $sortType)->paginate(50); + + // ===== 画面へ(Blade 側が参照するすべての変数を渡す)===== + return view('admin.regularcontracts.list', [ + 'list' => $list, + 'sort' => $sort, + 'sort_type' => $sortType, + + // 入力保持(テキスト) + 'contract_qr_id' => $contract_qr_id, + 'user_id' => $user_id, + 'park_id' => $park_id, + 'user_phonetic' => $user_phonetic, + 'phone' => $phone, + 'email' => $email, + 'usertype_name' => $usertype_name_kw, + 'park_name' => $park_name_kw, + + // 入力保持(日付) + 'reserve_date_from' => $reserve_from, + 'reserve_date_to' => $reserve_to, + 'contract_created_from' => $created_from, + 'contract_created_to' => $created_to, + 'contract_updated_from' => $updated_from, + 'contract_updated_to' => $updated_to, + 'contract_canceled_from' => $canceled_from, + 'contract_canceled_to' => $canceled_to, + + // 入力保持(列挙) + 'contract_flag' => $contract_flag, + 'contract_permission' => $contract_permission, + 'tag_qr_flag' => $tag_qr_flag, + 'update_flag' => $update_flag, + 'contract_cancel_flag' => $contract_cancel_flag, + ]); + } + + /** + * 定期契約編集(GET: 画面表示 / POST: 更新実行) + * - 主キー: contract_id + */ + public function edit(Request $request, $id) + { + $id = (int) $id; + + if ($request->isMethod('get')) { + $row = DB::table('regular_contract')->where('contract_id', $id)->first(); + if (!$row) { + abort(404); + } + return view('admin.regularcontracts.edit', [ + 'row' => $row, + 'contract_id' => $id, + ]); + } + + $v = Validator::make($request->all(), [ + 'user_id' => ['required', 'integer'], + 'park_id' => ['required', 'integer'], + // 任意項目 + 'contract_qr_id' => ['nullable', 'string', 'max:255'], + 'user_categoryid' => ['nullable', 'integer'], + 'reserve_id' => ['nullable', 'integer'], + 'price_parkplaceid' => ['nullable', 'integer'], + 'user_securitynum' => ['nullable', 'string', 'max:255'], + 'reserve_date' => ['nullable', 'date'], + 'contract_reserve' => ['nullable', 'string', 'max:255'], + 'contract_created_at' => ['nullable', 'date'], + 'contract_updated_at' => ['nullable', 'date'], + 'contract_cancelday' => ['nullable', 'date'], + 'contract_flag' => ['nullable', 'integer'], + 'contract_permission' => ['nullable', 'integer'], + 'contract_cancel_flag' => ['nullable', 'integer'], + 'tag_qr_flag' => ['nullable', 'integer'], + 'park_position' => ['nullable', 'string', 'max:255'], + 'ope_id' => ['nullable', 'integer'], + ]); + + if ($v->fails()) { + return back()->withErrors($v)->withInput(); + } + + $data = [ + 'contract_qr_id' => $request->input('contract_qr_id'), + 'user_id' => (int) $request->input('user_id'), + 'user_categoryid' => $request->input('user_categoryid'), + 'reserve_id' => $request->input('reserve_id'), + 'park_id' => (int) $request->input('park_id'), + 'price_parkplaceid' => $request->input('price_parkplaceid'), + 'user_securitynum' => $request->input('user_securitynum'), + 'reserve_date' => $request->input('reserve_date'), + 'contract_reserve' => $request->input('contract_reserve'), + 'contract_created_at' => $request->input('contract_created_at'), + 'contract_updated_at' => $request->input('contract_updated_at'), + 'contract_cancelday' => $request->input('contract_cancelday'), + 'contract_flag' => $request->input('contract_flag'), + 'contract_permission' => $request->input('contract_permission'), + 'contract_cancel_flag' => $request->input('contract_cancel_flag'), + 'tag_qr_flag' => $request->input('tag_qr_flag'), + 'park_position' => $request->input('park_position'), + 'ope_id' => $request->input('ope_id'), + 'updated_at' => now(), + ]; + + DB::table('regular_contract')->where('contract_id', $id)->update($data); + + return redirect()->route('regularcontracts')->with('success', '定期契約を更新しました。'); + } + + /** + * 定期契約削除 + * - 物理削除(必要なら cancel フラグ運用に切替) + */ + public function delete(Request $request) + { + $id = (int) $request->input('id'); + DB::table('regular_contract')->where('contract_id', $id)->delete(); + + // 例:論理削除運用にする場合(必要なら運用側で切替) + // DB::table('regular_contract')->where('contract_id', $id)->update([ + // 'contract_cancel_flag' => 1, + // 'contract_cancelday' => now(), + // 'updated_at' => now(), + // ]); + + return redirect()->route('regularcontracts')->with('success', '定期契約を削除しました。'); + } + + /** + * 定期契約インポート(仮実装) + */ + public function import(Request $request) + { + if ($request->isMethod('get')) { + // GET で来たら一覧へ + return redirect()->route('regularcontracts'); + } + + // ファイル必須 & 形式チェック + $request->validate([ + 'file' => ['required', 'file', 'mimetypes:text/plain,text/csv,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'], + ], [], [ + 'file' => 'インポートファイル', + ]); + + $file = $request->file('file'); + + // TODO: ここで実際のインポート処理(CSV/XLSXの解析とレコード登録)を書く + // 例:Storage::putFile('imports', $file); で一旦保存してバッチに回す etc. + + return redirect()->route('regularcontracts')->with('success', 'インポートを受け付けました。'); + } + + + + /** + * 定期契約エクスポート(仮実装) + * - 現時点では何もしません。ルーティング確認用のプレーンテキストを返します。 + * - 後で CSV / Excel 出力処理に置き換えてください。 + */ + + public function export(Request $request) + { + // ── 出力タイプ(通常 / SMBC / 役所) ────────────────────────────── + $type = $request->query('type'); // null | smbc | city + + // ── 出力ファイル名 ─────────────────────────────────────────────── + $downloadName = '定期契約マスタ.csv'; + if ($type === 'smbc') + $downloadName = '定期契約マスタ_SMBC.csv'; + if ($type === 'city') + $downloadName = '定期契約マスタ_役所提出用.csv'; + + // ── 生成先(storage/app/tmp 配下の一時ファイル) ───────────────── + $tmpDir = storage_path('app/tmp'); + if (!is_dir($tmpDir)) { + @mkdir($tmpDir, 0755, true); + } + $tmpPath = $tmpDir . '/' . uniqid('regularcontracts_', true) . '.csv'; + + // ── CSV を作成(Excel を考慮し UTF-8 BOM を付与) ─────────────── + $fp = fopen($tmpPath, 'w+'); + if ($fp === false) { + abort(500, 'CSV一時ファイルを作成できませんでした。'); + } + // Excel 対策:BOM + fwrite($fp, "\xEF\xBB\xBF"); + + // ヘッダー行(必要に応じて列を増減) + fputcsv($fp, ['定期契約ID', '利用者ID', '駐輪場ID', '契約日時']); + + // ── データ取得(大量件数に備え chunk で分割取得) ──────────────── + // ※ list() と同等の JOIN/SELECT を最低限に簡略化 + DB::table('regular_contract as rc') + ->leftJoin('user as u', 'u.user_id', '=', 'rc.user_id') + ->orderBy('rc.contract_id', 'asc') + ->select([ + 'rc.contract_qr_id', + 'rc.user_id', + 'rc.park_id', + 'rc.contract_created_at', + ]) + ->chunk(1000, function ($rows) use ($fp) { + foreach ($rows as $r) { + fputcsv($fp, [ + $r->contract_qr_id, + $r->user_id, + $r->park_id, + $r->contract_created_at, + ]); + } + }); + + fclose($fp); + + // ── ダウンロードレスポンス(送信後に一時ファイル削除) ──────────── + return response()->download( + $tmpPath, + $downloadName, + [ + 'Content-Type' => 'text/csv; charset=UTF-8', + 'Content-Disposition' => 'attachment; filename="' . $downloadName . '"', + 'Pragma' => 'no-cache', + 'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0', + 'Expires' => '0', + ] + )->deleteFileAfterSend(true); + } + + + + + // 追加:新規登録(GET: 画面表示 / POST: 登録実行) + public function add(Request $request) + { + // 画面表示 + if ($request->isMethod('get')) { + return view('admin.regularcontracts.add'); + } + + // ========= バリデーション ========= + // ※ 必須最小限。その他は任意(nullable) + $v = Validator::make( + $request->all(), + [ + 'user_id' => ['required', 'integer'], + 'park_id' => ['required', 'integer'], + 'contract_qr_id' => ['nullable', 'string', 'max:255'], + 'user_categoryid' => ['nullable', 'integer'], + 'reserve_id' => ['nullable', 'integer'], + 'price_parkplaceid' => ['nullable', 'integer'], + 'reserve_date' => ['nullable', 'date'], + 'contract_created_at' => ['nullable', 'date'], + 'contract_cancelday' => ['nullable', 'date'], + 'contract_permission' => ['nullable', 'integer'], + 'contract_cancel_flag' => ['nullable', 'integer'], + 'tag_qr_flag' => ['nullable', 'integer'], + 'update_flag' => ['nullable', 'integer'], + 'park_position' => ['nullable', 'string', 'max:255'], + 'ope_id' => ['nullable', 'integer'], + // 画面の「定期有効月数」は DB の contract_valid_months に保存する + 'enable_months' => ['nullable', 'integer', 'min:0'], + ], + [], + [ + 'user_id' => '利用者ID', + 'park_id' => '駐輪場ID', + 'contract_qr_id' => '定期契約QRID', + 'user_categoryid' => '利用者分類ID', + 'reserve_id' => '定期予約ID', + 'price_parkplaceid' => '駐輪場所ID', + 'reserve_date' => '予約日時', + 'contract_created_at' => '契約日時', + 'contract_cancelday' => '解約日時', + 'contract_permission' => 'シール発行許可', + 'contract_cancel_flag' => '解約フラグ', + 'tag_qr_flag' => 'タグ・QR', + 'update_flag' => '(更新元)契約更新済フラグ', + 'park_position' => '駐輪位置番号', + 'ope_id' => 'オペレータID', + 'enable_months' => '定期有効月数', + ] + ); + + if ($v->fails()) { + return back()->withErrors($v)->withInput(); + } + + // ========= 登録データ作成 ========= + // ここでは「regular_contract」テーブルに確実にある列を中心に保存します。 + // 追加したい列があれば、同様にキーを増やして下さい。 + $data = [ + 'contract_qr_id' => $request->input('contract_qr_id'), + 'user_id' => (int) $request->input('user_id'), + 'user_categoryid' => $request->input('user_categoryid'), + 'reserve_id' => $request->input('reserve_id'), + 'park_id' => (int) $request->input('park_id'), + 'price_parkplaceid' => $request->input('price_parkplaceid'), + 'reserve_date' => $request->input('reserve_date'), + 'contract_created_at' => $request->input('contract_created_at') ?: now(), // 未指定なら現在時刻 + 'contract_cancelday' => $request->input('contract_cancelday'), + 'contract_permission' => $request->input('contract_permission'), + 'contract_cancel_flag' => $request->input('contract_cancel_flag'), + 'tag_qr_flag' => $request->input('tag_qr_flag'), + 'update_flag' => $request->input('update_flag'), + 'park_position' => $request->input('park_position'), + 'ope_id' => $request->input('ope_id'), + // 画面の enable_months → DB の contract_valid_months + 'contract_valid_months' => $request->input('enable_months'), + 'created_at' => now(), + 'updated_at' => now(), + ]; + + DB::table('regular_contract')->insert($data); + + return redirect() + ->route('regularcontracts') + ->with('success', '定期契約を登録しました。'); + } + + + +} diff --git a/app/Http/Controllers/Admin/RegularContractController_bk.php b/app/Http/Controllers/Admin/RegularContractController_bk.php new file mode 100644 index 0000000..a5d05cd --- /dev/null +++ b/app/Http/Controllers/Admin/RegularContractController_bk.php @@ -0,0 +1,408 @@ + 0, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + 'page' => $request->get('page', 1), + ]; + $inputs['list'] = RegularContract::search($inputs); + //dd($inputs['list']->items()); + +// dd($inputs); + if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) { + return redirect()->route('regular_contracts'); + } + return view('admin.regular_contracts.list', $inputs); + } + + public function add(Request $request) + { + $inputs = [ + 'contract_qr_id' => $request->input('contract_qr_id'), // 定期契約QRID + 'user_id' => $request->input('user_id'), // 利用者ID + 'user_categoryid' => $request->input('user_categoryid'), // 利用者分類ID + 'reserve_id' => $request->input('reserve_id'), // 定期予約ID + 'park_id' => $request->input('park_id'), // 駐輪場ID + 'price_parkplaceid' => $request->input('price_parkplaceid'), // 駐輪場所ID + 'user_securitynum' => $request->input('user_securitynum'), // 防犯登録番号 + 'reserve_date' => $request->input('reserve_date'), // 予約日時 + 'contract_reserve' => $request->input('contract_reserve'), // 予約移行フラグ + 'contract_created_at' => $request->input('contract_created_at'), // 契約日時 + 'contract_updated_at' => $request->input('contract_updated_at'), // 更新可能日 + 'contract_cancelday' => $request->input('contract_cancelday'), // 解約日時 + 'contract_reduction' => $request->input('contract_reduction'), // 減免措置 + 'contract_periods' => $request->input('contract_periods'), // 有効期間S + 'contract_periode' => $request->input('contract_periode'), // 有効期間E + 'contract_taxid' => $request->input('contract_taxid'), // 消費税ID + 'billing_amount' => $request->input('billing_amount'), // 請求金額 + 'contract_payment_day' => $request->input('contract_payment_day'), // 授受日時 + 'contract_money' => $request->input('contract_money'), // 授受金額 + 'refunds' => $request->input('refunds'), // 解約時返戻金 + 'refunds_comment' => $request->input('refunds_comment'), // 返戻金付随情報 + 'repayment_at' => $request->input('repayment_at'), // 返金日 + 'contact_guid' => $request->input('contact_guid'), // 決済コード + 'contact_shop_code' => $request->input('contact_shop_code'), // 店舗コード + 'contract_cvs_class' => $request->input('contract_cvs_class'), // 授受種別 + 'contract_flag' => $request->input('contract_flag'), // 授受フラグ + 'settlement_transaction_id' => $request->input('settlement_transaction_id'), // 決済トランザクションID + 'contract_seal_issue' => $request->input('contract_seal_issue'), // シール発行数 + 'seal_reissue_request' => $request->input('seal_reissue_request'), // シール再発行リクエスト + 'contract_permission' => $request->input('contract_permission'), // シール発行許可 + 'contract_cancel_flag' => $request->input('contract_cancel_flag'), // 解約フラグ + 'tag_qr_flag' => $request->input('tag_qr_flag'), // タグ/QRフラグ + 'tag_change_flag' => $request->input('tag_change_flag'), // オペレータータグ変更フラグ + 'park_position' => $request->input('park_position'), // 駐輪位置番号 + 'ope_id' => $request->input('ope_id'), // オペレータID + 'contract_manual' => $request->input('contract_manual'), // 手動通知 + 'contract_notice' => $request->input('contract_notice'), // 通知方法 + 'contract_payment_number' => $request->input('contract_payment_number'), // 受付番号 + 'created_at' => $request->input('created_at'), + 'updated_at' => $request->input('updated_at'), + ]; + $dataList = $this->getDataDropList(); + $inputs = array_merge($inputs, $dataList); + if ($request->isMethod('POST')) { + $type = false; + $validation = new RegularContractRequest(); + $rules = $validation->rules(); + if(!empty($inputs['billing_amount']) ){ + $rules['billing_amount'] = 'numeric|between:0,999999999999.99'; + } + if(!empty($inputs['contract_money']) ){ + $rules['contract_money'] = 'numeric|between:0,999999999999.99'; + } + if(!empty($inputs['user_aid']) ){ + $rules['refunds'] ='numeric|between:0,999999999999.99'; + } + if(!empty($inputs['settlement_transaction_id']) ){ + $rules['settlement_transaction_id'] = 'integer'; + } + if(!empty($inputs['contract_seal_issue']) ){ + $rules['contract_seal_issue'] = 'integer'; + } + if(!empty($inputs['ope_id']) ){ + $rules['ope_id'] = 'integer'; + } + $validator = Validator::make($request->all(), $rules, $validation->messages()); + if (!$validator->fails()) { + \DB::transaction(function () use ($inputs, &$type) { + $new = new RegularContract(); + $new->fill($inputs); + if ($new->save()) { + $type = true; + } + + }); + if ($type) { + $request->session()->flash('success', __('新しい成功を創造する。')); + return redirect()->route('regular_contracts'); + } else { + $request->session()->flash('error', __('新しい作成に失敗しました')); + } + } else { + $inputs['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + + return view('admin.regular_contracts.add', $inputs); + } + + public function edit(Request $request, $contract_id, $view = '') + { + $regular_contract = RegularContract::getByPk($contract_id); + if (empty($contract_id) || empty($regular_contract)) { + abort('404'); + } + $data = $regular_contract->getAttributes(); + $dataList = $this->getDataDropList(); + $data = array_merge($data, $dataList); + if ($request->isMethod('POST')) { + $type = false; + $inputs = $request->all(); + $validation = new RegularContractRequest(); + $rules = $validation->rules(); + if(!empty($inputs['billing_amount']) ){ + $rules['billing_amount'] = 'numeric|between:0,999999999999.99'; + } + if(!empty($inputs['contract_money']) ){ + $rules['contract_money'] = 'numeric|between:0,999999999999.99'; + } + if(!empty($inputs['user_aid']) ){ + $rules['refunds'] ='numeric|between:0,999999999999.99'; + } + if(!empty($inputs['settlement_transaction_id']) ){ + $rules['settlement_transaction_id'] = 'integer'; + } + if(!empty($inputs['contract_seal_issue']) ){ + $rules['contract_seal_issue'] = 'integer'; + } + if(!empty($inputs['ope_id']) ){ + $rules['ope_id'] = 'integer'; + } + $validator = Validator::make($inputs, $rules, $validation->messages()); + $data = array_merge($data, $inputs); + if (!$validator->fails()) { + \DB::transaction(function () use ($data, &$type, $regular_contract) { + $regular_contract->fill($data); + $regular_contract->save(); + $type = true; + }); + if ($type) { + $request->session()->flash('success', __('更新に成功しました')); + return redirect()->route('regular_contracts'); + } else { + $request->session()->flash('error', __('更新に失敗しました')); + } + } else { + $data['errorMsg'] = $this->__buildErrorMessasges($validator); + } + } + if ($view != '') { + return view($view, $data); + } + return view('admin.regular_contracts.edit', $data); + } + + public function delete(Request $request) + { + $arr_pk = $request->get('pk'); + if ($arr_pk) { + if (RegularContract::deleteByPk($arr_pk)) { + return redirect()->route('regular_contracts')->with('success', __("削除が完了しました。")); + } else { + return redirect()->route('regular_contracts')->with('error', __('削除に失敗しました。')); + } + } + return redirect()->route('regular_contracts')->with('error', __('削除するユーザーを選択してください。')); + } + + public function info(Request $request, $contract_id) + { + return $this->edit($request, $contract_id, 'admin.regular_contracts.info'); + } + + public function getDataDropList() + { + $data['users'] = User::getList(); + $data['listUserType'] = Usertype::getList(); + $data['park'] = Park::getList(); + return $data; + } + + + public function export(Request $request) + { + + $headers = array( + "Content-type" => "text/csv;charset=UTF-8", + 'Content-Encoding: UTF-8', + "Content-Disposition" => "attachment; filename=file.csv", + "Pragma" => "no-cache", + "Cache-Control" => "must-revalidate, post-check=0, pre-check=0", + "Expires" => "0" + ); + $inputs = [ + 'isMethodPost' => 0, + 'isExport' => 1, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + + ]; + + $dataExport = RegularContract::search($inputs); + $columns = array( + __('定期契約ID'), + __('定期契約QRID'),// 1 + __('利用者ID'),// 2 + __('利用者分類ID'),// 3 + __('定期予約ID'),// 4 + __('駐輪場ID'),// 5 + __('駐輪場所ID'),// 6 + __('防犯登録番号'),// 7 + __('予約日時'),// 8 + __('予約移行フラグ'),// 9 + __('契約日時'),// 10 + __('更新可能日'),// 11 + __('解約日時'),// 12 + __('減免措置'),// 13 + __('有効期間S'),// 14 + __('有効期間E'),// 15 + __('消費税ID'),// 16 + __('請求金額'),// 17 + __('授受日時'),// 18 + __('授受金額'),// 19 + __('解約時返戻金'),// 20 + __('返戻金付随情報'),// 21 + __('返金日'),// 22 + __('決済コード'),// 23 + __('店舗コード'),// 24 + __('授受種別'),// 25 + __('授受フラグ'),// 26 + __('決済トランザクションID'),// 27 + __('シール発行数'),// 28 + __('シール再発行リクエスト'),// 29 + __('シール発行許可'),// 30 + __('解約フラグ'),// 31 + __('タグ/QRフラグ'),// 32 + __('オペレータータグ変更フラグ'),// 33 + __('駐輪位置番号'),// 34 + __('オペレータID'),// 35 + __('手動通知'),// 36 + __('通知方法'),// 37 + __('受付番号'),// 38 + ); + $filename = "定期契約マスタ.csv"; + $file = fopen($filename, 'w+'); + fputcsv($file, $columns); + foreach ($dataExport as $items) { + fputcsv($file, array( + $items->contract_id, // 0 + $items->contract_qr_id, // 1 + $items->user_id, // 2 + $items->user_categoryid, // 3 + $items->reserve_id, // 4 + $items->park_id, // 5 + $items->price_parkplaceid, // 6 + $items->user_securitynum, // 7 + $items->reserve_date, // 8 + $items->contract_reserve, // 9 + $items->contract_created_at, // 10 + $items->contract_updated_at, // 11 + $items->contract_cancelday, // 12 + $items->contract_reduction, // 13 + $items->contract_periods, // 14 + $items->contract_periode, // 15 + $items->contract_taxid, // 16 + $items->billing_amount, // 17 + $items->contract_payment_day, // 18 + $items->contract_money, // 19 + $items->refunds, // 20 + $items->refunds_comment, // 21 + $items->repayment_at, // 22 + $items->contact_guid, // 23 + $items->contact_shop_code, // 24 + $items->contract_cvs_class, // 25 + $items->contract_flag, // 26 + $items->settlement_transaction_id, // 27 + $items->contract_seal_issue, // 28 + $items->seal_reissue_request, // 29 + $items->contract_permission, // 30 + $items->contract_cancel_flag, // 31 + $items->tag_qr_flag, // 32 + $items->tag_change_flag, // 33 + $items->park_position, // 34 + $items->ope_id, // 35 + $items->contract_manual, // 36 + $items->contract_notice, // 37 + $items->contract_payment_number, // 38 + ) + ); + } + fclose($file); + return Response::download($filename, $filename, $headers); + } + + public function import(Request $request) + { + $file = $request->file('file'); + if (!empty($file)) { + $data = Utils::csvToArray($file); + $type = 1; + $msg = ''; + $record = 0; + DB::beginTransaction(); + try { + RegularContract::query()->delete(); + $col = 39; + foreach ($data as $key => $items) { + $record = $key + 2; + if (count($items) == $col) { + $row = new RegularContract(); + $row->contract_id = $items[0]; + $row->contract_qr_id = $items[1]; + $row->user_id = $items[2]; + $row->user_categoryid = $items[3]; + $row->reserve_id = $items[4]; + $row->park_id = $items[5]; + $row->price_parkplaceid = $items[6]; + $row->user_securitynum = $items[7]; + $row->reserve_date = $items[8]; + $row->contract_reserve = $items[9]; + $row->contract_created_at = $items[10]; + $row->contract_updated_at = $items[11]; + $row->contract_cancelday = $items[12]; + $row->contract_reduction = $items[13]; + $row->contract_periods = $items[14]; + $row->contract_periode = $items[15]; + $row->contract_taxid = $items[16]; + $row->billing_amount = $items[17]; + $row->contract_payment_day = $items[18]; + $row->contract_money = $items[19]; + $row->refunds = $items[20]; + $row->refunds_comment = $items[21]; + $row->repayment_at = $items[22]; + $row->contact_guid = $items[23]; + $row->contact_shop_code = $items[24]; + $row->contract_cvs_class = $items[25]; + $row->contract_flag = $items[26]; + $row->settlement_transaction_id = $items[27]; + $row->contract_seal_issue = $items[28]; + $row->seal_reissue_request = $items[29]; + $row->contract_permission = $items[30]; + $row->contract_cancel_flag = $items[31]; + $row->tag_qr_flag = $items[32]; + $row->tag_change_flag = $items[33]; + $row->park_position = $items[34]; + $row->ope_id = $items[35]; + $row->contract_manual = $items[36]; + $row->contract_notice = $items[37]; + $row->contract_payment_number = $items[38]; + 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('regular_contracts')->with('success', __('輸入成功')); + } else { + DB::rollBack(); + return redirect()->route('regular_contracts')->with('error', __($msg, ['record' => $record])); + } + } else { + return redirect()->route('regular_contracts')->with('error', __('あなたはcsvファイルを選択していません。')); + } + } +} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/ReservationController.php b/app/Http/Controllers/Admin/ReservationController.php new file mode 100644 index 0000000..99510ff --- /dev/null +++ b/app/Http/Controllers/Admin/ReservationController.php @@ -0,0 +1,99 @@ +select([ + 'r.user_id', + 'u.user_name', + 'u.user_phonetic', + 'u.user_regident_zip', + 'u.user_regident_pre', + 'u.user_regident_city', + 'u.user_regident_add', + 'u.user_relate_zip', + 'u.user_relate_pre', + 'u.user_relate_city', + 'u.user_relate_add', + 'u.user_birthdate', + 'u.user_gender', + 'u.user_mobile', + 'u.user_homephone', + 'u.user_school', + 'u.user_graduate', + 'u.user_remarks', + 'r.reserve_id', + 'r.park_id', + 'p.park_name', + 'r.price_parkplaceid', + 'r.psection_id', + 'r.reserve_date', + 'r.reserve_reduction as reduction', + 'r.800m_flag as within_800m_flag', + ]) + ->leftJoin('user as u', 'r.user_id', '=', 'u.user_id') + ->leftJoin('park as p', 'r.park_id', '=', 'p.park_id'); // 追加 + + // フィルター条件 + if ($request->filled('park_id')) { + $q->where('r.park_id', $request->input('park_id')); + } + if ($request->filled('user_id')) { + $q->where('r.user_id', $request->input('user_id')); + } + if ($request->filled('user_categoryid')) { + $q->where('r.user_categoryid', $request->input('user_categoryid')); + } + if ($request->filled('user_tag_serial')) { + $q->where('u.user_tag_serial', 'like', '%' . $request->input('user_tag_serial') . '%'); + } + if ($request->filled('user_tag_serial_64')) { + $q->where('u.user_tag_serial_64', 'like', '%' . $request->input('user_tag_serial_64') . '%'); + } + if ($request->filled('user_phonetic')) { + $q->where('u.user_phonetic', 'like', '%' . $request->input('user_phonetic') . '%'); + } + if ($request->filled('user_mobile')) { + $q->where(function($sub) use ($request) { + $sub->where('u.user_mobile', 'like', '%' . $request->input('user_mobile') . '%') + ->orWhere('u.user_homephone', 'like', '%' . $request->input('user_mobile') . '%'); + }); + } + if ($request->filled('user_primemail')) { + $q->where('u.user_primemail', 'like', '%' . $request->input('user_primemail') . '%'); + } + if ($request->filled('user_workplace')) { + $q->where('u.user_workplace', 'like', '%' . $request->input('user_workplace') . '%'); + } + if ($request->filled('user_school')) { + $q->where('u.user_school', 'like', '%' . $request->input('user_school') . '%'); + } + + // ソート + $sort = $request->input('sort', 'r.reserve_id'); + $sortType = $request->input('sort_type', 'desc'); + $allowSorts = ['r.reserve_id', 'r.reserve_date', 'r.reserve_start', 'r.reserve_end']; + if (!in_array($sort, $allowSorts)) { + $sort = 'r.reserve_id'; + } + $sortType = ($sortType === 'asc') ? 'asc' : 'desc'; + + $rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString(); + + // 駐輪場リスト取得(必要なら) + $parks = DB::table('park')->select('park_id', 'park_name')->get(); + + return view('admin.reservation.list', compact('rows', 'sort', 'sortType', 'parks')); + } +} diff --git a/app/Http/Controllers/Admin/ReservesController.php b/app/Http/Controllers/Admin/ReservesController.php new file mode 100644 index 0000000..5d3c9eb --- /dev/null +++ b/app/Http/Controllers/Admin/ReservesController.php @@ -0,0 +1,309 @@ +input('sort', 'reserve_id'); + $sortType = strtolower($request->input('sort_type', 'desc')) === 'asc' ? 'asc' : 'desc'; + + // ── 絞り込み(必要最低限:利用者/駐輪場/期間)────────────────── + $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', '')); // 利用者名かな など + + // ── クエリ構築 ──────────────────────────────────────────────── + $q = DB::table('reserve as r') + ->leftJoin('user as u', 'u.user_id', '=', 'r.user_id') // user: user_name, user_phonetic 等【turn12file9†L26-L34】 + ->leftJoin('park as p', 'p.park_id', '=', 'r.park_id') // park: park_name 等【turn12file4†L17-L25】 + ->select([ + 'r.reserve_id', + 'r.contract_id', + 'r.user_id', + 'r.park_id', + 'r.price_parkplaceid', + 'r.psection_id', + 'r.reserve_date', + 'r.reserve_start', + 'r.reserve_end', + 'r.reserve_cancelday', + 'r.valid_flag', + 'r.ope_id', + 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'), + ]); + + if ($userId !== '') + $q->where('r.user_id', 'like', "%{$userId}%"); + if ($parkId !== '') + $q->where('r.park_id', 'like', "%{$parkId}%"); + + if ($fromDt) + $q->whereDate('r.reserve_date', '>=', $fromDt); + if ($toDt) + $q->whereDate('r.reserve_date', '<=', $toDt); + + if ($keyword !== '') { + $q->where(function ($w) use ($keyword) { + $w->where('u.user_name', 'like', "%{$keyword}%") + ->orWhere('u.user_phonetic', 'like', "%{$keyword}%"); + }); + } + + // ソート許可カラム(JOIN 先も含む) + $sortable = [ + 'reserve_id', + 'contract_id', + 'user_id', + 'park_id', + 'reserve_date', + 'reserve_start', + 'reserve_end', + 'reserve_cancelday', + 'valid_flag', + 'ope_id', + 'user_name', + 'user_phonetic', + 'user_mobile', + 'park_name', + ]; + if (!in_array($sort, $sortable, true)) + $sort = 'reserve_id'; + + $sortMap = [ + 'user_name' => 'u.user_name', + 'user_phonetic' => 'u.user_phonetic', + 'user_mobile' => 'u.user_mobile', + 'park_name' => 'p.park_name', + ]; + $sortCol = $sortMap[$sort] ?? ('r.' . $sort); + + $list = $q->orderBy($sortCol, $sortType)->paginate(50); + + 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, + ]); + } + + /** + * 予約追加(GET: 画面表示 / POST: 登録) + */ + public function add(Request $request) + { + if ($request->isMethod('get')) { + return view('admin.reserves.add'); + } + + // 予約の最低限バリデーション(必要に応じて追加) + $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(); + } + + DB::table('reserve')->insert([ + 'user_id' => (int) $request->input('user_id'), + 'park_id' => (int) $request->input('park_id'), + 'contract_id' => $request->input('contract_id'), // 任意:regular_contract と紐づける場合【turn12file7†L20-L28】 + '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'), + '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') + ->limit(5000) + ->pluck(DB::raw("concat(park_id, ' ', 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/UpdateCandidateController.php b/app/Http/Controllers/Admin/UpdateCandidateController.php new file mode 100644 index 0000000..b24ed1d --- /dev/null +++ b/app/Http/Controllers/Admin/UpdateCandidateController.php @@ -0,0 +1,104 @@ +select([ + 'rc.contract_id', + 'rc.contract_qr_id', + 'rc.user_id', + 'rc.user_categoryid', + 'rc.park_id', + 'rc.contract_created_at', + 'rc.contract_periods', + 'rc.contract_periode', + 'rc.tag_qr_flag', + 'rc.contract_flag', + 'rc.contract_cancel_flag', + 'rc.contract_payment_day', + 'rc.contract_money', + 'rc.billing_amount', + 'rc.contract_permission', + 'rc.contract_manual', + 'rc.contract_notice', + 'p.park_name', + 'u.user_name', + 'u.user_phonetic', + 'u.user_mobile', + 'u.user_homephone', + 'u.user_primemail', + 'u.user_gender', + 'u.user_birthdate', + 'u.user_regident_zip', + 'u.user_regident_pre', + 'u.user_regident_city', + 'u.user_regident_add', + 'u.user_relate_zip', + 'u.user_relate_pre', + 'u.user_relate_city', + 'u.user_relate_add', + 'u.user_graduate', + 'u.user_workplace', + 'u.user_school', + 'u.user_remarks', + ]) + ->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id') + ->leftJoin('user as u', 'rc.user_id', '=', 'u.user_id') + ->whereNull('rc.update_flag'); // 未更新のみ + + // 対象月による有効期限の絞り込み + if ($request->filled('target_month')) { + $now = now(); + switch ($request->input('target_month')) { + case 'last': + $start = $now->copy()->subMonth()->startOfMonth(); + $end = $now->copy()->subMonth()->endOfMonth(); + break; + case 'this': + $start = $now->copy()->startOfMonth(); + $end = $now->copy()->endOfMonth(); + break; + case 'next': + $start = $now->copy()->addMonth()->startOfMonth(); + $end = $now->copy()->addMonth()->endOfMonth(); + break; + case 'after2': + $start = $now->copy()->addMonths(2)->startOfMonth(); + $end = $now->copy()->addMonths(2)->endOfMonth(); + break; + default: + $start = null; + $end = null; + } + if ($start && $end) { + $q->whereBetween('rc.contract_periode', [$start->toDateString(), $end->toDateString()]); + } + } + + $sort = $request->input('sort', 'rc.contract_id'); + $sortType = $request->input('sort_type', 'desc'); + $allowSorts = ['rc.contract_id']; + if (!in_array($sort, $allowSorts)) { + $sort = 'rc.contract_id'; + } + $sortType = ($sortType === 'asc') ? 'asc' : 'desc'; + + $rows = $q->orderBy($sort, $sortType)->paginate(20)->withQueryString(); + + // 駐輪場リスト(プルダウン用) + $parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get(); + + return view('admin.update_candidate.list', compact('rows', 'sort', 'sortType', 'parks')); + } +} diff --git a/app/Http/Controllers/Admin/UsersController.php b/app/Http/Controllers/Admin/UsersController.php new file mode 100644 index 0000000..426a624 --- /dev/null +++ b/app/Http/Controllers/Admin/UsersController.php @@ -0,0 +1,318 @@ +input('sort', 'user_seq'); + $sortType = strtolower($request->input('sort_type', 'desc')) === 'asc' ? 'asc' : 'desc'; + if (!in_array($sort, $sortable, true)) { + $sort = 'user_seq'; + } + + // ▼ 絞り込み値('' のときだけ無視。'0' は有効値として扱う) + $user_id = trim((string) $request->input('user_id', '')); + $member_id = trim((string) $request->input('member_id', '')); + $user_tag_serial = trim((string) $request->input('user_tag_serial', '')); + $user_phonetic = trim((string) $request->input('user_phonetic', '')); + $phone = trim((string) $request->input('phone', '')); // 携帯/自宅の両方対象 + $crime = trim((string) $request->input('crime', '')); // 防犯登録番号(暫定: qr_code) + $user_categoryid = (string) $request->input('user_categoryid', ''); + $tag_qr_flag = (string) $request->input('tag_qr_flag', ''); // 0=タグ / 1=QR + $quit_flag = (string) $request->input('quit_flag', ''); // 0=いいえ / 1=はい + $quit_from = (string) $request->input('quit_from', ''); // YYYY-MM-DD + $quit_to = (string) $request->input('quit_to', ''); // YYYY-MM-DD + + // ▼ ベースクエリ(一覧で使う列が多いので一旦 * を許容) + $query = DB::table('user')->select('user.*'); + + // ▼ テキスト系 + if ($user_id !== '') + $query->where('user.user_id', 'like', "%{$user_id}%"); + if ($member_id !== '') + $query->where('user.member_id', 'like', "%{$member_id}%"); + if ($user_tag_serial !== '') + $query->where('user.user_tag_serial', 'like', "%{$user_tag_serial}%"); + if ($user_phonetic !== '') + $query->where('user.user_phonetic', 'like', "%{$user_phonetic}%"); + if ($phone !== '') { + $query->where(function ($w) use ($phone) { + $w->where('user.user_mobile', 'like', "%{$phone}%") + ->orWhere('user.user_homephone', 'like', "%{$phone}%"); + }); + } + if ($crime !== '') { + // ※ dump に防犯登録番号の明確なカラムが無いため暫定的に qr_code を対象 + $query->where('user.qr_code', 'like', "%{$crime}%"); + } + + // ▼ セレクト/ラジオ('' 以外なら適用。'0' も通す) + if ($user_categoryid !== '') + $query->where('user.user_categoryid', $user_categoryid); + if ($tag_qr_flag !== '') + $query->where('user.tag_qr_flag', (int) $tag_qr_flag); + if ($quit_flag !== '') + $query->where('user.user_quit_flag', (int) $quit_flag); + + // ▼ 日付範囲(退会日) + if ($quit_from !== '') + $query->where('user.user_quitday', '>=', $quit_from); + if ($quit_to !== '') + $query->where('user.user_quitday', '<=', $quit_to); + + // ▼ 並び & ページング + $list = $query->orderBy("user.{$sort}", $sortType)->paginate(20); + + // ▼ 画面に渡す(フォーム再描画用に絞り込み値も) + return view('admin.users.list', [ + 'list' => $list, + 'sort' => $sort, + 'sort_type' => $sortType, + 'user_id' => $user_id, + 'member_id' => $member_id, + 'user_tag_serial' => $user_tag_serial, + 'user_phonetic' => $user_phonetic, + 'phone' => $phone, + 'crime' => $crime, + 'user_categoryid' => $user_categoryid, + 'tag_qr_flag' => $tag_qr_flag, + 'quit_flag' => $quit_flag, + 'quit_from' => $quit_from, + 'quit_to' => $quit_to, + ]); + } + + /** + * CSV 出力(一覧と同じ絞り込みを適用) + */ + public function export(Request $request): StreamedResponse + { + $q = DB::table('user'); + + // ▼ テキスト系 + if (($v = trim((string) $request->input('user_id', ''))) !== '') + $q->where('user_id', 'like', "%{$v}%"); + + if (($v = trim((string) $request->input('user_tag_serial', ''))) !== '') + $q->where('user_tag_serial', 'like', "%{$v}%"); + + if (($v = trim((string) $request->input('user_phonetic', ''))) !== '') + $q->where('user_phonetic', 'like', "%{$v}%"); + + if (($v = trim((string) $request->input('phone', ''))) !== '') { + $q->where(function ($w) use ($v) { + $w->where('user_mobile', 'like', "%{$v}%") + ->orWhere('user_homephone', 'like', "%{$v}%"); + }); + } + + if (($v = trim((string) $request->input('email', ''))) !== '') + $q->where('user_primemail', 'like', "%{$v}%"); + + // ▼ セレクト/ラジオ('' だけスキップ。'0' は適用) + $val = (string) $request->input('user_categoryid', ''); + if ($val !== '') + $q->where('user_categoryid', $val); + + $val = (string) $request->input('tag_qr_flag', ''); + if ($val !== '') + $q->where('tag_qr_flag', (int) $val); + + $val = (string) $request->input('quit_flag', ''); + if ($val !== '') + $q->where('user_quit_flag', (int) $val); + + // ▼ 退会日 範囲 + if (($from = (string) $request->input('quit_from', '')) !== '') + $q->where('user_quitday', '>=', $from); + if (($to = (string) $request->input('quit_to', '')) !== '') + $q->where('user_quitday', '<=', $to); + + // ▼ 取得・並び + $q->orderBy('user_seq', 'desc'); + + $rows = $q->get([ + 'user_id', + 'tag_qr_flag', + 'user_categoryid', + 'user_name', + 'user_phonetic', + 'user_birthdate', + 'user_age', + 'user_mobile', + 'user_homephone', + 'user_primemail', + 'user_idcard', + 'user_idcard_chk_flag', + 'user_chk_day', + 'user_quit_flag', + 'user_quitday', + ]); + + $headers = [ + '利用者ID', + 'タグ/QRフラグ', + '利用者分類ID', + '利用者名', + 'フリガナ', + '生年月日', + '年齢', + '携帯電話番号', + '自宅電話番号', + 'メールアドレス', + '本人確認書類', + '本人確認チェック済', + '本人確認日時', + '退会フラグ', + '退会日', + ]; + + $filename = 'users_' . date('Ymd_His') . '.csv'; + + return response()->streamDownload(function () use ($headers, $rows) { + // ▼ BOM(Excel対策) + echo "\xEF\xBB\xBF"; + $out = fopen('php://output', 'w'); + + fputcsv($out, $headers); + + foreach ($rows as $r) { + // ▼ 表示値変換 + $tagQr = ((int) $r->tag_qr_flag === 1) ? 'QR' : 'タグ'; + $idChk = ((int) ($r->user_idcard_chk_flag ?? 0) === 1) ? '手動チェックOK' : '未チェック'; + $quitFlg = ((int) $r->user_quit_flag === 1) ? 'はい' : 'いいえ'; + $birth = $r->user_birthdate ? mb_substr($r->user_birthdate, 0, 10) : ''; + $chkDay = $r->user_chk_day ? mb_substr($r->user_chk_day, 0, 10) : ''; + $quitDay = $r->user_quitday ? mb_substr($r->user_quitday, 0, 10) : ''; + + fputcsv($out, [ + $r->user_id, + $tagQr, + $r->user_categoryid, + $r->user_name, + $r->user_phonetic, + $birth, + $r->user_age, + $r->user_mobile, + $r->user_homephone, + $r->user_primemail, + $r->user_idcard, + $idChk, + $chkDay, + $quitFlg, + $quitDay, + ]); + } + fclose($out); + }, $filename, [ + 'Content-Type' => 'text/csv; charset=UTF-8', + 'Content-Disposition' => 'attachment; filename="' . $filename . '"', + ]); + } + + /** + * 利用者登録(GET: 画面表示 / POST: 登録実行) + * - 必須は最小限(user_id, user_name, user_gender, user_primemail) + * - created_at/updated_at は DB 側に任せるかここで now() を入れてもOK + */ + public function add(Request $request) + { + if ($request->isMethod('get')) { + return view('admin.users.add'); + } + + + // ▼ バリデーション(user_id は半角数字のみ) + $rules = [ + 'user_id' => ['required', 'regex:/^\d+$/'], // 半角数字のみ許可 + 'user_name' => ['required', 'string', 'max:255'], + // 任意 + 'user_primemail' => ['nullable', 'email', 'max:255'], + 'user_gender' => ['nullable', 'in:男性,女性'], + 'member_id' => ['nullable', 'string', 'max:255'], + 'user_mobile' => ['nullable', 'string', 'max:255'], + 'user_homephone' => ['nullable', 'string', 'max:255'], + 'user_birthdate' => ['nullable', 'date'], + 'user_categoryid' => ['nullable', 'integer'], + ]; + + // ▼ エラーメッセージ(日本語) + $messages = [ + 'user_id.required' => '利用者IDは必須です。', + 'user_id.regex' => '利用者IDは半角数字のみで入力してください。', + ]; + + // ▼ 属性名(日本語ラベル) + $attributes = [ + 'user_id' => '利用者ID', + 'user_name' => '氏名', + 'user_gender' => '性別', + 'user_primemail' => '主メール', + ]; + + $v = Validator::make($request->all(), $rules, $messages, $attributes); + + if ($v->fails()) { + return back()->withErrors($v)->withInput(); + } + + // 実在カラム名に合わせて挿入(不要なら削る/必要なら増やす) + $data = [ + 'user_id' => $request->input('user_id'), + 'user_name' => $request->input('user_name'), + 'user_gender' => $request->input('user_gender'), + 'user_primemail' => $request->input('user_primemail'), + 'member_id' => $request->input('member_id'), + 'user_mobile' => $request->input('user_mobile'), + 'user_homephone' => $request->input('user_homephone'), + 'user_birthdate' => $request->input('user_birthdate'), + 'user_categoryid' => $request->input('user_categoryid'), + 'created_at' => now(), + 'updated_at' => now(), + ]; + + DB::table('user')->insert($data); + + return redirect()->route('users')->with('success', '利用者を登録しました。'); + } + +} diff --git a/app/Http/Controllers/Admin/UsertypeController.php b/app/Http/Controllers/Admin/UsertypeController.php new file mode 100644 index 0000000..424b3a1 --- /dev/null +++ b/app/Http/Controllers/Admin/UsertypeController.php @@ -0,0 +1,291 @@ + 0, + 'isExport' => 0, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + 'page' => $request->get('page', 1), + + ]; + $inputs['isMethodPost'] = $request->isMethod('post'); + $inputs['list'] = Usertype::search($inputs); + if ($inputs['list']->total() > 0 && $inputs['page'] > $inputs['list']->lastPage()) { + return redirect()->route('usertypes'); + } + return view('admin.usertypes.list', $inputs); + } + + public function add(Request $request) + { + // 画面に戻すための初期値 + $viewData = [ + 'sort_order' => old('sort_order', ''), + 'category_name1' => old('category_name1', ''), + 'category_name2' => old('category_name2', ''), + 'category_name3' => old('category_name3', ''), + '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'), + 'category_name1' => $request->input('category_name1'), + 'category_name2' => $request->input('category_name2'), + 'category_name3' => $request->input('category_name3'), + 'print_name' => $request->input('print_name'), + 'usertype_money' => $request->input('usertype_money'), + 'usertype_remarks' => $request->input('usertype_remarks'), + ]; + + // バリデーションルール(最小限) + $rules = [ + 'sort_order' => 'nullable|integer', + 'category_name1' => 'nullable|string|max:255', + 'category_name2' => 'nullable|string|max:255', + 'category_name3' => 'nullable|string|max:255', + 'print_name' => 'required|string|max:255', + 'usertype_money' => 'nullable|string|max:255', + 'usertype_remarks' => 'nullable|string|max:255', + ]; + $messages = [ + 'print_name.required' => '印字名は必須です。', + 'sort_order.integer' => 'ソートオーダーは数値で入力してください。', + ]; + + $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) + { + $usertype = Usertype::findOrFail($id); + + // 画面に渡す初期データ(既存の構成に合わせて attributes を使う) + $data = $usertype->getAttributes(); + if (method_exists($this, 'getDataDropList')) { + $dataList = $this->getDataDropList(); + $data = array_merge($data, $dataList); + } + + if ($request->isMethod('POST')) { + $type = false; + + // ▼ 内蔵バリデーション(FormRequest を使わない) + $rules = [ + 'sort_order' => 'nullable|integer', + 'category_name1' => 'nullable|string|max:255', + 'category_name2' => 'nullable|string|max:255', + 'category_name3' => 'nullable|string|max:255', + 'print_name' => 'required|string|max:255', + 'usertype_money' => 'nullable|string|max:255', + 'usertype_remarks' => 'nullable|string|max:255', + ]; + $messages = [ + 'print_name.required' => '印字名は必須です。', + 'sort_order.integer' => 'ソートオーダーは数値で入力してください。', + ]; + + $validator = Validator::make($request->all(), $rules, $messages); + + // 入力値を $data にマージ(既存ロジック踏襲) + $requestAll = $request->all(); + $data = array_merge($data, $requestAll); + + if ($validator->fails()) { + return back()->withErrors($validator)->withInput(); + } + + \DB::transaction(function () use ($data, &$type, $usertype) { + // fill するフィールドだけを明示したい場合は only(...) で絞ってもOK + $usertype->fill([ + 'sort_order' => $data['sort_order'] ?? null, + 'category_name1' => $data['category_name1'] ?? null, + 'category_name2' => $data['category_name2'] ?? null, + 'category_name3' => $data['category_name3'] ?? null, + 'print_name' => $data['print_name'] ?? null, + 'usertype_money' => $data['usertype_money'] ?? null, + 'usertype_remarks' => $data['usertype_remarks'] ?? null, + ]); + $usertype->save(); + $type = true; + }); + + if ($type) { + return redirect()->route('usertypes')->with('success', '更新しました。'); + } + return back()->with('error', '更新に失敗しました。')->withInput(); + } + + // 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', '削除するユーザーを選択してください。'); + } + + 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) + { + + $headers = array( + "Content-type" => "text/csv;charset=UTF-8", + 'Content-Encoding: UTF-8', + "Content-Disposition" => "attachment; filename=file.csv", + "Pragma" => "no-cache", + "Cache-Control" => "must-revalidate, post-check=0, pre-check=0", + "Expires" => "0" + ); + $inputs = [ + 'isMethodPost' => 0, + 'isExport' => 1, + 'sort' => $request->input('sort', ''), + 'sort_type' => $request->input('sort_type', ''), + + ]; + + $dataExport = Usertype::search($inputs); + $columns = array( + __('利用者分類ID'),// 0 + __('分類名'),// 1 + __('適用料率'),// 2 + __('備考'),// 3 + ); + $filename = "利用者分類マスタ.csv"; + $file = fopen($filename, 'w+'); + fputcsv($file, $columns); + foreach ($dataExport as $items) { + fputcsv( + $file, + array( + $items->user_categoryid, + $items->print_name, + $items->usertype_money, + $items->usertype_remarks, // 3 + ) + ); + } + fclose($file); + return Response::download($filename, $filename, $headers); + } + + public function import(Request $request) + { + $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ファイルを選択していません。')); + } + } + + +} \ No newline at end of file diff --git a/app/Models/City.php b/app/Models/City.php new file mode 100644 index 0000000..97cb3b1 --- /dev/null +++ b/app/Models/City.php @@ -0,0 +1,34 @@ + '1ヶ月', + 2 => '2ヶ月', + 3 => '3ヶ月', + 4 => '6ヶ月', + 5 => '12ヶ月', + ]; + + protected $table = 'price_a'; + protected $primaryKey = 'price_parkplaceid'; + + protected $fillable = [ + 'prine_name', + 'price_month', + 'park_id', + 'psection_id', + 'price_ptypeid', + 'user_categoryid', + 'pplace_id', + 'price' + ]; + + public static function boot() + { + parent::boot(); + self::creating(function (Price $model) { + $model->operator_id = Auth::user()->ope_id; + }); + } + + public static function search($inputs) + { + $list = self::query(); + // 只有在sort是有效字段时才排序 + $allowedSortColumns = [ + 'price_parkplaceid', + 'prine_name', + 'price_month', + 'park_id', + 'psection_id', + 'price_ptypeid', + 'user_categoryid', + 'pplace_id', + 'price' + ]; + $sort_column = $inputs['sort'] ?? ''; + $sort_type = strtolower($inputs['sort_type'] ?? 'asc'); + if (in_array($sort_column, $allowedSortColumns)) { + if (!in_array($sort_type, ['asc', 'desc'])) { + $sort_type = 'asc'; + } + $list->orderBy($sort_column, $sort_type); + } + if ($inputs['isExport']) { + $list = $list->get(); + } else { + $list = $list->paginate(Utils::item_per_page); + } + return $list; + } + + + public static function getByPk($pk) + { + return self::find($pk); + } + + public static function deleteByPk($arr) + { + return self::whereIn('price_parkplaceid', $arr)->delete(); + } + + //TODO 駐車場所ID not found in database specs + + //TODO 駐車車室ID not found in database specs + + public function getPark() + { + return $this->belongsTo(Park::class, 'park_id', 'park_id')->first(); + } + public function getPSection() + { + return $this->belongsTo(Psection::class, 'psection_id', 'psection_id')->first(); + } + public function getPType() + { + return $this->belongsTo(Ptype::class, 'price_ptypeid', 'ptype_id')->first(); + } + public function getUserType() + { + return $this->belongsTo(Usertype::class, 'user_categoryid', 'user_categoryid')->first(); + } + +} \ No newline at end of file diff --git a/app/Models/PriceB.php b/app/Models/PriceB.php new file mode 100644 index 0000000..091eb81 --- /dev/null +++ b/app/Models/PriceB.php @@ -0,0 +1,25 @@ +where('park_id', $parkId); + } +} diff --git a/app/Models/PriceList.php b/app/Models/PriceList.php new file mode 100644 index 0000000..15b5327 --- /dev/null +++ b/app/Models/PriceList.php @@ -0,0 +1,22 @@ + 'integer', + 'operator_id' => 'integer', + 'created_at' => 'datetime', + 'updated_at' => 'datetime' + ]; + + + // 主キーが自動増分でない場合はfalseに設定 + public $incrementing = false; + // タイムスタンプ管理しない場合はfalseに設定 + public $timestamps = false; + + + + /** + * 売上集計との関連 + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function earningsSummaries() + { + return $this->hasMany(EarningsSummary::class, 'psection_id', 'psection_id'); + } + + /** + * 定期契約との関連 + * + * @return \Illuminate\Database\Eloquent\Relations\HasMany + */ + public function regularContracts() + { + return $this->hasMany(RegularContract::class, 'psection_id', 'psection_id'); + } + + /** + * アクティブな車種区分一覧を取得 + * + * @return \Illuminate\Database\Eloquent\Collection + */ + public static function getActivePsections() + { + return self::orderBy('psection_id')->get(); + } + + /** + * 車種区分名で検索 + * + * @param string $subject 車種区分名 + * @return Psection|null + */ + public static function findBySubject(string $subject): ?Psection + { + return self::where('psection_subject', $subject)->first(); + } + + /** + * 文字列表現 + * + * @return string + */ + public function __toString(): string + { + return sprintf( + 'Psection[ID:%d, Subject:%s]', + $this->psection_id, + $this->psection_subject + ); + } + + + + + + + + + + // 新規作成時にoperator_idを自動設定(operator_idカラムがある場合のみ) + public static function boot() + { + parent::boot(); + self::creating(function (Psection $model) { + // ログインしている場合のみセット + if (\Auth::check()) { + $model->operator_id = Auth::user()->ope_id; + } + }); + } + + // 車種区分リストを取得(プルダウン用) + public static function getList() + { + return self::orderBy('psection_id')->pluck('psection_subject', 'psection_id'); + } +} diff --git a/app/Models/Usertype.php b/app/Models/Usertype.php new file mode 100644 index 0000000..ac73bd2 --- /dev/null +++ b/app/Models/Usertype.php @@ -0,0 +1,66 @@ +operator_id = Auth::user()->ope_id; + }); + } + + public static function search($inputs) + { + $list = self::query(); + if ($inputs['isMethodPost']) { + + } + // Sort + if ($inputs['sort']) { + $list->orderBy($inputs['sort'], $inputs['sort_type']); + } + if ($inputs['isExport']){ + $list = $list->get(); + }else{ + $list = $list->paginate(Utils::item_per_page); + } + return $list; + } + + public static function getByPk($pk) + { + return self::find($pk); + } + + public static function deleteByPk($arr) + { + return self::whereIn('user_categoryid', $arr)->delete(); + } + + //TODO 利用者分類ID not found in database specs + + //TODO 利用者分類名 not found in database specs + public static function getList(){ + return self::pluck('print_name','user_categoryid'); + } + +} \ No newline at end of file diff --git a/app/Models/Utils.php b/app/Models/Utils.php new file mode 100644 index 0000000..e69aef1 --- /dev/null +++ b/app/Models/Utils.php @@ -0,0 +1,134 @@ +getClientOriginalExtension(); + + if ($file->move($destinationPath, $fileName)) { + $filePath = $destinationPath.$fileName; + if (file_exists($filePath)){ + chmod($filePath, 0755); // ファイル権限設定 + } + return $fileName; + } + return false; + } + + /** + * 画像パスを取得 + * + * @param string $filname ファイル名 + * @return string 画像パス + */ + public static function getImagePath($filname = '') + { + $path = self::image_path; + if ($filname) $path .= $filname; + return $path; + } + + /** + * 画像URLを取得 + * + * @param string $filname ファイル名 + * @return string 画像URL + */ + public static function getImageUrl($filname = '') + { + return url(self::getImagePath($filname)); + } + + /** + * パスワードのハッシュ化 + * Laravel 12変更点:Hashファサードを使用してハッシュ化 + * Laravel 5.7: 独自のソルト処理を実装していた + * + * @param string $pw 平文パスワード + * @param string $seq ユーザーシーケンス(ソルト用) + * @return string ハッシュ化されたパスワード + */ + public static function getHashPassword($pw, $seq) + { + // 旧システムと同じソルト形式を維持 + $salt = $seq.'SOMSALT'; + + // Laravel 12: Argon2ハッシュアルゴリズムを使用 + return Hash::make($pw, [ + 'memory' => 1024, + 'time' => 25, + 'threads' => 2, + 'salt' => $salt + ]); + } + + /** + * CSVファイルを配列に変換 + * Laravel 5.7から継承したメソッド(データインポート用) + * + * @param string $filename CSVファイルパス + * @param string $delimiter 区切り文字(デフォルト:カンマ) + * @return array|false 変換された配列、またはfalse(失敗時) + */ + public static function csvToArray($filename = '', $delimiter = ',') + { + // ファイル存在確認 + if (!file_exists($filename) || !is_readable($filename)) + return false; + + $header = null; + $data = array(); + + // CSVファイルを読み込み + if (($handle = fopen($filename, 'r')) !== false) + { + while (($row = fgetcsv($handle, 1000, $delimiter)) !== false) + { + if (!$header) + $header = $row; // 最初の行はヘッダーとして扱う + else + $data[] = $row; // データ行として配列に追加 + } + fclose($handle); + } + + return $data; + } +} \ No newline at end of file diff --git a/resources/views/admin/CityMaster/_form.blade.php b/resources/views/admin/CityMaster/_form.blade.php new file mode 100644 index 0000000..05e9cae --- /dev/null +++ b/resources/views/admin/CityMaster/_form.blade.php @@ -0,0 +1,24 @@ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
diff --git a/resources/views/admin/CityMaster/add.blade.php b/resources/views/admin/CityMaster/add.blade.php new file mode 100644 index 0000000..e362958 --- /dev/null +++ b/resources/views/admin/CityMaster/add.blade.php @@ -0,0 +1,43 @@ +@extends('layouts.app') + +@section('title', '[東京都|〇〇駐輪場] マスタ管理') + +@section('content') + +
+
+
+
+

[東京都|〇〇駐輪場] マスタ管理

+
+
+ +
+
+
+
+ + +
+

市区マスタ 新規登録

+ +
+
+
+ @csrf + @include('admin.CityMaster._form', ['isEdit' => 0, 'isInfo' => 0]) +
+ + 戻る +
+
+
+
+
+@endsection diff --git a/resources/views/admin/CityMaster/edit.blade.php b/resources/views/admin/CityMaster/edit.blade.php new file mode 100644 index 0000000..6b86c8c --- /dev/null +++ b/resources/views/admin/CityMaster/edit.blade.php @@ -0,0 +1,54 @@ +@extends('layouts.app') + +@section('title', '市区マスタ編集') + +@section('content') + +
+
+
+
+

[東京都|〇〇駐輪場] 市区マスタ

+
+
+ +
+
+
+
+ + + +
+
+

市区マスタ 編集

+ + @includeIf('common.flash') + +
+
+
+ @csrf + @method('POST') + + @include('admin.CityMaster._form', [ + 'isEdit' => 1, + 'isInfo' => 0, + 'city' => $city, + ]) + +
+ + 戻る +
+
+
+
+
+
+@endsection diff --git a/resources/views/admin/CityMaster/info.blade.php b/resources/views/admin/CityMaster/info.blade.php new file mode 100644 index 0000000..cc3c5d4 --- /dev/null +++ b/resources/views/admin/CityMaster/info.blade.php @@ -0,0 +1,51 @@ +@extends('layouts.app') + +@section('content') + + +
+
+
+
+

[東京都|〇〇駐輪場] 市区マスタ

+
+
+ +
+
+
+
+ + + +
+
+ + +
+
+
+
+ + + + @include('admin.users._form',['isEdit'=>0,'isInfo'=>1]) +
+
+
+
+ +
+ + +
+
+
+ + +@endsection diff --git a/resources/views/admin/CityMaster/list.blade.php b/resources/views/admin/CityMaster/list.blade.php new file mode 100644 index 0000000..9b76039 --- /dev/null +++ b/resources/views/admin/CityMaster/list.blade.php @@ -0,0 +1,96 @@ +@extends('layouts.app') + +@section('title', '市区マスタ') + +@section('content') + +
+
+
+
+

市区マスタ

+
+
+ +
+
+
+
+ + +
+
+ + +
+ 新規 + +
+ + @if ($list->count() > 0) +
+ @csrf +
+ + + + + + + + + + + + + + @foreach ($list as $city) + + + + + + + + + + @endforeach + +
+ + 市区ID + @if($sort === 'city_id') + + @endif + + + + 市区名 + @if($sort === 'city_name') + + @endif + + 印字レイアウトファイル顧客M入力不要フィールドID備考
+ + 編集 + {{ $city->city_id }}{{ $city->city_name }}{{ $city->print_layout }}{{ $city->city_user }}{{ $city->city_remarks }} 
+
+
+
+ {{ $list->appends(request()->except('page'))->links('pagination::bootstrap-4') }} +
+ @else +
表示する市区データがありません。
+ @endif + +
+
+@endsection \ No newline at end of file diff --git a/resources/views/admin/PriceList/add.blade.php b/resources/views/admin/PriceList/add.blade.php new file mode 100644 index 0000000..080df97 --- /dev/null +++ b/resources/views/admin/PriceList/add.blade.php @@ -0,0 +1,17 @@ + +@extends('layouts.app') + +@section('content') +
+

金額更新

+
+ @csrf + +
+ + +
+ +
+
+@endsection diff --git a/resources/views/admin/PriceList/list.blade.php b/resources/views/admin/PriceList/list.blade.php new file mode 100644 index 0000000..18afd61 --- /dev/null +++ b/resources/views/admin/PriceList/list.blade.php @@ -0,0 +1,129 @@ +@extends('layouts.app') + +@section('content') +
+ {{-- ログインボタン --}} +
+ ログイン +
+ +

料金一覧表

+ + {{-- 上部ツールバー:左=駐輪場セレクト、右(同列)=登録 --}} +
+ {{-- 駐輪場選択(GET) --}} +
+ + +
+ + {{-- 登録(POST フォームを指定して送信) --}} + +
+ + {{-- 一括更新フォーム(POST) --}} +
+ @csrf + {{-- 必要なら park_id を一緒に送る --}} + + + @if(isset($masterList) && count($masterList)) + @foreach($masterList as $master) +
+
+ {{ $master['name'] }} + +
+ +
+ + + + + + + + + + + + + + + + + + + + @forelse($master['groups'] as $group) + + + + + + + + + + {{-- 自転車 --}} + + + + + + + {{-- 原付 --}} + + + + + + + {{-- 自動二輪 --}} + + + + + + + @empty + + @endforelse + +
駐輪分類駐輪車室番号分類1分類2分類3自転車原付自動二輪
1ヶ月2ヶ月3ヶ月6ヶ月12ヶ月1ヶ月2ヶ月3ヶ月6ヶ月12ヶ月1ヶ月2ヶ月3ヶ月6ヶ月12ヶ月
{{ $group['classification'] ?? '' }}{{ $group['room_number'] ?? '' }}{{ $group['category1'] ?? '' }}{{ $group['category2'] ?? '' }}{{ $group['category3'] ?? '' }}
データがありません。
+
+
+ @endforeach + @else +
+
+ + …(省略:空表のヘッダは従来どおり)… + + + +
データがありません。
+
+
+ @endif +
+
+ + +@endsection diff --git a/resources/views/admin/contractor/list.blade.php b/resources/views/admin/contractor/list.blade.php new file mode 100644 index 0000000..e1b8a0e --- /dev/null +++ b/resources/views/admin/contractor/list.blade.php @@ -0,0 +1,254 @@ +@extends('layouts.app') + +@section('title', '契約者一覧') + +@section('content') +
+
+
+
+

契約者一覧

+
+
+ +
+
+
+
+ +
+
+ + {{-- 絞り込みフィルター --}} +
+
+
絞り込みフィルター
+
+ {{-- 左カラム --}} +
+
+ +
+ @isset($parks) + + @else + + @endisset +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+ + {{-- 右カラム --}} +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ +
+ + 解除 +
+
+
+ + {{-- 一覧テーブル --}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @forelse ($rows as $row) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @empty + + + + @endforelse + +
利用者ID氏名フリガナ + + 定期契約ID + @if(request('sort') === 'rc.contract_id') + @if(request('sort_type') === 'asc') + ▲ + @else + ▼ + @endif + @endif + + タグ・QR駐輪場車種区分減免措置利用者分類1利用者分類2利用者分類3携帯電話番号自宅電話番号生年月日性別居住所:郵便番号居住所:都道府県居住所:市区群居住所:住所関連住所:郵便番号関連住所:都道府県関連住所:市区群関連住所:住所契約日利用期間有効期間定期券区分勤務先名学校卒業予定シール発行回数防犯登録備考
{{ $row->user_id }}{{ $row->user_name }}{{ $row->user_phonetic }}{{ $row->contract_id }}{{ $row->tag_qr_flag ? 'QR' : 'タグ' }}{{ $row->park_name }}{{ $row->vehicle_type ?? '' }}{{ $row->user_reduction ?? '' }}{{ $row->user_category1 ?? '' }}{{ $row->user_category2 ?? '' }}{{ $row->user_category3 ?? '' }}{{ $row->user_mobile }}{{ $row->user_homephone }}{{ $row->user_birthdate }}{{ $row->user_gender }}{{ $row->user_regident_zip }}{{ $row->user_regident_pre }}{{ $row->user_regident_city }}{{ $row->user_regident_add }}{{ $row->user_relate_zip }}{{ $row->user_relate_pre }}{{ $row->user_relate_city }}{{ $row->user_relate_add }}{{ $row->contract_created_at }}{{ $row->contract_periods }}{{ $row->contract_periode }}{{ $row->ticket_type ?? '' }}{{ $row->user_workplace }}{{ $row->user_school }}{{ $row->user_graduate }}{{ $row->seal_issue_count ?? '' }}{{ $row->crime_prevention ?? '' }}{{ $row->user_remarks }}
データがありません。
+
+ +
+ {{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }} +
+
+
+ +{{-- 画面用スタイル(表頭をグレー、データ部分を白) --}} + +@endsection diff --git a/resources/views/admin/contractor_list/list.blade.php b/resources/views/admin/contractor_list/list.blade.php new file mode 100644 index 0000000..895eaa7 --- /dev/null +++ b/resources/views/admin/contractor_list/list.blade.php @@ -0,0 +1,254 @@ +@extends('layouts.app') + +@section('title', '未更新者一覧') + +@section('content') +
+
+
+
+

未更新者一覧

+
+
+ +
+
+
+
+ +
+
+ + {{-- 絞り込みフィルター --}} +
+
+
絞り込みフィルター
+
+ {{-- 左カラム --}} +
+
+ +
+ @isset($parks) + + @else + + @endisset +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+ + {{-- 右カラム --}} +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ +
+ + 解除 +
+
+
+ + {{-- 一覧テーブル --}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @forelse ($rows as $row) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @empty + + + + @endforelse + +
利用者ID氏名フリガナ + + 定期契約ID + @if(request('sort') === 'contract_id') + @if(request('sort_type') === 'asc') + ▲ + @else + ▼ + @endif + @endif + + タグ・QR駐輪場車種区分減免措置利用者分類1利用者分類2利用者分類3携帯電話番号自宅電話番号生年月日性別居住所:郵便番号居住所:都道府県居住所:市区群居住所:住所関連住所:郵便番号関連住所:都道府県関連住所:市区群関連住所:住所契約日利用期間有効期間定期券区分勤務先名学校卒業予定シール発行回数防犯登録備考
{{ $row->user_id }}{{ $row->user_name }}{{ $row->user_phonetic }}{{ $row->contract_id }}{{ $row->tag_qr_flag ? 'QR' : 'タグ' }}{{ $row->park_name }}{{ $row->vehicle_type ?? '' }}{{ $row->user_reduction ?? '' }}{{ $row->user_category1 ?? '' }}{{ $row->user_category2 ?? '' }}{{ $row->user_category3 ?? '' }}{{ $row->user_mobile }}{{ $row->user_homephone }}{{ $row->user_birthdate }}{{ $row->user_gender }}{{ $row->user_regident_zip }}{{ $row->user_regident_pre }}{{ $row->user_regident_city }}{{ $row->user_regident_add }}{{ $row->user_relate_zip }}{{ $row->user_relate_pre }}{{ $row->user_relate_city }}{{ $row->user_relate_add }}{{ $row->contract_created_at }}{{ $row->contract_periods }}{{ $row->contract_periode }}{{ $row->ticket_type ?? '' }}{{ $row->user_workplace }}{{ $row->user_school }}{{ $row->user_graduate }}{{ $row->seal_issue_count ?? '' }}{{ $row->crime_prevention ?? '' }}{{ $row->user_remarks }}
データがありません。
+
+ +
+ {{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }} +
+
+
+ +{{-- 画面用スタイル(表頭をグレー、データ部分を白) --}} + +@endsection diff --git a/resources/views/admin/news/_form.blade.php b/resources/views/admin/news/_form.blade.php new file mode 100644 index 0000000..05e9cae --- /dev/null +++ b/resources/views/admin/news/_form.blade.php @@ -0,0 +1,24 @@ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
diff --git a/resources/views/admin/news/add.blade.php b/resources/views/admin/news/add.blade.php new file mode 100644 index 0000000..55d68ac --- /dev/null +++ b/resources/views/admin/news/add.blade.php @@ -0,0 +1,73 @@ +@extends('layouts.app') +@section('title', 'ニュース新規作成') + +@section('content') +{{-- ▼ コンテンツヘッダー(パンくず) --}} +
+
+
+

ニュース新規作成

+
+ +
+
+
+
+ +
+
+ + {{-- ▼ バリデーションエラー表示 --}} + @if ($errors->any()) +
    @foreach($errors->all() as $e)
  • {{ $e }}
  • @endforeach
+ @endif + + {{-- ▼ 入力フォーム --}} +
+
+
+ @csrf +
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ 戻る + +
+
+
+
+
+
+@endsection diff --git a/resources/views/admin/news/edit.blade.php b/resources/views/admin/news/edit.blade.php new file mode 100644 index 0000000..1ebe305 --- /dev/null +++ b/resources/views/admin/news/edit.blade.php @@ -0,0 +1,81 @@ +@extends('layouts.app') +@section('title', 'ニュース編集') + +@section('content') +{{-- ▼ コンテンツヘッダー(パンくず) --}} +
+
+
+

ニュース編集

+
+ +
+
+
+
+ +
+
+ + {{-- ▼ フラッシュ/エラー表示 --}} + @if(session('success'))
{{ session('success') }}
@endif + @if ($errors->any()) +
    @foreach($errors->all() as $e)
  • {{ $e }}
  • @endforeach
+ @endif + + {{-- ▼ 入力フォーム --}} +
+
+
+ @csrf +
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+
+ + +
+
+
+ + +
+
+ 一覧に戻る + +
+
+
+
+ + {{-- ▼ 登録/更新メタ情報 --}} +
+
登録日時:{{ $news->created_at }}
+
更新日時:{{ $news->updated_at }}
+
+
+
+@endsection diff --git a/resources/views/admin/news/info.blade.php b/resources/views/admin/news/info.blade.php new file mode 100644 index 0000000..cd0b51f --- /dev/null +++ b/resources/views/admin/news/info.blade.php @@ -0,0 +1,59 @@ +@extends('layouts.app') +@section('title', 'ニュース詳細') + +@section('content') +{{-- ▼ コンテンツヘッダー(パンくず) --}} +
+
+
+

ニュース詳細

+
+ +
+
+
+
+ +
+
+ {{-- ▼ 詳細表示 --}} +
+
+
+
ニュースID
{{ $news->id }}
+
ニュース内容
{{ $news->news }}
+
公開日時
{{ $news->open_datetime }}
+
リンクURL
{{ $news->link_url }}
+
画像1URL
{{ $news->image1_filename }}
+
画像2URL
{{ $news->image2_filename }}
+
表示モード
+
+ @php $modeLabel = [0=>'非表示',1=>'公開',2=>'下書き']; @endphp + + {{ $modeLabel[$news->mode] ?? $news->mode }} + +
+
登録日時
{{ $news->created_at }}
+
更新日時
{{ $news->updated_at }}
+
オペレーターID
{{ $news->operator_id }}
+
+ + {{-- ▼ 操作ボタン --}} +
+ 編集 +
+ @csrf + + +
+ 一覧に戻る +
+
+
+
+
+@endsection diff --git a/resources/views/admin/news/list.blade.php b/resources/views/admin/news/list.blade.php new file mode 100644 index 0000000..54c2355 --- /dev/null +++ b/resources/views/admin/news/list.blade.php @@ -0,0 +1,120 @@ +@extends('layouts.app') +@section('title', '最新ニュース登録') + +@section('content') +@php + // ▼ 表示モードのラベル + $modeLabel = [0=>'非表示', 1=>'公開', 2=>'下書き', 3=>'自動公開']; +@endphp + +{{-- ▼ コンテンツヘッダー(パンくず) --}} +
+
+
+

最新ニュース登録

+
+ +
+
+
+
+ +
+
+ + {{-- ▼ フラッシュメッセージ --}} + @if(session('success'))
{{ session('success') }}
@endif + @if(session('error'))
{{ session('error') }}
@endif + +
+ + {{-- ▼ ヘッダー:新規/削除 --}} +
+ 新規 + +
+ + {{-- ▼ 一覧テーブル --}} +
+
+ @csrf +
+ {{-- ← table-striped は使わない --}} + + + {{-- 統合列:ヘッダーも同色 --}} + + {{-- データ列 --}} + + + + + + + + + + + + + @forelse($rows as $r) + + {{-- ▼ 統合セル--}} + + + {{-- ▼ データ本体 --}} + + + + + + + + + + + @empty + + + + @endforelse + +
+
+ + +
+
ニュースIDニュース内容公開日時リンクURL画像1URL画像2URL表示モード登録日時更新日時
+
+ + 編集 +
+
{{ $r->id }}{{ \Illuminate\Support\Str::limit($r->news, 80) }}{{ $r->open_datetime }}{{ $r->link_url }}{{ $r->image1_filename }}{{ $r->image2_filename }}{{ $modeLabel[$r->mode] ?? $r->mode }}{{ $r->created_at }}{{ $r->updated_at }}
データがありません。
+
+ + {{-- ▼ フッター:ページネーション右寄せ --}} +
+
+ {{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }} +
+
+
+
+
+
+
+ +{{-- ▼ スクリプト:全選択/全解除 --}} + +@endsection diff --git a/resources/views/admin/periodical/area.blade.php b/resources/views/admin/periodical/area.blade.php new file mode 100644 index 0000000..df0831b --- /dev/null +++ b/resources/views/admin/periodical/area.blade.php @@ -0,0 +1,62 @@ +@extends('layouts.app') + +@section('title', '区画別利用状況') + +@section('content') +
+
+
+
+

区画別利用状況

+
+
+ +
+
+
+
+ +
+
+
+
+ + + + + + + + + + +
区画名駐輪場名市区名利用数
+
+
+
+
+ +@push('scripts') + +@endpush +@endsection diff --git a/resources/views/admin/periodical/list.blade.php b/resources/views/admin/periodical/list.blade.php new file mode 100644 index 0000000..a024bb7 --- /dev/null +++ b/resources/views/admin/periodical/list.blade.php @@ -0,0 +1,226 @@ +@extends('layouts.app') + +@section('title', '定期利用・契約状況') + +@section('content') +
+
+
+
+

定期利用・契約状況

+
+
+ +
+
+
+
+ +
+
+ + {{-- 検索条件 --}} +
+
+
+ + +
+ 以下に記載以外の期間情報を参照したい場合は、マスタ管理>定期期間マスタ のCSV出力を利用してください。 +
+
+ + {{-- 契約状況 --}} +
+
+ 契約状況 +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
契約状況一般学生利用計空き合計直近契約
件数件数予約日契約日
+
+
+
+ + {{-- 空き待ち状況 --}} +
+
+ 空き待ち状況 +
+
+
+ + + + + + + + + + + + + + + + +
空き待ち状況一般学生合計
件数先頭日件数先頭日
+
+
+
+ + {{-- 更新状況 --}} +
+
+ 更新状況 +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
自転車原付その他
一般学生一般学生一般学生
+
+
+
+ +
+
+ +@push('scripts') + +@endpush +@endsection diff --git a/resources/views/admin/psection/_form.blade.php b/resources/views/admin/psection/_form.blade.php new file mode 100644 index 0000000..1bb85db --- /dev/null +++ b/resources/views/admin/psection/_form.blade.php @@ -0,0 +1,172 @@ +{{-- 駐輪場マスタ 共通フォーム --}} + +
+ @csrf + + {{-- 駐輪場ID --}} +
+ +
+ +
+
+ + {{-- 市区 --}} +
+ +
+ +
+
+ + {{-- 駐輪場名 --}} +
+ +
+ +
+
+ + {{-- 駐輪場ふりがな --}} +
+ +
+ +
+
+ + {{-- 駐輪場五十音 --}} +
+ +
+ +
+
+ + {{-- 住所 --}} +
+ +
+ +
+
+ + {{-- 閉設フラグ --}} +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + {{-- 閉設日 --}} +
+ +
+ +
+
+ + {{-- 残警告チェックフラグ --}} +
+ +
+ +
+
+ + {{-- 印字数 --}} +
+ +
+ +
+
+ + {{-- 最新キープアライブ --}} +
+ +
+ +
+
+ + {{-- ---- 以下为未来扩展的字段,请用时补充数据库和控制器变量,并去掉注释 ---- --}} + + {{-- +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ --}} + + {{-- 備考 --}} +
+ +
+ +
+
+ + {{-- ここから他のフィールドも同様に追加 --}} + {{-- ... --}} + + {{-- 图片上传字段样例 --}} + {{-- +
+ +
+ + @if(!empty($parking_image1_url)) + 駐輪場画像1 + @endif +
+
+ --}} + +
diff --git a/resources/views/admin/psection/add.blade.php b/resources/views/admin/psection/add.blade.php new file mode 100644 index 0000000..5c87345 --- /dev/null +++ b/resources/views/admin/psection/add.blade.php @@ -0,0 +1,48 @@ +@extends('layouts.app') +@section('title', '車種区分新規登録') +@section('content') +
+
+
+

車種区分新規登録

+
+ +
+
+
+
+
+
+ + {{-- 显示错误信息 --}} + @if ($errors->any()) +
+
    + @foreach ($errors->all() as $error) +
  • {{ $error }}
  • + @endforeach +
+
+ @endif + +
+ @csrf +
+ + +
+
+ + +
+ + 戻る +
+
+
+@endsection diff --git a/resources/views/admin/psection/edit.blade.php b/resources/views/admin/psection/edit.blade.php new file mode 100644 index 0000000..195236a --- /dev/null +++ b/resources/views/admin/psection/edit.blade.php @@ -0,0 +1,35 @@ +@extends('layouts.app') +@section('title', '車種区分新規登録') +@section('content') +
+
+
+

車種区分新規登録

+
+ +
+
+
+
+
+
+
+ @csrf +
+ + +
+
+ + +
+ + 戻る +
+
+
+@endsection diff --git a/resources/views/admin/psection/info.blade.php b/resources/views/admin/psection/info.blade.php new file mode 100644 index 0000000..fff7b58 --- /dev/null +++ b/resources/views/admin/psection/info.blade.php @@ -0,0 +1,31 @@ +@extends('layouts.app') +@section('title', '車種区分詳細') +@section('content') +
+
+
+

車種区分詳細

+
+ +
+
+
+
+
+
+
+ + +
+
+ + +
+ 一覧に戻る +
+
+@endsection diff --git a/resources/views/admin/psection/list.blade.php b/resources/views/admin/psection/list.blade.php new file mode 100644 index 0000000..af3ac17 --- /dev/null +++ b/resources/views/admin/psection/list.blade.php @@ -0,0 +1,102 @@ +@extends('layouts.app') + +@section('title', '車種区分マスタ') + +@section('content') +{{-- ▼ コンテンツヘッダー(パンくず) --}} +
+
+
+
+

車種区分マスタ

+
+
+ +
+
+
+
+ +
+
+ + {{-- ▼ アクションボタン(市区マスタ準拠) --}} +
+ 新規 + +
+ + @if ($list->count() > 0) +
+ @csrf + +
+ + + + {{-- ▼ 統合列:チェック + 編集(背景色は #faebd7) --}} + + + {{-- ▼ 表頭:ソート対応(ID / 名称) --}} + + + + + + + @foreach ($list as $item) + + {{-- ▼ 統合セル:チェック + 編集(市区マスタの老書式に合わせる) --}} + + + {{-- ▼ データ列 --}} + + + + @endforeach + +
+ + + + + 車種区分ID + @if($sort == 'id') + @if($direction == 'asc') + + @else + + @endif + @endif + + + + 車種区分名 + @if($sort == 'subject') + @if($direction == 'asc') + + @else + + @endif + @endif + +
+ + 編集 + {{ $item->psection_id }}{{ $item->psection_subject }}
+
+
+ @else + {{-- ▼ データ無し表示 --}} +
表示するデータがありません。
+ @endif +
+
+@endsection diff --git a/resources/views/admin/regularcontracts/_form.blade.php b/resources/views/admin/regularcontracts/_form.blade.php new file mode 100644 index 0000000..388c284 --- /dev/null +++ b/resources/views/admin/regularcontracts/_form.blade.php @@ -0,0 +1,555 @@ +@if(Session::has('success')) + +@elseif(Session::has('error')) +
+ +

エラー:

+ {!! Session::get('error') !!} +
+@elseif(isset($errorMsg)) +
+ +

エラー:

+ {!! $errorMsg !!} +
+@endif + +
+ @if($isInfo) + 登録 + 編集 + @endIf +
+
+
+ + @if($isEdit || $isInfo) + {{-- 定期契約ID --}} +
+ +
+
+
+ +
+
+ @endif + + {{-- 定期契約QRID --}} +
+ +
+
+
+ +
+
+ + {{-- 利用者ID --}} +
+ +
+
+
+ +
+
+ + {{-- 利用者分類ID --}} +
+ +
+
+
+ +
+
+ + {{-- 定期予約ID --}} +
+ +
+
+
+ +
+
+ + {{-- 駐輪場ID --}} +
+ +
+
+
+ +
+
+ + {{-- 駐輪場所ID --}} +
+ +
+
+
+ +
+
+ + {{-- 防犯登録番号 --}} +
+ +
+
+
+ +
+
+ + {{-- 予約日時 --}} +
+ +
+
+
+ +
+
+ + {{-- 予約移行 --}} +
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + {{-- 契約日時 --}} +
+ +
+
+
+ +
+
+ + {{-- 更新可能日 --}} +
+ +
+
+
+ +
+
+ + {{-- 解約日時 --}} +
+ +
+
+
+ +
+
+ + {{-- 減免措置 --}} +
+ +
+
+
+ +
+
+ + {{-- 有効期間S --}} +
+ +
+
+
+ +
+
+ + {{-- 有効期間E --}} +
+ +
+
+
+ +
+
+ + {{-- 消費税ID --}} +
+ +
+
+
+ +
+
+ + {{-- 請求金額 --}} +
+ +
+
+
+ +
+
+ + {{-- 授受日時 --}} +
+ +
+
+
+ +
+
+ + {{-- 授受金額 --}} +
+ +
+
+
+ +
+
+ + {{-- 解約時返戻金 --}} +
+ +
+
+
+ +
+
+ + {{-- 返戻金付随情報 --}} +
+ +
+
+
+ +
+
+ + {{-- 返金日 --}} +
+ +
+
+
+ +
+
+ + {{-- 決済コード --}} +
+ +
+
+
+ +
+
+ + {{-- 店舗コード --}} +
+ +
+
+
+ +
+
+ + {{-- 授受種別 --}} +
+ +
+
+
+ +
+
+ + {{-- 授受フラグ --}} +
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + {{-- 決済トランザクションID --}} +
+ +
+
+
+ +
+
+ + {{-- シール発行数 --}} +
+ +
+
+
+ +
+
+ + {{-- シール再発行リクエスト --}} +
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + {{-- シール発行許可 --}} +
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + {{-- 解約フラグ --}} +
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + {{-- タグ・QR --}} +
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + {{-- オペレータータグ変更フラグ --}} +
+ +
+
+
+
+ + +
+
+ + +
+
+
+ + {{-- 駐輪位置番号 --}} +
+ +
+
+
+ +
+
+ + {{-- オペレータID --}} +
+ +
+
+
+ +
+
+ + {{-- 手動通知 --}} +
+ +
+
+
+ +
+
+ + {{-- 通知方法 --}} +
+ +
+
+
+ +
+
+ + {{-- 受付番号 --}} +
+ +
+
+
+ +
+
+ +
+ + @if($isInfo) + 登録 + 編集 + @else + + @endIf +
diff --git a/resources/views/admin/regularcontracts/add.blade.php b/resources/views/admin/regularcontracts/add.blade.php new file mode 100644 index 0000000..1cf76ce --- /dev/null +++ b/resources/views/admin/regularcontracts/add.blade.php @@ -0,0 +1,347 @@ +{{-- resources/views/admin/regularcontracts/add.blade.php --}} +@extends('layouts.app') +@section('title', '新規|定期契約マスタ') + +@section('content') + + +
+
+
+
+

新規

+ +
+
+
+ +
+
+ + {{-- 上部:登録ボタン(駐輪場所・料金マスタのトーンに合わせた薄いボタン) --}} +
+ +
+ +
+
+
+ @csrf + + {{-- ====== 1段目 ====== --}} +
+
+
+

旧定期契約番号

+
+
+
+

定期契約QRID

+
+
+
+

利用者ID

+
+
+
+

利用者分類ID

+
+
+
+

定期予約ID

+
+
+
+

駐輪場ID

+
+
+
+

駐輪場所ID

+
+
+
+

防犯登録番号

+
+
+ +
+

予約日時

+
+ +
+
+
+

契約日時

+
+ +
+
+
+

更新可能日

+
+
+
+

解約日時

+
+ +
+
+ +
+

有効期間S

+
+
+
+

有効期間E

+
+
+
+

定期有効月数

+
+
+
+

シール印刷可能日

+
+
+
+

請求金額

+
+
+
+

車室割り当てフラグ

+
+ +
+
+
+

授受日時

+
+
+
+

授受金額

+
+
+
+

授受フラグ

+
+ +
+
+
+ + {{-- 右列 --}} +
+
+

決済トランザクションID

+
+
+
+

シール発行数

+
+
+
+

シール発行リクエスト

+
+
+ + +
+
+ + +
+
+
+ +
+

定期継続フラグ

+
+ +
+
+
+

シール発行可

+
+ +
+
+
+

減免フラグ

+
+ +
+
+
+

80MOM以内

+
+ +
+
+ +
+

タグ/QRフラグ

+
+
+ + +
+
+ + +
+
+
+
+

オペレータ名変更フラグ

+
+ +
+
+ +
+

駐輪位置番号

+
+
+
+

手動通知

+
+
+
+

通知方法

+
+
+
+

受付番号

+
+
+
+

オペレータID

+
+
+ +
+

シール発行許可

+
+ +
+
+
+

解約フラグ

+
+ +
+
+ +
+

収納企業コード

+
+
+
+

共有先収納企業コード

+
+
+
+

(更新元)契約更新済フラグ

+
+ +
+
+
+

車種区分ID

+
+
+ + {{-- チェック用(検索補助の控え) --}} +
+

チェック用_フリガナ

+
+
+
+

チェック用_居住所郵便番号

+
+
+
+

チェック用_携帯電話番号

+
+
+
+

チェック用_自宅電話番号

+
+
+
+

チェック用_旧会員番号

+
+
+ +
+
+ + {{-- 下部:登録ボタン --}} +
+ + 戻る +
+
+
+
+ +
+
+
+@endsection diff --git a/resources/views/admin/regularcontracts/edit.blade.php b/resources/views/admin/regularcontracts/edit.blade.php new file mode 100644 index 0000000..6a696a4 --- /dev/null +++ b/resources/views/admin/regularcontracts/edit.blade.php @@ -0,0 +1,77 @@ +@extends('layouts.app') +@section('title', '定期契約マスタ - 編集') + +@section('content') + + +
+
+
+
+

編集

+ +
+ + {{-- ← ここが “目標” のボタン帯 --}} +
+
+ {{-- 登録:edit-form を submit --}} + + {{-- 領収書発行:後で好きなルートに差し替えてOK(今はダミー) --}} + +
+ + {{-- 右側:削除 --}} +
+ @csrf + + +
+
+ {{-- /ボタン帯 --}} +
+
+ +
+
+
+ {{-- 本体フォーム(登録はこの form を submit) --}} +
+ @csrf + @include('admin.regularcontracts._form', array_merge( + ['isEdit'=>1,'isInfo'=>0], + (array) $row + )) +
+
+
+
+
+ + +@endsection diff --git a/resources/views/admin/regularcontracts/info.blade.php b/resources/views/admin/regularcontracts/info.blade.php new file mode 100644 index 0000000..d4a3c2a --- /dev/null +++ b/resources/views/admin/regularcontracts/info.blade.php @@ -0,0 +1,53 @@ + +@extends('layouts.app') +@section('title', '[東京都|〇〇駐輪場] 定期契約マスタ') + +@section('content') + +
+
+
+
+

[東京都|〇〇駐輪場] 定期契約マスタ

+
+
+ +
+
+
+
+ + + +
+
+ + +
+
+
+
+ + + + @include('admin.regularcontracts._form',['isEdit'=>0,'isInfo'=>1]) +
+
+
+
+ +
+ + + +
+
+
+ + +@endsection diff --git a/resources/views/admin/regularcontracts/list.blade.php b/resources/views/admin/regularcontracts/list.blade.php new file mode 100644 index 0000000..0b274da --- /dev/null +++ b/resources/views/admin/regularcontracts/list.blade.php @@ -0,0 +1,531 @@ +@extends('layouts.app') +@section('title', '定期契約マスタ') + +@section('content') + + +
+
+
+
+
+

定期契約マスタ

+
+
+ +
+
+

※この画面のデータは通常変更する必要はありません。

+
+
+ +
+
+ + {{-- 絞り込みフィルター(2カラム) --}} +
+
+

絞り込みフィルター

+
+
+
+ @csrf + + + +
+ {{-- 左カラム --}} +
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+
+ +
+
+
+
+ + {{-- 右カラム --}} +
+
+ +
+
+
+ +
+ + + +
+
+
+ +
+ + + +
+
+
+ +
+ + + +
+
+
+ +
+ + + +
+
+
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+ +
+
+
+
+ + {{-- フィルターボタン(見た目統一) --}} +
+ + 解除 +
+
+
+
+ + {{-- ツールバー:左=ボタン群、右=ページャ --}} +
+
+ 新規 + + + {{-- 3種のエクスポートは共通の確認モーダルを使い、data-url に出力先URLを渡す --}} + + + + + +
+
+ {{ $list->appends(['sort' => $sort, 'sort_type' => $sort_type])->links('pagination') }} +
+
+ + + + {{-- 一覧テーブル --}} +
+ @csrf +
+ + + + @php $next = ($sort === 'contract_id' && $sort_type === 'asc') ? 'desc' : 'asc'; @endphp + + + {{-- 操作列(チェック+編集。背景色を付与) --}} + + + {{-- 表頭(要件に合わせて網羅) --}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @foreach($list as $item) + + {{-- 先頭の並び替え列(行の contract_id を表示) --}} + + + {{-- 操作列:チェック + 編集(背景色つき) --}} + + + {{-- データ列 --}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @endforeach + +
+ + 定期契約ID旧定期契約番号ゾーンID車室番号利用者ID利用者分類IDタグ・QR駐輪場ID有効期間S有効期間E駐輪場所ID防犯登録番号契約日時更新可能日解約日時減免措置定期有効月数シール印刷可能日請求金額車室割り当てフラグ授受日時授受金額授受フラグ決済トランザクションIDシール発行数シール発行許可解約フラグ収納企業コード共有先収納企業コード受付番号(更新元)契約更新済フラグ車種区分IDチェック用_フリガナチェック用_居住所郵便番号チェック用_携帯電話番号チェック用_自宅電話番号チェック用_旧会員番号
{{ $item->contract_id }} +
+ + 編集 +
+
{{ $item->contract_qr_id }}{{ $item->old_contract_number ?? '' }}{{ $item->zone_id ?? '' }}{{ $item->room_number ?? '' }}{{ $item->user_id }}{{ $item->user_categoryid }}{{ $item->tag_qr_flag ? 'QR' : 'タグ' }}{{ $item->park_id }}{{ $item->valid_from ?? '' }}{{ $item->valid_to ?? '' }}{{ $item->price_arkplaceid ?? $item->price_parkplaceid ?? '' }}{{ $item->crime_prevention_registration_number ?? '' }}{{ $item->contract_created_at ?? '' }}{{ $item->renewable_date ?? '' }}{{ $item->contract_cancelday ?? '' }}{{ $item->reduction ?? '' }}{{ $item->contract_valid_months ?? '' }}{{ $item->label_printable_date ?? '' }}{{ $item->billing_amount ?? '' }}{{ ($item->assign_flag ?? null) === null ? '' : (($item->assign_flag) ? '割当済' : '未割当') }}{{ $item->receipt_delivery_date ?? '' }}{{ $item->receipt_delivery_amount ?? '' }} + {{ ($item->receipt_delivery_flag ?? null) === null ? '' : (($item->receipt_delivery_flag) ? '済' : '未') }} + {{ $item->payment_transaction_id ?? '' }}{{ $item->label_issue_count ?? '' }}{{ ($item->contract_permission ?? 0) ? '許可' : '未許可' }}{{ ($item->contract_cancel_flag ?? 0) ? 'キャンセル' : '-' }}{{ $item->company_code ?? '' }}{{ $item->shared_company_code ?? '' }}{{ $item->accept_number ?? '' }}{{ ($item->update_flag ?? 0) ? '更新済' : '未更新' }}{{ $item->vehicle_type_id ?? '' }}{{ $item->user_phonetic ?? '' }}{{ $item->user_regident_zip ?? '' }}{{ $item->user_mobile ?? '' }}{{ $item->user_homephone ?? '' }}{{ $item->old_member_number ?? '' }}
+
+
+ + {{-- 下側のページャ(右寄せ) --}} +
+ {{ $list->appends(['sort' => $sort, 'sort_type' => $sort_type])->links('pagination') }} +
+
+
+
+ + {{-- インポート用モーダル(ファイル選択) --}} + + + {{-- エクスポート用モーダル(確認のみ。リンク先でダウンロード) --}} + + + {{-- 画面内スクリプト:インポートのファイル名表示、エクスポートのURL差し替え --}} + + +@endsection \ No newline at end of file diff --git a/resources/views/admin/reservation/list.blade.php b/resources/views/admin/reservation/list.blade.php new file mode 100644 index 0000000..e924859 --- /dev/null +++ b/resources/views/admin/reservation/list.blade.php @@ -0,0 +1,211 @@ +@extends('layouts.app') + +@section('title', '予約者一覧') + +@section('content') +
+
+
+
+

予約者一覧

+
+
+ +
+
+
+
+ +
+
+ + {{-- 絞り込みフィルター(順序を画像に完全一致) --}} +
+
+
絞り込みフィルター
+
+ {{-- 左カラム:駐輪場 → 利用者ID → 利用者分類 → タグシリアル → タグシリアル64進 --}} +
+
+ +
+ @isset($parks) + + @else + + @endisset +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+ + {{-- 右カラム:フリガナ → 電話番号 → メールアドレス → 勤務先 → 学校 --}} +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ +
+ + 解除 +
+
+
+ + {{-- 一覧テーブル(そのまま) --}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @forelse ($rows as $row) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @empty + + @endforelse + +
利用者ID氏名フリガナ居住所:郵便番号居住所:都道府県居住所:市区群居住所:住所関連住所:郵便番号関連住所:都道府県関連住所:市区群関連住所:住所生年月日性別携帯電話番号自宅電話番号学校卒業予定備考定期予約ID利用者分類1利用者分類2利用者分類3駐輪場ID駐輪場名 駐輪場所ID車種区分ID予約日時減免措置800M以内フラグ
{{ $row->user_id }}{{ $row->user_name }}{{ $row->user_phonetic }}{{ $row->user_regident_zip }}{{ $row->user_regident_pre }}{{ $row->user_regident_city }}{{ $row->user_regident_add }}{{ $row->user_relate_zip }}{{ $row->user_relate_pre }}{{ $row->user_relate_city }}{{ $row->user_relate_add }}{{ $row->user_birthdate }}{{ $row->user_gender }}{{ $row->user_mobile }}{{ $row->user_homephone }}{{ $row->user_school }}{{ $row->user_graduate }}{{ $row->user_remarks }}{{ data_get($row,'reserve_id', data_get($row,'contract_id','')) }}{{ $row->park_id }}{{ $row->park_name }}{{ $row->price_parkplaceid }}{{ $row->psection_id }}{{ $row->reserve_date }}{{ data_get($row,'reduction', data_get($row,'reserve_reduction','')) }} + @php $f800 = data_get($row,'within_800m_flag', data_get($row,'flag_800m', null)); @endphp + {{ (string)$f800 === '1' ? '800M以内' : '-' }} +
データがありません。
+
+ +
+ {{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }} +
+
+
+ + +@endsection diff --git a/resources/views/admin/reserves/add.blade.php b/resources/views/admin/reserves/add.blade.php new file mode 100644 index 0000000..c9154a3 --- /dev/null +++ b/resources/views/admin/reserves/add.blade.php @@ -0,0 +1,277 @@ +@extends('layouts.app') +@section('title', '定期予約登録') + +@section('content') + + +
+ {{-- パンくず&見出し --}} +
+
+
+

新規

+
+ +
+
+ @if($errors->any()) +
+
    + @foreach($errors->all() as $e)
  • {{ $e }}
  • @endforeach +
+
+ @endif +
+
+ +
+
+
+
+ +
+ +
+ @csrf +
+ + {{-- 画面上部(ID系) --}} +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ {{-- 任意:必要に応じて選択肢を与える(今は簡易にテキスト or 「全て」) --}} + +
+
+ +
+ +
+ +
+
+ + {{-- 基本情報 --}} +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ + {{-- ラジオ系 --}} +
+ +
+
+ + +
+
+ + +
+
+
+ + {{-- リマインド --}} +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ + {{-- 期間・状態 --}} +
+ +
+ +
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ + {{-- 通知 --}} +
+ +
+
+ + +
+
+ + +
+
+
+ +
+ +
+
+ + +
+
+ + +
+
+
+ +
+ +
+ +
+
+ +
+ +
+ +
小さいほど優先度が高い想定
+
+
+ + {{-- 任意:開始/終了(必要なら表示) --}} +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ + +
+
+
+
+
+@endsection diff --git a/resources/views/admin/reserves/delete.blade.php b/resources/views/admin/reserves/delete.blade.php new file mode 100644 index 0000000..92838c6 --- /dev/null +++ b/resources/views/admin/reserves/delete.blade.php @@ -0,0 +1,123 @@ +{{-- resources/views/admin/reserves/delete.blade.php --}} +@extends('layouts.app') +@section('title', '定期予約 削除確認') + +@section('content') +@php + // === 削除対象IDを堅牢に収集($rows / $ids / request('ids') のいずれでも可)=== + $collectedIds = []; + if (!empty($rows)) { + foreach ($rows as $r) { $collectedIds[] = (int)$r->reserve_id; } + } elseif (!empty($ids)) { + $collectedIds = array_map('intval', (array)$ids); + } else { + // クエリやPOSTで "ids" が来ている場合(ids[]= / ids=1,2 どちらも吸収) + $raw = request()->input('ids', []); + if (is_string($raw)) $raw = explode(',', $raw); + $collectedIds = array_map('intval', (array)$raw); + } + $collectedIds = array_values(array_unique(array_filter($collectedIds, fn($v)=>$v>0))); +@endphp + + + +
+ {{-- ヘッダー / パンくず --}} +
+
+
+

削除確認

+
+ +
+
+ + @if(count($collectedIds)) +
+ 選択した定期予約を削除します。この操作は取り消せません。よろしいですか? +
+ @else +
+ 削除対象が選択されていません。一覧に戻って、チェックボックスで対象を選択してください。 +
+ @endif +
+
+ +
+
+ + {{-- 対象一覧(可能なら情報を表示。$rows が無いときはIDのバッジだけ) --}} +
+
+

削除対象

+
+
+ @if(!empty($rows) && count($rows)) +
+ + + + + + + + + + + + @foreach($rows as $r) + + + + + + {{-- ※ 実テーブル列名に合わせて reserve_date を使用 --}} + + + @endforeach + +
予約ID定期契約ID利用者名駐輪場予約日時
{{ $r->reserve_id }}{{ $r->contract_id ?? '' }}{{ $r->user_name ?? '' }}{{ $r->park_name ?? '' }}{{ $r->reserve_date ?? '' }}
+
+ @elseif(count($collectedIds)) +

+ 削除対象ID: + @foreach($collectedIds as $id) + {{ $id }} + @endforeach +

+ @else +

削除対象が取得できませんでした。

+ @endif +
+
+ + {{-- 確認フォーム --}} +
+ @csrf + {{-- コントローラ側で「確認済み」を判定できるようにフラグを送る --}} + + + {{-- hidden に対象 ID を埋め込む --}} + @foreach($collectedIds as $id) + + @endforeach + + キャンセル + +
+ +
+
+
+@endsection diff --git a/resources/views/admin/reserves/edit.blade.php b/resources/views/admin/reserves/edit.blade.php new file mode 100644 index 0000000..e317afa --- /dev/null +++ b/resources/views/admin/reserves/edit.blade.php @@ -0,0 +1,340 @@ +{{-- resources/views/admin/reserves/edit.blade.php --}} +@extends('layouts.app') +@section('title', '定期予約マスタ - 編集') + +@section('content') + + +@php + // 只读显示用:从现有 options 推断名称(不改控制器也能显示) + $userName = ''; + if (!empty($row->user_id ?? null) && !empty($userOptions[$row->user_id] ?? null)) { + // $userOptions 形如 "12345 山田太郎" → 去掉开头ID只留名字 + $userName = trim(preg_replace('/^\s*\d+\s*/', '', $userOptions[$row->user_id])); + } + $parkName = ''; + if (!empty($row->park_id ?? null) && !empty($parkOptions[$row->park_id] ?? null)) { + $parkName = trim(preg_replace('/^\s*\d+\s*/', '', $parkOptions[$row->park_id])); + } +@endphp + +
+ {{-- ヘッダ --}} +
+
+
+

編集

+
+ + + + @if(session('success')) +
{{ session('success') }}
+ @endif + @if($errors->any()) +
+
    @foreach($errors->all() as $e)
  • {{ $e }}
  • @endforeach
+
+ @endif +
+
+ + {{-- 本体 --}} +
+
+
+ {{-- GET と同一ルートで POST 更新 --}} +
+ @csrf + +
+
+ {{-- 左カラム(目标图顺序) --}} +
+ {{-- 定期予約ID(読み取り) --}} +
+ +
+
+ + {{-- 定期契約ID --}} +
+ +
+ +
+
+ + {{-- 利用者分類ID(先頭「全て」) --}} +
+ +
+ +
+
+ + {{-- 予約日時 --}} +
+ +
+ +
+
+ + {{-- 利用者名(読み取り)※目標画面に合わせて表示のみ --}} +
+ +
+
+ + {{-- 利用者ID --}} +
+ +
+ +
+
+ + {{-- 駐輪場(読み取り) --}} +
+ +
+
+ + {{-- 駐輪場ID --}} +
+ +
+ +
+
+ + {{-- 駐輪場所ID --}} +
+ +
+ +
+
+ + {{-- 車種区分ID --}} +
+ +
+ +
+
+ + {{-- 駐輪分類ID --}} +
+ +
+ +
+
+
+ + {{-- 右カラム(目标图顺序) --}} +
+ {{-- 減免措置 --}} +
+ +
+ @php $reduction = old('reduction', $row->reduction ?? ''); @endphp + + +
+
+ + {{-- 自動リマインド日 --}} +
+ +
+ +
+
+ + {{-- 手動リマインド日 --}} +
+ +
+ +
+
+ + {{-- 800M以内フラグ --}} +
+ +
+ @php $m800 = old('within_800m_flag', $row->within_800m_flag ?? ''); @endphp + + +
+
+ + {{-- 解約日 --}} +
+ +
+ +
+
+ + {{-- 有効フラグ --}} +
+ +
+ @php $valid = old('valid_flag', $row->valid_flag ?? ''); @endphp + + +
+
+ + {{-- 空き待ちメール送信日時 --}} +
+ +
+ +
+
+ + {{-- 手動通知 --}} +
+ +
+ @php $mnotice = old('manual_notice', $row->manual_notice ?? ''); @endphp + + +
+
+ + {{-- 手動通知方法 --}} +
+ +
+ @php $mhow = old('manual_notice_method', $row->manual_notice_method ?? ''); @endphp + + +
※ 必要に応じて選択肢は調整してください。
+
+
+ + {{-- 空き待ち順 --}} +
+ +
+ +
+
+
+
+
+ + {{-- 下部操作(保留:目标图底部有登録/削除) --}} + +
+ + {{-- 削除POST(confirmed + ids[]) --}} + +
+
+
+
+ + +@endsection diff --git a/resources/views/admin/reserves/list.blade.php b/resources/views/admin/reserves/list.blade.php new file mode 100644 index 0000000..b4b18eb --- /dev/null +++ b/resources/views/admin/reserves/list.blade.php @@ -0,0 +1,263 @@ +@extends('layouts.app') +@section('title', '定期予約マスタ') + +@section('content') + + +
+ {{-- パンくず・ヘッダ --}} +
+
+
+

定期予約マスタ

+
+ +
+
+ @if(session('success')) +
{{ session('success') }}
+ @endif + @if($errors->any()) +
+
    + @foreach($errors->all() as $e)
  • {{ $e }}
  • @endforeach +
+
+ @endif +

※この画面では予約情報の検索・一括削除が行えます。

+
+
+ +
+
+ + {{-- 絞り込みフィルター(ここは前回どおり。必要に応じて調整可) --}} +
+

絞り込みフィルター

+
+
+ @csrf + + + +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + + +
+
+
+ +
+
+ +
+ +
+
+
+
+ +
+ + 解除 +
+
+
+
+ + {{-- ツールバー:左=ボタン群、右=ページャ(CSV出力→削除) --}} +
+
+ 新規 + +
+
+ {{ $list->appends(['sort'=>$sort,'sort_type'=>$sort_type])->links('pagination') }} +
+
+ + {{-- 一覧テーブル(先頭列の並び替えを削除/操作列にチェック+編集) --}} +
+
+ @csrf + +
+ + + + {{-- 操作(全選択チェック+編集)※表頭は灰色 --}} + + + {{-- ▼ 要求どおりの見出し(順番も完全一致) --}} + + + + + + + + + + + + + + + + + + + + + + + + @foreach($list as $row) + + {{-- 操作セル--}} + + + {{-- データ列(存在しないカラムは空文字で安全に表示) --}} + {{-- 定期予約ID --}} + {{-- 定期契約ID --}} + {{-- 定期契約日時 --}} + {{-- 利用者分類ID --}} + {{-- 利用者ID --}} + {{-- 予約日時 --}} + {{-- 駐輪場ID --}} + {{-- 駐輪場所ID --}} + {{-- 車種区分ID --}} + {{-- 駐輪分類ID --}} + {{-- 減免措置 --}} + {{-- 自動リマインド日 --}} + {{-- 手動リマインド日 --}} + {{-- 800M以内フラグ --}} + {{-- 解約日 --}} + {{-- 有効フラグ --}} + {{-- メール送信日時 --}} + {{-- 手動通知 --}} + {{-- 手動通知方法 --}} + {{-- 空き待ち順 --}} + + @endforeach + +
+ + + 定期予約ID定期契約ID定期契約日時利用者分類ID利用者ID予約日時駐輪場ID駐輪場所ID車種区分ID駐輪分類ID減免措置自動リマインド日手動リマインド日800M以内フラグ解約日有効フラグメール送信日時手動通知手動通知方法空き待ち順
+
+ + 編集 +
+
{{ $row->reserve_id }}{{ $row->contract_id ?? '' }}{{ $row->contract_created_at ?? '' }}{{ $row->user_categoryid ?? '' }}{{ $row->user_id }}{{ $row->reserve_date ?? '' }}{{ $row->park_id ?? '' }}{{ $row->price_parkplaceid ?? '' }}{{ $row->psection_id ?? '' }}{{ $row->ptype_id ?? '' }}{{ $row->reduction ?? '' }}{{ $row->auto_remind_date ?? '' }}{{ $row->manual_remind_date ?? '' }}{{ isset($row->within_800m_flag) ? (($row->within_800m_flag)?'有':'無') : '' }}{{ $row->contract_cancelday ?? '' }}{{ isset($row->valid_flag) ? (($row->valid_flag)?'有効':'無効') : '' }}{{ $row->mail_sent_at ?? '' }}{{ isset($row->manual_notice) ? (($row->manual_notice)?'有':'無') : '' }}{{ $row->manual_notice_method ?? '' }}{{ $row->waitlist_order ?? '' }}
+
+
+
+ + {{-- 下側ページャ(右寄せ) --}} +
+ {{ $list->appends(['sort'=>$sort,'sort_type'=>$sort_type])->links('pagination') }} +
+
+
+
+ +{{-- 一括削除のフロント処理(jQuery不要) --}} + +@endsection diff --git a/resources/views/admin/update_candidate/list.blade.php b/resources/views/admin/update_candidate/list.blade.php new file mode 100644 index 0000000..7ee4e5f --- /dev/null +++ b/resources/views/admin/update_candidate/list.blade.php @@ -0,0 +1,281 @@ +@extends('layouts.app') + +@section('title', '更新予定者一覧') + +@section('content') +
+
+
+
+

更新予定者一覧

+
+
+ +
+
+
+
+ +
+
+ + {{-- 絞り込みフィルター(左右2カラム、ラベル3/入力9で整列) --}} +
+
+
絞り込みフィルター
+
+ {{-- 左カラム --}} +
+
+ +
+ @isset($parks) + + @else + + @endisset +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ @php + $target_month = request('target_month', 'this'); + @endphp +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + {{-- 右カラム --}} +
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ +
+ + 解除 +
+
+
+ + {{-- 一覧テーブル(非折返し表示/表頭グレー) --}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @forelse ($rows as $row) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{-- 授受フラグ/授受日時(カラム名不確定のため安全アクセス) --}} + + + + @empty + + + + @endforelse + +
利用者ID氏名フリガナ + + 定期契約ID + @if(request('sort') === 'contract_id') + @if(request('sort_type') === 'asc') ▲ @else ▼ @endif + @endif + + タグ・QR駐輪場車種区分減免措置利用者分類1利用者分類2利用者分類3携帯電話番号自宅電話番号生年月日性別居住所:郵便番号居住所:都道府県居住所:市区群居住所:住所関連住所:郵便番号関連住所:都道府県関連住所:市区群関連住所:住所契約日利用期間有効期間定期券区分勤務先名学校卒業予定シール発行回数防犯登録備考授受フラグ授受日時
{{ $row->user_id }}{{ $row->user_name }}{{ $row->user_phonetic }}{{ $row->contract_id }}{{ $row->tag_qr_flag ? 'QR' : 'タグ' }}{{ $row->park_name }}{{ $row->vehicle_type ?? '' }}{{ $row->user_reduction ?? '' }}{{ $row->user_category1 ?? '' }}{{ $row->user_category2 ?? '' }}{{ $row->user_category3 ?? '' }}{{ $row->user_mobile }}{{ $row->user_homephone }}{{ $row->user_birthdate }}{{ $row->user_gender }}{{ $row->user_regident_zip }}{{ $row->user_regident_pre }}{{ $row->user_regident_city }}{{ $row->user_regident_add }}{{ $row->user_relate_zip }}{{ $row->user_relate_pre }}{{ $row->user_relate_city }}{{ $row->user_relate_add }}{{ $row->contract_created_at }}{{ $row->contract_periods }}{{ $row->contract_periode }}{{ $row->ticket_type ?? '' }}{{ $row->user_workplace }}{{ $row->user_school }}{{ $row->user_graduate }}{{ $row->seal_issue_count ?? '' }}{{ $row->crime_prevention ?? '' }}{{ $row->user_remarks }} + {{ $row->receive_flag ?? $row->handover_flag ?? $row->transfer_flag ?? '' }} + + {{ $row->receive_datetime ?? $row->handover_datetime ?? $row->transfer_datetime ?? '' }} +
データがありません。
+
+ +
+ {{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }} +
+
+
+ +{{-- 画面用スタイル(表頭をグレー、明朝は非推奨・可読優先/データ折返し禁止) --}} + +@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index f2b0e84..2c26d2b 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -1,5 +1,6 @@ + @@ -33,25 +34,26 @@ - + - -
- - - - - + + +
+ @yield('content')
- - + - -
- @yield('content') + @stack('scripts') + + + + + + +
- + - - + + + + + + + + + + + + + + + - - - -
- + + + + + + + + + + + + + + + + - - - - - - - - - - - - - + //Datemask dd/mm/yyyy + $('#datemask').inputmask('dd/mm/yyyy', { 'placeholder': 'dd/mm/yyyy' }) + //Datemask2 mm/dd/yyyy + $('#datemask2').inputmask('mm/dd/yyyy', { 'placeholder': 'mm/dd/yyyy' }) + //Money Euro + $('[data-mask]').inputmask() - - - - - - - - - - - - - - - - + //Timepicker + $('.timepicker').timepicker({ + showInputs: false + }) + }); + - - + + + diff --git a/routes/web.php b/routes/web.php index 3e8e2ec..2ecc111 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,24 @@ use Illuminate\Support\Facades\Route; +use App\Http\Controllers\Admin\CityController; +use App\Http\Controllers\Admin\ParkController; +use App\Http\Controllers\Admin\PriceListController; +use App\Http\Controllers\Admin\PriceController; +use App\Http\Controllers\Admin\PsectionController; +use App\Http\Controllers\Admin\PtypeController; +use App\Http\Controllers\Admin\PeriodicalController; +use App\Http\Controllers\Admin\NewsController; +use App\Http\Controllers\Admin\UsersController; +use App\Http\Controllers\Admin\RegularContractController; +use App\Http\Controllers\Admin\ReservesController; +use App\Http\Controllers\Admin\UsertypeController; +use App\Http\Controllers\Admin\ContractorController; +use App\Http\Controllers\Admin\ContractorListController; +use App\Http\Controllers\Admin\UpdateCandidateController; +use App\Http\Controllers\Admin\ReservationController; + + /** * Laravel 12変更点:ルート定義の書き方が変更 * Laravel 5.7: Route::get('url', 'Controller@method') の形式 @@ -93,4 +111,276 @@ Route::middleware('auth')->group(function () { // Laravel 12対応:RESTful API エンドポイント Route::get('/using_status/api', [App\Http\Controllers\Admin\UsingStatusController::class, 'apiGetUtilization'])->name('using_status.api'); Route::get('/using_status/export', [App\Http\Controllers\Admin\UsingStatusController::class, 'exportCsv'])->name('using_status.export'); + + // [東京都|〇〇駐輪場] 定期種別マスタ + Route::match(['get', 'post'], '/regular_types', [App\Http\Controllers\Admin\RegularTypeController::class, 'list'])->name('regular_types'); + Route::match(['get', 'post'], '/regular_types/add', [App\Http\Controllers\Admin\RegularTypeController::class, 'add'])->name('regular_type_add'); + Route::match(['get', 'post'], '/regular_types/edit/{id}', [App\Http\Controllers\Admin\RegularTypeController::class, 'edit'])->where(['id' => '[0-9]+'])->name('regular_type_edit'); + Route::match(['get', 'post'], '/regular_types/info/{id}', [App\Http\Controllers\Admin\RegularTypeController::class, 'info'])->where(['id' => '[0-9]+'])->name('regular_type_info'); + Route::match(['get', 'post'], '/regular_types/delete', [App\Http\Controllers\Admin\RegularTypeController::class, 'delete'])->name('regular_types_delete'); + Route::match(['get', 'post'], '/regular_types/import', [App\Http\Controllers\Admin\RegularTypeController::class, 'import'])->name('regular_types_import'); + Route::get('/regular_types/export', [App\Http\Controllers\Admin\RegularTypeController::class, 'export'])->name('regular_types_export'); + + // [東京都|〇〇駐輪場] 近傍駅マスタ + Route::match(['get', 'post'], '/neighbor_stations', [App\Http\Controllers\Admin\NeighborStationController::class, 'list'])->name('neighbor_stations'); + Route::match(['get', 'post'], '/neighbor_stations/add', [App\Http\Controllers\Admin\NeighborStationController::class, 'add'])->name('neighbor_station_add'); + Route::match(['get', 'post'], '/neighbor_stations/edit/{id}', [App\Http\Controllers\Admin\NeighborStationController::class, 'edit'])->where(['id' => '[0-9]+'])->name('neighbor_station_edit'); + Route::get('/neighbor_stations/info/{id}', [App\Http\Controllers\Admin\NeighborStationController::class, 'info'])->where(['id' => '[0-9]+'])->name('neighbor_station_info'); + Route::match(['get', 'post'], '/neighbor_stations/delete', [App\Http\Controllers\Admin\NeighborStationController::class, 'delete'])->name('neighbor_stations_delete'); + Route::post('/neighbor_stations/import', [App\Http\Controllers\Admin\NeighborStationController::class, 'import'])->name('neighbor_stations_import'); + Route::get('/neighbor_stations/export', [App\Http\Controllers\Admin\NeighborStationController::class, 'export'])->name('neighbor_stations_export'); + + // [東京都|〇〇駐輪場] 利用契約マスタ + Route::match(['get', 'post'], '/terms', [App\Http\Controllers\Admin\TermsController::class, 'list'])->name('terms'); // 一覧表示 + Route::match(['get', 'post'], '/terms/add', [App\Http\Controllers\Admin\TermsController::class, 'add'])->name('terms_add'); // 新規登録画面・登録処理 + Route::match(['get', 'post'], '/terms/edit/{term_id}', [App\Http\Controllers\Admin\TermsController::class, 'edit'])->where(['term_id' => '[0-9]+'])->name('terms_edit'); // 編集画面・更新処理 + Route::match(['get', 'post'], '/terms/info/{term_id}', [App\Http\Controllers\Admin\TermsController::class, 'info'])->where(['term_id' => '[0-9]+'])->name('terms_info'); // 詳細表示 + Route::match(['get', 'post'], '/terms/delete', [App\Http\Controllers\Admin\TermsController::class, 'delete'])->name('terms_delete'); // 削除処理(複数可) + Route::match(['get', 'post'], '/terms/import', [App\Http\Controllers\Admin\TermsController::class, 'import'])->name('terms_import'); // CSVインポート(仮) + Route::get('/terms/export', [App\Http\Controllers\Admin\TermsController::class, 'export'])->name('terms_export'); // CSVエクスポート + + + // [東京都|〇〇駐輪場] 管轄駐輪場マスタ + Route::match(['get', 'post'], '/jurisdiction_parkings', [App\Http\Controllers\Admin\JurisdictionParkingController::class, 'list'])->name('jurisdiction_parkings'); // 一覧表示 + Route::match(['get', 'post'], '/jurisdiction_parkings/add', [App\Http\Controllers\Admin\JurisdictionParkingController::class, 'add'])->name('jurisdiction_parkings_add'); // 新規登録画面・登録処理 + Route::match(['get', 'post'], '/jurisdiction_parkings/edit/{jurisdiction_parking_id}', [App\Http\Controllers\Admin\JurisdictionParkingController::class, 'edit'])->where(['jurisdiction_parking_id' => '[0-9]+'])->name('jurisdiction_parkings_edit'); // 編集画面・更新処理 + Route::match(['get', 'post'], '/jurisdiction_parkings/info/{jurisdiction_parking_id}', [App\Http\Controllers\Admin\JurisdictionParkingController::class, 'info'])->where(['jurisdiction_parking_id' => '[0-9]+'])->name('jurisdiction_parkings_info'); // 詳細表示 + Route::match(['get', 'post'], '/jurisdiction_parkings/delete', [App\Http\Controllers\Admin\JurisdictionParkingController::class, 'delete'])->name('jurisdiction_parkings_delete'); // 削除処理(複数可) + Route::match(['get', 'post'], '/jurisdiction_parkings/import', [App\Http\Controllers\Admin\JurisdictionParkingController::class, 'import'])->name('jurisdiction_parkings_import'); // CSVインポート(仮) + Route::get('/jurisdiction_parkings/export', [App\Http\Controllers\Admin\JurisdictionParkingController::class, 'export'])->name('jurisdiction_parkings_export'); // CSVエクスポート + + + // [東京都|〇〇駐輪場] シール印刷範囲マスタ + Route::match(['get', 'post'], '/print_areas', [App\Http\Controllers\Admin\PrintAreaController::class, 'list'])->name('print_areas'); + Route::match(['get', 'post'], '/print_areas/add', [App\Http\Controllers\Admin\PrintAreaController::class, 'add'])->name('print_areas_add'); + Route::match(['get', 'post'], '/print_areas/edit/{print_area_id}', [App\Http\Controllers\Admin\PrintAreaController::class, 'edit'])->name('print_areas_edit')->where(['print_area_id' => '[0-9]+']); + Route::match(['get', 'post'], '/print_areas/info/{print_area_id}', [App\Http\Controllers\Admin\PrintAreaController::class, 'info'])->name('print_areas_info')->where(['print_area_id' => '[0-9]+']); + Route::match(['get', 'post'], '/print_areas/delete', [App\Http\Controllers\Admin\PrintAreaController::class, 'delete'])->name('print_areas_delete'); + Route::match(['get', 'post'], '/print_areas/import', [App\Http\Controllers\Admin\PrintAreaController::class, 'import'])->name('print_areas_import'); + Route::get('/print_areas/export', [App\Http\Controllers\Admin\PrintAreaController::class, 'export'])->name('print_areas_export'); + + + // [東京都|〇〇駐輪場] 契約許容市区マスタ + Route::match(['get', 'post'], '/contract_allowable_cities', [App\Http\Controllers\Admin\ContractAllowableCityController::class, 'list'])->name('contract_allowable_cities'); + Route::match(['get', 'post'], '/contract_allowable_cities/add', [App\Http\Controllers\Admin\ContractAllowableCityController::class, 'add'])->name('contract_allowable_cities_add'); + Route::match(['get', 'post'], '/contract_allowable_cities/edit/{contract_allowable_city_id}', [App\Http\Controllers\Admin\ContractAllowableCityController::class, 'edit'])->name('contract_allowable_cities_edit')->where(['contract_allowable_city_id' => '[0-9]+']); + Route::match(['get', 'post'], '/contract_allowable_cities/info/{contract_allowable_city_id}', [App\Http\Controllers\Admin\ContractAllowableCityController::class, 'info'])->name('contract_allowable_cities_info')->where(['contract_allowable_city_id' => '[0-9]+']); + Route::match(['get', 'post'], '/contract_allowable_cities/delete', [App\Http\Controllers\Admin\ContractAllowableCityController::class, 'delete'])->name('contract_allowable_cities_delete'); + Route::match(['get', 'post'], '/contract_allowable_cities/import', [App\Http\Controllers\Admin\ContractAllowableCityController::class, 'import'])->name('contract_allowable_cities_import'); + Route::get('/contract_allowable_cities/export', [App\Http\Controllers\Admin\ContractAllowableCityController::class, 'export'])->name('contract_allowable_cities_export'); + + + // [東京都|〇〇駐輪場] 管駐輪場管理者マスタ + Route::match(['get', 'post'], '/managers', [App\Http\Controllers\Admin\ManagerController::class, 'list'])->name('managers'); + Route::match(['get', 'post'], '/managers/add', [App\Http\Controllers\Admin\ManagerController::class, 'add'])->name('managers_add'); + Route::match(['get', 'post'], '/managers/edit/{manager_id}', [App\Http\Controllers\Admin\ManagerController::class, 'edit'])->name('managers_edit')->where(['manager_id' => '[0-9]+']); + Route::match(['get', 'post'], '/managers/info/{manager_id}', [App\Http\Controllers\Admin\ManagerController::class, 'info'])->name('managers_info')->where(['manager_id' => '[0-9]+']); + Route::match(['get', 'post'], '/managers/delete', [App\Http\Controllers\Admin\ManagerController::class, 'delete'])->name('managers_delete'); + Route::match(['get', 'post'], '/managers/import', [App\Http\Controllers\Admin\ManagerController::class, 'import'])->name('managers_import'); + Route::get('/managers/export', [App\Http\Controllers\Admin\ManagerController::class, 'export'])->name('managers_export'); + + + // [東京都|〇〇駐輪場] 消費税マスタ + Route::match(['get', 'post'], '/tax', [App\Http\Controllers\Admin\TaxController::class, 'list'])->name('tax'); + Route::match(['get', 'post'], '/tax/add', [App\Http\Controllers\Admin\TaxController::class, 'add'])->name('tax_add'); + Route::match(['get', 'post'], '/tax/edit/{tax_id}', [App\Http\Controllers\Admin\TaxController::class, 'edit']) + ->name('tax_edit')->where(['tax_id' => '[0-9]+']); + Route::match(['get', 'post'], '/tax/info/{tax_id}', [App\Http\Controllers\Admin\TaxController::class, 'info']) + ->name('tax_info')->where(['tax_id' => '[0-9]+']); + Route::match(['get', 'post'], '/tax/delete', [App\Http\Controllers\Admin\TaxController::class, 'delete'])->name('tax_delete'); + Route::match(['get', 'post'], '/tax/import', [App\Http\Controllers\Admin\TaxController::class, 'import'])->name('tax_import'); + Route::get('/tax/export', [App\Http\Controllers\Admin\TaxController::class, 'export'])->name('tax_export'); + + // [東京都|〇〇駐輪場] 決済情報マスタ + Route::match(['get', 'post'], '/payments', [App\Http\Controllers\Admin\PaymentController::class, 'list'])->name('payments'); + Route::match(['get', 'post'], '/payments/add', [App\Http\Controllers\Admin\PaymentController::class, 'add'])->name('payments_add'); + Route::match(['get', 'post'], '/payments/edit/{payment_id}', [App\Http\Controllers\Admin\PaymentController::class, 'edit']) + ->name('payments_edit')->where(['payment_id' => '[0-9]+']); + Route::match(['get', 'post'], '/payments/info/{payment_id}', [App\Http\Controllers\Admin\PaymentController::class, 'info']) + ->name('payments_info')->where(['payment_id' => '[0-9]+']); + Route::match(['get', 'post'], '/payments/delete', [App\Http\Controllers\Admin\PaymentController::class, 'delete'])->name('payments_delete'); + Route::match(['get', 'post'], '/payments/import', [App\Http\Controllers\Admin\PaymentController::class, 'import'])->name('payments_import'); + Route::get('/payments/export', [App\Http\Controllers\Admin\PaymentController::class, 'export'])->name('payments_export'); + + // [東京都|〇〇駐輪場] 決済トランザクション + Route::match(['get', 'post'], '/settlement_transactions', [App\Http\Controllers\Admin\SettlementTransactionController::class, 'list'])->name('settlement_transactions'); + Route::match(['get', 'post'], '/settlement_transactions/add', [App\Http\Controllers\Admin\SettlementTransactionController::class, 'add'])->name('settlement_transactions_add'); + Route::match(['get', 'post'], '/settlement_transactions/edit/{settlement_transaction_id}', [App\Http\Controllers\Admin\SettlementTransactionController::class, 'edit']) + ->name('settlement_transactions_edit')->where(['settlement_transaction_id' => '[0-9]+']); + Route::match(['get', 'post'], '/settlement_transactions/info/{settlement_transaction_id}', [App\Http\Controllers\Admin\SettlementTransactionController::class, 'info']) + ->name('settlement_transactions_info')->where(['settlement_transaction_id' => '[0-9]+']); + Route::match(['get', 'post'], '/settlement_transactions/delete', [App\Http\Controllers\Admin\SettlementTransactionController::class, 'delete'])->name('settlement_transactions_delete'); + Route::match(['get', 'post'], '/settlement_transactions/import', [App\Http\Controllers\Admin\SettlementTransactionController::class, 'import'])->name('settlement_transactions_import'); + Route::get('/settlement_transactions/export', [App\Http\Controllers\Admin\SettlementTransactionController::class, 'export'])->name('settlement_transactions_export'); + + // [東京都|〇〇駐輪場] オペレーターマスタ + Route::match(['get','post'], '/ope', [App\Http\Controllers\Admin\OpeController::class, 'list'])->name('opes'); + Route::match(['get','post'], '/ope/add', [App\Http\Controllers\Admin\OpeController::class, 'add'])->name('opes_add'); + Route::match(['get','post'], '/ope/edit/{id}', [App\Http\Controllers\Admin\OpeController::class, 'edit']) + ->where(['id' => '[0-9]+'])->name('opes_edit'); + Route::match(['get','post'], '/ope/info/{id}', [App\Http\Controllers\Admin\OpeController::class, 'info']) + ->where(['id' => '[0-9]+'])->name('opes_info'); + Route::match(['get','post'], '/ope/delete', [App\Http\Controllers\Admin\OpeController::class, 'delete'])->name('opes_delete'); + Route::match(['get','post'], '/ope/import', [App\Http\Controllers\Admin\OpeController::class, 'import'])->name('opes_import'); + Route::get('/ope/export', [App\Http\Controllers\Admin\OpeController::class, 'export'])->name('opes_export'); + + + // [東京都|〇〇駐輪場] デバイス管理マスタ + Route::match(['get', 'post'], '/device', [App\Http\Controllers\Admin\DeviceController::class, 'list'])->name('devices'); + Route::match(['get', 'post'], '/device/add', [App\Http\Controllers\Admin\DeviceController::class, 'add'])->name('devices_add'); + Route::match(['get', 'post'], '/device/edit/{id}', [App\Http\Controllers\Admin\DeviceController::class, 'edit']) + ->where(['id' => '[0-9]+'])->name('devices_edit'); + Route::match(['get', 'post'], '/device/info/{id}', [App\Http\Controllers\Admin\DeviceController::class, 'info']) + ->where(['id' => '[0-9]+'])->name('devices_info'); + Route::match(['get', 'post'], '/device/delete', [App\Http\Controllers\Admin\DeviceController::class, 'delete'])->name('devices_delete'); + Route::match(['get', 'post'], '/device/import', [App\Http\Controllers\Admin\DeviceController::class, 'import'])->name('devices_import'); + Route::get('/device/export', [App\Http\Controllers\Admin\DeviceController::class, 'export'])->name('devices_export'); + + // [東京都|〇〇駐輪場] オペレーターキュー + Route::match(['get', 'post'], '/operator_que', [App\Http\Controllers\Admin\OperatorQueController::class, 'list'])->middleware('auth')->name('operator_ques'); + Route::match(['get', 'post'], '/operator_que/add', [App\Http\Controllers\Admin\OperatorQueController::class, 'add'])->middleware('auth')->name('operator_ques_add'); + Route::match(['get', 'post'], '/operator_que/edit/{id}', [App\Http\Controllers\Admin\OperatorQueController::class, 'edit'])->where(['id' => '[0-9]+'])->middleware('auth')->name('operator_ques_edit'); + Route::match(['get', 'post'], '/operator_que/info/{id}', [App\Http\Controllers\Admin\OperatorQueController::class, 'info'])->where(['id' => '[0-9]+'])->middleware('auth')->name('operator_ques_info'); + Route::match(['get', 'post'], '/operator_que/delete', [App\Http\Controllers\Admin\OperatorQueController::class, 'delete'])->name('operator_ques_delete'); + Route::match(['get', 'post'], '/operator_ques/import', [App\Http\Controllers\Admin\OperatorQueController::class, 'import'])->name('operator_ques_import'); + Route::get('/operator_ques/export', [App\Http\Controllers\Admin\OperatorQueController::class, 'export'])->name('operator_ques_export'); + + // [東京都|〇〇駐輪場] 設定マスタ + Route::match(['get', 'post'], '/setting', [App\Http\Controllers\Admin\SettingController::class, 'list']) + ->middleware('auth')->name('settings'); + Route::match(['get', 'post'], '/setting/add', [App\Http\Controllers\Admin\SettingController::class, 'add']) + ->middleware('auth')->name('settings_add'); + Route::match(['get', 'post'], '/setting/edit/{id}', [App\Http\Controllers\Admin\SettingController::class, 'edit']) + ->where(['id' => '[0-9]+'])->middleware('auth')->name('settings_edit'); + Route::match(['get', 'post'], '/setting/info/{id}', [App\Http\Controllers\Admin\SettingController::class, 'info']) + ->where(['id' => '[0-9]+'])->middleware('auth')->name('settings_info'); + Route::match(['get', 'post'], '/setting/delete', [App\Http\Controllers\Admin\SettingController::class, 'delete']) + ->middleware('auth')->name('settings_delete'); + + + // sou start + // [東京都|〇〇駐輪場] 定期契約マスタ + Route::match(['get', 'post'], '/regular_contracts', [App\Http\Controllers\Admin\RegularContractController::class, 'list'])->name('regular_contracts'); + Route::match(['get', 'post'], '/regular_contracts/add', [App\Http\Controllers\Admin\RegularContractController::class, 'add'])->name('regular_contract_add'); + Route::match(['get', 'post'], '/regular_contracts/edit/{contract_id}', [App\Http\Controllers\Admin\RegularContractController::class, 'edit'])->name('regular_contract_edit')->where(['contract_id' => '[0-9]+']); + Route::match(['get', 'post'], '/regular_contracts/info/{contract_id}', [App\Http\Controllers\Admin\RegularContractController::class, 'info'])->name('regular_contract_info')->where(['contract_id' => '[0-9]+']); + Route::match(['get', 'post'], '/regular_contracts/delete', [App\Http\Controllers\Admin\RegularContractController::class, 'delete'])->name('regular_contracts_delete'); + Route::match(['get', 'post'], '/regular_contracts/import', [App\Http\Controllers\Admin\RegularContractController::class, 'import'])->name('regular_contracts_import'); + Route::get('/regular_contracts/export', [App\Http\Controllers\Admin\RegularContractController::class, 'export'])->name('regular_contracts_export'); + + // [東京都|〇〇駐輪場] 駐輪車室マスタ + Route::match(['get', 'post'], '/pplace', [PplaceController::class, 'list'])->name('pplace'); + Route::match(['get', 'post'], '/pplace/add', [PplaceController::class, 'add'])->name('pplace_add'); + Route::match(['get', 'post'], '/pplace/edit/{id}', [PplaceController::class, 'edit'])->name('pplace_edit')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/pplace/info/{id}', [PplaceController::class, 'info'])->name('pplace_info')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/pplace/delete', [PplaceController::class, 'delete'])->name('pplace_delete'); + Route::match(['get', 'post'], '/pplace/import', [PplaceController::class, 'import'])->name('pplace_import'); + Route::get('/pplace/export', [PplaceController::class, 'export'])->name('pplace_export'); + // sou end + + // ou start + // 市区マスタ + Route::match(['get', 'post'], '/city', [CityController::class, 'list'])->name('city'); + Route::match(['get', 'post'], '/city/add', [CityController::class, 'add'])->name('city_add'); + Route::match(['get', 'post'], '/city/edit/{id}', [CityController::class, 'edit'])->where(['id' => '[0-9]+'])->name('city_edit'); + Route::match(['get', 'post'], '/city/info/{id}', [CityController::class, 'info'])->where(['id' => '[0-9]+'])->name('city_info'); + Route::match(['get', 'post'], '/city/delete', [CityController::class, 'delete'])->name('city_delete'); + + // 駐輪場マスタ + Route::get('/parks', [ParkController::class, 'list'])->name('parks'); + Route::get('/parks/add', [ParkController::class, 'add'])->name('parks.add'); + Route::post('/parks/add', [ParkController::class, 'add'])->name('parks.store'); + Route::match(['get', 'post', 'put'], '/parks/edit/{id}', [ParkController::class, 'edit'])->name('parks.edit'); + Route::put('/parks/edit/{id}', [ParkController::class, 'edit'])->name('parks.update'); + Route::match(['get', 'post'], '/parks/delete', [ParkController::class, 'delete'])->name('parks.delete'); + Route::get('/parks/export', [ParkController::class, 'export'])->name('parks.export'); + Route::post('/parks/check-duplicate', [App\Http\Controllers\Admin\ParkController::class, 'checkDuplicate'])->name('parks.check_duplicate'); + + // 料金一覧表マスタ + Route::match(['get', 'post'], '/admin/pricelist', [PriceListController::class, 'list'])->name('pricelist'); + Route::post('/admin/pricelist/update', [PriceListController::class, 'update'])->name('pricelist_update'); + Route::post('/admin/pricelist/insert', [PriceListController::class, 'insert'])->name('pricelist_insert'); + + //駐輪場所、料金マスタ + Route::match(['get', 'post'], '/admin/prices', [PriceController::class, 'list'])->name('prices'); + Route::match(['get', 'post'], '/admin/prices/add', [PriceController::class, 'add'])->name('price_add'); + Route::match(['get', 'post'], '/admin/prices/edit/{id}', [PriceController::class, 'edit'])->name('price_edit')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/admin/prices/info/{id}', [PriceController::class, 'info'])->name('price_info')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/admin/prices/delete', [PriceController::class, 'delete'])->name('prices_delete'); + Route::match(['get', 'post'], '/admin/prices/import', [PriceController::class, 'import'])->name('prices_import'); + Route::get('/admin/prices/export', [PriceController::class, 'export'])->name('prices_export'); + + //車種区分マスタ + Route::match(['get', 'post'], '/admin/psection', [PsectionController::class, 'list'])->name('psection'); + Route::match(['get', 'post'], '/admin/psection/add', [PsectionController::class, 'add'])->name('psection_add'); + Route::match(['get', 'post'], '/admin/psection/edit/{id}', [PsectionController::class, 'edit'])->name('psection_edit')->where(['id' => '[0-9]+']); + Route::post('/admin/psection/delete', [PsectionController::class, 'delete'])->name('psection_delete'); + + //駐輪分類マスタ + Route::match(['get', 'post'], '/admin/ptypes', [PtypeController::class, 'list'])->name(name: 'ptypes'); + Route::match(['get', 'post'], '/admin/ptypes/add', [PtypeController::class, 'add'])->name('ptype_add'); + Route::match(['get', 'post'], '/admin/ptypes/edit/{id}', [PtypeController::class, 'edit'])->name('ptype_edit')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/admin/ptypes/info/{id}', [PtypeController::class, 'info'])->name('ptype_info')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/admin/ptypes/delete', [PtypeController::class, 'delete'])->name('ptype_delete'); + Route::match(['get', 'post'], '/admin/ptypes/import', [PtypeController::class, 'import'])->name('ptype_import'); + Route::get('/admin/ptypes/export', [PtypeController::class, 'export'])->name('ptype_export'); + + //定期利用・契約状況 + Route::match(['get', 'post'], '/periodical', [PeriodicalController::class, 'list'])->name('periodical'); + Route::get('/periodical/list-data', [PeriodicalController::class, 'listData'])->name('periodical.listData'); + Route::get('/periodical/area', [PeriodicalController::class, 'area'])->name('periodical.area'); + Route::get('/periodical/area-list-data', [PeriodicalController::class, 'areaListData'])->name('periodical.areaListData'); + + // 一般ウェブ管理 > 最新ニュース登録 + Route::match(['get', 'post'], '/web/news', [NewsController::class, 'list'])->name('news'); + Route::match(['get', 'post'], '/web/news/add', [NewsController::class, 'add'])->name('news_add'); + Route::match(['get', 'post'], '/web/news/edit/{id}', [NewsController::class, 'edit'])->where(['id' => '[0-9]+'])->name('news_edit'); + Route::match(['get', 'post'], '/web/news/info/{id}', [NewsController::class, 'info'])->where(['id' => '[0-9]+'])->name('news_info'); + Route::match(['get', 'post'], '/web/news/delete', [NewsController::class, 'delete'])->name('news_delete'); + + // 利用者マスタ + Route::match(['get', 'post'], '/users', [UsersController::class, 'list'])->name('users'); + Route::match(['get', 'post'], '/users/add', [UsersController::class, 'add'])->name('users_add'); + Route::match(['get', 'post'], '/users/export', [UsersController::class, 'export'])->name('users_export'); + + // 定期契約マスタ + Route::match(['get', 'post'], '/regularcontracts', [RegularContractController::class, 'list'])->name('regularcontracts'); + Route::match(['get', 'post'], '/regularcontracts/add', [RegularContractController::class, 'add'])->name('regularcontracts_add'); + Route::match(['get', 'post'], '/regularcontracts/edit/{contract_id}', [RegularContractController::class, 'edit'])->where(['contract_id' => '[0-9]+'])->name('regularcontracts_edit'); + Route::match(['get', 'post'], '/regularcontracts/import', [RegularContractController::class, 'import'])->name('regularcontracts_import'); + Route::get('/regularcontracts/export', [RegularContractController::class, 'export'])->name('regularcontracts_export')->middleware('auth'); + Route::match(['get', 'post'], '/regularcontracts/info/{contract_id}', [RegularContractController::class, 'info'])->where(['contract_id' => '[0-9]+'])->name('regularcontracts_info'); + Route::match(['get', 'post'], '/regularcontracts/delete', [RegularContractController::class, 'delete'])->name('regularcontracts_delete'); + + // 定期予約マスタ + Route::match(['get', 'post'], '/reserves', [ReservesController::class, 'list'])->name('reserves'); + Route::match(['get', 'post'], '/reserves/add', [ReservesController::class, 'add'])->name('reserves_add'); + Route::match(['get', 'post'], '/reserves/edit/{reserve_id}', [ReservesController::class, 'edit'])->name('reserves_edit'); + Route::match(['get', 'post'], '/reserves/delete', [ReservesController::class, 'delete'])->name('reserves_delete'); + Route::match(['get', 'post'], '/reserves/export', [ReservesController::class, 'export'])->name('reserves_export'); + + // 利用者分類マスタ + Route::match(['get', 'post'], '/usertypes', [UsertypeController::class, 'list'])->name('usertypes'); + Route::match(['get', 'post'], '/usertypes/add', [UsertypeController::class, 'add'])->name('usertype_add'); + Route::match(['get', 'post'], '/usertypes/edit/{id}', [UsertypeController::class, 'edit'])->name('usertype_edit')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/usertypes/info/{id}', [UsertypeController::class, 'info'])->name('usertype_info')->where(['id' => '[0-9]+']); + Route::match(['get', 'post'], '/usertypes/delete', [UsertypeController::class, 'delete'])->name('usertypes_delete'); + Route::match(['get', 'post'], '/usertypes/import', [UsertypeController::class, 'import'])->name('usertypes_import'); + Route::get('/usertypes/export', [UsertypeController::class, 'export'])->name('usertypes_export'); + + // 契約者一覧 + Route::match(['get', 'post'], '/contractor', [ContractorController::class, 'list'])->name('contractor'); + + // 未更新者一覧 + Route::match(['get', 'post'], '/contractor_list', [ContractorListController::class, 'list'])->name('contractor_List'); + + // 更新予定者一覧 + Route::match(['get', 'post'], '/update_candidate', [UpdateCandidateController::class, 'list'])->name('update_candidate'); + + // 予約者一覧 + Route::match(['get', 'post'], '/reservation', [ReservationController::class, 'list'])->name('reservation'); + + + + });