input('sort', 'manager_id'); $sort_type = $request->input('sort_type', 'asc'); if (!in_array($sort, $sortable)) $sort = 'manager_id'; if (!in_array(strtolower($sort_type), ['asc','desc'])) $sort_type = 'asc'; $list = Manager::with(['park','device1','device2']) ->orderBy($sort, $sort_type) ->paginate(20); return view('admin.managers.list', compact('list','sort','sort_type')); } /** 新規登録画面・登録処理 */ public function add(Request $request) { if ($request->isMethod('post')) { $validated = $this->validated($request); Manager::create($validated); return redirect() ->route('managers') ->with('success', '登録しました。'); } return view('admin.managers.add', $this->viewVars()); } /** 編集(GET:画面表示 / POST:更新) */ public function edit(Request $request, $id) { $manager = Manager::findOrFail($id); if ($request->isMethod('post')) { $validated = $this->validated($request); $manager->update($validated); return redirect() ->route('managers') ->with('success', '更新されました。'); } return view('admin.managers.edit', $this->viewVars($manager)); } /** 詳細(閲覧) */ public function info($manager_id) { $manager = Manager::with(['park','device1','device2'])->findOrFail($manager_id); $view = $this->viewVars($manager); return view('admin.managers.info', $view); } /** 一括削除(一覧・詳細・編集共通で pk[] を受ける) */ public function delete(Request $request) { $ids = (array) $request->input('pk', []); if (!$ids) { return back()->with('error', '削除対象が選択されていません。'); } DB::transaction(fn() => Manager::whereIn('manager_id', $ids)->delete()); // 一覧画面へリダイレクト + 成功メッセージ return redirect() ->route('managers') ->with('success', '削除しました。'); } /** CSV出力 */ public function export(): StreamedResponse { $headers = [ 'Content-Type' => 'text/csv; charset=UTF-8', 'Content-Disposition' => 'attachment; filename=managers.csv', ]; $columns = [ 'manager_id','manager_name','manager_type','manager_parkid', 'manager_device1','manager_device2','manager_mail','manager_tel', 'manager_alert1','manager_alert2','manager_quit_flag','manager_quitday' ]; return response()->stream(function () use ($columns) { $out = fopen('php://output', 'w'); fwrite($out, "\xEF\xBB\xBF"); // BOM fputcsv($out, $columns); Manager::chunk(500, function ($rows) use ($out, $columns) { foreach ($rows as $r) { fputcsv($out, array_map(fn($c) => data_get($r, $c), $columns)); } }); fclose($out); }, 200, $headers); } /** CSVインポート(input name="file") */ public function import(Request $request) { if (!$request->hasFile('file')) { return back()->with('error', 'CSVファイルを選択してください。'); } $fp = fopen($request->file('file')->getRealPath(), 'r'); if (!$fp) return back()->with('error', 'CSVを読み込めませんでした。'); $header = fgetcsv($fp); if (!$header) { fclose($fp); return back()->with('error', 'ヘッダ行が読み取れません。'); } $required = [ 'manager_id','manager_name','manager_type','manager_parkid', 'manager_device1','manager_device2','manager_mail','manager_tel', 'manager_alert1','manager_alert2','manager_quit_flag','manager_quitday' ]; foreach ($required as $c) { if (!in_array($c, $header)) { fclose($fp); return back()->with('error', "CSVに {$c} がありません。"); } } DB::beginTransaction(); try { while (($row = fgetcsv($fp)) !== false) { $data = array_combine($header, $row); if (!$data) continue; Manager::updateOrCreate( ['manager_id' => $data['manager_id']], [ 'manager_name' => $data['manager_name'] ?? null, 'manager_type' => $data['manager_type'] ?? null, 'manager_parkid' => $data['manager_parkid'] ?: null, 'manager_device1' => $data['manager_device1'] ?: null, 'manager_device2' => $data['manager_device2'] ?: null, 'manager_mail' => $data['manager_mail'] ?? null, 'manager_tel' => $data['manager_tel'] ?? null, 'manager_alert1' => (int)($data['manager_alert1'] ?? 0), 'manager_alert2' => (int)($data['manager_alert2'] ?? 0), 'manager_quit_flag' => (int)($data['manager_quit_flag'] ?? 0), 'manager_quitday' => $data['manager_quitday'] ?: null, ] ); } fclose($fp); DB::commit(); return back()->with('success', 'インポートが完了しました。'); } catch (\Throwable $e) { if (is_resource($fp)) fclose($fp); DB::rollBack(); return back()->with('error', 'インポートに失敗しました:'.$e->getMessage()); } } /** バリデーション + 前処理 */ private function validated(Request $request): array { // 電話番号を全角に変換(半角入力があっても自動で全角に揃える) $request->merge([ 'manager_tel' => mb_convert_kana($request->input('manager_tel'), 'N') // 半角数字→全角数字 ]); // select の未選択 "" を null に補正 foreach (['manager_device2'] as $f) { if ($request->input($f) === "") { $request->merge([$f => null]); } } return $request->validate([ 'manager_name' => ['required','string','max:32'], 'manager_type' => ['required','string','max:10'], 'manager_parkid' => ['required','integer','exists:park,park_id'], 'manager_device1' => ['required','integer','exists:device,device_id'], 'manager_device2' => ['nullable','integer','exists:device,device_id'], 'manager_mail' => ['nullable','email','max:128'], 'manager_tel' => ['required','regex:/^[0-9]+$/u','max:13'], // 全角数字のみ 'manager_alert1' => ['nullable','boolean'], 'manager_alert2' => ['nullable','boolean'], 'manager_quit_flag' => ['required','in:0,1'], 'manager_quitday' => ['nullable','date'], ], [], [ 'manager_name' => '駐輪場管理者名', 'manager_type' => '種別', 'manager_parkid' => '所属駐輪場ID', 'manager_device1' => '管理デバイス1', 'manager_device2' => '管理デバイス2', 'manager_mail' => 'メールアドレス', 'manager_tel' => '電話番号', 'manager_alert1' => 'アラート1送信', 'manager_alert2' => 'アラート2送信', 'manager_quit_flag' => '退職フラグ', 'manager_quitday' => '退職日', ]); } /** 画面に渡す変数を作る(_form.blade.php が個別変数を参照するため) */ private function viewVars(?Manager $m = null): array { $parks = Park::orderBy('park_name')->pluck('park_name','park_id')->toArray(); $devices = Device::orderBy('device_subject')->pluck('device_subject','device_id')->toArray(); return [ // _form が参照する個別変数 'manager_id' => $m->manager_id ?? null, 'manager_name' => $m->manager_name ?? null, 'manager_type' => $m->manager_type ?? null, 'manager_parkid' => $m->manager_parkid ?? null, 'manager_device1' => $m->manager_device1 ?? null, 'manager_device2' => $m->manager_device2 ?? null, 'manager_mail' => $m->manager_mail ?? null, 'manager_tel' => $m->manager_tel ?? null, 'manager_alert1' => (int)($m->manager_alert1 ?? 0), 'manager_alert2' => (int)($m->manager_alert2 ?? 0), 'manager_quit_flag' => isset($m) ? (int)$m->manager_quit_flag : 0, 'manager_quitday' => isset($m) && $m->manager_quitday ? $m->manager_quitday->format('Y-m-d') : null, // セレクトの候補 'parks' => $parks, 'devices' => $devices, // _form で必要なフラグ(各ビューで上書きしてもOK) 'isEdit' => isset($m), 'isInfo' => false, 'record' => $m, // 互換用(あなた的 edit.blade.php で参照しているなら) ]; } }