駐輪場マスタ規約修正
All checks were successful
Deploy main / deploy (push) Successful in 22s

This commit is contained in:
kin.rinzen 2026-02-05 19:10:07 +09:00
parent 4fa9a8a297
commit b13e91d592
8 changed files with 204 additions and 176 deletions

View File

@ -20,18 +20,21 @@ class ParkController extends Controller
/**
* 一覧
* Route: GET /parks name=parks -> list()
*/
public function index(ParkRequest $request)
public function list(ParkRequest $request)
{
$filters = $request->filters();
$parks = $this->parkService->paginate($filters, 20);
$parks = $this->parkService->paginate($filters, \App\Utils::item_per_page);
$cities = City::orderBy('city_id')->get();
$sort = $filters['sort'] ?? 'p.park_id';
$sort_type = $filters['sort_type'] ?? 'asc';
return view('admin.parks.index', compact(
// list.blade.php
return view('admin.parks.list', compact(
'parks',
'cities',
'sort',
@ -41,16 +44,19 @@ class ParkController extends Controller
/**
* 新規(画面)
* Route: GET /parks/add name=parks.add -> add()
*/
public function create()
public function add()
{
$cities = City::orderBy('city_id')->get();
return view('admin.parks.create', compact('cities'));
// add.blade.php
return view('admin.parks.add', compact('cities'));
}
/**
* 新規(登録)
* Route: POST /parks/add name=parks.store -> store()
*/
public function store(ParkRequest $request)
{
@ -70,28 +76,29 @@ class ParkController extends Controller
);
return redirect()
->route('parks.index')
->route('parks')
->with('success', __('新規登録に完了しました。'));
}
/**
* 編集(画面)
* Route: GET /parks/edit/{id} name=parks.edit -> edit()
*/
public function edit(int $id)
{
$record = $this->parkService->findOrFail($id);
$cities = City::orderBy('city_id')->get();
// edit.blade.php
return view('admin.parks.edit', compact(
'record',
'cities'
));
}
/**
* 編集(更新)
* Route: PUT /parks/edit/{id} name=parks.update -> update()
*/
public function update(ParkRequest $request, int $id)
{
@ -103,41 +110,39 @@ class ParkController extends Controller
// 駐輪場五十音を設定
$payload['park_syllabary'] = $this->toSyllabaryGroup(
$payload['park_ruby'] ?? null);
// 駐輪場五十音を設定してから Service に渡す
$this->parkService->update(
$park, $payload, $operatorId);
$payload['park_ruby'] ?? null
);
// ※二重更新をやめるpayload 上書き事故防止)
$this->parkService->update(
$park,
$request->payload(),
$payload,
$operatorId
);
return redirect()
->route('parks.index')
->route('parks')
->with('success', __('更新に成功しました。'));
}
/**
* 削除(複数)
* Route: POST /parks/delete name=parks.delete -> delete()
*/
public function destroy(Request $request)
public function delete(Request $request)
{
$ids = (array) $request->input('pk', []);
if (empty($ids)) {
return redirect()
->route('parks.index')
->route('parks')
->with('error', __('削除するデータを選択してください。'));
}
$ok = $this->parkService->deleteByIds($ids);
return redirect()
->route('parks.index')
->route('parks')
->with(
$ok ? 'success' : 'error',
$ok ? __('削除が完了しました。') : __('削除に失敗しました。')
@ -146,6 +151,7 @@ class ParkController extends Controller
/**
* CSV 出力
* Route: GET /parks/export name=parks.export -> export()
*/
public function export(): StreamedResponse
{
@ -236,6 +242,7 @@ class ParkController extends Controller
/**
* 重複チェックAJAX
* Route: POST /parks/check-duplicate name=parks.check_duplicate -> checkDuplicate()
*/
public function checkDuplicate(Request $request)
{
@ -268,7 +275,7 @@ class ParkController extends Controller
// 先取第1文字UTF-8
$first = mb_substr($ruby, 0, 1, 'UTF-8');
// 小き/濁点などを正規化(必要最低限)
// 小き/濁点などを正規化(必要最低限)
$map = [
'が'=>'か','ぎ'=>'き','ぐ'=>'く','げ'=>'け','ご'=>'こ',
'ざ'=>'さ','じ'=>'し','ず'=>'す','ぜ'=>'せ','ぞ'=>'そ',
@ -304,5 +311,4 @@ class ParkController extends Controller
// ひらがな以外(空/英数など)は null
return null;
}
}

View File

@ -18,80 +18,85 @@ class ParkRequest extends FormRequest
*/
public function rules(): array
{
if ($this->isMethod('post') || $this->isMethod('put')) {
if (!$this->isMethod('post') && !$this->isMethod('put')) {
return [];
}
return [
// 必須
'city_id' => ['required', 'integer'],
'city_id' => ['required', 'integer'],
'park_name' => ['required', 'string', 'max:255'],
// 文字系
'park_ruby' => ['nullable', 'string', 'max:255'],
'park_ruby' => ['nullable', 'string', 'max:255'],
'park_syllabary' => ['nullable', 'string', 'max:3'],
'park_adrs' => ['nullable', 'string', 'max:255'],
'price_memo' => ['nullable', 'string', 'max:1000'],
'park_adrs' => ['nullable', 'string', 'max:255'],
'price_memo' => ['nullable', 'string', 'max:1000'],
// フラグ / 種別系integer想定
'park_close_flag' => ['nullable', 'integer'],
'inverse_use_flag1' => ['nullable', 'integer'], // 逆利用フラグ(一覧)
'inverse_use_flag2' => ['nullable', 'integer'], // 逆利用フラグ(学生)
'parking_regulations_flag' => ['nullable', 'integer'], // 駐輪規定フラグ
'alert_flag' => ['nullable', 'integer'], // 残警告チェックフラグ
'immediate_use_perm' => ['nullable', 'integer'], // 契約後即利用許可
'gender_display_flag' => ['nullable', 'integer'], // 項目表示設定:性別
'bd_display_flag' => ['nullable', 'integer'], // 項目表示設定:生年月日
'securityreg_display_flag' => ['nullable', 'integer'], // 項目表示設定:防犯登録番号
'park_fixed_contract' => ['nullable', 'integer'], // 駐輪場契約形態(定期)
'park_temporary_contract' => ['nullable', 'integer'], // 駐輪場契約形態(一時利用)
'park_available_time_flag' => ['nullable', 'integer'], // 利用可能時間制限フラグ
'park_manager_flag' => ['nullable', 'integer'], // 常駐管理人フラグ
'park_roof_flag' => ['nullable', 'integer'], // 屋根フラグ
'park_issuing_machine_flag' => ['nullable', 'integer'], // シール発行機フラグ
'reduction_guide_display_flag' => ['nullable', 'integer'], // 減免案内表示フラグ
'overyear_flag' => ['nullable', 'integer'], // 年跨ぎ
'park_close_flag' => ['nullable', 'integer'],
'inverse_use_flag1' => ['nullable', 'integer'], // 逆利用フラグ(一覧)
'inverse_use_flag2' => ['nullable', 'integer'], // 逆利用フラグ(学生)
'parking_regulations_flag' => ['nullable', 'integer'], // 駐輪規定フラグ
'alert_flag' => ['nullable', 'integer'], // 残警告チェックフラグ
// ★ここexport/DB側は immediate_use_permit
'immediate_use_permit' => ['nullable', 'integer'], // 契約後即利用許可
'gender_display_flag' => ['nullable', 'integer'],
'bd_display_flag' => ['nullable', 'integer'],
'securityreg_display_flag' => ['nullable', 'integer'],
'park_fixed_contract' => ['nullable', 'integer'],
'park_temporary_contract' => ['nullable', 'integer'],
'park_available_time_flag' => ['nullable', 'integer'],
'park_manager_flag' => ['nullable', 'integer'],
'park_roof_flag' => ['nullable', 'integer'],
'park_issuing_machine_flag' => ['nullable', 'integer'],
'reduction_guide_display_flag' => ['nullable', 'integer'],
'overyear_flag' => ['nullable', 'integer'],
// 数値系
'print_number' => ['nullable', 'integer'], // 印字数
'distance_twopoints' => ['nullable', 'integer'], // 二点間距離
'reduction_age' => ['nullable', 'integer'], // 減免対象年齢
'reduction_guide_display_start_month' => ['nullable', 'integer'], // 減免案内表示開始月数
'print_number' => ['nullable', 'integer'],
'distance_twopoints' => ['nullable', 'integer'],
'reduction_age' => ['nullable', 'integer'],
'reduction_guide_display_start_month' => ['nullable', 'integer'],
// 日付/時刻系date/time/datetime
'park_day' => ['nullable', 'date'], // 閉設日
'keep_alive' => ['nullable', 'date'], // 最新キープアライブ
'update_grace_period_start_date' => ['nullable', 'integer', 'between:1,31'], // 更新期間開始日
'update_grace_period_start_time' => ['nullable', 'date_format:H:i'], // 更新期間開始時
'update_grace_period_end_date' => ['nullable', 'integer', 'between:1,31'], // 更新期間終了日
'update_grace_period_end_time' => ['nullable', 'date_format:H:i'], // 更新期間終了時
'parking_start_grace_period' => ['nullable', 'integer', 'between:1,31'], // 駐輪開始猶予期間
// 日付/時刻系
'park_day' => ['nullable', 'date'],
'keep_alive' => ['nullable', 'date'],
'reminder_type' => ['nullable', 'integer'], // リマインダー種別
'reminder_time' => ['nullable', 'date_format:H:i'], // リマインダー時間
'park_available_time_from' => ['nullable', 'date_format:H:i'], // 利用可能時間(開始)
'park_available_time_to' => ['nullable', 'date_format:H:i'], // 利用可能時間(終了)
'park_manager_resident_from' => ['nullable', 'date_format:H:i'], // 常駐時間(開始)
'park_manager_resident_to' => ['nullable', 'date_format:H:i'], // 常駐時間(終了)
'update_grace_period_start_date' => ['nullable', 'integer', 'between:1,31'],
'update_grace_period_start_time' => ['nullable', 'date_format:H:i'],
'update_grace_period_end_date' => ['nullable', 'integer', 'between:1,31'],
'update_grace_period_end_time' => ['nullable', 'date_format:H:i'],
'parking_start_grace_period' => ['nullable', 'integer', 'between:1,31'],
'reminder_type' => ['nullable', 'integer'],
'reminder_time' => ['nullable', 'date_format:H:i'],
'park_available_time_from' => ['nullable', 'date_format:H:i'],
'park_available_time_to' => ['nullable', 'date_format:H:i'],
'park_manager_resident_from' => ['nullable', 'date_format:H:i'],
'park_manager_resident_to' => ['nullable', 'date_format:H:i'],
// 緯度/経度/電話など
'park_latitude' => ['nullable', 'string', 'max:50'], // 駐車場座標(緯度)
'park_longitude' => ['nullable', 'string', 'max:50'], // 駐車場座標(経度)
'park_tel' => ['nullable', 'string', 'max:50'], // 電話番号
'park_latitude' => ['nullable', 'string', 'max:50'],
'park_longitude' => ['nullable', 'string', 'max:50'],
'park_tel' => ['nullable', 'string', 'max:50'],
// 備考/自由入力
'park_restriction' => ['nullable', 'string', 'max:50'], // 車種制限
'park_procedure' => ['nullable', 'string', 'max:50'], // 手続方法
'park_payment' => ['nullable', 'string', 'max:100'], // 支払方法
'park_using_method' => ['nullable', 'string', 'max:1000'], // 駐輪場利用方法
'park_contract_renewal_term' => ['nullable', 'string', 'max:255'], // 定期更新期間
'park_reservation' => ['nullable', 'string', 'max:255'], // 空き待ち予約
'park_reference' => ['nullable', 'string', 'max:1000'], // 特記事項
'student_id_confirmation_type' => ['nullable', 'string', 'max:255'], // 学生証確認種別
];
}
'park_restriction' => ['nullable', 'string', 'max:50'],
'park_procedure' => ['nullable', 'string', 'max:50'],
'park_payment' => ['nullable', 'string', 'max:100'],
'park_using_method' => ['nullable', 'string', 'max:1000'],
'park_contract_renewal_term' => ['nullable', 'string', 'max:255'],
'park_reservation' => ['nullable', 'string', 'max:255'],
'park_reference' => ['nullable', 'string', 'max:1000'],
return [];
// ★ここexport/DB側は student_id_confirm_type
'student_id_confirm_type' => ['nullable', 'string', 'max:255'],
];
}
//
protected function prepareForValidation(): void
{
foreach ([
@ -102,14 +107,14 @@ class ParkRequest extends FormRequest
'update_grace_period_start_time',
'update_grace_period_end_time',
'reminder_time',
] as $key) {
if ($this->filled($key)) {
$v = (string) $this->input($key);
$this->merge([$key => substr($v, 0, 5)]); // HH:MM로 통일
$this->merge([$key => substr($v, 0, 5)]); // HH:MM に統一
}
}
}
/**
* add / edit payload
*/
@ -121,12 +126,10 @@ class ParkRequest extends FormRequest
public function filters(): array
{
return [
'park_name' => $this->input('park_name'),
'city_id' => $this->input('city_id'),
'sort' => $this->input('sort'),
'sort_type' => $this->input('sort_type', 'asc'),
'park_name' => $this->input('park_name'),
'city_id' => $this->input('city_id'),
'sort' => $this->input('sort'),
'sort_type' => $this->input('sort_type', 'asc'),
];
}
}

View File

@ -47,20 +47,21 @@
<div class="card-body">
<div class="row">
{{-- 駐輪場ID編集時のみ表示 --}}
@if(!empty($isEdit))
<div class="form-group col-3">
<label>{{ __('駐輪場ID') }}</label>
{{-- 駐輪場ID編集時のみ表示 --}}
@if(!empty($isEdit))
<div class="form-group col-3">
<label>{{ __('駐輪場ID') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="text"
name="park_id"
class="form-control form-control-lg bg-light"
value="{{ old('park_id', $record->park_id ?? '') }}"
readonly>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="text"
class="form-control form-control-lg bg-light"
value="{{ old('park_id', $record->park_id ?? '') }}"
readonly>
</div>
</div>
@endif
</div>
@endif
{{-- 市区 --}}
<div class="form-group col-3">

View File

@ -15,7 +15,7 @@
<a href="{{ route('home') }}">ホーム</a>
</li>
<li class="breadcrumb-item">
<a href="{{ route('parks.index') }}">駐輪場マスタ</a>
<a href="{{ route('parks') }}">駐輪場マスタ</a>
</li>
<li class="breadcrumb-item active">新規</li>
</ol>
@ -40,7 +40,9 @@
@csrf
@include('admin.parks._form', [
'isEdit' => false
'isEdit' => false,
'record' => null,
'cities' => $cities ?? [],
])
</form>

View File

@ -2,76 +2,78 @@
@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="{{ route('home') }}">ホーム</a></li>
<li class="breadcrumb-item"><a href="{{ route('parks') }}">駐輪場マスタ</a></li>
<li class="breadcrumb-item active">編集</li>
</ol>
</div>
<!-- Content Header -->
<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="{{ route('home') }}">ホーム</a>
</li>
<li class="breadcrumb-item">
<a href="{{ route('parks') }}">駐輪場マスタ</a>
</li>
<li class="breadcrumb-item active">編集</li>
</ol>
</div>
</div>
</div>
</div>
</div>
</div>
{{-- 編集フォーム --}}
<div class="card shadow">
<form id="park-edit-form" method="POST" action="{{ route('parks.update', $park->park_id) }}" enctype="multipart/form-data">
@csrf
@method('PUT')
<!-- Main content -->
<section class="content">
<div class="container-fluid">
<div class="card-header">
{{-- ボタンエリア(上部) --}}
<div class="mt-2">
<button type="button" class="btn btn-default mt-2 btn-submit">登録</button>
<a href="javascript:void(0)" class="btn btn-default mt-2">減免確認編集</a>
<a href="javascript:void(0)" class="btn btn-default mt-2">駐輪状況編集</a>
<button type="button" class="btn btn-default mt-2">削除</button>
</div>
</div>
<div class="card-body">
{{-- 入力フォーム --}}
@include('admin.parks._form')
<div class="row">
<div class="col-lg-12">
{{-- フッター(下部ボタン) --}}
<div class="form-footer mt-4 text-end">
<button type="button" class="btn btn-default btn-submit">登録</button>
<a href="{{ route('parks') }}" class="btn btn-default">戻る</a>
</div>
</div>
</form>
</div>
<div class="card">
{{-- 上部ボタン --}}
<div class="card-header">
{{-- 減免マスタ --}}
<button type="button"
id="btn_reduction_master"
class="btn btn-default mr-2">
減免マスタ
</button>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
{{-- 駐輪規定マスタ --}}
<button type="button"
id="btn_parking_regulation"
class="btn btn-default mr-2">
駐輪規定マスタ
</button>
</div>
<!-- jQuery Confirm -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-confirm@3.3.4/css/jquery-confirm.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery-confirm@3.3.4/js/jquery-confirm.min.js"></script>
{{-- 編集フォーム --}}
<form id="form_edit"
method="POST"
action="{{ route('parks.update', ['id' => $record->park_id]) }}?back={{ urlencode(request()->get('back', request()->fullUrl())) }}"
enctype="multipart/form-data">
@csrf
@method('PUT')
<script>
$(function () {
$('.btn-submit').on('click', function () {
$.confirm({
title: '登録確認',
content: 'この内容で登録してよろしいですか?',
buttons: {
はい: {
btnClass: 'btn-primary',
action: function () {
$('#park-edit-form').submit();
}
},
いいえ: function () {}
}
});
});
});
</script>
@include('admin.parks._form', [
'isEdit' => true,
'record' => $record,
'cities' => $cities ?? [],
])
</form>
{{-- 単体削除(編集画面) --}}
<form id="form_delete" method="POST" action="{{ route('parks.delete') }}">
@csrf
<input type="hidden" name="pk[]" value="{{ $record->park_id }}">
</form>
</div>
</div>
</div>
</div>
</section>
@endsection

View File

@ -26,7 +26,7 @@
<div class="card mb-3">
<div class="card-body">
<form method="GET" action="{{ route('parks.index') }}" id="filter-form">
<form method="GET" action="{{ route('parks') }}" id="filter-form">
<div class="row">
@ -74,7 +74,7 @@
絞り込み
</button>
<a href="{{ route('parks.index') }}" class="btn btn-outline-secondary">
<a href="{{ route('parks') }}" class="btn btn-outline-secondary">
解除
</a>
</div>
@ -88,7 +88,7 @@
<div class="container-fluid">
{{-- 並び替え用 hidden --}}
<form method="GET" action="{{ route('parks.index') }}" id="list-form">
<form method="GET" action="{{ route('parks') }}" id="list-form">
<input type="hidden" name="sort" id="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" id="sort_type" value="{{ $sort_type ?? '' }}">
</form>
@ -98,7 +98,7 @@
<div class="col-lg-12 mb-3 px-0">
<button type="button"
class="btn btn-sm btn-primary mr10"
onclick="location.href='{{ route('parks.create') }}?back={{ urlencode(request()->fullUrl()) }}'">
onclick="location.href='{{ route('parks.add') }}?back={{ urlencode(request()->fullUrl()) }}'">
新規
</button>
@ -149,7 +149,7 @@
{{-- テーブル --}}
<div class="col-lg-12 mb20 px-0">
<div class="table-responsive">
<form id="form_delete" method="POST" action="{{ route('parks.destroy') }}">
<form id="form_delete" method="POST" action="{{ route('parks.delete') }}">
@csrf
<table class="table table-bordered dataTable text-nowrap">

View File

@ -440,11 +440,14 @@
<span style="margin-left:20px;">市区マスタ</span>
</a>
</li>
<li class="nav-item">
<a href="{{ route('parks', ['city_id' => $city->city_id]) }}" class="nav-link @if ($currentRoute === 'parks') active @endif">
<a href="{{ route('parks', ['city_id' => $city->city_id]) }}"
class="nav-link {{ request()->routeIs('parks') ? 'active' : '' }}">
<span style="margin-left:20px;">駐輪場マスタ</span>
</a>
</li>
<li class="nav-item">
<a href="{{ route('pricelist', ['city_id' => $city->city_id]) }}" class="nav-link @if ($currentRoute === 'pricelist') active @endif">
<span style="margin-left:20px;">料金一覧表</span>

View File

@ -191,15 +191,26 @@ Route::middleware('auth')->group(function () {
Route::match(['get', 'post'], '/city/info/{id}', [CityController::class, 'info'])->where(['id' => '[0-9]+'])->name('city_info');
Route::match(['get', 'post'], '/city/delete', [CityController::class, 'delete'])->name('city_delete');
//2026.02.05 kin
// 駐輪場マスタ
Route::get('/parks', [ParkController::class, 'list'])->name('parks');
Route::get('/parks/add', [ParkController::class, 'add'])->name('parks.add');
Route::post('/parks/add', [ParkController::class, 'add'])->name('parks.store');
Route::match(['get', 'post', 'put'], '/parks/edit/{id}', [ParkController::class, 'edit'])->name('parks.edit');
Route::put('/parks/edit/{id}', [ParkController::class, 'edit'])->name('parks.update');
Route::match(['get', 'post'], '/parks/delete', [ParkController::class, 'delete'])->name('parks.delete');
Route::post('/parks/add', [ParkController::class, 'store'])->name('parks.store');
Route::get('/parks/edit/{id}', [ParkController::class, 'edit'])->name('parks.edit');
Route::put('/parks/edit/{id}', [ParkController::class, 'update'])->name('parks.update');
Route::post('/parks/delete', [ParkController::class, 'delete'])->name('parks.delete');
Route::get('/parks/export', [ParkController::class, 'export'])->name('parks.export');
Route::post('/parks/check-duplicate', [App\Http\Controllers\Admin\ParkController::class, 'checkDuplicate'])->name('parks.check_duplicate');
Route::post('/parks/check-duplicate', [ParkController::class, 'checkDuplicate'])
->name('parks.check_duplicate');
//2026.02.05 kin end
// 料金一覧表マスタ
Route::match(['get', 'post'], '/admin/pricelist', [PriceListController::class, 'list'])->name('pricelist');