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..6fefb99
--- /dev/null
+++ b/app/Models/City.php
@@ -0,0 +1,24 @@
+ '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 @@
+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')
+
+
+
+
+
+@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')
+
+
+
+
+@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')
+
+
+
+
+
+
+
+
+
+@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)
+
+
+ {{ $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')
+
+@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) --}}
+
+
+
+
+@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')
+
+
+
+
+
+ {{-- 絞り込みフィルター --}}
+
+
+ {{-- 一覧テーブル --}}
+
+
+
+
+ | 利用者ID |
+ 氏名 |
+ フリガナ |
+
+
+ 定期契約ID
+ @if(request('sort') === 'rc.contract_id')
+ @if(request('sort_type') === 'asc')
+ ▲
+ @else
+ ▼
+ @endif
+ @endif
+
+ |
+ タグ・QR |
+ 駐輪場 |
+ 車種区分 |
+ 減免措置 |
+ 利用者分類1 |
+ 利用者分類2 |
+ 利用者分類3 |
+ 携帯電話番号 |
+ 自宅電話番号 |
+ 生年月日 |
+ 性別 |
+ 居住所:郵便番号 |
+ 居住所:都道府県 |
+ 居住所:市区群 |
+ 居住所:住所 |
+ 関連住所:郵便番号 |
+ 関連住所:都道府県 |
+ 関連住所:市区群 |
+ 関連住所:住所 |
+ 契約日 |
+ 利用期間 |
+ 有効期間 |
+ 定期券区分 |
+ 勤務先名 |
+ 学校 |
+ 卒業予定 |
+ シール発行回数 |
+ 防犯登録 |
+ 備考 |
+
+
+
+ @forelse ($rows as $row)
+
+ | {{ $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 }} |
+
+ @empty
+
+ | データがありません。 |
+
+ @endforelse
+
+
+
+
+
+ {{ $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')
+
+
+
+
+
+ {{-- 絞り込みフィルター --}}
+
+
+ {{-- 一覧テーブル --}}
+
+
+
+
+ | 利用者ID |
+ 氏名 |
+ フリガナ |
+
+
+ 定期契約ID
+ @if(request('sort') === 'contract_id')
+ @if(request('sort_type') === 'asc')
+ ▲
+ @else
+ ▼
+ @endif
+ @endif
+
+ |
+ タグ・QR |
+ 駐輪場 |
+ 車種区分 |
+ 減免措置 |
+ 利用者分類1 |
+ 利用者分類2 |
+ 利用者分類3 |
+ 携帯電話番号 |
+ 自宅電話番号 |
+ 生年月日 |
+ 性別 |
+ 居住所:郵便番号 |
+ 居住所:都道府県 |
+ 居住所:市区群 |
+ 居住所:住所 |
+ 関連住所:郵便番号 |
+ 関連住所:都道府県 |
+ 関連住所:市区群 |
+ 関連住所:住所 |
+ 契約日 |
+ 利用期間 |
+ 有効期間 |
+ 定期券区分 |
+ 勤務先名 |
+ 学校 |
+ 卒業予定 |
+ シール発行回数 |
+ 防犯登録 |
+ 備考 |
+
+
+
+ @forelse ($rows as $row)
+
+ | {{ $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 }} |
+
+ @empty
+
+ | データがありません。 |
+
+ @endforelse
+
+
+
+
+
+ {{ $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
+
+ {{-- ▼ 入力フォーム --}}
+
+
+
+@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
+
+ {{-- ▼ 入力フォーム --}}
+
+
+
+
+
+
+ {{-- ▼ 登録/更新メタ情報 --}}
+
+
登録日時:{{ $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 }}
+
+
+ {{-- ▼ 操作ボタン --}}
+
+
編集
+
+
一覧に戻る
+
+
+
+
+
+@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
+
+
+
+ {{-- ▼ ヘッダー:新規/削除 --}}
+
+
+ {{-- ▼ 一覧テーブル --}}
+
+
+
+
+
+
+
+{{-- ▼ スクリプト:全選択/全解除 --}}
+
+@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 @@
+{{-- 駐輪場マスタ 共通フォーム --}}
+
+
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
+
+
+
+
+@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')
+
+
+@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)
+
+ @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'))
+
+
+ {{ Session::get('success') }}
+
+@elseif(Session::has('error'))
+
+
+
エラー:
+ {!! Session::get('error') !!}
+
+@elseif(isset($errorMsg))
+
+
+
エラー:
+ {!! $errorMsg !!}
+
+@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')
+
+
+
+
+
+
+
+
+ {{-- 上部:登録ボタン(駐輪場所・料金マスタのトーンに合わせた薄いボタン) --}}
+
+
+
+
+
+
+
+
+
+@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')
+
+
+
+
+
+
+
+
+ {{-- 本体フォーム(登録はこの form を submit) --}}
+
+
+
+
+
+
+
+@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')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+@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カラム) --}}
+
+
+
+
+
+
+
+ {{-- ツールバー:左=ボタン群、右=ページャ --}}
+
+
+
+
+ {{-- 一覧テーブル --}}
+
+
+ {{-- 下側のページャ(右寄せ) --}}
+
+ {{ $list->appends(['sort' => $sort, 'sort_type' => $sort_type])->links('pagination') }}
+
+
+
+
+
+ {{-- インポート用モーダル(ファイル選択) --}}
+
+
+
+
+
+
+
+
+
+ {{-- エクスポート用モーダル(確認のみ。リンク先でダウンロード) --}}
+
+
+
+
+
CSVファイルを出力します。よろしいですか?
+
+
+
+
+
+ {{-- 画面内スクリプト:インポートのファイル名表示、エクスポートの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 |
+ 氏名 |
+ フリガナ |
+ 居住所:郵便番号 |
+ 居住所:都道府県 |
+ 居住所:市区群 |
+ 居住所:住所 |
+ 関連住所:郵便番号 |
+ 関連住所:都道府県 |
+ 関連住所:市区群 |
+ 関連住所:住所 |
+ 生年月日 |
+ 性別 |
+ 携帯電話番号 |
+ 自宅電話番号 |
+ 学校 |
+ 卒業予定 |
+ 備考 |
+ 定期予約ID |
+ 利用者分類1 |
+ 利用者分類2 |
+ 利用者分類3 |
+ 駐輪場ID |
+ 駐輪場名 |
+ 駐輪場所ID |
+ 車種区分ID |
+ 予約日時 |
+ 減免措置 |
+ 800M以内フラグ |
+
+
+
+ @forelse ($rows as $row)
+
+ | {{ $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以内' : '-' }}
+ |
+
+ @empty
+ | データがありません。 |
+ @endforelse
+
+
+
+
+
+ {{ $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')
+
+
+
+ {{-- パンくず&見出し --}}
+
+
+
+
+
+
+
+
+
+
+
+
+@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
+
+
+
+
+ {{-- ヘッダー / パンくず --}}
+
+
+
+
+
+ {{-- 対象一覧(可能なら情報を表示。$rows が無いときはIDのバッジだけ) --}}
+
+
+
+ @if(!empty($rows) && count($rows))
+
+
+
+
+ | 予約ID |
+ 定期契約ID |
+ 利用者名 |
+ 駐輪場 |
+ 予約日時 |
+
+
+
+ @foreach($rows as $r)
+
+ | {{ $r->reserve_id }} |
+ {{ $r->contract_id ?? '' }} |
+ {{ $r->user_name ?? '' }} |
+ {{ $r->park_name ?? '' }} |
+ {{-- ※ 実テーブル列名に合わせて reserve_date を使用 --}}
+ {{ $r->reserve_date ?? '' }} |
+
+ @endforeach
+
+
+
+ @elseif(count($collectedIds))
+
+ 削除対象ID:
+ @foreach($collectedIds as $id)
+ {{ $id }}
+ @endforeach
+
+ @else
+
削除対象が取得できませんでした。
+ @endif
+
+
+
+ {{-- 確認フォーム --}}
+
+
+
+
+
+@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
+
+
+ {{-- ヘッダ --}}
+
+
+ {{-- 本体 --}}
+
+
+
+
+@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')
+
+
+
+ {{-- パンくず・ヘッダ --}}
+
+
+
+
+
+ {{-- 絞り込みフィルター(ここは前回どおり。必要に応じて調整可) --}}
+
+
+
+
+
+
+
+ {{-- ツールバー:左=ボタン群、右=ページャ(CSV出力→削除) --}}
+
+
+ {{-- 一覧テーブル(先頭列の並び替えを削除/操作列にチェック+編集) --}}
+
+
+ {{-- 下側ページャ(右寄せ) --}}
+
+ {{ $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で整列) --}}
+
+
+ {{-- 一覧テーブル(非折返し表示/表頭グレー) --}}
+
+
+
+
+ | 利用者ID |
+ 氏名 |
+ フリガナ |
+
+
+ 定期契約ID
+ @if(request('sort') === 'contract_id')
+ @if(request('sort_type') === 'asc') ▲ @else ▼ @endif
+ @endif
+
+ |
+ タグ・QR |
+ 駐輪場 |
+ 車種区分 |
+ 減免措置 |
+ 利用者分類1 |
+ 利用者分類2 |
+ 利用者分類3 |
+ 携帯電話番号 |
+ 自宅電話番号 |
+ 生年月日 |
+ 性別 |
+ 居住所:郵便番号 |
+ 居住所:都道府県 |
+ 居住所:市区群 |
+ 居住所:住所 |
+ 関連住所:郵便番号 |
+ 関連住所:都道府県 |
+ 関連住所:市区群 |
+ 関連住所:住所 |
+ 契約日 |
+ 利用期間 |
+ 有効期間 |
+ 定期券区分 |
+ 勤務先名 |
+ 学校 |
+ 卒業予定 |
+ シール発行回数 |
+ 防犯登録 |
+ 備考 |
+ 授受フラグ |
+ 授受日時 |
+
+
+
+ @forelse ($rows as $row)
+
+ | {{ $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 ?? '' }}
+ |
+
+ @empty
+
+ | データがありません。 |
+
+ @endforelse
+
+
+
+
+
+ {{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
+
+
+
+
+{{-- 画面用スタイル(表頭をグレー、明朝は非推奨・可読優先/データ折返し禁止) --}}
+
+@endsection
diff --git a/resources/views/layouts/app.blade -bk.php b/resources/views/layouts/app.blade -bk.php
new file mode 100644
index 0000000..4502f18
--- /dev/null
+++ b/resources/views/layouts/app.blade -bk.php
@@ -0,0 +1,600 @@
+
+
+
+
+
+ @yield('title') | So-Manager管理パネル
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @yield('content')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php
index f2b0e84..04f4e11 100644
--- a/resources/views/layouts/app.blade.php
+++ b/resources/views/layouts/app.blade.php
@@ -1,5 +1,6 @@
+
@@ -33,25 +34,26 @@
-
+
-
-
-
-