This commit is contained in:
parent
5df6c31b86
commit
0a5e21cd9a
111
app/Http/Controllers/Admin/ReductionConfirmMasterController.php
Normal file
111
app/Http/Controllers/Admin/ReductionConfirmMasterController.php
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
48
app/Models/ReductionMaster.php
Normal file
48
app/Models/ReductionMaster.php
Normal 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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -2,76 +2,79 @@
|
||||
@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>
|
||||
{{-- ▼ パンくず --}}
|
||||
<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')
|
||||
{{-- ▼ 編集フォーム --}}
|
||||
<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')
|
||||
|
||||
<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 class="card-header">
|
||||
{{-- ▼ ボタンエリア(上部) --}}
|
||||
<div class="mt-2">
|
||||
<button type="button" class="btn btn-default mt-2 btn-submit">登録</button>
|
||||
<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>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{{-- ▼ 入力フォーム --}}
|
||||
@include('admin.parks._form')
|
||||
|
||||
{{-- ▼ フッター(下部ボタン) --}}
|
||||
<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-body">
|
||||
{{-- ▼ 入力フォーム --}}
|
||||
@include('admin.parks._form')
|
||||
|
||||
{{-- ▼ フッター(下部ボタン) --}}
|
||||
<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>
|
||||
<!-- jQuery -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
|
||||
<!-- jQuery -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<!-- 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>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<script>
|
||||
$(function () {
|
||||
$('.btn-submit').on('click', function () {
|
||||
$.confirm({
|
||||
title: '登録確認',
|
||||
content: 'この内容で登録してよろしいですか?',
|
||||
buttons: {
|
||||
はい: {
|
||||
btnClass: 'btn-primary',
|
||||
action: function () {
|
||||
$('#park-edit-form').submit();
|
||||
}
|
||||
},
|
||||
いいえ: function () {}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$(function() {
|
||||
$('.btn-submit').on('click', function() {
|
||||
$.confirm({
|
||||
title: '登録確認',
|
||||
content: 'この内容で登録してよろしいですか?',
|
||||
buttons: {
|
||||
はい: {
|
||||
btnClass: 'btn-primary',
|
||||
action: function() {
|
||||
$('#park-edit-form').submit();
|
||||
}
|
||||
},
|
||||
いいえ: function() {}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
64
resources/views/admin/reduction_confirm/_form.blade.php
Normal file
64
resources/views/admin/reduction_confirm/_form.blade.php
Normal 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>
|
||||
152
resources/views/admin/reduction_confirm/index.blade.php
Normal file
152
resources/views/admin/reduction_confirm/index.blade.php
Normal 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">×</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">×</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
|
||||
@ -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');
|
||||
|
||||
|
||||
|
||||
// 契約者一覧
|
||||
|
||||
Loading…
Reference in New Issue
Block a user