319 lines
12 KiB
PHP
319 lines
12 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Admin;
|
||
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\DB;
|
||
use Illuminate\Support\Facades\Validator;
|
||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||
class UsersController
|
||
{
|
||
/**
|
||
* 利用者一覧
|
||
* - テーブル名: user
|
||
* - 主キー: user_seq(AUTO_INCREMENT):contentReference[oaicite:3]{index=3}
|
||
* - よく使う表示項目のみ選択(必要に応じて拡張)
|
||
*/
|
||
// 先确保:use App\Http\Controllers\Controller; を追加し、必要なら extends Controller にする
|
||
// use Symfony\Component\HttpFoundation\StreamedResponse; は既にOK
|
||
|
||
/**
|
||
* 一覧(絞り込み + ページング)
|
||
*/
|
||
public function list(Request $request)
|
||
{
|
||
// ▼ 並び順(ホワイトリスト)
|
||
$sortable = [
|
||
'user_seq',
|
||
'user_id',
|
||
'member_id',
|
||
'contract_number',
|
||
'user_tag_serial',
|
||
'user_tag_serial_64',
|
||
'qr_code',
|
||
'tag_qr_flag',
|
||
'user_aid',
|
||
'user_place_qrid',
|
||
'user_categoryid',
|
||
'user_name',
|
||
'user_birthdate',
|
||
'user_age',
|
||
'user_homephone',
|
||
'user_primemail',
|
||
'user_submail',
|
||
'user_school',
|
||
];
|
||
$sort = $request->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', '利用者を登録しました。');
|
||
}
|
||
|
||
}
|