【定期契約マスタ】画面修正
All checks were successful
Deploy main / deploy (push) Successful in 22s

This commit is contained in:
你的名字 2025-10-31 22:14:50 +09:00
parent b709765361
commit 06756440ce

View File

@ -3,126 +3,100 @@
@section('content') @section('content')
<style> <style>
/* 画面全体のフォント/サイズを統一(やや小さめ) */ /* ===== 画面全般(フォント・サイズ) ===== */
.rc-page, .rc-page,
.rc-page .card, .rc-page .card,
.rc-page .form-control, .rc-page .form-control,
.rc-page .btn, .rc-page .btn,
.rc-page table, .rc-page table,
.rc-page .breadcrumb { .rc-page .breadcrumb {
font-family: "Noto Sans JP", "Hiragino Kaku Gothic ProN", "Meiryo", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-family: "Noto Sans JP","Hiragino Kaku Gothic ProN","Meiryo",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
font-size: 13px; font-size: 13px;
line-height: 1.45; line-height: 1.45;
} }
/* フィルター1行左ラベル右入力、を縦に積む */ /* ===== フィルター列レイアウト ===== */
.rc-filter .field { .rc-filter .field{display:flex;align-items:center;margin-bottom:.6rem;}
display: flex; .rc-filter .label{flex:0 0 180px;margin:0;color:#333;font-weight:600;white-space:nowrap;}
align-items: center; .rc-filter .input{flex:1 1 auto;min-width:220px;}
margin-bottom: .6rem; .rc-filter .form-control,.rc-filter .custom-select{height:calc(2.0rem + 2px);padding:.25rem .5rem;}
.rc-filter .inline-range{display:flex;gap:.5rem;align-items:center;}
.rc-filter .tilde{color:#666;}
/* ===== 一覧テーブル基礎 ===== */
.rc-table th,.rc-table td{padding:.35rem .5rem;font-size:12px;}
.rc-table thead th{white-space:nowrap;background:#f2f2f2;color:#333;border-bottom-color:#ddd;}
.rc-page .rc-table tbody td:not(.op-cell){background:#fff;}
.rc-page .rc-table tbody td.op-cell{background:#faebd7;}
.rc-table thead th .sort-arrows{display:inline-flex;flex-direction:row;align-items:center;gap:.1rem;margin-left:.2rem;font-size:12px;line-height:1;font-weight:700;text-decoration:none;letter-spacing:-5px;}
.rc-table thead th .sort-arrows .up,.rc-table thead th .sort-arrows .down{color:#b5b5b5;text-decoration:none;}
.rc-table thead th.sorting_asc .sort-arrows .up{color:#000;}
.rc-table thead th.sorting_desc .sort-arrows .down{color:#000;}
/* ===== スクロール固定ヘッダ固定列freeze-table ===== */
.scroll.freeze-table{
position:relative;
background:#fff;
}
/* ===== スクロールラッパsticky正確動作用にposition:relativeを追加 ===== */
.scroll.freeze-table .scroll-x {
position: relative; /* ← ★ これが重要 */
min-width: max-content;
} }
.rc-filter .label { .scroll.freeze-table table{
flex: 0 0 180px; border-collapse:collapse;
margin: 0; width:100%;
color: #333;
font-weight: 600;
white-space: nowrap;
} }
.rc-filter .input {
flex: 1 1 auto; /* ヘッダー固定 */
min-width: 220px; .scroll.freeze-table thead th{
position:sticky;
top:0;
z-index:10; /* ヘッダーを前面 */
background:#f2f2f2;
} }
.rc-filter .form-control, /* ===== 左1列No固定幅 50px ===== */
.rc-filter .custom-select { .scroll.freeze-table thead th:first-child,
height: calc(2.0rem + 2px); .scroll.freeze-table tbody td:first-child {
padding: .25rem .5rem; position: sticky;
} left: 0;
z-index: 20;
.rc-filter .inline-range {
display: flex;
gap: .5rem;
align-items: center;
}
.rc-filter .tilde {
color: #666;
}
/* 一覧テーブル:斑馬(ゼブラ)無し、やや詰め気味 */
.rc-table th,
.rc-table td {
padding: .35rem .5rem;
font-size: 12px;
}
.rc-table thead th {
white-space: nowrap;
}
/* ツールバー:左にボタン群、右にページャ */
.rc-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
gap: .75rem;
flex-wrap: wrap;
}
.rc-toolbar .btn+.btn {
margin-left: .4rem;
}
/* 表頭=薄いグレー、本文=白 */
.rc-page .rc-table thead th {
background: #f2f2f2;
color: #333;
border-bottom-color: #ddd;
}
.rc-page .rc-table tbody td:not(.op-cell) {
background: #fff; background: #fff;
} width: 50px;
min-width: 50px;
max-width: 50px;
}
/* 操作列(チェック+編集) */ /* ===== 左2列目操作列固定幅 120px ===== */
.rc-page .rc-table tbody td.op-cell { .scroll.freeze-table thead th:nth-child(2),
.scroll.freeze-table tbody td:nth-child(2) {
position: sticky;
left: 50px; /* No列と同じ幅 */
z-index: 19; /* 少し下げる(重なり順) */
background: #faebd7; background: #faebd7;
} width: 120px;
min-width: 120px;
max-width: 120px;
box-shadow: inset -1px 0 #ddd; /* 境界を自然にする */
}
.rc-table thead th .sort-arrows {
display: inline-flex; /* 行ホバーの視認性(薄め) */
flex-direction: row; .scroll.freeze-table tbody tr:hover td{background-color:rgba(0,0,0,.02);}
align-items: center;
gap: 0.1rem; /* ツールバー(左:ボタン群/右:ページャ) */
margin-left: .2rem; .rc-toolbar{display:flex;align-items:center;justify-content:space-between;gap:.75rem;flex-wrap:wrap;}
font-size: 12px; .rc-toolbar .btn+.btn{margin-left:.4rem;}
line-height: 1;
font-weight: 700;
text-decoration: none;
letter-spacing: -5px; /* ↑↓を詰める */
}
.rc-table thead th .sort-arrows .up,
.rc-table thead th .sort-arrows .down {
color: #b5b5b5;
text-decoration: none;
}
.rc-table thead th.sorting_asc .sort-arrows .up {
color: #000;
}
.rc-table thead th.sorting_desc .sort-arrows .down {
color: #000;
}
</style> </style>
<div class="rc-page"> <div class="rc-page">
<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-lg-6"> <div class="col-lg-6"><h1 class="m-0 text-dark">定期契約マスタ</h1></div>
<h1 class="m-0 text-dark">定期契約マスタ</h1>
</div>
<div class="col-lg-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="{{ route('home') }}">ホーム</a></li> <li class="breadcrumb-item"><a href="{{ route('home') }}">ホーム</a></li>
@ -137,11 +111,9 @@
<section class="content"> <section class="content">
<div class="container-fluid"> <div class="container-fluid">
{{-- 絞り込みフィルター2カラム --}} {{-- 絞り込みフィルター2カラム --}}
<div class="card rc-filter"> <div class="card rc-filter">
<div class="card-header"> <div class="card-header"><h3 class="card-title">絞り込みフィルター</h3></div>
<h3 class="card-title">絞り込みフィルター</h3>
</div>
<div class="card-body"> <div class="card-body">
<form action="{{ route('regularcontracts') }}" method="get" id="list-form"> <form action="{{ route('regularcontracts') }}" method="get" id="list-form">
@csrf @csrf
@ -151,46 +123,32 @@
<div class="row"> <div class="row">
{{-- 左カラム --}} {{-- 左カラム --}}
<div class="col-lg-6"> <div class="col-lg-6">
<div class="field"> <div class="field"><label class="label">利用者ID</label>
<label class="label">利用者ID</label> <div class="input"><input type="text" class="form-control" name="user_id" value="{{ $user_id ?? '' }}" placeholder="123456"></div>
<div class="input"><input type="text" class="form-control" name="user_id" value="{{ $user_id ?? '' }}"
placeholder="123456"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">利用者分類</label>
<label class="label">利用者分類</label>
<div class="input"> <div class="input">
<select class="form-control" name="user_categoryid"> <select class="form-control" name="user_categoryid">
<option value="">全て</option> <option value="">全て</option>
@foreach(($userTypeOptions ?? []) as $id => $label) @foreach(($userTypeOptions ?? []) as $id => $label)
<option value="{{ $id }}" {{ (string)($user_categoryid ?? '') === (string) $id ? 'selected' : '' }}> <option value="{{ $id }}" {{ (string)($user_categoryid ?? '') === (string) $id ? 'selected' : '' }}>{{ $label }}</option>
{{ $label }}
</option>
@endforeach @endforeach
</select> </select>
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">タグシリアル</label>
<label class="label">タグシリアル</label> <div class="input"><input type="text" class="form-control" name="user_tag_serial" value="{{ $user_tag_serial ?? '' }}" placeholder="キーワード…"></div>
<div class="input"><input type="text" class="form-control" name="user_tag_serial"
value="{{ $user_tag_serial ?? '' }}" placeholder="キーワード…"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">フリガナ</label>
<label class="label">フリガナ</label> <div class="input"><input type="text" class="form-control" name="user_phonetic" value="{{ $user_phonetic ?? '' }}" placeholder="キーワード…"></div>
<div class="input"><input type="text" class="form-control" name="user_phonetic"
value="{{ $user_phonetic ?? '' }}" placeholder="キーワード…"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">電話番号</label>
<label class="label">電話番号</label> <div class="input"><input type="text" class="form-control" name="phone" value="{{ $phone ?? '' }}" placeholder="携帯/自宅いずれも可"></div>
<div class="input"><input type="text" class="form-control" name="phone" value="{{ $phone ?? '' }}"
placeholder="携帯/自宅いずれも可"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">メールアドレス</label>
<label class="label">メールアドレス</label> <div class="input"><input type="text" class="form-control" name="email" value="{{ $email ?? '' }}" placeholder="キーワード…"></div>
<div class="input"><input type="text" class="form-control" name="email" value="{{ $email ?? '' }}" placeholder="キーワード…">
</div> </div>
</div> <div class="field"><label class="label">ワークレコード</label>
<div class="field">
<label class="label">ワークレコード</label>
<div class="input"> <div class="input">
<select class="form-control" name="work_record"> <select class="form-control" name="work_record">
<option value="0" {{ ($work_record ?? '0') === '0' ? 'selected' : '' }}>全レコード表示</option> <option value="0" {{ ($work_record ?? '0') === '0' ? 'selected' : '' }}>全レコード表示</option>
@ -199,18 +157,13 @@
</select> </select>
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">定期契約ID</label>
<label class="label">定期契約ID</label> <div class="input"><input type="text" class="form-control" name="contract_qr_id" value="{{ $contract_qr_id ?? '' }}" placeholder="定期契約ID"></div>
<div class="input"><input type="text" class="form-control" name="contract_qr_id"
value="{{ $contract_qr_id ?? '' }}" placeholder="定期契約ID"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">検索</label>
<label class="label">検索</label> <div class="input"><input type="text" class="form-control" name="zone_keyword" value="{{ $zone_keyword ?? '' }}" placeholder="ゾーンID, 車室番号, 旧会員番号"></div>
<div class="input"><input type="text" class="form-control" name="zone_keyword"
value="{{ $zone_keyword ?? '' }}" placeholder="ゾーンID, 車室番号, 旧会員番号"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">関連住所入力あり</label>
<label class="label">関連住所入力あり</label>
<div class="input"> <div class="input">
<div class="form-check" style="padding-left:0;"> <div class="form-check" style="padding-left:0;">
<input type="checkbox" class="form-check-input" id="has_address" name="has_address" value="1" {{ !empty($has_address) ? 'checked' : '' }}> <input type="checkbox" class="form-check-input" id="has_address" name="has_address" value="1" {{ !empty($has_address) ? 'checked' : '' }}>
@ -221,61 +174,45 @@
{{-- 右カラム --}} {{-- 右カラム --}}
<div class="col-lg-6"> <div class="col-lg-6">
<div class="field"> <div class="field"><label class="label">駐輪場</label>
<label class="label">駐輪場</label>
<div class="input"> <div class="input">
<select class="form-control" name="park_id"> <select class="form-control" name="park_id">
<option value="">全て</option> <option value="">全て</option>
@foreach(($parkOptions ?? []) as $id => $name) @foreach(($parkOptions ?? []) as $id => $name)
<option value="{{ $id }}" {{ (string)($park_id ?? '') === (string) $id ? 'selected' : '' }}> <option value="{{ $id }}" {{ (string)($park_id ?? '') === (string) $id ? 'selected' : '' }}>{{ $name }}</option>
{{ $name }}
</option>
@endforeach @endforeach
</select> </select>
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">予約日時</label>
<label class="label">予約日時</label>
<div class="input inline-range"> <div class="input inline-range">
<input type="datetime-local" class="form-control" name="reserve_date_from" <input type="datetime-local" class="form-control" name="reserve_date_from" value="{{ $reserve_date_from ?? '' }}">
value="{{ $reserve_date_from ?? '' }}">
<span class="tilde"></span> <span class="tilde"></span>
<input type="datetime-local" class="form-control" name="reserve_date_to" <input type="datetime-local" class="form-control" name="reserve_date_to" value="{{ $reserve_date_to ?? '' }}">
value="{{ $reserve_date_to ?? '' }}">
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">契約日時</label>
<label class="label">契約日時</label>
<div class="input inline-range"> <div class="input inline-range">
<input type="datetime-local" class="form-control" name="contract_created_from" <input type="datetime-local" class="form-control" name="contract_created_from" value="{{ $contract_created_from ?? '' }}">
value="{{ $contract_created_from ?? '' }}">
<span class="tilde"></span> <span class="tilde"></span>
<input type="datetime-local" class="form-control" name="contract_created_to" <input type="datetime-local" class="form-control" name="contract_created_to" value="{{ $contract_created_to ?? '' }}">
value="{{ $contract_created_to ?? '' }}">
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">解約日時</label>
<label class="label">解約日時</label>
<div class="input inline-range"> <div class="input inline-range">
<input type="datetime-local" class="form-control" name="contract_canceled_from" <input type="datetime-local" class="form-control" name="contract_canceled_from" value="{{ $contract_canceled_from ?? '' }}">
value="{{ $contract_canceled_from ?? '' }}">
<span class="tilde"></span> <span class="tilde"></span>
<input type="datetime-local" class="form-control" name="contract_canceled_to" <input type="datetime-local" class="form-control" name="contract_canceled_to" value="{{ $contract_canceled_to ?? '' }}">
value="{{ $contract_canceled_to ?? '' }}">
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">授受日時</label>
<label class="label">授受日時</label>
<div class="input inline-range"> <div class="input inline-range">
<input type="datetime-local" class="form-control" name="receipt_delivery_from" <input type="datetime-local" class="form-control" name="receipt_delivery_from" value="{{ $receipt_delivery_from ?? '' }}">
value="{{ $receipt_delivery_from ?? '' }}">
<span class="tilde"></span> <span class="tilde"></span>
<input type="datetime-local" class="form-control" name="receipt_delivery_to" <input type="datetime-local" class="form-control" name="receipt_delivery_to" value="{{ $receipt_delivery_to ?? '' }}">
value="{{ $receipt_delivery_to ?? '' }}">
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">定期有効月数</label>
<label class="label">定期有効月数</label>
<div class="input"> <div class="input">
<select class="form-control" name="contract_valid_months"> <select class="form-control" name="contract_valid_months">
<option value="">全て</option> <option value="">全て</option>
@ -287,8 +224,7 @@
</select> </select>
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">定期契約継続</label>
<label class="label">定期契約継続</label>
<div class="input"> <div class="input">
<select class="form-control" name="update_flag"> <select class="form-control" name="update_flag">
<option value="0" {{ ($update_flag ?? '0') === '0' ? 'selected' : '' }}>全て</option> <option value="0" {{ ($update_flag ?? '0') === '0' ? 'selected' : '' }}>全て</option>
@ -297,32 +233,25 @@
</select> </select>
</div> </div>
</div> </div>
<div class="field"> <div class="field"><label class="label">名寄フリガナ</label>
<label class="label">名寄フリガナ</label> <div class="input"><input type="text" class="form-control" name="merge_phonetic" value="{{ $merge_phonetic ?? '' }}" placeholder="キーワード…"></div>
<div class="input"><input type="text" class="form-control" name="merge_phonetic"
value="{{ $merge_phonetic ?? '' }}" placeholder="キーワード…"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">ゾーン名検索</label>
<label class="label">ゾーン名検索</label> <div class="input"><input type="text" class="form-control" name="zone_name" value="{{ $zone_name ?? '' }}" placeholder="キーワード…"></div>
<div class="input"><input type="text" class="form-control" name="zone_name"
value="{{ $zone_name ?? '' }}" placeholder="キーワード…"></div>
</div> </div>
<div class="field"> <div class="field"><label class="label">タグ・QR</label>
<label class="label">タグ・QR</label>
<div class="input"> <div class="input">
<select class="form-control" name="tag_qr_flag"> <select class="form-control" name="tag_qr_flag">
<option value="">全て</option> <option value="">全て</option>
<option value="0" {{ (isset($tag_qr_flag) && (string) $tag_qr_flag === '0') ? 'selected' : '' }}>タグ <option value="0" {{ (isset($tag_qr_flag) && (string)$tag_qr_flag === '0') ? 'selected' : '' }}>タグ</option>
</option> <option value="1" {{ (isset($tag_qr_flag) && (string)$tag_qr_flag === '1') ? 'selected' : '' }}>QR</option>
<option value="1" {{ (isset($tag_qr_flag) && (string) $tag_qr_flag === '1') ? 'selected' : '' }}>QR
</option>
</select> </select>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{{-- フィルターボタン(見た目統一) --}} {{-- フィルターボタン --}}
<div class="mt-2"> <div class="mt-2">
<button type="submit" class="btn btn-default">絞り込み</button> <button type="submit" class="btn btn-default">絞り込み</button>
<a href="{{ route('regularcontracts') }}" class="btn btn-default">解除</a> <a href="{{ route('regularcontracts') }}" class="btn btn-default">解除</a>
@ -331,19 +260,14 @@
</div> </div>
</div> </div>
{{-- ツールバー:左=ボタン群、右=ページャ --}} {{-- ツールバー(左:ボタン群/右:ページャ) --}}
<div class="rc-toolbar mb-2"> <div class="rc-toolbar mb-2">
<div class="left"> <div class="left">
<a href="{{ route('regularcontracts_add') }}" class="btn btn-sm btn-default">新規</a> <a href="{{ route('regularcontracts_add') }}" class="btn btn-sm btn-default">新規</a>
<button type="button" class="btn btn-sm btn-default" id="btn-delete-selected">削除</button> <button type="button" class="btn btn-sm btn-default" id="btn-delete-selected">削除</button>
<button type="button" class="btn btn-sm btn-default" data-toggle="modal" <button type="button" class="btn btn-sm btn-default" data-toggle="modal" data-target="#importModal">インポート</button>
data-target="#importModal">インポート</button>
{{-- 3種のエクスポートは共通の確認モーダルを使い、data-url に出力先URLを渡す --}}
<button type="button" class="btn btn-sm btn-default js-export" data-url="{{ route('regularcontracts_export') }}">CSV出力</button> <button type="button" class="btn btn-sm btn-default js-export" data-url="{{ route('regularcontracts_export') }}">CSV出力</button>
<button type="button" class="btn btn-sm btn-default js-export" data-url="{{ route('regularcontracts_export', [], false) }}?type=smbc">SMBC出力</button> <button type="button" class="btn btn-sm btn-default js-export" data-url="{{ route('regularcontracts_export', [], false) }}?type=smbc">SMBC出力</button>
<button type="button" class="btn btn-sm btn-default js-export" data-url="{{ route('regularcontracts_export', [], false) }}?type=city">役所提出用CSV出力</button> <button type="button" class="btn btn-sm btn-default js-export" data-url="{{ route('regularcontracts_export', [], false) }}?type=city">役所提出用CSV出力</button>
</div> </div>
<div class="right"> <div class="right">
@ -353,191 +277,94 @@
<iframe id="dlFrame" name="dlFrame" style="width:0;height:0;border:0;visibility:hidden;"></iframe> <iframe id="dlFrame" name="dlFrame" style="width:0;height:0;border:0;visibility:hidden;"></iframe>
{{-- 一覧テーブル --}} {{-- 一覧テーブルfreeze-table でヘッダ左2列固定 --}}
<form action="{{ route('regularcontracts_delete') }}" method="post" id="form_delete"> <form action="{{ route('regularcontracts_delete') }}" method="post" id="form_delete">
@csrf @csrf
<div class="table-responsive">
<div class="scroll freeze-table">
<div class="scroll-x">
<table class="table table-bordered table-hover rc-table mb-0 text-nowrap"> <table class="table table-bordered table-hover rc-table mb-0 text-nowrap">
@php @php
$currentSort = $sort ?? 'contract_id'; $currentSort = $sort ?? 'contract_id';
$currentDir = strtolower($sort_type ?? 'asc'); $currentDir = strtolower($sort_type ?? 'asc');
if (!in_array($currentDir, ['asc', 'desc'], true)) { if (!in_array($currentDir, ['asc','desc'], true)) $currentDir = 'asc';
$currentDir = 'asc'; $sortClass = function(string $key) use($currentSort,$currentDir){
}
$sortClass = function (string $key) use ($currentSort, $currentDir) {
$base = 'sorting'; $base = 'sorting';
if ($currentSort === $key) { return $currentSort === $key ? $base.' '.($currentDir==='asc'?'sorting_asc':'sorting_desc') : $base;
return $base . ' ' . ($currentDir === 'asc' ? 'sorting_asc' : 'sorting_desc');
}
return $base;
}; };
@endphp $renderSortIcon = static function(string $key){
@php
$renderSortIcon = static function (string $key) {
return '<span class="sort-arrows"><span class="up">↑</span><span class="down">↓</span></span>'; return '<span class="sort-arrows"><span class="up">↑</span><span class="down">↓</span></span>';
}; };
@endphp @endphp
<thead> <thead>
<tr> <tr>
<th style="width:50px; text-align:right;"></th> <th class="text-right no-col">No</th>
{{-- 操作列(チェック+編集。背景色を付与 --}} {{-- 操作列(チェック+編集幅120px ※左固定のため列幅は固定推奨 --}}
<th style="width:120px"> <th style="width:120px">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<input type="checkbox" id="check-all" class="mr-1"> <input type="checkbox" id="check-all" class="mr-1"><span></span>
<span></span>
</div> </div>
</th> </th>
<th class="text-right {{ $sortClass('contract_id') }}" sort="contract_id" style="white-space:nowrap;">
契約ID {!! $renderSortIcon('contract_id') !!} <th class="text-right {{ $sortClass('contract_id') }}" sort="contract_id" style="white-space:nowrap;">契約ID {!! $renderSortIcon('contract_id') !!}</th>
</th> <th class="text-right {{ $sortClass('contract_qr_id') }}" sort="contract_qr_id">定期契約ID {!! $renderSortIcon('contract_qr_id') !!}</th>
{{-- 表頭(要件に合わせて網羅) --}} <th class="{{ $sortClass('old_contract_id') }}" sort="old_contract_id">旧定期契約番号 {!! $renderSortIcon('old_contract_id') !!}</th>
<th class="text-right {{ $sortClass('contract_qr_id') }}" sort="contract_qr_id"> <th class="{{ $sortClass('pplace_no') }}" sort="pplace_no">車室番号 {!! $renderSortIcon('pplace_no') !!}</th>
定期契約ID {!! $renderSortIcon('contract_qr_id') !!} <th class="{{ $sortClass('user_id') }}" sort="user_id">利用者ID {!! $renderSortIcon('user_id') !!}</th>
</th> <th class="{{ $sortClass('user_categoryid') }}" sort="user_categoryid">利用者分類ID {!! $renderSortIcon('user_categoryid') !!}</th>
<th class="{{ $sortClass('old_contract_id') }}" sort="old_contract_id"> <th class="{{ $sortClass('tag_qr_flag') }}" sort="tag_qr_flag">タグ・QR {!! $renderSortIcon('tag_qr_flag') !!}</th>
旧定期契約番号 {!! $renderSortIcon('old_contract_id') !!} <th class="text-right {{ $sortClass('park_id') }}" sort="park_id">駐輪場ID {!! $renderSortIcon('park_id') !!}</th>
</th> <th class="{{ $sortClass('reserve_date') }}" sort="reserve_date">予約日時 {!! $renderSortIcon('reserve_date') !!}</th>
<th class="{{ $sortClass('pplace_no') }}" sort="pplace_no"> <th class="{{ $sortClass('contract_periods') }}" sort="contract_periods">有効期間S {!! $renderSortIcon('contract_periods') !!}</th>
車室番号 {!! $renderSortIcon('pplace_no') !!} <th class="{{ $sortClass('contract_periode') }}" sort="contract_periode">有効期間E {!! $renderSortIcon('contract_periode') !!}</th>
</th> <th class="text-right {{ $sortClass('price_parkplaceid') }}" sort="price_parkplaceid">駐輪場所ID {!! $renderSortIcon('price_parkplaceid') !!}</th>
<th class="{{ $sortClass('user_id') }}" sort="user_id"> <th class="{{ $sortClass('user_securitynum') }}" sort="user_securitynum">防犯登録番号 {!! $renderSortIcon('user_securitynum') !!}</th>
利用者ID {!! $renderSortIcon('user_id') !!} <th class="{{ $sortClass('contract_created_at') }}" sort="contract_created_at">契約日時 {!! $renderSortIcon('contract_created_at') !!}</th>
</th> <th class="{{ $sortClass('contract_updated_at') }}" sort="contract_updated_at">更新可能日 {!! $renderSortIcon('contract_updated_at') !!}</th>
<th class="{{ $sortClass('user_categoryid') }}" sort="user_categoryid"> <th class="{{ $sortClass('contract_cancelday') }}" sort="contract_cancelday">解約日時 {!! $renderSortIcon('contract_cancelday') !!}</th>
利用者分類ID {!! $renderSortIcon('user_categoryid') !!} <th class="{{ $sortClass('contract_reduction') }}" sort="contract_reduction">減免措置 {!! $renderSortIcon('contract_reduction') !!}</th>
</th> <th class="text-right {{ $sortClass('enable_months') }}" sort="enable_months">定期有効月数 {!! $renderSortIcon('enable_months') !!}</th>
<th class="{{ $sortClass('tag_qr_flag') }}" sort="tag_qr_flag"> <th class="{{ $sortClass('printable_date') }}" sort="printable_date">シール印刷可能日 {!! $renderSortIcon('printable_date') !!}</th>
タグ・QR {!! $renderSortIcon('tag_qr_flag') !!} <th class="text-right {{ $sortClass('billing_amount') }}" sort="billing_amount">請求金額 {!! $renderSortIcon('billing_amount') !!}</th>
</th> <th class="{{ $sortClass('pplace_allocation_flag') }}" sort="pplace_allocation_flag">車室割り当てフラグ {!! $renderSortIcon('pplace_allocation_flag') !!}</th>
<th class="text-right {{ $sortClass('park_id') }}" sort="park_id"> <th class="{{ $sortClass('contract_payment_day') }}" sort="contract_payment_day">授受日時 {!! $renderSortIcon('contract_payment_day') !!}</th>
駐輪場ID {!! $renderSortIcon('park_id') !!} <th class="text-right {{ $sortClass('contract_money') }}" sort="contract_money">授受金額 {!! $renderSortIcon('contract_money') !!}</th>
</th> <th class="{{ $sortClass('contract_flag') }}" sort="contract_flag">授受フラグ {!! $renderSortIcon('contract_flag') !!}</th>
<th class="{{ $sortClass('reserve_date') }}" sort="reserve_date"> <th class="{{ $sortClass('settlement_transaction_id') }}" sort="settlement_transaction_id">決済トランザクションID {!! $renderSortIcon('settlement_transaction_id') !!}</th>
予約日時 {!! $renderSortIcon('reserve_date') !!} <th class="text-right {{ $sortClass('contract_seal_issue') }}" sort="contract_seal_issue">シール発行数 {!! $renderSortIcon('contract_seal_issue') !!}</th>
</th> <th class="{{ $sortClass('storage_company_code') }}" sort="storage_company_code">収納企業コード {!! $renderSortIcon('storage_company_code') !!}</th>
<th class="{{ $sortClass('contract_periods') }}" sort="contract_periods"> <th class="{{ $sortClass('share_storage_company_code') }}" sort="share_storage_company_code">共有先収納企業コード {!! $renderSortIcon('share_storage_company_code') !!}</th>
有効期間S {!! $renderSortIcon('contract_periods') !!} <th class="{{ $sortClass('accept_number') }}" sort="accept_number">受付番号 {!! $renderSortIcon('accept_number') !!}</th>
</th> <th class="{{ $sortClass('update_flag') }}" sort="update_flag">(更新元)契約更新済フラグ {!! $renderSortIcon('update_flag') !!}</th>
<th class="{{ $sortClass('contract_periode') }}" sort="contract_periode"> <th class="{{ $sortClass('vehicle_type_id') }}" sort="vehicle_type_id">車種区分ID {!! $renderSortIcon('vehicle_type_id') !!}</th>
有効期間E {!! $renderSortIcon('contract_periode') !!} <th class="{{ $sortClass('user_phonetic') }}" sort="user_phonetic">チェック用_フリガナ {!! $renderSortIcon('user_phonetic') !!}</th>
</th> <th class="{{ $sortClass('user_regident_zip') }}" sort="user_regident_zip">チェック用_居住所郵便番号 {!! $renderSortIcon('user_regident_zip') !!}</th>
<th class="text-right {{ $sortClass('price_parkplaceid') }}" sort="price_parkplaceid"> <th class="{{ $sortClass('user_mobile') }}" sort="user_mobile">チェック用_携帯電話番号 {!! $renderSortIcon('user_mobile') !!}</th>
駐輪場所ID {!! $renderSortIcon('price_parkplaceid') !!} <th class="{{ $sortClass('user_homephone') }}" sort="user_homephone">チェック用_自宅電話番号 {!! $renderSortIcon('user_homephone') !!}</th>
</th> <th class="{{ $sortClass('old_member_number') }}" sort="old_member_number">チェック用_旧会員番号 {!! $renderSortIcon('old_member_number') !!}</th>
<th class="{{ $sortClass('user_securitynum') }}" sort="user_securitynum">
防犯登録番号 {!! $renderSortIcon('user_securitynum') !!}
</th>
<th class="{{ $sortClass('contract_created_at') }}" sort="contract_created_at">
契約日時 {!! $renderSortIcon('contract_created_at') !!}
</th>
<th class="{{ $sortClass('contract_updated_at') }}" sort="contract_updated_at">
更新可能日 {!! $renderSortIcon('contract_updated_at') !!}
</th>
<th class="{{ $sortClass('contract_cancelday') }}" sort="contract_cancelday">
解約日時 {!! $renderSortIcon('contract_cancelday') !!}
</th>
<th class="{{ $sortClass('contract_reduction') }}" sort="contract_reduction">
減免措置 {!! $renderSortIcon('contract_reduction') !!}
</th>
<th class="text-right {{ $sortClass('enable_months') }}" sort="enable_months">
定期有効月数 {!! $renderSortIcon('enable_months') !!}
</th>
<th class="{{ $sortClass('printable_date') }}" sort="printable_date">
シール印刷可能日 {!! $renderSortIcon('printable_date') !!}
</th>
<th class="text-right {{ $sortClass('billing_amount') }}" sort="billing_amount">
請求金額 {!! $renderSortIcon('billing_amount') !!}
</th>
<th class="{{ $sortClass('pplace_allocation_flag') }}" sort="pplace_allocation_flag">
車室割り当てフラグ {!! $renderSortIcon('pplace_allocation_flag') !!}
</th>
<th class="{{ $sortClass('contract_payment_day') }}" sort="contract_payment_day">
授受日時 {!! $renderSortIcon('contract_payment_day') !!}
</th>
<th class="text-right {{ $sortClass('contract_money') }}" sort="contract_money">
授受金額 {!! $renderSortIcon('contract_money') !!}
</th>
<th class="{{ $sortClass('contract_flag') }}" sort="contract_flag">
授受フラグ {!! $renderSortIcon('contract_flag') !!}
</th>
<th class="{{ $sortClass('settlement_transaction_id') }}" sort="settlement_transaction_id">
決済トランザクションID {!! $renderSortIcon('settlement_transaction_id') !!}
</th>
<th class="text-right {{ $sortClass('contract_seal_issue') }}" sort="contract_seal_issue">
シール発行数 {!! $renderSortIcon('contract_seal_issue') !!}
</th>
<th class="{{ $sortClass('storage_company_code') }}" sort="storage_company_code">
収納企業コード {!! $renderSortIcon('storage_company_code') !!}
</th>
<th class="{{ $sortClass('share_storage_company_code') }}" sort="share_storage_company_code">
共有先収納企業コード {!! $renderSortIcon('share_storage_company_code') !!}
</th>
<th class="{{ $sortClass('accept_number') }}" sort="accept_number">
受付番号 {!! $renderSortIcon('accept_number') !!}
</th>
<th class="{{ $sortClass('update_flag') }}" sort="update_flag">
(更新元)契約更新済フラグ {!! $renderSortIcon('update_flag') !!}
</th>
<th class="{{ $sortClass('vehicle_type_id') }}" sort="vehicle_type_id">
車種区分ID {!! $renderSortIcon('vehicle_type_id') !!}
</th>
<th class="{{ $sortClass('user_phonetic') }}" sort="user_phonetic">
チェック用_フリガナ {!! $renderSortIcon('user_phonetic') !!}
</th>
<th class="{{ $sortClass('user_regident_zip') }}" sort="user_regident_zip">
チェック用_居住所郵便番号 {!! $renderSortIcon('user_regident_zip') !!}
</th>
<th class="{{ $sortClass('user_mobile') }}" sort="user_mobile">
チェック用_携帯電話番号 {!! $renderSortIcon('user_mobile') !!}
</th>
<th class="{{ $sortClass('user_homephone') }}" sort="user_homephone">
チェック用_自宅電話番号 {!! $renderSortIcon('user_homephone') !!}
</th>
<th class="{{ $sortClass('old_member_number') }}" sort="old_member_number">
チェック用_旧会員番号 {!! $renderSortIcon('old_member_number') !!}
</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@php @php
$formatYmd = static function ($value) { $formatYmd = static function($v){ if(empty($v)) return ''; try{return \Illuminate\Support\Carbon::parse($v)->format('Y-m-d');}catch(\Throwable $e){return mb_substr((string)$v,0,10);} };
if (empty($value)) { $formatYmdHi = static function($v){ if(empty($v)) return ''; try{return \Illuminate\Support\Carbon::parse($v)->format('Y-m-d H:i');}catch(\Throwable $e){return mb_substr((string)$v,0,16);} };
return '';
}
try {
return \Illuminate\Support\Carbon::parse($value)->format('Y-m-d');
} catch (\Throwable $e) {
return mb_substr((string) $value, 0, 10);
}
};
$formatYmdHi = static function ($value) {
if (empty($value)) {
return '';
}
try {
return \Illuminate\Support\Carbon::parse($value)->format('Y-m-d H:i');
} catch (\Throwable $e) {
return mb_substr((string) $value, 0, 16);
}
};
@endphp @endphp
@foreach($list as $item) @foreach($list as $item)
<tr> <tr>
{{-- No左固定 --}}
<td class="text-right" style="width:50px;">{{ $loop->iteration }}</td>
<td class="text-right">{{ $loop->iteration }}</td> {{-- 操作列(左固定) --}}
<td style="width:120px;">
{{-- 操作列:チェック + 編集(背景色つき) --}}
<td class="op-cell">
<div class="d-flex align-items-center"> <div class="d-flex align-items-center">
<input type="checkbox" class="mr-2 row-check" name="ids[]" value="{{ $item->contract_id }}"> <input type="checkbox" class="mr-2 row-check" name="ids[]" value="{{ $item->contract_id }}">
<a href="{{ route('regularcontracts_edit', ['contract_id' => $item->contract_id]) }}" <a href="{{ route('regularcontracts_edit', ['contract_id' => $item->contract_id]) }}" class="btn btn-sm btn-default">編集</a>
class="btn btn-sm btn-default">編集</a>
</div> </div>
</td> </td>
{{-- 先頭の並び替え列(行の contract_id を表示) --}} {{-- 以降データ列 --}}
<td class="text-right">{{ $item->contract_id }}</td> <td class="text-right">{{ $item->contract_id }}</td>
{{-- データ列 --}}
<td class="text-right">{{ $item->contract_qr_id }}</td> <td class="text-right">{{ $item->contract_qr_id }}</td>
<td>{{ $item->old_contract_id ?? '' }}</td> <td>{{ $item->old_contract_id ?? '' }}</td>
<td>{{ $item->pplace_no ?? '' }}</td> <td>{{ $item->pplace_no ?? '' }}</td>
@ -554,11 +381,8 @@
@endif @endif
</td> </td>
@php @php
$userCategoryLabel = collect([ $userCategoryLabel = collect([$item->usertype_subject1 ?? '',$item->usertype_subject2 ?? '',$item->usertype_subject3 ?? ''])
$item->usertype_subject1 ?? '', ->filter(fn($v)=>$v!=='')->implode('/');
$item->usertype_subject2 ?? '',
$item->usertype_subject3 ?? '',
])->filter(fn ($v) => $v !== '')->implode('/');
@endphp @endphp
<td>{{ $userCategoryLabel ?: $item->user_categoryid }}</td> <td>{{ $userCategoryLabel ?: $item->user_categoryid }}</td>
<td>{{ $item->tag_qr_flag ? 'QR' : 'タグ' }}</td> <td>{{ $item->tag_qr_flag ? 'QR' : 'タグ' }}</td>
@ -574,11 +398,11 @@
<td>{{ $item->contract_reduction ?? '' }}</td> <td>{{ $item->contract_reduction ?? '' }}</td>
<td class="text-right">{{ $item->enable_months ?? '' }}</td> <td class="text-right">{{ $item->enable_months ?? '' }}</td>
<td>{{ $formatYmd($item->printable_date ?? '') }}</td> <td>{{ $formatYmd($item->printable_date ?? '') }}</td>
<td class="text-right">{{ $item->billing_amount ?? '' }}</td> <td class="text-right">{{ isset($item->billing_amount) ? number_format($item->billing_amount) : '' }}</td>
<td>{{ ($item->pplace_allocation_flag ?? null) === null ? '' : (($item->pplace_allocation_flag) ? '割当済' : '未割当') }}</td> <td>{{ ($item->pplace_allocation_flag ?? null) === null ? '' : ($item->pplace_allocation_flag ? '割当済' : '未割当') }}</td>
<td>{{ $formatYmd($item->contract_payment_day ?? '') }}</td> <td>{{ $formatYmd($item->contract_payment_day ?? '') }}</td>
<td class="text-right">{{ $item->contract_money ?? '' }}</td> <td class="text-right">{{ $item->contract_money ?? '' }}</td>
<td>{{ ($item->contract_flag ?? null) === null ? '' : (($item->contract_flag) ? '済' : '未') }}</td> <td>{{ ($item->contract_flag ?? null) === null ? '' : ($item->contract_flag ? '済' : '未') }}</td>
<td>{{ $item->settlement_transaction_id ?? '' }}</td> <td>{{ $item->settlement_transaction_id ?? '' }}</td>
<td class="text-right">{{ $item->contract_seal_issue ?? '' }}</td> <td class="text-right">{{ $item->contract_seal_issue ?? '' }}</td>
<td>{{ $item->storage_company_code ?? '' }}</td> <td>{{ $item->storage_company_code ?? '' }}</td>
@ -596,20 +420,19 @@
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
</form> </form>
</div> </div>
</section> </section>
</div> </div>
{{-- インポート用モーダル(ファイル選択) --}} {{-- インポート用モーダル --}}
<div class="modal fade" id="importModal" tabindex="-1" role="dialog" aria-labelledby="importModalLabel" <div class="modal fade" id="importModal" tabindex="-1" role="dialog" aria-labelledby="importModalLabel" aria-hidden="true">
aria-hidden="true">
<div class="modal-dialog modal-sm" role="document"> <div class="modal-dialog modal-sm" role="document">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header py-2"> <div class="modal-header py-2">
<h5 class="modal-title" id="importModalLabel">確認</h5> <h5 class="modal-title" id="importModalLabel">確認</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
aria-hidden="true">&times;</span></button>
</div> </div>
<form method="post" action="{{ route('regularcontracts_import') }}" enctype="multipart/form-data"> <form method="post" action="{{ route('regularcontracts_import') }}" enctype="multipart/form-data">
@csrf @csrf
@ -619,8 +442,7 @@
新規追加のみの場合は識別列を空欄のままインポートしてください。 新規追加のみの場合は識別列を空欄のままインポートしてください。
</p> </p>
<div class="custom-file"> <div class="custom-file">
<input type="file" name="file" id="importFile" class="custom-file-input" accept=".csv,.xlsx,.xls,.tsv,.txt" <input type="file" name="file" id="importFile" class="custom-file-input" accept=".csv,.xlsx,.xls,.tsv,.txt" required>
required>
<label class="custom-file-label" for="importFile">ファイルの選択</label> <label class="custom-file-label" for="importFile">ファイルの選択</label>
</div> </div>
</div> </div>
@ -633,9 +455,9 @@
</div> </div>
</div> </div>
{{-- 画面内スクリプトインポートのファイル名表示、エクスポートのURL差し替え --}} {{-- 画面内スクリプト --}}
<script> <script>
// インポート:選択したファイル名をラベルに反映 // インポート:選択ファイル名をラベルへ反映
document.addEventListener('change', function (e) { document.addEventListener('change', function (e) {
if (e.target && e.target.id === 'importFile') { if (e.target && e.target.id === 'importFile') {
var label = e.target.nextElementSibling; var label = e.target.nextElementSibling;
@ -643,41 +465,27 @@
} }
}); });
// エクスポート:モーダル表示時に押下ボタンの data-url を「はい」へセット
(function () { (function () {
var exportModal = document.getElementById('exportModal');
var deleteForm = document.getElementById('form_delete'); var deleteForm = document.getElementById('form_delete');
var deleteBtn = document.getElementById('btn-delete-selected'); var deleteBtn = document.getElementById('btn-delete-selected');
var masterCheckbox = document.getElementById('check-all'); var masterCheckbox = document.getElementById('check-all');
var rowSelector = '.row-check'; var rowSelector = '.row-check';
var exportButtons = document.querySelectorAll('.js-export'); // エクスポート各種
if (exportButtons.length) { document.querySelectorAll('.js-export').forEach(function (btn) {
exportButtons.forEach(function (btn) {
btn.addEventListener('click', function () { btn.addEventListener('click', function () {
var url = btn.getAttribute('data-url'); var url = btn.getAttribute('data-url');
if (!url) { if (!url) return;
return;
}
var doExport = function () { var doExport = function () {
var iframe = document.getElementById('dlFrame'); var iframe = document.getElementById('dlFrame');
if (iframe) { if (iframe) iframe.src = url; else window.location.href = url;
iframe.src = url;
} else {
window.location.href = url;
}
}; };
if (window.jQuery && typeof window.jQuery.confirm === 'function') { if (window.jQuery && typeof window.jQuery.confirm === 'function') {
window.jQuery.confirm({ window.jQuery.confirm({
title: '確認ダイアログ。', title: '確認ダイアログ。',
content: 'CSVファイルを出力します。よろしいですか はい/いいえ', content: 'CSVファイルを出力します。よろしいですか はい/いいえ',
buttons: { buttons: {
ok: { ok: { text: 'はい', btnClass: 'btn-primary', keys: ['enter'], action: doExport },
text: 'はい',
btnClass: 'btn-primary',
keys: ['enter'],
action: doExport
},
いいえ: function () {} いいえ: function () {}
} }
}); });
@ -686,60 +494,39 @@
} }
}); });
}); });
}
// 一括削除
if (deleteBtn && deleteForm) { if (deleteBtn && deleteForm) {
deleteBtn.addEventListener('click', function () { deleteBtn.addEventListener('click', function () {
var checked = document.querySelectorAll(rowSelector + ':checked'); var checked = document.querySelectorAll(rowSelector + ':checked');
if (!checked.length) { if (!checked.length) { alert('削除する定期契約を選択してください。'); return; }
alert('削除する定期契約を選択してください。'); var submitDelete = function () { deleteForm.submit(); };
return;
}
var submitDelete = function () {
deleteForm.submit();
};
if (window.jQuery && typeof window.jQuery.confirm === 'function') { if (window.jQuery && typeof window.jQuery.confirm === 'function') {
window.jQuery.confirm({ window.jQuery.confirm({
title: '確認ダイアログ。', title: '確認ダイアログ。',
content: '削除してよろしいですか? はい/いいえ', content: '削除してよろしいですか? はい/いいえ',
buttons: { buttons: {
ok: { ok: { text: 'はい', btnClass: 'btn-primary', keys: ['enter'], action: submitDelete },
text: 'はい',
btnClass: 'btn-primary',
keys: ['enter'],
action: submitDelete
},
いいえ: function () {} いいえ: function () {}
} }
}); });
} else if (confirm('削除してよろしいですか? はい/いいえ')) { } else if (confirm('削除してよろしいですか? はい/いいえ')) { submitDelete(); }
submitDelete();
}
}); });
} }
// 全選択/個別選択
if (masterCheckbox) { if (masterCheckbox) {
var updateMasterState = function () { var updateMasterState = function () {
var allRows = document.querySelectorAll(rowSelector); var allRows = document.querySelectorAll(rowSelector);
var checkedRows = document.querySelectorAll(rowSelector + ':checked'); var checkedRows = document.querySelectorAll(rowSelector + ':checked');
masterCheckbox.checked = allRows.length > 0 && checkedRows.length === allRows.length; masterCheckbox.checked = allRows.length > 0 && checkedRows.length === allRows.length;
}; };
masterCheckbox.addEventListener('change', function () { masterCheckbox.addEventListener('change', function () {
var allRows = document.querySelectorAll(rowSelector); document.querySelectorAll(rowSelector).forEach(function (cb) { cb.checked = masterCheckbox.checked; });
allRows.forEach(function (checkbox) {
checkbox.checked = masterCheckbox.checked;
}); });
});
document.addEventListener('change', function (e) { document.addEventListener('change', function (e) {
if (e.target && e.target.matches(rowSelector)) { if (e.target && e.target.matches(rowSelector)) updateMasterState();
updateMasterState();
}
}); });
updateMasterState(); updateMasterState();
} }
})(); })();