【減免確認マスタ】初版作成
All checks were successful
Deploy main / deploy (push) Successful in 23s

This commit is contained in:
OU.ZAIKOU 2026-02-01 02:21:00 +09:00
parent 5df6c31b86
commit 0a5e21cd9a
6 changed files with 449 additions and 66 deletions

View File

@ -0,0 +1,111 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Park;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ReductionConfirmMasterController extends Controller
{
/**
* 減免確認マスタ画面を表示
*
* @param Request $request park_id をクエリパラメータで受け取る
* @return \Illuminate\View\View
*/
public function index(Request $request)
{
// park_id の検証
$request->validate([
'park_id' => 'required|integer|exists:park,park_id',
], [
'park_id.required' => '駐輪場IDは必須です。',
'park_id.integer' => '駐輪場IDは整数である必要があります。',
'park_id.exists' => '指定された駐輪場が見つかりません。',
]);
$parkId = (int) $request->input('park_id');
// 駐輪場情報を取得
$park = Park::where('park_id', $parkId)->firstOrFail();
// reduction_confirm を主テーブルとして、usertype と JOIN して一覧を取得
// WHERE park_id = ? で対象駐輪場のレコードのみ取得
$reductionData = DB::table('reduction_confirm')
->leftJoin('usertype', 'reduction_confirm.user_categoryid', '=', 'usertype.user_categoryid')
->where('reduction_confirm.park_id', $parkId)
->orderBy('reduction_confirm.user_categoryid', 'asc')
->select(
'reduction_confirm.park_id',
'reduction_confirm.user_categoryid',
'reduction_confirm.reduction_confirm_type',
'usertype.usertype_subject1',
'usertype.usertype_subject2',
'usertype.usertype_subject3'
)
->paginate(50);
return view('admin.reduction_confirm.index', [
'park' => $park,
'parkId' => $parkId,
'reductionData' => $reductionData,
]);
}
/**
* 減免確認情報を一括更新
*
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function store(Request $request)
{
// バリデーション
$validated = $request->validate([
'park_id' => 'required|integer|exists:park,park_id',
'reduction_confirm_type' => 'array',
'reduction_confirm_type.*' => 'in:0,1,2',
], [
'park_id.required' => '駐輪場IDは必須です。',
'park_id.integer' => '駐輪場IDは整数である必要があります。',
'park_id.exists' => '指定された駐輪場が見つかりません。',
'reduction_confirm_type.*.in' => '減免確認種別は0, 1, 2 のいずれかである必要があります。',
]);
$parkId = (int) $validated['park_id'];
$types = $validated['reduction_confirm_type'] ?? [];
// ログイン中のオペレータID取得
$opeId = auth()->user()->ope_id ?? null;
try {
// トランザクションで更新処理を実行
DB::transaction(function () use ($parkId, $types, $opeId) {
foreach ($types as $userCategoryId => $type) {
DB::table('reduction_confirm')
->where('park_id', $parkId)
->where('user_categoryid', (int) $userCategoryId)
->update([
'reduction_confirm_type' => (int) $type,
'updated_at' => now(),
'ope_id' => $opeId,
]);
}
});
return redirect()->route('reduction_confirm.index', ['park_id' => $parkId])
->with('success', '減免確認マスタを更新しました。');
} catch (\Exception $e) {
\Log::error('ReductionConfirm update failed', [
'park_id' => $parkId,
'error' => $e->getMessage(),
]);
return back()->withErrors(['error' => '更新に失敗しました。管理者にお問い合わせください。'])
->withInput();
}
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
class ReductionMaster extends Model
{
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';
protected $table = 'reduction_confirm';
protected $primaryKey = null; // 複合キーを使用
public $incrementing = false;
protected $fillable = [
'park_id',
'user_categoryid',
'reduction_check_type',
'operator_id',
'created_at',
'updated_at',
];
/**
* 複合キー (park_id, user_categoryid) で既存レコードを検索または作成
*/
public static function findOrCreateByKeys($parkId, $userCategoryId)
{
return self::where('park_id', $parkId)
->where('user_categoryid', $userCategoryId)
->first();
}
/**
* レコード保存時に operator_id を自動設定
*/
public static function boot()
{
parent::boot();
self::saving(function (ReductionMaster $model) {
if (!isset($model->operator_id) || $model->operator_id === null) {
$model->operator_id = Auth::user()->ope_id ?? null;
}
});
}
}

View File

@ -22,7 +22,8 @@
{{-- 編集フォーム --}}
<div class="card shadow">
<form id="park-edit-form" method="POST" action="{{ route('parks.update', $park->park_id) }}" enctype="multipart/form-data">
<form id="park-edit-form" method="POST" action="{{ route('parks.update', $park->park_id) }}"
enctype="multipart/form-data">
@csrf
@method('PUT')
@ -30,7 +31,9 @@
{{-- ボタンエリア(上部) --}}
<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="{{ route('reduction_confirm.index', ['park_id' => $park->park_id]) }}" 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>

View File

@ -0,0 +1,64 @@
{{-- 減免確認マスタテーブル行(各利用者分類) --}}
@php
// reduction_confirm テーブルから取得したレコード
$userCategoryId = $row->user_categoryid;
$checkType = $row->reduction_confirm_type;
$oldCheckType = old("reduction_confirm_type.$userCategoryId", $checkType);
// 学生分類かどうかを判定
$isStudent = $row->usertype_subject1 === '学生';
$rowClass = $isStudent ? 'table-secondary' : '';
$isDisabled = $isStudent;
@endphp
<tr class="{{ $rowClass }}">
<td class="text-center">{{ $userCategoryId }}</td>
<td>{{ $row->usertype_subject1 ?? '-' }}</td>
<td>{{ $row->usertype_subject2 ?? '-' }}</td>
<td>{{ $row->usertype_subject3 ?? '-' }}</td>
<td>
<div class="d-flex justify-content-center gap-3">
{{-- 確認しない0 --}}
<div class="custom-control custom-radio">
<input type="radio"
id="check_type_{{ $userCategoryId }}_0"
name="reduction_confirm_type[{{ $userCategoryId }}]"
value="0"
class="custom-control-input"
@checked($oldCheckType == 0)
@disabled($isDisabled)>
<label class="custom-control-label" for="check_type_{{ $userCategoryId }}_0">
確認しない
</label>
</div>
{{-- 年1回1 --}}
<div class="custom-control custom-radio">
<input type="radio"
id="check_type_{{ $userCategoryId }}_1"
name="reduction_confirm_type[{{ $userCategoryId }}]"
value="1"
class="custom-control-input"
@checked($oldCheckType == 1)
@disabled($isDisabled)>
<label class="custom-control-label" for="check_type_{{ $userCategoryId }}_1">
年1回
</label>
</div>
{{-- 毎更新時2 --}}
<div class="custom-control custom-radio">
<input type="radio"
id="check_type_{{ $userCategoryId }}_2"
name="reduction_confirm_type[{{ $userCategoryId }}]"
value="2"
class="custom-control-input"
@checked($oldCheckType == 2)
@disabled($isDisabled)>
<label class="custom-control-label" for="check_type_{{ $userCategoryId }}_2">
毎更新時
</label>
</div>
</div>
</td>
</tr>

View File

@ -0,0 +1,152 @@
@extends('layouts.app')
@section('title', '減免確認マスタ')
@section('content')
<!-- 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 active">減免確認マスタ</li>
</ol>
</div>
</div>
</div>
</div>
<section class="content">
<div class="container-fluid">
{{-- エラーメッセージ表示 --}}
@if ($errors->any())
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="alert-heading">エラーが発生しました</h4>
<ul class="mb-0">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
{{-- 成功メッセージ表示 --}}
@if (session('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
{{ session('success') }}
</div>
@endif
<!-- 駐輪場情報カード -->
<div class="col-lg-12 px-0">
<div class="card">
<div class="card-header">
<h3 class="card-title">駐輪場情報</h3>
</div>
<div class="card-body">
<div class="row align-items-center">
<div class="col-md-2">
<label class="font-weight-bold mb-0">駐輪場名</label>
</div>
<div class="col-md-10">
<div class="park-name-display">
{{ $park->park_name ?? '' }}
</div>
</div>
</div>
</div>
</div>
</div>
{{--
<div class="text-right mb-2">
{{ $list->total() }} 件中 {{ $list->firstItem() }}{{ $list->lastItem() }} 件を表示
</div>
<div class="ml-auto">
{{ $list->appends(keepUserListQuery())->links('pagination') }}
</div>
--}}
</div>
<!-- 減免確認マスタ テーブル -->
<div class="col-lg-12 px-0 ">
<form action="{{ route('reduction_confirm.store') }}" method="POST" id="reduction-form">
{{-- 登録ボタン --}}
<div class="container-fluid mb20">
<button type="submit" class="btn btn-primary mt-2 btn-submit">登録</button>
</div>
@csrf
<input type="hidden" name="park_id" value="{{ $parkId }}">
<div class="table-responsive">
<table class="table table-bordered">
<thead class="thead-light">
<tr>
<th style="width: 5%; text-align: center;">利用者分類</th>
<th style="width: 10%;">分類名1</th>
<th style="width: 10%;">分類名2</th>
<th style="width: 10%;">分類名3</th>
<th style="width: 20%; text-align: center;">減免確認種別</th>
</tr>
</thead>
<tbody>
@forelse ($reductionData as $row)
@include('admin.reduction_confirm._form', ['row' => $row])
@empty
<tr>
<td colspan="5" class="text-center text-muted">
利用者分類がありません。
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</form>
</div>
</section>
<style>
.gap-3 {
gap: 1rem !important;
}
.custom-control {
display: flex;
align-items: center;
}
.custom-control-label {
margin-bottom: 0;
margin-left: 0.25rem;
}
.park-name-display {
background-color: #e9ecef;
border-radius: 6px;
padding: 10px 14px;
font-size: 16px;
color: #6c757d;
width: fit-content;
min-width: 320px;
}
.sample03-wrapper {
background-color: white;
}
</style>
@endsection

View File

@ -42,6 +42,7 @@ use App\Http\Controllers\Admin\MailTemplateController;
use App\Http\Controllers\Admin\InvSettingController;
use App\Http\Controllers\Admin\ZoneController;
use App\Http\Controllers\Admin\PplaceController;
use App\Http\Controllers\Admin\ReductionConfirmMasterController;
use App\Http\Controllers\HomeController;
use App\Http\Controllers\Auth\EmailOtpController;
@ -276,6 +277,10 @@ Route::middleware('auth')->group(function () {
Route::match(['get', 'post'], '/usertypes/import', [UsertypeController::class, 'import'])->name('usertypes_import');
Route::match(['get', 'post'], '/usertypes/export', [UsertypeController::class, 'export'])->name('usertypes_export');
// 減免確認マスタ
Route::get('/reduction-confirm-master', [ReductionConfirmMasterController::class, 'index'])->name('reduction_confirm.index');
Route::post('/reduction-confirm-master', [ReductionConfirmMasterController::class, 'store'])->name('reduction_confirm.store');
// 契約者一覧