From 6640453c180c3786aae9efbdf69f6f2f0065f66e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=A0=E7=9A=84=E5=90=8D=E5=AD=97?= <你的邮箱> Date: Fri, 3 Oct 2025 18:18:39 +0900 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E5=88=A9=E7=94=A8=E8=80=85=E3=83=9E?= =?UTF-8?q?=E3=82=B9=E3=82=BF=EF=BC=88=E3=80=91=E7=B7=A8=E9=9B=86=E7=94=BB?= =?UTF-8?q?=E9=9D=A2=E8=BF=BD=E5=8A=A0=EF=BC=86=E4=B8=A6=E3=81=B3=E6=9B=BF?= =?UTF-8?q?=E3=81=88=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/Admin/UsersController.php | 153 ++++++- resources/views/admin/users/edit.blade.php | 382 ++++++++++++++++++ resources/views/admin/users/list.blade.php | 115 +++++- routes/web.php | 2 + 4 files changed, 628 insertions(+), 24 deletions(-) create mode 100644 resources/views/admin/users/edit.blade.php diff --git a/app/Http/Controllers/Admin/UsersController.php b/app/Http/Controllers/Admin/UsersController.php index 426a624..07afcd3 100644 --- a/app/Http/Controllers/Admin/UsersController.php +++ b/app/Http/Controllers/Admin/UsersController.php @@ -6,8 +6,30 @@ use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Validator; use Symfony\Component\HttpFoundation\StreamedResponse; +use Illuminate\Support\Facades\Hash; + class UsersController { + /** + * 利用者分類選択肢を取得 + */ + private function buildCategoryOptions(): array + { + return DB::table('usertype') + ->orderBy('user_categoryid', 'asc') + ->get() + ->mapWithKeys(function ($row) { + $label = collect([ + $row->usertype_subject1 ?? '', + $row->usertype_subject2 ?? '', + $row->usertype_subject3 ?? '', + ])->filter(fn ($v) => $v !== '')->implode('/'); + + return [$row->user_categoryid => $label !== '' ? $label : (string) $row->user_categoryid]; + }) + ->toArray(); + } + /** * 利用者一覧 * - テーブル名: user @@ -38,13 +60,15 @@ class UsersController 'user_name', 'user_birthdate', 'user_age', + 'user_mobile', 'user_homephone', 'user_primemail', 'user_submail', 'user_school', ]; $sort = $request->input('sort', 'user_seq'); - $sortType = strtolower($request->input('sort_type', 'desc')) === 'asc' ? 'asc' : 'desc'; + $dirParam = strtolower((string) $request->input('dir', $request->input('sort_type', 'asc'))); + $sortType = $dirParam === 'asc' ? 'asc' : 'desc'; if (!in_array($sort, $sortable, true)) { $sort = 'user_seq'; } @@ -56,6 +80,7 @@ class UsersController $user_phonetic = trim((string) $request->input('user_phonetic', '')); $phone = trim((string) $request->input('phone', '')); // 携帯/自宅の両方対象 $crime = trim((string) $request->input('crime', '')); // 防犯登録番号(暫定: qr_code) + $email = trim((string) $request->input('email', '')); $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=はい @@ -63,7 +88,14 @@ class UsersController $quit_to = (string) $request->input('quit_to', ''); // YYYY-MM-DD // ▼ ベースクエリ(一覧で使う列が多いので一旦 * を許容) - $query = DB::table('user')->select('user.*'); + $query = DB::table('user') + ->leftJoin('usertype', 'user.user_categoryid', '=', 'usertype.user_categoryid') + ->select( + 'user.*', + 'usertype.usertype_subject1', + 'usertype.usertype_subject2', + 'usertype.usertype_subject3' + ); // ▼ テキスト系 if ($user_id !== '') @@ -84,6 +116,8 @@ class UsersController // ※ dump に防犯登録番号の明確なカラムが無いため暫定的に qr_code を対象 $query->where('user.qr_code', 'like', "%{$crime}%"); } + if ($email !== '') + $query->where('user.user_primemail', 'like', "%{$email}%"); // ▼ セレクト/ラジオ('' 以外なら適用。'0' も通す) if ($user_categoryid !== '') @@ -107,17 +141,20 @@ class UsersController 'list' => $list, 'sort' => $sort, 'sort_type' => $sortType, + 'dir' => $sortType, 'user_id' => $user_id, 'member_id' => $member_id, 'user_tag_serial' => $user_tag_serial, 'user_phonetic' => $user_phonetic, 'phone' => $phone, 'crime' => $crime, + 'email' => $email, 'user_categoryid' => $user_categoryid, 'tag_qr_flag' => $tag_qr_flag, 'quit_flag' => $quit_flag, 'quit_from' => $quit_from, 'quit_to' => $quit_to, + 'categoryOptions' => $this->buildCategoryOptions(), ]); } @@ -260,10 +297,9 @@ class UsersController return view('admin.users.add'); } - // ▼ バリデーション(user_id は半角数字のみ) $rules = [ - 'user_id' => ['required', 'regex:/^\d+$/'], // 半角数字のみ許可 + 'user_id' => ['required', 'regex:/^\d+$/', 'digits_between:1,10'], // 半角数字(最大10桁) 'user_name' => ['required', 'string', 'max:255'], // 任意 'user_primemail' => ['nullable', 'email', 'max:255'], @@ -279,6 +315,8 @@ class UsersController $messages = [ 'user_id.required' => '利用者IDは必須です。', 'user_id.regex' => '利用者IDは半角数字のみで入力してください。', + 'user_id.digits_between' => '利用者IDは最大10桁以内で入力してください。', + 'user_name.required' => '氏名は必須です。', ]; // ▼ 属性名(日本語ラベル) @@ -315,4 +353,111 @@ class UsersController return redirect()->route('users')->with('success', '利用者を登録しました。'); } + /** + * 利用者編集(GET: 表示 / POST: 更新) + */ + public function edit(Request $request, int $seq) + { + $user = DB::table('user')->where('user_seq', $seq)->first(); + if (!$user) { + abort(404, '利用者情報が見つかりません。'); + } + + $operators = DB::table('ope') + ->select('ope_id', 'ope_name') + ->orderBy('ope_name') + ->get(); + + $categoryOptions = $this->buildCategoryOptions(); + + if ($request->isMethod('get')) { + return view('admin.users.edit', [ + 'user' => $user, + 'operators' => $operators, + 'categoryOptions' => $categoryOptions, + ]); + } + + $rules = [ + 'user_id' => ['required', 'regex:/^\d+$/', 'digits_between:1,10'], + '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', 'exists:usertype,user_categoryid'], + 'user_age' => ['nullable', 'integer', 'min:0'], + 'user_chk_day' => ['nullable', 'date'], + 'user_quitday' => ['nullable', 'date'], + 'ope_id' => ['nullable', 'integer', 'exists:ope,ope_id'], + ]; + + $messages = [ + 'user_id.required' => '利用者IDは必須です。', + 'user_id.regex' => '利用者IDは半角数字のみで入力してください。', + 'user_id.digits_between' => '利用者IDは最大10桁以内で入力してください。', + 'user_name.required' => '氏名は必須です。', + ]; + + $validator = Validator::make($request->all(), $rules, $messages); + if ($validator->fails()) { + return back()->withErrors($validator)->withInput(); + } + + $data = [ + 'user_id' => $request->input('user_id'), + 'member_id' => $request->input('member_id'), + 'user_name' => $request->input('user_name'), + 'user_gender' => $request->input('user_gender'), + 'user_mobile' => $request->input('user_mobile'), + 'user_homephone' => $request->input('user_homephone'), + 'user_birthdate' => $request->input('user_birthdate'), + 'user_age' => $request->input('user_age'), + 'user_categoryid' => $request->input('user_categoryid'), + 'user_phonetic' => $request->input('user_phonetic'), + 'user_tag_serial' => $request->input('user_tag_serial'), + 'user_tag_serial_64' => $request->input('user_tag_serial_64'), + 'qr_code' => $request->input('qr_code'), + 'tag_qr_flag' => $request->input('tag_qr_flag', '0'), + 'user_aid' => $request->input('user_aid'), + 'user_place_qrid' => $request->input('user_place_qrid'), + 'user_primemail' => $request->input('user_primemail'), + 'user_submail' => $request->input('user_submail'), + 'ward_residents' => $request->input('ward_residents'), + 'user_workplace' => $request->input('user_workplace'), + 'user_school' => $request->input('user_school'), + 'user_graduate' => $request->input('user_graduate'), + 'user_idcard' => $request->input('user_idcard'), + 'user_idcard_chk_flag' => $request->input('user_idcard_chk_flag', '0'), + 'user_chk_day' => $request->input('user_chk_day'), + 'user_chk_opeid' => $request->input('ope_id'), + 'ope_id' => $request->input('ope_id'), + 'user_regident_zip' => $request->input('user_regident_zip'), + 'user_regident_pre' => $request->input('user_regident_pre'), + 'user_regident_city' => $request->input('user_regident_city'), + 'user_regident_add' => $request->input('user_regident_add'), + 'user_relate_zip' => $request->input('user_relate_zip'), + 'user_relate_pre' => $request->input('user_relate_pre'), + 'user_relate_city' => $request->input('user_relate_city'), + 'user_relate_add' => $request->input('user_relate_add'), + 'user_tag_issue' => $request->input('user_tag_issue'), + 'issue_permission' => $request->input('issue_permission', '1'), + 'user_quit_flag' => $request->input('user_quit_flag', '0'), + 'user_quitday' => $request->input('user_quitday'), + 'user_remarks' => $request->input('user_remarks'), + 'updated_at' => now(), + ]; + + if ($request->filled('user_pass')) { + $data['user_pass'] = Hash::make($request->input('user_pass')); + } + + DB::table('user')->where('user_seq', $seq)->update($data); + + return redirect() + ->route('users_edit', ['seq' => $seq]) + ->with('status', '利用者情報を更新しました。'); + } } diff --git a/resources/views/admin/users/edit.blade.php b/resources/views/admin/users/edit.blade.php new file mode 100644 index 0000000..82a1cca --- /dev/null +++ b/resources/views/admin/users/edit.blade.php @@ -0,0 +1,382 @@ +@extends('layouts.app') + +@section('title', '利用者マスタ|編集') + +@section('content') +@php + /** @var \Illuminate\Support\ViewErrorBag $errors */ + $isEdit = isset($user); + $value = static function (string $key, $default = '') use ($isEdit, $user) { + return old($key, $isEdit ? ($user->{$key} ?? $default) : $default); + }; + $hasDeleteRoute = Route::has('users_delete_confirm'); + $operators = $operators ?? collect(); + $categoryOptions = $categoryOptions ?? []; +@endphp + +
+
+
+
+

編集

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

基本情報

+
+ + @if ($isEdit && $hasDeleteRoute) + + @endif +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
利用者連番
利用者ID*
会員ID
氏名*
フリガナ
パスワード + + 未入力の場合は変更されません。 +
メインメールアドレス
予備メールアドレス
携帯電話番号
固定電話番号
性別 + @foreach (['男性','女性','未入力'] as $gender) + @php $id = 'user_gender_'.$gender; @endphp +
+ + +
+ @endforeach +
生年月日
年齢
学校名
卒業予定
勤務先名
区民区分
本人確認書類
本人確認チェック + @foreach ([0 => '未チェック', 1 => '手動チェックOK'] as $flag => $label) + @php $id = 'user_idcard_chk_flag_'.$flag; @endphp +
+ + +
+ @endforeach +
本人確認日時
本人確認オペレータ + +
タグ/QRフラグ +
+ + +
+
+ + +
+
タグシリアル
タグシリアル(64進)
QRコード
AID
設置場所QRID
利用者分類 + +
タグ発行数
タグ発行許可 +
+ + +
+
+ + +
+
退会フラグ +
+ + +
+
+ + +
+
退会日
現住所 郵便番号
現住所 都道府県
現住所 市区町村
現住所 番地・建物名
連絡先 郵便番号
連絡先 都道府県
連絡先 市区町村
連絡先 番地・建物名
本人確認書類ファイル1
本人確認書類ファイル2
備考
+
+ + +
+
+ + @if ($isEdit && $hasDeleteRoute) +
+ @csrf + +
+ @endif +
+
+ +@push('scripts') +@if ($isEdit && $hasDeleteRoute) + +@endif +@endpush + + +@endsection diff --git a/resources/views/admin/users/list.blade.php b/resources/views/admin/users/list.blade.php index dfdf3c8..6d773c9 100644 --- a/resources/views/admin/users/list.blade.php +++ b/resources/views/admin/users/list.blade.php @@ -1,8 +1,42 @@ @extends('layouts.app') -@section('title', '[東京都|〇〇駐輪場]利用者マスタ') +@section('title', '利用者マスタ') @section('content') +@php + $curSort = $sort ?? request('sort', 'user_seq'); + $curDir = strtolower($dir ?? request('dir', $sort_type ?? 'desc')); + if (!in_array($curDir, ['asc', 'desc'], true)) { + $curDir = 'desc'; + } + + $queryBase = collect([ + 'user_id' => $user_id ?? null, + 'user_categoryid' => $user_categoryid ?? null, + 'user_tag_serial' => $user_tag_serial ?? null, + 'quit_flag' => $quit_flag ?? null, + 'user_phonetic' => $user_phonetic ?? null, + 'phone' => $phone ?? null, + 'email' => $email ?? null, + 'tag_qr_flag' => $tag_qr_flag ?? null, + 'quit_from' => $quit_from ?? null, + 'quit_to' => $quit_to ?? null, + ])->filter(function ($value) { + return !is_null($value) && $value !== ''; + })->all(); + + $thClass = function (string $key) use ($curSort, $curDir) { + if ($curSort !== $key) { + return 'sorting'; + } + return $curDir === 'asc' ? 'sorting_asc' : 'sorting_desc'; + }; + + $urlFor = function (string $key) use ($curSort, $curDir, $queryBase) { + $next = ($curSort === $key && $curDir === 'asc') ? 'desc' : 'asc'; + return route('users', array_merge($queryBase, ['sort' => $key, 'dir' => $next])); + }; +@endphp {{-- ▼ コンテンツヘッダー(パンくず) --}}
@@ -12,8 +46,7 @@
@@ -24,6 +57,23 @@
+ @if (session('success')) + + @endif + @if (session('error')) + + @endif + {{-- ===================== 案内文(図2 準拠) ===================== --}}

この画面のデータ修正等の必要はありません。 @@ -35,11 +85,10 @@

絞り込みフィルター

-
- @csrf + {{-- ▼ ソート保持 --}} - + {{-- ▼ 1段目(左右2カラム) --}}
@@ -210,18 +259,26 @@ @csrf
- +
- + - + - - + + @@ -233,21 +290,25 @@ @forelse($list as $item) @php - // ▼ 詳細/編集リンク生成(命名ルート優先) - $userInfoUrl = Route::has('user_info') - ? route('user_info', ['seq' => $item->user_seq]) - : (Route::has('users_info') - ? route('users_info', ['id' => $item->user_seq]) - : url('/users/info/' . $item->user_seq)); + $userEditUrl = Route::has('users_edit') + ? route('users_edit', ['seq' => $item->user_seq]) + : (Route::has('user_edit') + ? route('user_edit', ['seq' => $item->user_seq]) + : url('/users/edit/' . $item->user_seq)); $chk = (string) ($item->user_idcard_chk_flag ?? '0'); - @endphp + $categoryDisplay = collect([ + $item->usertype_subject1 ?? '', + $item->usertype_subject2 ?? '', + $item->usertype_subject3 ?? '', + ])->filter(fn ($v) => $v !== '')->implode('/'); + @endphp {{-- 利用者ID(リンク) --}} - + {{-- タグ/QR --}} {{-- 利用者分類ID/氏名/フリガナ --}} - + {{-- 生年月日/年齢 --}} @@ -284,6 +345,20 @@ #users-list tfoot th { background: #fff !important; } + .table-users thead th .header-link { + color: #212529 !important; + text-decoration: none !important; + display: block; + white-space: nowrap; + padding-right: 1.8rem; + } + .table-users.dataTable thead th.sorting, + .table-users.dataTable thead th.sorting_asc, + .table-users.dataTable thead th.sorting_desc { + background-repeat: no-repeat; + background-position: right .6rem center !important; + padding-right: 1.8rem; + } /* 斑馬柄などの行背景も抑止 */ #users-list .table-striped tbody tr:nth-of-type(odd), diff --git a/routes/web.php b/routes/web.php index 9173959..3b50a19 100644 --- a/routes/web.php +++ b/routes/web.php @@ -218,7 +218,9 @@ Route::middleware('auth')->group(function () { // 利用者マスタ Route::match(['get', 'post'], '/users', [UsersController::class, 'list'])->name('users'); Route::match(['get', 'post'], '/users/add', [UsersController::class, 'add'])->name('users_add'); + Route::match(['get', 'post'], '/users/edit/{seq}', [UsersController::class, 'edit'])->where(['seq' => '[0-9]+'])->name('users_edit'); Route::match(['get', 'post'], '/users/export', [UsersController::class, 'export'])->name('users_export'); + Route::post('/users/delete-confirm', [UsersController::class, 'deleteConfirm'])->name('users_delete_confirm'); // 定期契約マスタ Route::match(['get', 'post'], '/regularcontracts', [RegularContractController::class, 'list'])->name('regularcontracts');
利用者ID + 利用者ID + タグ/QRフラグ 利用者分類ID 利用者名フリガナ + フリガナ + 生年月日 年齢携帯電話番号自宅電話番号 + 携帯電話番号 + + 自宅電話番号 + メールアドレス 本人確認書類 本人確認チェック済
{{ $item->user_id }}{{ $item->user_id }}{{ $item->tag_qr_flag ? 'QR' : 'タグ' }}{{ $item->user_categoryid }}{{ $categoryDisplay ?: $item->user_categoryid }} {{ $item->user_name }} {{ $item->user_phonetic }}