577 lines
23 KiB
PHP
577 lines
23 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('title', '未更新者一覧')
|
||
|
||
@section('content')
|
||
<div class="content-header">
|
||
<div class="container-fluid">
|
||
<div class="row mb-2">
|
||
<div class="col-lg-6">
|
||
<h1 class="m-0 text-dark">未更新者一覧</h1>
|
||
</div>
|
||
<div class="col-lg-6">
|
||
<ol class="breadcrumb float-sm-right text-sm">
|
||
<li class="breadcrumb-item"><a href="{{ url('/home') }}">ホーム</a></li>
|
||
<li class="breadcrumb-item active">未更新者一覧</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<section class="content">
|
||
|
||
<form method="GET" action="{{ route('contractor_List') }}" class="mb-3" id="list-form">
|
||
<input type="hidden" name="sort" value="{{ $sort ?? request('sort') }}">
|
||
<input type="hidden" name="sort_type" value="{{ $sortType ?? request('sort_type') }}">
|
||
|
||
{{-- ▼ カード全体 --}}
|
||
<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="col-md-6">
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">駐輪場</label>
|
||
<div class="col-sm-9">
|
||
@isset($parks)
|
||
<select name="park_id" class="form-control">
|
||
<option value="">全て</option>
|
||
@foreach($parks as $p)
|
||
<option value="{{ $p->park_id }}" {{ (string) request('park_id') === (string) $p->park_id ? 'selected' : '' }}>
|
||
{{ $p->park_name }}
|
||
</option>
|
||
@endforeach
|
||
</select>
|
||
@else
|
||
<input type="text" name="park_name" value="{{ request('park_name') }}" class="form-control"
|
||
placeholder="123456">
|
||
@endisset
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">利用者ID</label>
|
||
<div class="col-sm-9">
|
||
<input type="text" name="user_id" value="{{ request('user_id') }}" class="form-control"
|
||
placeholder="123456">
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ===== 利用者分類:input を select に変更 ===== --}}
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">利用者分類</label>
|
||
<div class="col-sm-9">
|
||
@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 class="form-group row">
|
||
<label class="col-sm-3 col-form-label">タグシリアル64進</label>
|
||
<div class="col-sm-9">
|
||
<input type="text" name="user_tag_serial_64" value="{{ request('user_tag_serial_64') }}"
|
||
class="form-control" placeholder="キーワード...">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">対象月</label>
|
||
<div class="col-sm-9 d-flex align-items-center">
|
||
@php
|
||
// 既定選択なし(送信時だけ適用)
|
||
$target_month = request('target_month');
|
||
@endphp
|
||
<div class="form-check mr-3">
|
||
<input class="form-check-input" type="radio" name="target_month" id="none_month" value="" {{ $target_month === null || $target_month === '' ? 'checked' : '' }}>
|
||
<label class="form-check-label" for="none_month">指定なし</label>
|
||
</div>
|
||
<div class="form-check mr-3">
|
||
<input class="form-check-input" type="radio" name="target_month" id="last_month" value="last" {{ $target_month === 'last' ? 'checked' : '' }}>
|
||
<label class="form-check-label" for="last_month">先月</label>
|
||
</div>
|
||
<div class="form-check mr-3">
|
||
<input class="form-check-input" type="radio" name="target_month" id="this_month" value="this" {{ $target_month === 'this' ? 'checked' : '' }}>
|
||
<label class="form-check-label" for="this_month">今月</label>
|
||
</div>
|
||
<div class="form-check mr-3">
|
||
<input class="form-check-input" type="radio" name="target_month" id="next_month" value="next" {{ $target_month === 'next' ? 'checked' : '' }}>
|
||
<label class="form-check-label" for="next_month">来月</label>
|
||
</div>
|
||
<div class="form-check">
|
||
<input class="form-check-input" type="radio" name="target_month" id="after_2_month" value="after2" {{ $target_month === 'after2' ? 'checked' : '' }}>
|
||
<label class="form-check-label" for="after_2_month">2か月後</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- 右カラム --}}
|
||
<div class="col-md-6">
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">フリガナ</label>
|
||
<div class="col-sm-9">
|
||
<input type="text" name="user_phonetic" value="{{ request('user_phonetic') }}" class="form-control"
|
||
placeholder="123456">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">電話番号</label>
|
||
<div class="col-sm-9">
|
||
<input type="text" name="user_mobile" value="{{ request('user_mobile') }}" class="form-control"
|
||
placeholder="08011112222">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">メールアドレス</label>
|
||
<div class="col-sm-9">
|
||
<input type="text" name="user_primemail" value="{{ request('user_primemail') }}" class="form-control"
|
||
placeholder="キーワード...">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">勤務先</label>
|
||
<div class="col-sm-9">
|
||
<input type="text" name="user_workplace" value="{{ request('user_workplace') }}" class="form-control"
|
||
placeholder="キーワード...">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">学校</label>
|
||
<div class="col-sm-9">
|
||
<input type="text" name="user_school" value="{{ request('user_school') }}" class="form-control"
|
||
placeholder="キーワード...">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group row">
|
||
<label class="col-sm-3 col-form-label">タグ・QR</label>
|
||
<div class="col-sm-9">
|
||
<select name="tag_qr_flag" class="form-control">
|
||
<option value="" {{ request('tag_qr_flag') === '' ? 'selected' : '' }}>全て</option>
|
||
<option value="1" {{ request('tag_qr_flag') === '1' ? 'selected' : '' }}>QR</option>
|
||
<option value="0" {{ request('tag_qr_flag') === '0' ? 'selected' : '' }}>タグ</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- ▼ 絞り込みボタン --}}
|
||
<div class="mt-2 mb-3 text-start">
|
||
<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 class="col-lg-12 row sample03-wrapper no_padding_right mb20">
|
||
<div class="table-responsive">
|
||
<table class="table table-bordered table-hover table-sm rv-table text-nowrap mb-0">
|
||
<thead class="thead-light">
|
||
<tr>
|
||
@php($activeSort = request('sort'))
|
||
@php($activeType = request('sort_type'))
|
||
<th
|
||
class="sorting {{ $activeSort === 'rc.user_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
|
||
sort="rc.user_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
|
||
class="sorting {{ $activeSort === 'u.user_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
|
||
sort="u.user_name"
|
||
>
|
||
<span class="sort-label">
|
||
氏名
|
||
<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.contract_id' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
|
||
sort="rc.contract_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
|
||
class="sorting {{ $activeSort === 'rc.tag_qr_flag' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
|
||
sort="rc.tag_qr_flag"
|
||
>
|
||
<span class="sort-label">
|
||
タグ・QR
|
||
<span class="sort-arrows" aria-hidden="true">
|
||
<span class="up">↑</span>
|
||
<span class="down">↓</span>
|
||
</span>
|
||
</span>
|
||
</th>
|
||
|
||
<th
|
||
class="sorting {{ $activeSort === 'p.park_name' ? ($activeType === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
|
||
sort="p.park_name"
|
||
>
|
||
<span class="sort-label">
|
||
駐輪場
|
||
<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>利用者分類1</th>
|
||
<th>利用者分類2</th>
|
||
<th>利用者分類3</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>
|
||
</thead>
|
||
<tbody>
|
||
@forelse ($rows as $row)
|
||
<tr>
|
||
<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_phonetic }}</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->park_name }}</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_category1 ?? '' }}</td>
|
||
<td>{{ $row->user_category2 ?? '' }}</td>
|
||
<td>{{ $row->user_category3 ?? '' }}</td>
|
||
<td>{{ $row->user_mobile }}</td>
|
||
<td>{{ $row->user_homephone }}</td>
|
||
<td>{{ $row->user_birthdate }}</td>
|
||
<td>{{ $row->user_gender }}</td>
|
||
<td>{{ $row->user_regident_zip }}</td>
|
||
<td>{{ $row->user_regident_pre }}</td>
|
||
<td>{{ $row->user_regident_city }}</td>
|
||
<td>{{ $row->user_regident_add }}</td>
|
||
<td>{{ $row->user_relate_zip }}</td>
|
||
<td>{{ $row->user_relate_pre }}</td>
|
||
<td>{{ $row->user_relate_city }}</td>
|
||
<td>{{ $row->user_relate_add }}</td>
|
||
<td>
|
||
{{-- 契約日を「yyyymmdd」形式で表示する --}}
|
||
{{ $row->contract_created_at
|
||
? \Illuminate\Support\Carbon::parse($row->contract_created_at)->format('Y-m-d')
|
||
: '' }}
|
||
</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_graduate }}</td>
|
||
<td>{{ $row->contract_seal_issue }}</td>
|
||
<td>{{ $row->user_securitynum }}</td>
|
||
<td>{{ $row->user_remarks }}</td>
|
||
</tr>
|
||
@empty
|
||
<tr>
|
||
<td colspan="25" class="text-center">データがありません。</td>
|
||
</tr>
|
||
@endforelse
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
</section>
|
||
|
||
@push('scripts')
|
||
<script>
|
||
// ▼ ソート機能(日本語コメント)
|
||
// 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
|