【指摘対応】
All checks were successful
Deploy main / deploy (push) Successful in 23s

This commit is contained in:
你的名字 2025-10-14 09:44:58 +09:00
parent 570d51d223
commit 3ec806682d
7 changed files with 1857 additions and 911 deletions

View File

@ -13,6 +13,7 @@ class ContractorController extends Controller
*/ */
public function list(Request $request) public function list(Request $request)
{ {
// ベースクエリを構築
$q = DB::table('regular_contract as rc') $q = DB::table('regular_contract as rc')
->leftJoin('user as u','rc.user_id','=','u.user_id') ->leftJoin('user as u','rc.user_id','=','u.user_id')
->select([ ->select([
@ -33,10 +34,12 @@ class ContractorController extends Controller
'rc.contract_permission', 'rc.contract_permission',
'rc.contract_manual', 'rc.contract_manual',
'rc.contract_notice', 'rc.contract_notice',
'rc.update_flag',
'p.park_name', 'p.park_name',
'u.user_name', 'u.user_name',
'u.user_phonetic', 'u.user_phonetic',
'u.user_mobile', 'u.user_mobile',
'u.user_seq',
'u.user_homephone', 'u.user_homephone',
'u.user_primemail', 'u.user_primemail',
'u.user_gender', 'u.user_gender',
@ -64,7 +67,7 @@ class ContractorController extends Controller
WHEN 12 THEN '年' WHEN 12 THEN '年'
ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"), ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"),
DB::raw('ps.psection_subject as vehicle_type'), DB::raw('ps.psection_subject as vehicle_type'),
// 利用者分類usertype テーブル // 利用者分類のラベルusertype テーブルの subject を取得
DB::raw('ut.usertype_subject1 as user_category1'), DB::raw('ut.usertype_subject1 as user_category1'),
DB::raw('ut.usertype_subject2 as user_category2'), DB::raw('ut.usertype_subject2 as user_category2'),
DB::raw('ut.usertype_subject3 as user_category3'), DB::raw('ut.usertype_subject3 as user_category3'),
@ -74,63 +77,73 @@ class ContractorController extends Controller
->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid'); ->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid');
// ===== 絞り込み条件 ===== // ===== 絞り込み条件 =====
// 駐輪場
// 駐輪場で絞る(完全一致)
if ($request->filled('park_id')) { if ($request->filled('park_id')) {
$q->where('rc.park_id', $request->park_id); $q->where('rc.park_id', $request->park_id);
} }
// 利用者ID完全一致
// 利用者IDで絞る完全一致
if ($request->filled('user_id')) { if ($request->filled('user_id')) {
$q->where('rc.user_id', $request->user_id); $q->where('rc.user_id', $request->user_id);
} }
// 分類名1完全一致: ut.usertype_subject1 = 入力値 // 利用者分類で絞る(※ select の value を user_categoryid にしているため、user テーブルのカラムで比較)
if ($request->filled('user_category1')) { if ($request->filled('user_category1')) {
$q->where('ut.usertype_subject1', $request->user_category1); $q->where('u.user_categoryid', $request->user_category1);
} }
// タグシリアル64進部分一致
// タグシリアル64進で部分一致検索
if ($request->filled('user_tag_serial_64')) { if ($request->filled('user_tag_serial_64')) {
$val = $request->user_tag_serial_64; $val = $request->user_tag_serial_64;
$q->where('u.user_tag_serial_64','like','%'.$val.'%'); $q->where('u.user_tag_serial_64','like','%'.$val.'%');
} }
// 有効期限(契約有効期間 終了日:指定日以前を抽出)
// 有効期限で絞る(指定日以前を抽出する= <= を使用)
if ($request->filled('contract_periode')) { if ($request->filled('contract_periode')) {
$raw = trim($request->contract_periode); $raw = trim($request->contract_periode);
$norm = str_replace('/', '-', $raw); // スラッシュ入力許容 $norm = str_replace('/', '-', $raw); // スラッシュ入力許容
try { try {
$target = \Carbon\Carbon::parse($norm)->format('Y-m-d'); $target = \Carbon\Carbon::parse($norm)->format('Y-m-d');
// 指定日 “以前” を含む (以前のみなら '<' に変更) // 指定日「以前」を含める
$q->whereDate('rc.contract_periode', '>=', $target); $q->whereDate('rc.contract_periode', '<=', $target);
} catch (\Exception $e) { } catch (\Exception $e) {
// 不正日付は無視 // 無効な日付は無視する
} }
} }
// フリガナ(部分一致)
// フリガナで部分一致
if ($request->filled('user_phonetic')) { if ($request->filled('user_phonetic')) {
$q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%'); $q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%');
} }
// 携帯電話(部分一致)
// 携帯電話で部分一致
if ($request->filled('user_mobile')) { if ($request->filled('user_mobile')) {
$q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%'); $q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%');
} }
// メール(部分一致)
// メールアドレスで部分一致
if ($request->filled('user_primemail')) { if ($request->filled('user_primemail')) {
$q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%'); $q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%');
} }
// 勤務先(部分一致)
// 勤務先で部分一致
if ($request->filled('user_workplace')) { if ($request->filled('user_workplace')) {
$q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%'); $q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%');
} }
// 学校(部分一致)
// 学校で部分一致
if ($request->filled('user_school')) { if ($request->filled('user_school')) {
$q->where('u.user_school', 'like', '%' . $request->user_school . '%'); $q->where('u.user_school', 'like', '%' . $request->user_school . '%');
} }
// タグ・QR完全一致
// タグ・QR フラグで絞る(空文字は無視)
if ($request->filled('tag_qr_flag') && $request->tag_qr_flag !== '') { if ($request->filled('tag_qr_flag') && $request->tag_qr_flag !== '') {
$q->where('rc.tag_qr_flag', $request->tag_qr_flag); $q->where('rc.tag_qr_flag', $request->tag_qr_flag);
} }
// ソート処理 // ===== ソート処理 =====
// パラメータが来た時だけ適用。未指定なら主キー昇順 // 指定があればその列でソート、なければデフォルトで契約IDの昇順
$sort = $request->input('sort'); // null 許容 $sort = $request->input('sort'); // null 許容
$sortType = $request->input('sort_type','asc'); $sortType = $request->input('sort_type','asc');
@ -145,18 +158,23 @@ class ContractorController extends Controller
$sortType = $sortType === 'desc' ? 'desc' : 'asc'; $sortType = $sortType === 'desc' ? 'desc' : 'asc';
$q->orderBy($sort, $sortType); $q->orderBy($sort, $sortType);
} else { } else {
// 初期表示は契約ID昇順 (物理順に近い) // デフォルトソート
$sort = null; $sort = null;
$sortType = null; $sortType = null;
$q->orderBy('rc.contract_id','asc'); $q->orderBy('rc.contract_id','asc');
} }
// ページネーション(クエリ文字列を引き継ぐ)
$rows = $q->paginate(20)->appends($request->query()); $rows = $q->paginate(20)->appends($request->query());
// 駐輪場セレクト用 // 駐輪場セレクト用データ取得
$parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get(); $parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get();
return view('admin.contractor.list', compact('rows', 'sort', 'sortType', 'parks')); // 利用者分類セレクト用:実際に使用されている分類のみを取得する
$categories = $this->buildCategoryOptions(true);
// ビューに渡す
return view('admin.contractor.list', compact('rows', 'sort', 'sortType', 'parks', 'categories'));
} }
/** /**
@ -164,6 +182,7 @@ class ContractorController extends Controller
*/ */
public function info($id) public function info($id)
{ {
// 指定契約IDの詳細を取得
$contract = DB::table('regular_contract as rc') $contract = DB::table('regular_contract as rc')
->select([ ->select([
'rc.*', 'rc.*',
@ -186,4 +205,55 @@ class ContractorController extends Controller
return view('admin.contractor.info', compact('contract')); return view('admin.contractor.info', compact('contract'));
} }
/**
* 利用者分類選択肢を取得
*
* @param bool $onlyUsed true の場合は regular_contract に出現する分類のみ返す
* @return array [user_categoryid => label, ...]
*/
private function buildCategoryOptions(bool $onlyUsed = false): array
{
if (! $onlyUsed) {
// 全件取得(既存の挙動)
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 と regular_contract と紐付くもの)
$rows = DB::table('usertype as ut')
->join('user as u', 'u.user_categoryid', '=', 'ut.user_categoryid')
->join('regular_contract as rc', 'rc.user_id', '=', 'u.user_id')
->select(
'ut.user_categoryid',
'ut.usertype_subject1',
'ut.usertype_subject2',
'ut.usertype_subject3'
)
->groupBy('ut.user_categoryid', 'ut.usertype_subject1', 'ut.usertype_subject2', 'ut.usertype_subject3')
->orderBy('ut.user_categoryid', 'asc')
->get();
// ラベルを組み立てて配列で返す
return $rows->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();
}
} }

View File

@ -9,10 +9,11 @@ use Illuminate\Support\Facades\DB;
class ContractorListController extends Controller class ContractorListController extends Controller
{ {
/** /**
* 未更新者一覧 (contract_renewal IS NULL) * 一覧表示GET/POST
*/ */
public function list(Request $request) public function list(Request $request)
{ {
// ベースクエリを構築
$q = DB::table('regular_contract as rc') $q = DB::table('regular_contract as rc')
->leftJoin('user as u','rc.user_id','=','u.user_id') ->leftJoin('user as u','rc.user_id','=','u.user_id')
->select([ ->select([
@ -33,10 +34,14 @@ class ContractorListController extends Controller
'rc.contract_permission', 'rc.contract_permission',
'rc.contract_manual', 'rc.contract_manual',
'rc.contract_notice', 'rc.contract_notice',
'rc.update_flag',
'rc.user_securitynum',
'rc.contract_seal_issue',
'p.park_name', 'p.park_name',
'u.user_name', 'u.user_name',
'u.user_phonetic', 'u.user_phonetic',
'u.user_mobile', 'u.user_mobile',
'u.user_seq',
'u.user_homephone', 'u.user_homephone',
'u.user_primemail', 'u.user_primemail',
'u.user_gender', 'u.user_gender',
@ -64,7 +69,7 @@ class ContractorListController extends Controller
WHEN 12 THEN '年' WHEN 12 THEN '年'
ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"), ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"),
DB::raw('ps.psection_subject as vehicle_type'), DB::raw('ps.psection_subject as vehicle_type'),
// 利用者分類usertype テーブル // 利用者分類のラベルusertype テーブルの subject を取得
DB::raw('ut.usertype_subject1 as user_category1'), DB::raw('ut.usertype_subject1 as user_category1'),
DB::raw('ut.usertype_subject2 as user_category2'), DB::raw('ut.usertype_subject2 as user_category2'),
DB::raw('ut.usertype_subject3 as user_category3'), DB::raw('ut.usertype_subject3 as user_category3'),
@ -74,89 +79,183 @@ class ContractorListController extends Controller
->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid'); ->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid');
// ===== 絞り込み条件 ===== // ===== 絞り込み条件 =====
// 駐輪場
// 駐輪場で絞る(完全一致)
if ($request->filled('park_id')) { if ($request->filled('park_id')) {
$q->where('rc.park_id', $request->park_id); $q->where('rc.park_id', $request->park_id);
} }
// 利用者ID完全一致
// 利用者IDで絞る完全一致
if ($request->filled('user_id')) { if ($request->filled('user_id')) {
$q->where('rc.user_id', $request->user_id); $q->where('rc.user_id', $request->user_id);
} }
// 分類名1完全一致
// 利用者分類で絞る(※ select の value を user_categoryid にしているため、user テーブルのカラムで比較)
if ($request->filled('user_category1')) { if ($request->filled('user_category1')) {
$q->where('ut.usertype_subject1', $request->user_category1); $q->where('u.user_categoryid', $request->user_category1);
} }
// タグシリアル64進部分一致
// タグシリアル64進で部分一致検索
if ($request->filled('user_tag_serial_64')) { if ($request->filled('user_tag_serial_64')) {
$val = $request->user_tag_serial_64; $val = $request->user_tag_serial_64;
$q->where('u.user_tag_serial_64','like','%'.$val.'%'); $q->where('u.user_tag_serial_64','like','%'.$val.'%');
} }
// 有効期限(契約有効期間 終了日:指定日以前を抽出)
// 有効期限で絞る(指定日以前を抽出する= <= を使用)
if ($request->filled('contract_periode')) { if ($request->filled('contract_periode')) {
$raw = trim($request->contract_periode); $raw = trim($request->contract_periode);
$norm = str_replace('/', '-', $raw); // スラッシュ入力許容 $norm = str_replace('/', '-', $raw); // スラッシュ入力許容
try { try {
$target = \Carbon\Carbon::parse($norm)->format('Y-m-d'); $target = \Carbon\Carbon::parse($norm)->format('Y-m-d');
// 指定日 “以前” を含む (以前のみなら '<' に変更) // 指定日「以前」を含める
$q->whereDate('rc.contract_periode', '>=', $target); $q->whereDate('rc.contract_periode', '<=', $target);
} catch (\Exception $e) { } catch (\Exception $e) {
// 不正日付は無視 // 無効な日付は無視する
} }
} }
// フリガナ(部分一致)
// フリガナで部分一致
if ($request->filled('user_phonetic')) { if ($request->filled('user_phonetic')) {
$q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%'); $q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%');
} }
// 携帯電話(部分一致)
// 携帯電話で部分一致
if ($request->filled('user_mobile')) { if ($request->filled('user_mobile')) {
$q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%'); $q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%');
} }
// メール(部分一致)
// メールアドレスで部分一致
if ($request->filled('user_primemail')) { if ($request->filled('user_primemail')) {
$q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%'); $q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%');
} }
// 勤務先(部分一致)
// 勤務先で部分一致
if ($request->filled('user_workplace')) { if ($request->filled('user_workplace')) {
$q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%'); $q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%');
} }
// 学校(部分一致)
// 学校で部分一致
if ($request->filled('user_school')) { if ($request->filled('user_school')) {
$q->where('u.user_school', 'like', '%' . $request->user_school . '%'); $q->where('u.user_school', 'like', '%' . $request->user_school . '%');
} }
// タグ・QR完全一致
// タグ・QR フラグで絞る(空文字は無視)
if ($request->filled('tag_qr_flag') && $request->tag_qr_flag !== '') { if ($request->filled('tag_qr_flag') && $request->tag_qr_flag !== '') {
$q->where('rc.tag_qr_flag', $request->tag_qr_flag); $q->where('rc.tag_qr_flag', $request->tag_qr_flag);
} }
// ---- ソート ---- // ===== ソート処理 =====
$sort = $request->input('sort',''); // 初期は未指定 // 指定があればその列でソート、なければデフォルトで契約IDの昇順
$sort = $request->input('sort'); // null 許容
$sortType = $request->input('sort_type','asc'); $sortType = $request->input('sort_type','asc');
$allowSorts = [ $allowSorts = [
'user_id' => 'rc.user_id', 'rc.contract_id',
'user_name' => 'u.user_name', 'rc.user_id',
'contract_id' => 'rc.contract_id', 'u.user_name',
'tag_qr_flag' => 'rc.tag_qr_flag', 'rc.tag_qr_flag',
'park_name' => 'p.park_name', 'p.park_name',
]; ];
if($sort !== '' && isset($allowSorts[$sort])){ if ($sort && in_array($sort, $allowSorts)) {
$sortType = $sortType === 'desc' ? 'desc' : 'asc'; $sortType = $sortType === 'desc' ? 'desc' : 'asc';
$q->orderBy($allowSorts[$sort], $sortType) $q->orderBy($sort, $sortType);
->orderBy('rc.contract_id','asc'); // セカンダリ安定
} else { } else {
// 初期表示: DB登録順の近似PK昇順 // デフォルトソート
$sort = ''; // Blade 側で未ソート状態 $sort = null;
$sortType = null;
$q->orderBy('rc.contract_id','asc'); $q->orderBy('rc.contract_id','asc');
} }
// 駐輪場選択 // ページネーション(クエリ文字列を引き継ぐ)
$parks = DB::table('park')
->select('park_id','park_name')
->orderBy('park_name')
->orderBy('park_id')
->get();
$rows = $q->paginate(20)->appends($request->query()); $rows = $q->paginate(20)->appends($request->query());
return view('admin.contractor_list.list', compact('rows','sort','sortType','parks')); // 駐輪場セレクト用データ取得
$parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get();
// 利用者分類セレクト用:実際に使用されている分類のみを取得する
$categories = $this->buildCategoryOptions(true);
// ビューに渡す
return view('admin.contractor_List.list', compact('rows', 'sort', 'sortType', 'parks', 'categories'));
}
/**
* 詳細表示
*/
public function info($id)
{
// 指定契約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_List.info', compact('contract'));
}
/**
* 利用者分類選択肢を取得
*
* @param bool $onlyUsed true の場合は regular_contract に出現する分類のみ返す
* @return array [user_categoryid => label, ...]
*/
private function buildCategoryOptions(bool $onlyUsed = false): array
{
if (! $onlyUsed) {
// 全件取得(既存の挙動)
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 と regular_contract と紐付くもの)
$rows = DB::table('usertype as ut')
->join('user as u', 'u.user_categoryid', '=', 'ut.user_categoryid')
->join('regular_contract as rc', 'rc.user_id', '=', 'u.user_id')
->select(
'ut.user_categoryid',
'ut.usertype_subject1',
'ut.usertype_subject2',
'ut.usertype_subject3'
)
->groupBy('ut.user_categoryid', 'ut.usertype_subject1', 'ut.usertype_subject2', 'ut.usertype_subject3')
->orderBy('ut.user_categoryid', 'asc')
->get();
// ラベルを組み立てて配列で返す
return $rows->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();
} }
} }

View File

@ -9,15 +9,45 @@ use Illuminate\Support\Facades\DB;
class ReservationController extends Controller class ReservationController extends Controller
{ {
/** /**
* 予約者一覧表示 * 一覧表示GET/POST
*/ */
public function list(Request $request) public function list(Request $request)
{ {
$q = DB::table('reserve as r') // ベースクエリを構築
$q = DB::table('regular_contract as rc')
->leftJoin('user as u','rc.user_id','=','u.user_id')
->select([ ->select([
'r.user_id', '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',
'rc.update_flag',
'rc.800m_flag',
'rc.price_parkplaceid',
'rc.psection_id',
'rc.reserve_date',
'p.park_name',
'u.user_name', 'u.user_name',
'u.user_phonetic', 'u.user_phonetic',
'u.user_mobile',
'u.user_seq',
'u.user_homephone',
'u.user_primemail',
'u.user_gender',
'u.user_birthdate',
'u.user_regident_zip', 'u.user_regident_zip',
'u.user_regident_pre', 'u.user_regident_pre',
'u.user_regident_city', 'u.user_regident_city',
@ -26,96 +56,195 @@ class ReservationController extends Controller
'u.user_relate_pre', 'u.user_relate_pre',
'u.user_relate_city', 'u.user_relate_city',
'u.user_relate_add', 'u.user_relate_add',
'u.user_birthdate',
'u.user_gender',
'u.user_mobile',
'u.user_homephone',
'u.user_school',
'u.user_graduate', 'u.user_graduate',
'u.user_workplace',
'u.user_school',
'u.user_remarks', 'u.user_remarks',
'r.reserve_id', 'u.user_tag_serial_64',
'r.park_id', 'u.user_reduction',
'p.park_name', DB::raw('rc.user_securitynum as crime_prevention'),
'r.price_parkplaceid', DB::raw('rc.contract_seal_issue as seal_issue_count'),
'r.psection_id', DB::raw("CASE rc.enable_months
WHEN 1 THEN '月極(1ヶ月)'
WHEN 3 THEN '3ヶ月'
WHEN 6 THEN '6ヶ月'
WHEN 12 THEN '年'
ELSE CONCAT(rc.enable_months, 'ヶ月') END as ticket_type"),
DB::raw('ps.psection_subject as vehicle_type'), DB::raw('ps.psection_subject as vehicle_type'),
// 利用者分類のラベルusertype テーブルの subject を取得)
DB::raw('ut.usertype_subject1 as user_category1'), DB::raw('ut.usertype_subject1 as user_category1'),
DB::raw('ut.usertype_subject2 as user_category2'), DB::raw('ut.usertype_subject2 as user_category2'),
DB::raw('ut.usertype_subject3 as user_category3'), DB::raw('ut.usertype_subject3 as user_category3'),
'r.reserve_date',
'r.reserve_reduction as reduction',
DB::raw('r.`800m_flag` as within_800m_flag'),
]) ])
->leftJoin('user as u', 'r.user_id', '=', 'u.user_id') ->leftJoin('park as p', 'rc.park_id', '=', 'p.park_id')
->leftJoin('park as p', 'r.park_id', '=', 'p.park_id') ->leftJoin('psection as ps', 'rc.psection_id', '=', 'ps.psection_id')
->leftJoin('psection as ps','r.psection_id','=','ps.psection_id') ->leftJoin('usertype as ut', 'u.user_categoryid', '=', 'ut.user_categoryid');
->leftJoin('usertype as ut','u.user_categoryid','=','ut.user_categoryid');
// フィルター条件 // ===== 絞り込み条件 =====
// 駐輪場で絞る(完全一致)
if ($request->filled('park_id')) { if ($request->filled('park_id')) {
$q->where('r.park_id', $request->input('park_id')); $q->where('rc.park_id', $request->park_id);
} }
// 利用者IDで絞る完全一致
if ($request->filled('user_id')) { if ($request->filled('user_id')) {
$q->where('r.user_id', $request->input('user_id')); $q->where('rc.user_id', $request->user_id);
} }
// 利用者分類契約者一覧に合わせ、分類名1の完全一致を優先
// 利用者分類で絞る(※ select の value を user_categoryid にしているため、user テーブルのカラムで比較)
if ($request->filled('user_category1')) { if ($request->filled('user_category1')) {
$val = trim(mb_convert_kana($request->input('user_category1'), 'asKV')); $q->where('u.user_categoryid', $request->user_category1);
$q->where('ut.usertype_subject1', $val);
} elseif ($request->filled('user_categoryid')) {
// 既存互換ID指定も残す
$q->where('u.user_categoryid', $request->input('user_categoryid'));
} }
// タグシリアルで部分一致検索
if ($request->filled('user_tag_serial')) { if ($request->filled('user_tag_serial')) {
$q->where('u.user_tag_serial', 'like', '%' . $request->input('user_tag_serial') . '%'); $q->where('u.user_tag_serial', 'like', '%' . $request->input('user_tag_serial') . '%');
} }
// タグシリアル64進で部分一致検索
if ($request->filled('user_tag_serial_64')) { if ($request->filled('user_tag_serial_64')) {
$q->where('u.user_tag_serial_64', 'like', '%' . $request->input('user_tag_serial_64') . '%'); $val = $request->user_tag_serial_64;
$q->where('u.user_tag_serial_64','like','%'.$val.'%');
} }
// フリガナで部分一致
if ($request->filled('user_phonetic')) { if ($request->filled('user_phonetic')) {
$q->where('u.user_phonetic', 'like', '%' . $request->input('user_phonetic') . '%'); $q->where('u.user_phonetic', 'like', '%' . $request->user_phonetic . '%');
} }
// 携帯電話で部分一致
if ($request->filled('user_mobile')) { if ($request->filled('user_mobile')) {
$q->where(function($sub) use ($request) { $q->where('u.user_mobile', 'like', '%' . $request->user_mobile . '%');
$sub->where('u.user_mobile', 'like', '%' . $request->input('user_mobile') . '%')
->orWhere('u.user_homephone', 'like', '%' . $request->input('user_mobile') . '%');
});
} }
// メールアドレスで部分一致
if ($request->filled('user_primemail')) { if ($request->filled('user_primemail')) {
$like = '%' . $request->input('user_primemail') . '%'; $q->where('u.user_primemail', 'like', '%' . $request->user_primemail . '%');
$q->where(function($w) use ($like){
$w->where('u.user_primemail','like',$like)
->orWhere('u.user_submail','like',$like);
});
} }
// 勤務先で部分一致
if ($request->filled('user_workplace')) { if ($request->filled('user_workplace')) {
$q->where('u.user_workplace', 'like', '%' . $request->input('user_workplace') . '%'); $q->where('u.user_workplace', 'like', '%' . $request->user_workplace . '%');
} }
// 学校で部分一致
if ($request->filled('user_school')) { if ($request->filled('user_school')) {
$q->where('u.user_school', 'like', '%' . $request->input('user_school') . '%'); $q->where('u.user_school', 'like', '%' . $request->user_school . '%');
} }
// ソート(契約者一覧に合わせて許可する列を拡張) // ===== ソート処理 =====
$sort = $request->input('sort', 'reserve_id'); // 指定があればその列でソート、なければデフォルトで契約IDの昇順
$sortType = $request->input('sort_type', 'asc'); $sort = $request->input('sort'); // null 許容
$allow = [ $sortType = $request->input('sort_type','asc');
'reserve_id' => 'r.reserve_id',
'user_id' => 'r.user_id', $allowSorts = [
'user_name' => 'u.user_name', 'rc.contract_id',
'park_id' => 'r.park_id', 'rc.user_id',
'price_parkplaceid' => 'r.price_parkplaceid', 'u.user_name',
'psection_id' => 'r.psection_id', 'rc.tag_qr_flag',
'reserve_date' => 'r.reserve_date', 'p.park_name',
]; ];
if (!isset($allow[$sort])) $sort = 'reserve_id'; if ($sort && in_array($sort, $allowSorts)) {
$sortType = $sortType === 'desc' ? 'desc' : 'asc'; $sortType = $sortType === 'desc' ? 'desc' : 'asc';
$q->orderBy($sort, $sortType);
} else {
// デフォルトソート
$sort = null;
$sortType = null;
$q->orderBy('rc.contract_id','asc');
}
$rows = $q->orderBy($allow[$sort], $sortType) // ページネーション(クエリ文字列を引き継ぐ)
->paginate(20)->withQueryString(); $rows = $q->paginate(20)->appends($request->query());
// 駐輪場リスト取得(必要なら) // 駐輪場セレクト用データ取得
$parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get(); $parks = DB::table('park')->select('park_id', 'park_name')->orderBy('park_name')->get();
return view('admin.reservation.list', compact('rows', 'sort', 'sortType', 'parks')); // 利用者分類セレクト用:実際に使用されている分類のみを取得する
$categories = $this->buildCategoryOptions(true);
// ビューに渡す
return view('admin.reservation.list', compact('rows', 'sort', 'sortType', 'parks', 'categories'));
}
/**
* 詳細表示
*/
public function info($id)
{
// 指定契約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.reservation.info', compact('contract'));
}
/**
* 利用者分類選択肢を取得
*
* @param bool $onlyUsed true の場合は regular_contract に出現する分類のみ返す
* @return array [user_categoryid => label, ...]
*/
private function buildCategoryOptions(bool $onlyUsed = false): array
{
if (! $onlyUsed) {
// 全件取得(既存の挙動)
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 と regular_contract と紐付くもの)
$rows = DB::table('usertype as ut')
->join('user as u', 'u.user_categoryid', '=', 'ut.user_categoryid')
->join('regular_contract as rc', 'rc.user_id', '=', 'u.user_id')
->select(
'ut.user_categoryid',
'ut.usertype_subject1',
'ut.usertype_subject2',
'ut.usertype_subject3'
)
->groupBy('ut.user_categoryid', 'ut.usertype_subject1', 'ut.usertype_subject2', 'ut.usertype_subject3')
->orderBy('ut.user_categoryid', 'asc')
->get();
// ラベルを組み立てて配列で返す
return $rows->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();
} }
} }

View File

@ -20,14 +20,21 @@
</div> </div>
<section class="content"> <section class="content">
<div class="container-fluid">
{{-- 絞り込みフィルター --}}
<form method="GET" action="{{ route('contractor') }}" class="mb-3" id="list-form"> <form method="GET" action="{{ route('contractor') }}" class="mb-3" id="list-form">
<input type="hidden" name="sort" value="{{ $sort ?? request('sort') }}"> <input type="hidden" name="sort" value="{{ $sort ?? request('sort') }}">
<input type="hidden" name="sort_type" value="{{ $sortType ?? request('sort_type') }}"> <input type="hidden" name="sort_type" value="{{ $sortType ?? request('sort_type') }}">
<div class="card p-3">
<h6 class="mb-3">絞り込みフィルター</h6> {{-- カード全体 --}}
<div class="col-lg-12">
<div class="card">
{{-- 絞り込みフィルターcard-header --}}
<div class="card-header" style="font-weight:bold;">
絞り込みフィルター
</div>
{{-- フィルター条件エリアcard-body --}}
<div class="card-body bg-white">
<div class="row"> <div class="row">
{{-- 左カラム --}} {{-- 左カラム --}}
<div class="col-md-6"> <div class="col-md-6">
@ -44,7 +51,8 @@
@endforeach @endforeach
</select> </select>
@else @else
<input type="text" name="park_name" value="{{ request('park_name') }}" class="form-control"> <input type="text" name="park_name" value="{{ request('park_name') }}" class="form-control"
placeholder="123456">
@endisset @endisset
</div> </div>
</div> </div>
@ -52,14 +60,29 @@
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">利用者ID</label> <label class="col-sm-3 col-form-label">利用者ID</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_id" value="{{ request('user_id') }}" class="form-control"> <input type="text" name="user_id" value="{{ request('user_id') }}" class="form-control"
placeholder="123456">
</div> </div>
</div> </div>
{{-- ===== 利用者分類input select に変更 ===== --}}
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">利用者分類</label> <label class="col-sm-3 col-form-label">利用者分類</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_category1" value="{{ request('user_category1') }}" class="form-control" placeholder="分類名1"> @isset($categories)
<select name="user_category1" class="form-control">
<option value="">全て</option>
@foreach($categories as $key => $label)
<option value="{{ $key }}"
{{ (string) request('user_category1') === (string) $key ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
@else
<input type="text" name="user_category1" value="{{ request('user_category1') }}" class="form-control"
placeholder="123456">
@endisset
</div> </div>
</div> </div>
@ -67,7 +90,7 @@
<label class="col-sm-3 col-form-label">タグシリアル64進</label> <label class="col-sm-3 col-form-label">タグシリアル64進</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_tag_serial_64" value="{{ request('user_tag_serial_64') }}" <input type="text" name="user_tag_serial_64" value="{{ request('user_tag_serial_64') }}"
class="form-control"> class="form-control" placeholder="キーワード...">
</div> </div>
</div> </div>
@ -85,35 +108,40 @@
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">フリガナ</label> <label class="col-sm-3 col-form-label">フリガナ</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_phonetic" value="{{ request('user_phonetic') }}" class="form-control"> <input type="text" name="user_phonetic" value="{{ request('user_phonetic') }}" class="form-control"
placeholder="123456">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">電話番号</label> <label class="col-sm-3 col-form-label">電話番号</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_mobile" value="{{ request('user_mobile') }}" class="form-control"> <input type="text" name="user_mobile" value="{{ request('user_mobile') }}" class="form-control"
placeholder="08011112222">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">メールアドレス</label> <label class="col-sm-3 col-form-label">メールアドレス</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_primemail" value="{{ request('user_primemail') }}" class="form-control"> <input type="text" name="user_primemail" value="{{ request('user_primemail') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">勤務先</label> <label class="col-sm-3 col-form-label">勤務先</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_workplace" value="{{ request('user_workplace') }}" class="form-control"> <input type="text" name="user_workplace" value="{{ request('user_workplace') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">学校</label> <label class="col-sm-3 col-form-label">学校</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_school" value="{{ request('user_school') }}" class="form-control"> <input type="text" name="user_school" value="{{ request('user_school') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
@ -130,55 +158,97 @@
</div> </div>
</div> </div>
<div class="mt-2"> {{-- 絞り込みボタン --}}
<button type="submit" class="btn btn-default">絞り込み</button> <div class="mt-2 mb-3 text-start">
<a href="{{ route('contractor') }}" class="btn btn-default">解除</a> <button type="submit" class="btn btn-default px-4">絞り込み</button>
<a href="{{ route('contractor') }}" class="btn btn-default px-4">解除</a>
</div>
</div>
</div>
{{-- ページネーションのラッパーを追加 --}}
<div class="container-fluid mb20 pagination-area">
{{-- ページネーションのビジュアルラッパー --}}
<div class="pagination-wrapper mt-2">
<nav aria-label="ページネーション">
{{-- Bootstrap のリンク出力(元の呼び出しをそのまま利用) --}}
{{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
</nav>
</div> </div>
</div> </div>
</form>
{{-- 一覧テーブル --}} {{-- 一覧テーブル部:スクロール対応 --}}
<div class="col-lg-12 row sample03-wrapper no_padding_right mb20">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered table-hover table-sm rv-table text-nowrap"> <table class="table table-bordered table-hover table-sm rv-table text-nowrap mb-0">
<thead> <thead class="thead-light">
<tr> <tr>
@php($activeSort = request('sort')) @php($activeSort = request('sort'))
@php($activeType = request('sort_type')) @php($activeType = request('sort_type'))
<th <th
class="sorting {{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.user_id" sort="rc.user_id"
aria-sort="{{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">利用者ID</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 利用者ID
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th <th
class="sorting {{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="u.user_name" sort="u.user_name"
aria-sort="{{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">氏名</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 氏名
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th>フリガナ</th> <th>フリガナ</th>
<th <th
class="sorting {{ $activeSort === 'rc.contract_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'rc.contract_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.contract_id" sort="rc.contract_id"
aria-sort="{{ $activeSort === 'rc.contract_id' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">定期契約ID</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 定期契約ID
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th <th
class="sorting {{ $activeSort === 'rc.tag_qr_flag' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'rc.tag_qr_flag' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.tag_qr_flag" sort="rc.tag_qr_flag"
aria-sort="{{ $activeSort === 'rc.tag_qr_flag' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">タグ・QR</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> タグ・QR
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th <th
class="sorting {{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="p.park_name" sort="p.park_name"
aria-sort="{{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">駐輪場</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 駐輪場
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th>車種区分</th> <th>車種区分</th>
<th>減免措置</th> <th>減免措置</th>
@ -193,29 +263,32 @@
<th>居住所:都道府県</th> <th>居住所:都道府県</th>
<th>居住所:市区群</th> <th>居住所:市区群</th>
<th>居住所:住所</th> <th>居住所:住所</th>
<th>関連住所:郵便番号</th>
<th>関連住所:都道府県</th>
<th>関連住所:市区群</th>
<th>関連住所:住所</th>
<th>契約日</th> <th>契約日</th>
<th>利用期間</th> <th>利用期間</th>
<th>有効期間</th> <th>有効期間</th>
<th>定期券区分</th> <th>定期券区分</th>
<th>勤務先名</th> <th>勤務先名</th>
<th>学校</th> <th>学校</th>
<th>卒業予定</th>
<th>シール発行回数</th>
<th>防犯登録</th>
<th>備考</th> <th>備考</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@forelse ($rows as $row) @forelse ($rows as $row)
<tr> <tr>
<td>{{ $row->user_id }}</td> <td>
<a href="{{ route('users_edit', ['seq' => $row->user_seq ?? $row->user_id]) }}">
{{ $row->user_id }}
</a>
</td>
<td>{{ $row->user_name }}</td> <td>{{ $row->user_name }}</td>
<td>{{ $row->user_phonetic }}</td> <td>{{ $row->user_phonetic }}</td>
<td>{{ $row->contract_id }}</td>
<td>
<a href="{{ route('regularcontracts_edit', ['contract_id' => $row->contract_id]) }}">
{{ $row->contract_id }}
</a>
</td>
<td>{{ $row->tag_qr_flag ? 'QR' : 'タグ' }}</td> <td>{{ $row->tag_qr_flag ? 'QR' : 'タグ' }}</td>
<td>{{ $row->park_name }}</td> <td>{{ $row->park_name }}</td>
<td>{{ $row->vehicle_type ?? '' }}</td> <td>{{ $row->vehicle_type ?? '' }}</td>
@ -231,83 +304,78 @@
<td>{{ $row->user_regident_pre }}</td> <td>{{ $row->user_regident_pre }}</td>
<td>{{ $row->user_regident_city }}</td> <td>{{ $row->user_regident_city }}</td>
<td>{{ $row->user_regident_add }}</td> <td>{{ $row->user_regident_add }}</td>
<td>{{ $row->user_relate_zip }}</td> <td>
<td>{{ $row->user_relate_pre }}</td> {{-- 契約日を「yyyymmdd」形式で表示する --}}
<td>{{ $row->user_relate_city }}</td> {{ $row->contract_created_at
<td>{{ $row->user_relate_add }}</td> ? \Illuminate\Support\Carbon::parse($row->contract_created_at)->format('Ymd')
<td>{{ $row->contract_created_at }}</td> : '' }}
<td>{{ $row->contract_periods }}</td> </td>
<td>{{ $row->contract_periode }}</td> <td>
<td>{{ $row->ticket_type ?? '' }}</td> <?php
// 直近ラベルを計算(本日と有効期間終了日の月差で判定)
$label = '';
try {
if (!empty($row->contract_periode)) {
$today = \Illuminate\Support\Carbon::now()->startOfDay();
$end = \Illuminate\Support\Carbon::parse($row->contract_periode)->startOfDay();
if ($end->lte($today)) {
$months = $end->diffInMonths($today);
if ($months <= 1) {
$label = '直近1ヶ月';
} elseif ($months <= 3) {
$label = '直近3ヶ月';
} elseif ($months <= 6) {
$label = '直近6ヶ月';
}
}
}
} catch (\Throwable $e) {
$label = '';
}
?>
{{ $label }}
</td>
<td>
{{ \Carbon\Carbon::parse($row->contract_periods)->format('Y-m-d') }}
{{ \Carbon\Carbon::parse($row->contract_periode)->format('Y-m-d') }}
</td>
<td>
@if($row->update_flag == 1)
継続
@elseif($row->update_flag == 2)
それ
@else
{{-- それ以外は空白 --}}
@endif
</td>
<td>{{ $row->user_workplace }}</td> <td>{{ $row->user_workplace }}</td>
<td>{{ $row->user_school }}</td> <td>{{ $row->user_school }}</td>
<td>{{ $row->user_graduate }}</td>
<td>{{ $row->seal_issue_count ?? '' }}</td>
<td>{{ $row->crime_prevention ?? '' }}</td>
<td>{{ $row->user_remarks }}</td> <td>{{ $row->user_remarks }}</td>
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="33" class="text-center">データがありません。</td> <td colspan="25" class="text-center">データがありません。</td>
</tr> </tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</div>
</form>
<div class="mt-3">
{{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
</div>
</div>
</section> </section>
{{-- 画面用スタイル(表頭をグレー、データ部分を白) --}}
<style>
.rv-table thead th {
background: #eeeeee;
/* settlement_transactions も薄グレー系 */
white-space: nowrap;
vertical-align: middle;
padding: 8px 10px;
/* settlement_transactions のデフォルトに近い余白 */
font-size: 0.875rem;
/* 視認性と行高を近づける */
}
.rv-table tbody tr {
background: #fff;
}
/* 矢印色制御:デフォルトはグレー、アクティブ方向のみ黒 */
th.sorting .th-arrows .up,
th.sorting .th-arrows .down {
color: #999;
}
th.sorting_asc .th-arrows .up {
color: #000;
}
th.sorting_desc .th-arrows .down {
color: #000;
}
/* アクセシビリティ向上:フォーカス時の視認性 */
th.sorting:focus,
th.sorting_asc:focus,
th.sorting_desc:focus {
outline: 2px solid #999;
outline-offset: -2px;
}
th[aria-sort] {
cursor: pointer;
}
</style>
@push('scripts') @push('scripts')
<script> <script>
// 契約者一覧:決済トランザクション方式のクリックソート // ▼ ソート機能(日本語コメント)
document.querySelectorAll('th.sorting, th.sorting_asc, th.sorting_desc').forEach(th => { // th 要素をクリックすると sort と sort_type を設定してフォーム送信します
document.querySelectorAll('th[sort]').forEach(th => {
th.classList.add('sorting'); // ベースクラスを確実に付ける
th.addEventListener('click', function () { th.addEventListener('click', function () {
const col = this.getAttribute('sort'); const col = this.getAttribute('sort');
if (!col) return; if (!col) return;
@ -320,11 +388,155 @@
if (current === col) { if (current === col) {
nextType = (currentType === 'asc') ? 'desc' : 'asc'; nextType = (currentType === 'asc') ? 'desc' : 'asc';
} }
sortInput.value = col; if (sortInput) sortInput.value = col;
typeInput.value = nextType; if (typeInput) typeInput.value = nextType;
// 視覚的にソートクラスを切り替え(矢印の色に反映)
document.querySelectorAll('th[sort]').forEach(h => {
h.classList.remove('sorting_asc', 'sorting_desc');
if (!h.classList.contains('sorting')) h.classList.add('sorting');
});
if (nextType === 'asc') {
this.classList.add('sorting_asc');
} else {
this.classList.add('sorting_desc');
}
form.submit(); form.submit();
}); });
}); });
</script> </script>
<style>
/* ----------------------------------------
ページネーションの横幅を確保して右寄せ(スクリーンショットは右寄せ)
---------------------------------------- */
.pagination-area .pagination-wrapper {
display: flex;
justify-content: flex-end; /* 右寄せ:必要なら center に変更 */
align-items: center;
width: 100%;
gap: 8px;
}
/* ========================================
ソート矢印の色ルール(日本語コメント)
状態:
未ソート -> ()灰色, ()灰色
昇順(asc) -> ()黒色, ()灰色
降順(desc) -> ()灰色, ()黒色
======================================== */
/* 既存の擬似要素で出る矢印を無効化(保険) */
th.sorting::after,
th.sorting_asc::after,
th.sorting_desc::after {
display: none !important;
content: none !important;
background-image: none !important;
background: none !important;
}
/* 矢印を水平に並べる(左: up, 右: down */
th[sort] .sort-arrows,
th.sorting .sort-arrows,
th.sorting_asc .sort-arrows,
th.sorting_desc .sort-arrows {
display: inline-flex !important;
flex-direction: row !important;
gap: 6px !important;
align-items: center !important;
justify-content: center !important;
line-height: 1 !important;
font-size: 12px !important;
user-select: none !important;
width: auto !important;
box-sizing: border-box;
vertical-align: middle;
color: #bfc9d6 !important; /* デフォルト灰 */
}
th[sort] .sort-arrows .up,
th[sort] .sort-arrows .down,
th.sorting .sort-arrows .up,
th.sorting .sort-arrows .down {
display: inline-block !important;
min-width: 14px;
text-align: center;
line-height: 1;
}
/* 未ソート: 両方灰 */
th.sorting:not(.sorting_asc):not(.sorting_desc) .sort-arrows .up,
th.sorting:not(.sorting_asc):not(.sorting_desc) .sort-arrows .down {
color: #bfc9d6 !important;
}
/* 昇順: 左(上) 黒、右(下) 灰 */
th.sorting_asc .sort-arrows .up,
th[sort].sorting_asc .sort-arrows .up {
color: #000000 !important;
}
th.sorting_asc .sort-arrows .down,
th[sort].sorting_asc .sort-arrows .down {
color: #bfc9d6 !important;
}
/* 降順: 左(上) 灰、右(下) 黒 */
th.sorting_desc .sort-arrows .up,
th[sort].sorting_desc .sort-arrows .up {
color: #bfc9d6 !important;
}
th.sorting_desc .sort-arrows .down,
th[sort].sorting_desc .sort-arrows .down {
color: #000000 !important;
}
/* 矢印間を詰めたい場合(例: 見た目で letter-spacing 相当) */
th[sort] .sort-arrows { gap: 0 !important; }
th[sort] .sort-arrows .down { margin-left: -5px !important; }
/* 矢印の下線を消す(リンク内にある場合の保険) */
th .sort-arrows,
th .sort-label,
th[sort] .sort-arrows,
th.sorting .sort-arrows {
text-decoration: none !important;
}
th .sort-label a,
th .sort-arrows a {
text-decoration: none !important;
border-bottom: none !important;
color: inherit !important;
}
/* SVG 対応(矢印が svg の場合) */
th[sort] .sort-arrows svg path,
th.sorting .sort-arrows svg path {
fill: #bfc9d6 !important;
}
th.sorting_asc .sort-arrows svg path,
th[sort].sorting_asc .sort-arrows svg path {
fill: #000 !important;
}
th.sorting_desc .sort-arrows svg path,
th[sort].sorting_desc .sort-arrows svg path {
fill: #000 !important;
}
/* レスポンシブ:小画面で間隔を狭める */
@media (max-width: 575.98px) {
th[sort] .sort-arrows { gap: 4px !important; font-size: 11px !important; }
}
/* フォーカス時の視認性(アクセシビリティ) */
th.sorting:focus,
th.sorting_asc:focus,
th.sorting_desc:focus {
outline: 2px solid rgba(0,0,0,0.08);
outline-offset: -2px;
}
</style>
@endpush @endpush
@endsection @endsection

View File

@ -20,14 +20,21 @@
</div> </div>
<section class="content"> <section class="content">
<div class="container-fluid">
{{-- 絞り込みフィルター --}}
<form method="GET" action="{{ route('contractor_List') }}" class="mb-3" id="list-form"> <form method="GET" action="{{ route('contractor_List') }}" class="mb-3" id="list-form">
<input type="hidden" name="sort" value="{{ $sort ?? request('sort','rc.contract_id') }}"> <input type="hidden" name="sort" value="{{ $sort ?? request('sort') }}">
<input type="hidden" name="sort_type" value="{{ $sortType ?? request('sort_type','desc') }}"> <input type="hidden" name="sort_type" value="{{ $sortType ?? request('sort_type') }}">
<div class="card p-3">
<h6 class="mb-3">絞り込みフィルター</h6> {{-- カード全体 --}}
<div class="col-lg-12">
<div class="card">
{{-- 絞り込みフィルターcard-header --}}
<div class="card-header" style="font-weight:bold;">
絞り込みフィルター
</div>
{{-- フィルター条件エリアcard-body --}}
<div class="card-body bg-white">
<div class="row"> <div class="row">
{{-- 左カラム --}} {{-- 左カラム --}}
<div class="col-md-6"> <div class="col-md-6">
@ -44,7 +51,8 @@
@endforeach @endforeach
</select> </select>
@else @else
<input type="text" name="park_name" value="{{ request('park_name') }}" class="form-control"> <input type="text" name="park_name" value="{{ request('park_name') }}" class="form-control"
placeholder="123456">
@endisset @endisset
</div> </div>
</div> </div>
@ -52,16 +60,29 @@
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">利用者ID</label> <label class="col-sm-3 col-form-label">利用者ID</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_id" value="{{ request('user_id') }}" class="form-control"> <input type="text" name="user_id" value="{{ request('user_id') }}" class="form-control"
placeholder="123456">
</div> </div>
</div> </div>
{{-- ===== 利用者分類input select に変更 ===== --}}
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">利用者分類</label> <label class="col-sm-3 col-form-label">利用者分類</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_category1" @isset($categories)
value="{{ request('user_category1') }}" <select name="user_category1" class="form-control">
class="form-control" placeholder="分類名1"> <option value="">全て</option>
@foreach($categories as $key => $label)
<option value="{{ $key }}"
{{ (string) request('user_category1') === (string) $key ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
@else
<input type="text" name="user_category1" value="{{ request('user_category1') }}" class="form-control"
placeholder="123456">
@endisset
</div> </div>
</div> </div>
@ -69,7 +90,7 @@
<label class="col-sm-3 col-form-label">タグシリアル64進</label> <label class="col-sm-3 col-form-label">タグシリアル64進</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_tag_serial_64" value="{{ request('user_tag_serial_64') }}" <input type="text" name="user_tag_serial_64" value="{{ request('user_tag_serial_64') }}"
class="form-control"> class="form-control" placeholder="キーワード...">
</div> </div>
</div> </div>
@ -87,35 +108,40 @@
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">フリガナ</label> <label class="col-sm-3 col-form-label">フリガナ</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_phonetic" value="{{ request('user_phonetic') }}" class="form-control"> <input type="text" name="user_phonetic" value="{{ request('user_phonetic') }}" class="form-control"
placeholder="123456">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">電話番号</label> <label class="col-sm-3 col-form-label">電話番号</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_mobile" value="{{ request('user_mobile') }}" class="form-control"> <input type="text" name="user_mobile" value="{{ request('user_mobile') }}" class="form-control"
placeholder="08011112222">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">メールアドレス</label> <label class="col-sm-3 col-form-label">メールアドレス</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_primemail" value="{{ request('user_primemail') }}" class="form-control"> <input type="text" name="user_primemail" value="{{ request('user_primemail') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">勤務先</label> <label class="col-sm-3 col-form-label">勤務先</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_workplace" value="{{ request('user_workplace') }}" class="form-control"> <input type="text" name="user_workplace" value="{{ request('user_workplace') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">学校</label> <label class="col-sm-3 col-form-label">学校</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_school" value="{{ request('user_school') }}" class="form-control"> <input type="text" name="user_school" value="{{ request('user_school') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
@ -132,57 +158,100 @@
</div> </div>
</div> </div>
<div class="mt-2"> {{-- 絞り込みボタン --}}
<button type="submit" class="btn btn-default">絞り込み</button> <div class="mt-2 mb-3 text-start">
<a href="{{ route('contractor_List') }}" class="btn btn-default">解除</a> <button type="submit" class="btn btn-default px-4">絞り込み</button>
<a href="{{ route('contractor_List') }}" class="btn btn-default px-4">解除</a>
</div>
</div>
</div>
{{-- ページネーションのラッパーを追加 --}}
<div class="container-fluid mb20 pagination-area">
{{-- ページネーションのビジュアルラッパー --}}
<div class="pagination-wrapper mt-2">
<nav aria-label="ページネーション">
{{-- Bootstrap のリンク出力(元の呼び出しをそのまま利用) --}}
{{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
</nav>
</div> </div>
</div> </div>
</form>
{{-- 一覧テーブル --}} {{-- 一覧テーブル部:スクロール対応 --}}
<div class="col-lg-12 row sample03-wrapper no_padding_right mb20">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered table-hover table-sm rv-table text-nowrap"> <table class="table table-bordered table-hover table-sm rv-table text-nowrap mb-0">
<thead> <thead class="thead-light">
<tr> <tr>
@php($activeSort = request('sort')) @php($activeSort = request('sort'))
@php($activeType = request('sort_type')) @php($activeType = request('sort_type'))
<th <th
class="sorting {{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.user_id" sort="rc.user_id"
aria-sort="{{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">利用者ID</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 利用者ID
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th <th
class="sorting {{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="u.user_name" sort="u.user_name"
aria-sort="{{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">氏名</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 氏名
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th>フリガナ</th> <th>フリガナ</th>
<th <th
class="sorting {{ $activeSort === 'rc.contract_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'rc.contract_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.contract_id" sort="rc.contract_id"
aria-sort="{{ $activeSort === 'rc.contract_id' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">定期契約ID</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 定期契約ID
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th <th
class="sorting {{ $activeSort === 'rc.tag_qr_flag' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'rc.tag_qr_flag' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.tag_qr_flag" sort="rc.tag_qr_flag"
aria-sort="{{ $activeSort === 'rc.tag_qr_flag' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">タグ・QR</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> タグ・QR
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th <th
class="sorting {{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}" class="sorting {{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="p.park_name" sort="p.park_name"
aria-sort="{{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'ascending' : 'descending') : 'none' }}"> >
<span class="th-inner"><span class="th-label">駐輪場</span><span class="th-arrows"><span <span class="sort-label">
class="up"></span><span class="down"></span></span></span> 駐輪場
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th> </th>
<th>車種区分</th> <th>車種区分</th>
<th>有効期間</th>
<th>減免措置</th> <th>減免措置</th>
<th>利用者分類1</th> <th>利用者分類1</th>
<th>利用者分類2</th> <th>利用者分類2</th>
@ -195,15 +264,13 @@
<th>居住所:都道府県</th> <th>居住所:都道府県</th>
<th>居住所:市区群</th> <th>居住所:市区群</th>
<th>居住所:住所</th> <th>居住所:住所</th>
<th>関連住所郵便番号</th> <th>関連住所:郵便番号</th>
<th>関連住所都道府県</th> <th>関連住所:都道府県</th>
<th>関連住所市区群</th> <th>関連住所:市区群</th>
<th>関連住所住所</th> <th>関連住所:住所</th>
<th>契約日</th> <th>契約日</th>
<th>利用期間</th> <th>利用期間</th>
<th>有効期間</th>
<th>定期券区分</th> <th>定期券区分</th>
<th>勤務先名</th>
<th>学校</th> <th>学校</th>
<th>卒業予定</th> <th>卒業予定</th>
<th>シール発行回数</th> <th>シール発行回数</th>
@ -214,13 +281,28 @@
<tbody> <tbody>
@forelse ($rows as $row) @forelse ($rows as $row)
<tr> <tr>
<td>{{ $row->user_id }}</td> <td>
<a href="{{ route('users_edit', ['seq' => $row->user_seq ?? $row->user_id]) }}">
{{ $row->user_id }}
</a>
</td>
<td>{{ $row->user_name }}</td> <td>{{ $row->user_name }}</td>
<td>{{ $row->user_phonetic }}</td> <td>{{ $row->user_phonetic }}</td>
<td>{{ $row->contract_id }}</td>
<td>
<a href="{{ route('regularcontracts_edit', ['contract_id' => $row->contract_id]) }}">
{{ $row->contract_id }}
</a>
</td>
<td>{{ $row->tag_qr_flag ? 'QR' : 'タグ' }}</td> <td>{{ $row->tag_qr_flag ? 'QR' : 'タグ' }}</td>
<td>{{ $row->park_name }}</td> <td>{{ $row->park_name }}</td>
<td>{{ $row->vehicle_type ?? '' }}</td> <td>{{ $row->vehicle_type ?? '' }}</td>
<td>
{{ \Carbon\Carbon::parse($row->contract_periods)->format('Y-m-d') }}
{{ \Carbon\Carbon::parse($row->contract_periode)->format('Y-m-d') }}
</td>
<td>{{ $row->user_reduction ?? '' }}</td> <td>{{ $row->user_reduction ?? '' }}</td>
<td>{{ $row->user_category1 ?? '' }}</td> <td>{{ $row->user_category1 ?? '' }}</td>
<td>{{ $row->user_category2 ?? '' }}</td> <td>{{ $row->user_category2 ?? '' }}</td>
@ -237,79 +319,75 @@
<td>{{ $row->user_relate_pre }}</td> <td>{{ $row->user_relate_pre }}</td>
<td>{{ $row->user_relate_city }}</td> <td>{{ $row->user_relate_city }}</td>
<td>{{ $row->user_relate_add }}</td> <td>{{ $row->user_relate_add }}</td>
<td>{{ $row->contract_created_at }}</td> <td>
<td>{{ $row->contract_periods }}</td> {{-- 契約日を「yyyymmdd」形式で表示する --}}
<td>{{ $row->contract_periode }}</td> {{ $row->contract_created_at
<td>{{ $row->ticket_type ?? '' }}</td> ? \Illuminate\Support\Carbon::parse($row->contract_created_at)->format('Ymd')
<td>{{ $row->user_workplace }}</td> : '' }}
</td>
<td>
<?php
// 直近ラベルを計算(本日と有効期間終了日の月差で判定)
$label = '';
try {
if (!empty($row->contract_periode)) {
$today = \Illuminate\Support\Carbon::now()->startOfDay();
$end = \Illuminate\Support\Carbon::parse($row->contract_periode)->startOfDay();
if ($end->lte($today)) {
$months = $end->diffInMonths($today);
if ($months <= 1) {
$label = '直近1ヶ月';
} elseif ($months <= 3) {
$label = '直近3ヶ月';
} elseif ($months <= 6) {
$label = '直近6ヶ月';
}
}
}
} catch (\Throwable $e) {
$label = '';
}
?>
{{ $label }}
</td>
<td>
@if($row->update_flag == 1)
継続
@elseif($row->update_flag == 2)
それ
@else
{{-- それ以外は空白 --}}
@endif
</td>
<td>{{ $row->user_school }}</td> <td>{{ $row->user_school }}</td>
<td>{{ $row->user_graduate }}</td> <td>{{ $row->user_graduate }}</td>
<td>{{ $row->seal_issue_count ?? '' }}</td> <td>{{ $row->contract_seal_issue }}</td>
<td>{{ $row->crime_prevention ?? '' }}</td> <td>{{ $row->user_securitynum }}</td>
<td>{{ $row->user_remarks }}</td> <td>{{ $row->user_remarks }}</td>
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="33" class="text-center">データがありません。</td> <td colspan="25" class="text-center">データがありません。</td>
</tr> </tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</div>
</form>
<div class="mt-3">
{{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
</div>
</div>
</section> </section>
{{-- 画面用スタイル(表頭をグレー、データ部分を白) --}}
<style>
.rv-table thead th {
background: #eeeeee;
/* settlement_transactions も薄グレー系 */
white-space: nowrap;
vertical-align: middle;
padding: 8px 10px;
/* settlement_transactions のデフォルトに近い余白 */
font-size: 0.875rem;
/* 視認性と行高を近づける */
}
.rv-table tbody tr {
background: #fff;
}
/* 矢印色制御:デフォルトはグレー、アクティブ方向のみ黒 */
th.sorting .th-arrows .up,
th.sorting .th-arrows .down {
color: #999;
}
th.sorting_asc .th-arrows .up {
color: #000;
}
th.sorting_desc .th-arrows .down {
color: #000;
}
/* アクセシビリティ向上:フォーカス時の視認性 */
th.sorting:focus,
th.sorting_asc:focus,
th.sorting_desc:focus {
outline: 2px solid #999;
outline-offset: -2px;
}
th[aria-sort] {
cursor: pointer;
}
</style>
@push('scripts') @push('scripts')
<script> <script>
// 未更新者一覧:決済トランザクション方式のクリックソート // ▼ ソート機能(日本語コメント)
document.querySelectorAll('th.sorting, th.sorting_asc, th.sorting_desc').forEach(th => { // th 要素をクリックすると sort と sort_type を設定してフォーム送信します
document.querySelectorAll('th[sort]').forEach(th => {
th.classList.add('sorting'); // ベースクラスを確実に付ける
th.addEventListener('click', function () { th.addEventListener('click', function () {
const col = this.getAttribute('sort'); const col = this.getAttribute('sort');
if (!col) return; if (!col) return;
@ -322,11 +400,155 @@
if (current === col) { if (current === col) {
nextType = (currentType === 'asc') ? 'desc' : 'asc'; nextType = (currentType === 'asc') ? 'desc' : 'asc';
} }
sortInput.value = col; if (sortInput) sortInput.value = col;
typeInput.value = nextType; if (typeInput) typeInput.value = nextType;
// 視覚的にソートクラスを切り替え(矢印の色に反映)
document.querySelectorAll('th[sort]').forEach(h => {
h.classList.remove('sorting_asc', 'sorting_desc');
if (!h.classList.contains('sorting')) h.classList.add('sorting');
});
if (nextType === 'asc') {
this.classList.add('sorting_asc');
} else {
this.classList.add('sorting_desc');
}
form.submit(); form.submit();
}); });
}); });
</script> </script>
<style>
/* ----------------------------------------
ページネーションの横幅を確保して右寄せ(スクリーンショットは右寄せ)
---------------------------------------- */
.pagination-area .pagination-wrapper {
display: flex;
justify-content: flex-end; /* 右寄せ:必要なら center に変更 */
align-items: center;
width: 100%;
gap: 8px;
}
/* ========================================
ソート矢印の色ルール(日本語コメント)
状態:
未ソート -> ()灰色, ()灰色
昇順(asc) -> ()黒色, ()灰色
降順(desc) -> ()灰色, ()黒色
======================================== */
/* 既存の擬似要素で出る矢印を無効化(保険) */
th.sorting::after,
th.sorting_asc::after,
th.sorting_desc::after {
display: none !important;
content: none !important;
background-image: none !important;
background: none !important;
}
/* 矢印を水平に並べる(左: up, 右: down */
th[sort] .sort-arrows,
th.sorting .sort-arrows,
th.sorting_asc .sort-arrows,
th.sorting_desc .sort-arrows {
display: inline-flex !important;
flex-direction: row !important;
gap: 6px !important;
align-items: center !important;
justify-content: center !important;
line-height: 1 !important;
font-size: 12px !important;
user-select: none !important;
width: auto !important;
box-sizing: border-box;
vertical-align: middle;
color: #bfc9d6 !important; /* デフォルト灰 */
}
th[sort] .sort-arrows .up,
th[sort] .sort-arrows .down,
th.sorting .sort-arrows .up,
th.sorting .sort-arrows .down {
display: inline-block !important;
min-width: 14px;
text-align: center;
line-height: 1;
}
/* 未ソート: 両方灰 */
th.sorting:not(.sorting_asc):not(.sorting_desc) .sort-arrows .up,
th.sorting:not(.sorting_asc):not(.sorting_desc) .sort-arrows .down {
color: #bfc9d6 !important;
}
/* 昇順: 左(上) 黒、右(下) 灰 */
th.sorting_asc .sort-arrows .up,
th[sort].sorting_asc .sort-arrows .up {
color: #000000 !important;
}
th.sorting_asc .sort-arrows .down,
th[sort].sorting_asc .sort-arrows .down {
color: #bfc9d6 !important;
}
/* 降順: 左(上) 灰、右(下) 黒 */
th.sorting_desc .sort-arrows .up,
th[sort].sorting_desc .sort-arrows .up {
color: #bfc9d6 !important;
}
th.sorting_desc .sort-arrows .down,
th[sort].sorting_desc .sort-arrows .down {
color: #000000 !important;
}
/* 矢印間を詰めたい場合(例: 見た目で letter-spacing 相当) */
th[sort] .sort-arrows { gap: 0 !important; }
th[sort] .sort-arrows .down { margin-left: -5px !important; }
/* 矢印の下線を消す(リンク内にある場合の保険) */
th .sort-arrows,
th .sort-label,
th[sort] .sort-arrows,
th.sorting .sort-arrows {
text-decoration: none !important;
}
th .sort-label a,
th .sort-arrows a {
text-decoration: none !important;
border-bottom: none !important;
color: inherit !important;
}
/* SVG 対応(矢印が svg の場合) */
th[sort] .sort-arrows svg path,
th.sorting .sort-arrows svg path {
fill: #bfc9d6 !important;
}
th.sorting_asc .sort-arrows svg path,
th[sort].sorting_asc .sort-arrows svg path {
fill: #000 !important;
}
th.sorting_desc .sort-arrows svg path,
th[sort].sorting_desc .sort-arrows svg path {
fill: #000 !important;
}
/* レスポンシブ:小画面で間隔を狭める */
@media (max-width: 575.98px) {
th[sort] .sort-arrows { gap: 4px !important; font-size: 11px !important; }
}
/* フォーカス時の視認性(アクセシビリティ) */
th.sorting:focus,
th.sorting_asc:focus,
th.sorting_desc:focus {
outline: 2px solid rgba(0,0,0,0.08);
outline-offset: -2px;
}
</style>
@endpush @endpush
@endsection @endsection

View File

@ -6,10 +6,10 @@
<div class="content-header"> <div class="content-header">
<div class="container-fluid"> <div class="container-fluid">
<div class="row mb-2"> <div class="row mb-2">
<div class="col-sm-6"> <div class="col-lg-6">
<h1 class="m-0 text-dark">予約者一覧</h1> <h1 class="m-0 text-dark">予約者一覧</h1>
</div> </div>
<div class="col-sm-6"> <div class="col-lg-6">
<ol class="breadcrumb float-sm-right text-sm"> <ol class="breadcrumb float-sm-right text-sm">
<li class="breadcrumb-item"><a href="{{ url('/home') }}">ホーム</a></li> <li class="breadcrumb-item"><a href="{{ url('/home') }}">ホーム</a></li>
<li class="breadcrumb-item active">予約者一覧</li> <li class="breadcrumb-item active">予約者一覧</li>
@ -20,14 +20,23 @@
</div> </div>
<section class="content"> <section class="content">
<div class="container-fluid">
{{-- 絞り込みフィルター(順序を画像に完全一致) --}} <form method="GET" action="{{ route('reservation') }}" class="mb-3" id="list-form">
<form method="GET" action="{{ route('reservation') }}" class="mb-3" id="filter-form"> <input type="hidden" name="sort" value="{{ $sort ?? request('sort') }}">
<div class="card p-3"> <input type="hidden" name="sort_type" value="{{ $sortType ?? request('sort_type') }}">
<h6 class="mb-3">絞り込みフィルター</h6>
{{-- カード全体 --}}
<div class="col-lg-12">
<div class="card">
{{-- 絞り込みフィルターcard-header --}}
<div class="card-header" style="font-weight:bold;">
絞り込みフィルター
</div>
{{-- フィルター条件エリアcard-body --}}
<div class="card-body bg-white">
<div class="row"> <div class="row">
{{-- 左カラム:駐輪場 利用者ID 利用者分類 タグシリアル タグシリアル64進 --}} {{-- 左カラム --}}
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">駐輪場</label> <label class="col-sm-3 col-form-label">駐輪場</label>
@ -36,13 +45,14 @@
<select name="park_id" class="form-control"> <select name="park_id" class="form-control">
<option value="">全て</option> <option value="">全て</option>
@foreach($parks as $p) @foreach($parks as $p)
<option value="{{ $p->park_id }}" {{ (string)request('park_id')===(string)$p->park_id ? 'selected' : '' }}> <option value="{{ $p->park_id }}" {{ (string) request('park_id') === (string) $p->park_id ? 'selected' : '' }}>
{{ $p->park_name }} {{ $p->park_name }}
</option> </option>
@endforeach @endforeach
</select> </select>
@else @else
<input type="text" name="park_name" value="{{ request('park_name') }}" class="form-control" > <input type="text" name="park_name" value="{{ request('park_name') }}" class="form-control"
placeholder="123456">
@endisset @endisset
</div> </div>
</div> </div>
@ -50,112 +60,143 @@
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">利用者ID</label> <label class="col-sm-3 col-form-label">利用者ID</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_id" value="{{ request('user_id') }}" class="form-control" > <input type="text" name="user_id" value="{{ request('user_id') }}" class="form-control"
placeholder="123456">
</div> </div>
</div> </div>
{{-- 利用者分類 --}}
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">利用者分類</label> <label class="col-sm-3 col-form-label">利用者分類</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_category1" value="{{ request('user_category1') }}" class="form-control" placeholder="分類名1"> @isset($categories)
{{-- 既存互換: IDパラメータが残る可能性があるため hidden で保持 --}} <select name="user_category1" class="form-control">
@if(request()->filled('user_categoryid')) <option value="">全て</option>
<input type="hidden" name="user_categoryid" value="{{ request('user_categoryid') }}"> @foreach($categories as $key => $label)
@endif <option value="{{ $key }}" {{ (string) request('user_category1') === (string) $key ? 'selected' : '' }}>
{{ $label }}
</option>
@endforeach
</select>
@else
<input type="text" name="user_category1" value="{{ request('user_category1') }}" class="form-control"
placeholder="123456">
@endisset
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">タグシリアル</label> <label class="col-sm-3 col-form-label">タグシリアル</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_tag_serial" value="{{ request('user_tag_serial') }}" class="form-control" > <input type="text" name="user_tag_serial" value="{{ request('user_tag_serial') }}"
class="form-control" placeholder="キーワード...">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">タグシリアル64進</label> <label class="col-sm-3 col-form-label">タグシリアル64進</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_tag_serial_64" value="{{ request('user_tag_serial_64') }}" class="form-control" > <input type="text" name="user_tag_serial_64" value="{{ request('user_tag_serial_64') }}"
class="form-control" placeholder="キーワード...">
</div> </div>
</div> </div>
</div> </div>
{{-- 右カラム:フリガナ 電話番号 メールアドレス 勤務先 学校 --}} {{-- 右カラム --}}
<div class="col-md-6"> <div class="col-md-6">
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">フリガナ</label> <label class="col-sm-3 col-form-label">フリガナ</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_phonetic" value="{{ request('user_phonetic') }}" class="form-control" > <input type="text" name="user_phonetic" value="{{ request('user_phonetic') }}" class="form-control"
placeholder="123456">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">電話番号</label> <label class="col-sm-3 col-form-label">電話番号</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_mobile" value="{{ request('user_mobile') }}" class="form-control" > <input type="text" name="user_mobile" value="{{ request('user_mobile') }}" class="form-control"
placeholder="08011112222">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">メールアドレス</label> <label class="col-sm-3 col-form-label">メールアドレス</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_primemail" value="{{ request('user_primemail') }}" class="form-control" > <input type="text" name="user_primemail" value="{{ request('user_primemail') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">勤務先</label> <label class="col-sm-3 col-form-label">勤務先</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_workplace" value="{{ request('user_workplace') }}" class="form-control" > <input type="text" name="user_workplace" value="{{ request('user_workplace') }}" class="form-control"
placeholder="キーワード...">
</div> </div>
</div> </div>
<div class="form-group row"> <div class="form-group row">
<label class="col-sm-3 col-form-label">学校</label> <label class="col-sm-3 col-form-label">学校</label>
<div class="col-sm-9"> <div class="col-sm-9">
<input type="text" name="user_school" value="{{ request('user_school') }}" class="form-control" > <input type="text" name="user_school" value="{{ request('user_school') }}" class="form-control"
placeholder="キーワード...">
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="mt-2"> {{-- 絞り込みボタン --}}
<button type="submit" class="btn btn-default">絞り込み</button> <div class="card-body pt-2">
<a href="{{ route('reservation') }}" class="btn btn-default">解除</a> <button type="submit" class="btn btn-default mr10">絞り込み</button>
<a href="{{ route('reservation') }}" class="btn btn-default mr10">解除</a>
</div>
</div>
</div>
{{-- ページネーションのラッパーを追加 --}}
<div class="container-fluid mb20 pagination-area">
{{-- ページネーションのビジュアルラッパー --}}
<div class="pagination-wrapper mt-2">
<nav aria-label="ページネーション">
{{-- Bootstrap のリンク出力(元の呼び出しをそのまま利用) --}}
{{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
</nav>
</div> </div>
</div> </div>
</form>
{{-- 一覧テーブル(ソート機能付きヘッダー) --}} {{-- 一覧テーブル部:スクロール対応 --}}
<div class="col-lg-12 row sample03-wrapper no_padding_right mb20">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered table-hover table-sm rv-table text-nowrap"> <table class="table table-bordered table-hover table-sm rv-table text-nowrap mb-0">
<thead> <thead class="thead-light">
<tr> <tr>
{{-- ソート可能な項目にはリンクを追加 --}} @php($activeSort = request('sort'))
<th> @php($activeType = request('sort_type'))
<a href="{{ request()->fullUrlWithQuery(['sort' => 'user_id', 'sort_type' => request('sort') === 'user_id' && request('sort_type') === 'desc' ? 'asc' : 'desc']) }}" class="text-dark text-decoration-none"> <th
class="sorting {{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.user_id">
<span class="sort-label">
利用者ID 利用者ID
@if(request('sort') === 'user_id' && request('sort_type') === 'asc') <span class="sort-arrows" aria-hidden="true">
<span class="text-muted"></span> <span class="up"></span>
@elseif(request('sort') === 'user_id' && request('sort_type') === 'desc') <span class="down"></span>
<span class="text-muted"></span> </span>
@else </span>
<span class="text-muted">↑↓</span>
@endif
</a>
</th> </th>
<th>
<a href="{{ request()->fullUrlWithQuery(['sort' => 'user_name', 'sort_type' => request('sort') === 'user_name' && request('sort_type') === 'desc' ? 'asc' : 'desc']) }}" class="text-dark text-decoration-none"> <th
class="sorting {{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="u.user_name">
<span class="sort-label">
氏名 氏名
@if(request('sort') === 'user_name' && request('sort_type') === 'asc') <span class="sort-arrows" aria-hidden="true">
<span class="text-muted"></span> <span class="up"></span>
@elseif(request('sort') === 'user_name' && request('sort_type') === 'desc') <span class="down"></span>
<span class="text-muted"></span> </span>
@else </span>
<span class="text-muted">↑↓</span>
@endif
</a>
</th> </th>
<th>フリガナ</th> <th>フリガナ</th>
<th>居住所:郵便番号</th> <th>居住所:郵便番号</th>
<th>居住所:都道府県</th> <th>居住所:都道府県</th>
@ -172,55 +213,46 @@
<th>学校</th> <th>学校</th>
<th>卒業予定</th> <th>卒業予定</th>
<th>備考</th> <th>備考</th>
<th>定期予約ID</th> <th
class="sorting {{ $activeSort === 'rc.reserve_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="rc.reserve_id">
<span class="sort-label">
定期予約ID
<span class="sort-arrows" aria-hidden="true">
<span class="up"></span>
<span class="down"></span>
</span>
</span>
</th>
<th>利用者分類1</th> <th>利用者分類1</th>
<th>利用者分類2</th> <th>利用者分類2</th>
<th>利用者分類3</th> <th>利用者分類3</th>
<th> <th
<a href="{{ request()->fullUrlWithQuery(['sort' => 'park_id', 'sort_type' => request('sort') === 'park_id' && request('sort_type') === 'desc' ? 'asc' : 'desc']) }}" class="text-dark text-decoration-none"> class="sorting {{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
駐輪場ID sort="p.park_name">
@if(request('sort') === 'park_id' && request('sort_type') === 'asc') <span class="sort-label">
<span class="text-muted"></span> 駐輪場
@elseif(request('sort') === 'park_id' && request('sort_type') === 'desc') <span class="sort-arrows" aria-hidden="true">
<span class="text-muted"></span> <span class="up"></span>
@else <span class="down"></span>
<span class="text-muted">↑↓</span> </span>
@endif </span>
</a>
</th>
<th>
<a href="{{ request()->fullUrlWithQuery(['sort' => 'price_parkplaceid', 'sort_type' => request('sort') === 'price_parkplaceid' && request('sort_type') === 'desc' ? 'asc' : 'desc']) }}" class="text-dark text-decoration-none">
駐輪場所ID
@if(request('sort') === 'price_parkplaceid' && request('sort_type') === 'asc')
<span class="text-muted"></span>
@elseif(request('sort') === 'price_parkplaceid' && request('sort_type') === 'desc')
<span class="text-muted"></span>
@else
<span class="text-muted">↑↓</span>
@endif
</a>
</th>
<th>
<a href="{{ request()->fullUrlWithQuery(['sort' => 'psection_id', 'sort_type' => request('sort') === 'psection_id' && request('sort_type') === 'desc' ? 'asc' : 'desc']) }}" class="text-dark text-decoration-none">
車種区分ID
@if(request('sort') === 'psection_id' && request('sort_type') === 'asc')
<span class="text-muted"></span>
@elseif(request('sort') === 'psection_id' && request('sort_type') === 'desc')
<span class="text-muted"></span>
@else
<span class="text-muted">↑↓</span>
@endif
</a>
</th> </th>
<th>駐輪場所ID</th>
<th>車種区分ID</th>
<th>予約日時</th> <th>予約日時</th>
<th>減免措置</th> <th>減免措置</th>
<th>M以内フラグ</th> <th>800M以内フラグ</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@forelse ($rows as $row) @forelse ($rows as $row)
<tr> <tr>
<td>{{ $row->user_id }}</td> <td>
<a href="{{ route('users_edit', ['seq' => $row->user_seq ?? $row->user_id]) }}">
{{ $row->user_id }}
</a>
</td>
<td>{{ $row->user_name }}</td> <td>{{ $row->user_name }}</td>
<td>{{ $row->user_phonetic }}</td> <td>{{ $row->user_phonetic }}</td>
<td>{{ $row->user_regident_zip }}</td> <td>{{ $row->user_regident_zip }}</td>
@ -238,35 +270,217 @@
<td>{{ $row->user_school }}</td> <td>{{ $row->user_school }}</td>
<td>{{ $row->user_graduate }}</td> <td>{{ $row->user_graduate }}</td>
<td>{{ $row->user_remarks }}</td> <td>{{ $row->user_remarks }}</td>
<td>{{ $row->reserve_id }}</td> <td>
<a href="{{ route('regularcontracts_edit', ['contract_id' => $row->contract_id]) }}">
{{ $row->contract_id }}
</a>
</td>
<td>{{ $row->user_category1 ?? '' }}</td> <td>{{ $row->user_category1 ?? '' }}</td>
<td>{{ $row->user_category2 ?? '' }}</td> <td>{{ $row->user_category2 ?? '' }}</td>
<td>{{ $row->user_category3 ?? '' }}</td> <td>{{ $row->user_category3 ?? '' }}</td>
<td>{{ $row->park_id }}</td> <td>{{ $row->park_id }}</td>
<td>{{ $row->price_parkplaceid }}</td> <td>{{ $row->price_parkplaceid }}</td>
<td>{{ $row->psection_id }}</td> <td>{{ [1 => '自転車', 2 => '原付', 3 => 'その他'][$row->psection_id] ?? '' }}</td>
<td>{{ $row->reserve_date }}</td> <td>{{ $row->reserve_date }}</td>
<td>{{ $row->reduction ?? '' }}</td> <td>{{ $row->user_reduction ?? '' }}</td>
<td> <td>{{ $row->{'800m_flag'} ?? '' }}</td>
@php $f800 = data_get($row,'within_800m_flag', data_get($row,'flag_800m', null)); @endphp
{{ (string)$f800 === '1' ? 'M以内' : '' }}
</td>
</tr> </tr>
@empty @empty
<tr><td colspan="28" class="text-center">データがありません。</td></tr> <tr>
<td colspan="25" class="text-center">データがありません。</td>
</tr>
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</div>
</form>
<div class="mt-3">
{{ $rows->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
</div>
</div>
</section> </section>
<style> @push('scripts')
.rv-table thead th{ background:#eeeeee; white-space:nowrap; vertical-align:middle; } <script>
.rv-table tbody tr{ background:#fff; } // ▼ ソート機能(日本語コメント)
</style> // th 要素をクリックすると sort と sort_type を設定してフォーム送信します
document.querySelectorAll('th[sort]').forEach(th => {
th.classList.add('sorting'); // ベースクラスを確実に付ける
th.addEventListener('click', function () {
const col = this.getAttribute('sort');
if (!col) return;
const form = document.getElementById('list-form');
const sortInput = form.querySelector('input[name="sort"]');
const typeInput = form.querySelector('input[name="sort_type"]');
const current = sortInput.value;
const currentType = typeInput.value;
let nextType = 'asc';
if (current === col) {
nextType = (currentType === 'asc') ? 'desc' : 'asc';
}
if (sortInput) sortInput.value = col;
if (typeInput) typeInput.value = nextType;
// 視覚的にソートクラスを切り替え(矢印の色に反映)
document.querySelectorAll('th[sort]').forEach(h => {
h.classList.remove('sorting_asc', 'sorting_desc');
if (!h.classList.contains('sorting')) h.classList.add('sorting');
});
if (nextType === 'asc') {
this.classList.add('sorting_asc');
} else {
this.classList.add('sorting_desc');
}
form.submit();
});
});
</script>
<style>
/* ----------------------------------------
ページネーションの横幅を確保して右寄せ(スクリーンショットは右寄せ)
---------------------------------------- */
.pagination-area .pagination-wrapper {
display: flex;
justify-content: flex-end;
/* 右寄せ:必要なら center に変更 */
align-items: center;
width: 100%;
gap: 8px;
}
/* ========================================
ソート矢印の色ルール(日本語コメント)
状態:
未ソート -> ()灰色, ()灰色
昇順(asc) -> ()黒色, ()灰色
降順(desc) -> ()灰色, ()黒色
======================================== */
/* 既存の擬似要素で出る矢印を無効化(保険) */
th.sorting::after,
th.sorting_asc::after,
th.sorting_desc::after {
display: none !important;
content: none !important;
background-image: none !important;
background: none !important;
}
/* 矢印を水平に並べる(左: up, 右: down */
th[sort] .sort-arrows,
th.sorting .sort-arrows,
th.sorting_asc .sort-arrows,
th.sorting_desc .sort-arrows {
display: inline-flex !important;
flex-direction: row !important;
gap: 6px !important;
align-items: center !important;
justify-content: center !important;
line-height: 1 !important;
font-size: 12px !important;
user-select: none !important;
width: auto !important;
box-sizing: border-box;
vertical-align: middle;
color: #bfc9d6 !important;
/* デフォルト灰 */
}
th[sort] .sort-arrows .up,
th[sort] .sort-arrows .down,
th.sorting .sort-arrows .up,
th.sorting .sort-arrows .down {
display: inline-block !important;
min-width: 14px;
text-align: center;
line-height: 1;
}
/* 未ソート: 両方灰 */
th.sorting:not(.sorting_asc):not(.sorting_desc) .sort-arrows .up,
th.sorting:not(.sorting_asc):not(.sorting_desc) .sort-arrows .down {
color: #bfc9d6 !important;
}
/* 昇順: 左(上) 黒、右(下) 灰 */
th.sorting_asc .sort-arrows .up,
th[sort].sorting_asc .sort-arrows .up {
color: #000000 !important;
}
th.sorting_asc .sort-arrows .down,
th[sort].sorting_asc .sort-arrows .down {
color: #bfc9d6 !important;
}
/* 降順: 左(上) 灰、右(下) 黒 */
th.sorting_desc .sort-arrows .up,
th[sort].sorting_desc .sort-arrows .up {
color: #bfc9d6 !important;
}
th.sorting_desc .sort-arrows .down,
th[sort].sorting_desc .sort-arrows .down {
color: #000000 !important;
}
/* 矢印間を詰めたい場合(例: 見た目で letter-spacing 相当) */
th[sort] .sort-arrows {
gap: 0 !important;
}
th[sort] .sort-arrows .down {
margin-left: -5px !important;
}
/* 矢印の下線を消す(リンク内にある場合の保険) */
th .sort-arrows,
th .sort-label,
th[sort] .sort-arrows,
th.sorting .sort-arrows {
text-decoration: none !important;
}
th .sort-label a,
th .sort-arrows a {
text-decoration: none !important;
border-bottom: none !important;
color: inherit !important;
}
/* SVG 対応(矢印が svg の場合) */
th[sort] .sort-arrows svg path,
th.sorting .sort-arrows svg path {
fill: #bfc9d6 !important;
}
th.sorting_asc .sort-arrows svg path,
th[sort].sorting_asc .sort-arrows svg path {
fill: #000 !important;
}
th.sorting_desc .sort-arrows svg path,
th[sort].sorting_desc .sort-arrows svg path {
fill: #000 !important;
}
/* レスポンシブ:小画面で間隔を狭める */
@media (max-width: 575.98px) {
th[sort] .sort-arrows {
gap: 4px !important;
font-size: 11px !important;
}
}
/* フォーカス時の視認性(アクセシビリティ) */
th.sorting:focus,
th.sorting_asc:focus,
th.sorting_desc:focus {
outline: 2px solid rgba(0, 0, 0, 0.08);
outline-offset: -2px;
}
</style>
@endpush
@endsection @endsection

View File

@ -51,11 +51,11 @@
<li class="nav-item d-lg-none"> <li class="nav-item d-lg-none">
<a class="nav-link" data-widget="pushmenu" href="#"><i class="fa fa-bars"></i></a> <a class="nav-link" data-widget="pushmenu" href="#"><i class="fa fa-bars"></i></a>
</li> </li>
<li class="nav-item d-none d-sm-inline-block"> <li class="nav-item d-none d-sm-inline-block">
<a class="nav-link" style="margin-left:20px;"> <a class="nav-link" style="margin-left:20px;">
{{ __('ようこそ、:ope_name様', ['ope_name' => Auth::user()->ope_name]) }} {{ __('ようこそ、:ope_name様', ['ope_name' => Auth::user()->ope_name]) }}
</a> </a>
</li> </li>
</ul> </ul>
<!-- SEARCH FORM --> <!-- SEARCH FORM -->
@ -705,7 +705,7 @@
@stack('scripts') @stack('scripts')
<!-- Main Footer --> <!-- Main Footer -->
<footer class="main-footer"> <footer class="main-footer" style="margin-left:270px;">
<strong>Copyright &copy; 2018 <a href="./index2.html">So-Manager for back office by so-rin <strong>Copyright &copy; 2018 <a href="./index2.html">So-Manager for back office by so-rin
Co.,Ltd.</a></strong> All rights reserved. Co.,Ltd.</a></strong> All rights reserved.
</footer> </footer>