Merge branch 'main' of https://git.so-manager-dev.com/so-manager/krgm.so-manager-dev.com
All checks were successful
Deploy main / deploy (push) Successful in 22s

This commit is contained in:
Your Name 2025-09-05 16:47:27 +09:00
commit 17689e7ef1
3 changed files with 421 additions and 134 deletions

View File

@ -5,37 +5,181 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Barryvdh\DomPDF\Facade\Pdf;
class TagissueController extends Controller class TagissueController extends Controller
{ {
// タグ発送宛名PDF生成
public function printUnissuedLabels(Request $request)
{
$ids = $request->input('ids', []);
if (empty($ids) || !is_array($ids)) {
return back()->with('error', '1件以上選択してください。');
}
// 利用者情報取得
$users = DB::table('user')
->whereIn('user_id', $ids)
->select('user_name', 'user_regident_zip', 'user_regident_pre')
->get();
// PDF生成Laravel-dompdf使用例
$pdfHtml = view('admin.tag_issue.pdf_labels', ['users' => $users])->render();
$pdf = \PDF::loadHTML($pdfHtml);
return $pdf->download('tag_labels.pdf');
}
public function list(Request $request) public function list(Request $request)
{ {
// userテーブルから必要なカラムを取得 // 絞り込み条件
$query = DB::table('user') $filterType = $request->input('filter_type'); // 'unissued', 'issued', 'all', 'unissued_toggle'
->select( $tagSerial = $request->input('tag_serial');
'user_seq', $tagSerial64 = $request->input('tag_serial_64');
'user_tag_serial',
'user_tag_serial_64',
'user_tag_issue',
'user_name',
'user_mobile',
'user_homephone',
'user_regident_zip',
'user_regident_pre',
'user_regident_city',
'user_regident_add'
)
->orderByDesc('user_seq');
// 必要に応じてフィルタ追加 // ソートパラメータ取得
// if ($request->filled('user_tag_issue')) { $sort = $request->input('sort');
// $query->where('user_tag_issue', $request->input('user_tag_issue')); $sortType = $request->input('sort_type', 'asc');
// }
// userテーブルとoperator_queテーブルをJOIN
$query = DB::table('user')
->leftJoin('operator_que', 'user.user_id', '=', 'operator_que.user_id')
->select(
'user.user_seq',
'user.user_id',
'user.user_tag_serial',
'user.user_tag_serial_64',
'user.user_tag_issue',
'user.user_name',
'user.user_mobile',
'user.user_homephone',
'user.user_regident_zip',
'user.user_regident_pre',
'user.user_regident_city',
'user.user_regident_add',
'operator_que.que_id',
'operator_que.que_class',
'operator_que.que_status'
);
// ソート項目に応じたorderBy
switch ($sort) {
case 'que_id':
$query->orderBy('operator_que.que_id', $sortType);
break;
case 'user_tag_serial':
$query->orderBy('user.user_tag_serial', $sortType);
break;
case 'user_tag_serial_64':
$query->orderBy('user.user_tag_serial_64', $sortType);
break;
case 'user_tag_issue':
$query->orderBy('user.user_tag_issue', $sortType);
break;
case 'user_name':
$query->orderBy('user.user_name', $sortType);
break;
default:
$query->orderByDesc('user.user_seq');
}
// 【種別フィルター】タグ未発送(通常)
if ($filterType === 'unissued') {
$query->where('operator_que.que_class', 3)
->where('operator_que.que_status', 1);
}
// 【種別フィルター】タグ未発送トグルque_class=3かつque_status≠3
if ($filterType === 'unissued_toggle') {
$query->where('operator_que.que_class', 3)
->where('operator_que.que_status', '<>', 3);
}
// 【種別フィルター】タグ発送済み(通常)
if ($filterType === 'issued') {
$query->where('operator_que.que_class', 3)
->where('operator_que.que_status', 3);
}
// 【種別フィルター】タグ発送済みトグルque_class=3 and que_status=3
if ($filterType === 'issued_toggle') {
$query->where('operator_que.que_class', 3)
->where('operator_que.que_status', 3);
}
// 【タグシリアル・タグシリアル64進フィルター】
if (!empty($tagSerial)) {
$query->where('user.user_tag_serial', 'like', "%$tagSerial%");
}
if (!empty($tagSerial64)) {
$query->where('user.user_tag_serial_64', 'like', "%$tagSerial64%");
}
$users = $query->paginate(20); $users = $query->paginate(20);
return view('admin.tag_issue.list', [ return view('admin.tag_issue.list', [
'users' => $users, 'users' => $users,
'filterType' => $filterType,
'tagSerial' => $tagSerial,
'tagSerial64' => $tagSerial64,
'sort' => $sort,
'sortType' => $sortType,
]);
}
// ステータス変更(タグ発送済み/未発送)
public function updateStatus(Request $request)
{
$ids = $request->input('ids', []); // チェックされたuser_id配列
$action = $request->input('action'); // 'to_issued' or 'to_unissued'
if (empty($ids) || !is_array($ids)) {
return back()->with('error', 'チェックボックスを選択してください。');
}
$operatorId = auth()->id();
$now = now();
// 対象ユーザーのoperator_queを取得
$ques = DB::table('operator_que')->whereIn('user_id', $ids)->get();
if ($action === 'to_issued') {
$alreadyIssued = $ques->where('que_status', 3)->pluck('user_id')->toArray();
if (count($alreadyIssued) > 0) {
return back()->with('error', 'すでにタグ発送済みのユーザーが含まれています。');
}
// 確認ダイアログはJS側で
DB::table('operator_que')->whereIn('user_id', $ids)
->update(['que_status' => 3, 'updated_at' => $now, 'operator_id' => $operatorId]);
return back()->with('success', 'ステータスをタグ発送済に変更しました。');
}
if ($action === 'to_unissued') {
$alreadyUnissued = $ques->where('que_status', 1)->pluck('user_id')->toArray();
if (count($alreadyUnissued) > 0) {
// 既にタグ未発送のユーザー名を取得
$names = DB::table('user')->whereIn('user_id', $alreadyUnissued)->pluck('user_name')->toArray();
return back()->with('error', 'すでにタグ未発送のユーザーが含まれています: ' . implode(', ', $names));
}
// すべてque_status=1以外なので更新
DB::table('operator_que')->whereIn('user_id', $ids)
->update(['que_status' => 1, 'updated_at' => $now, 'operator_id' => $operatorId]);
return back()->with('success', 'ステータスをタグ未発送に変更しました。');
}
return back()->with('error', '不正な操作です。');
}
// Ajax: 選択user_idのque_statusを返すタグ発送済み/未発送判定)
public function checkStatus(Request $request)
{
$ids = $request->input('ids', []);
$type = $request->input('type'); // 'issued' or 'unissued'
$users = DB::table('user')
->leftJoin('operator_que', 'user.user_id', '=', 'operator_que.user_id')
->whereIn('user.user_id', $ids)
->select('user.user_name', 'operator_que.que_status')
->get();
$alreadyIssued = [];
$alreadyUnissued = [];
foreach ($users as $u) {
if ($type === 'issued' && $u->que_status == 3) {
$alreadyIssued[] = $u->user_name;
}
if ($type === 'unissued' && $u->que_status == 1) {
$alreadyUnissued[] = $u->user_name;
}
}
return response()->json([
'alreadyIssued' => $alreadyIssued,
'alreadyUnissued' => $alreadyUnissued
]); ]);
} }
} }

View File

@ -2,7 +2,7 @@
@section('title', 'タグ発行キュー処理、履歴表示') @section('title', 'タグ発行キュー処理、履歴表示')
@section('content') @section('content')
<div class="container-fluid"> <div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-2"> <div class="d-flex justify-content-between align-items-center mb-2">
<h3 class="m-0 text-dark">タグ発行キュー処理、履歴表示</h3> <h3 class="m-0 text-dark">タグ発行キュー処理、履歴表示</h3>
<nav aria-label="breadcrumb" class="mb-0" style="background: transparent;"> <nav aria-label="breadcrumb" class="mb-0" style="background: transparent;">
@ -22,7 +22,41 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="row g-1"> <div class="row g-1">
<div class="col-md-2 mb-1"> <div class="col-md-2 mb-1">
<button class="btn btn-outline-secondary btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送宛名印刷</button> <button type="button" class="btn btn-outline-secondary btn-xs w-100 py-1 px-2"
style="font-size:0.85rem;" onclick="handlePrintLabels()">タグ発送宛名印刷</button>
<script>
function handlePrintLabels() {
var checkboxes = document.querySelectorAll('input[name="ids[]"]:checked');
if (checkboxes.length === 0) {
alert('1件以上選択してください。');
return;
}
if (confirm('未発送のタグ発送用宛名を印刷してよろしいですか?')) {
// 送信用form生成
var form = document.createElement('form');
form.method = 'POST';
form.action = '/tagissue/print-unissued-labels';
form.target = '_blank';
// CSRF
var csrf = document.createElement('input');
csrf.type = 'hidden';
csrf.name = '_token';
csrf.value = '{{ csrf_token() }}';
form.appendChild(csrf);
// ids
checkboxes.forEach(function(cb) {
var input = document.createElement('input');
input.type = 'hidden';
input.name = 'ids[]';
input.value = cb.value;
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
}
}
</script>
</div> </div>
<div class="col-md-10 mb-1"></div> <div class="col-md-10 mb-1"></div>
</div> </div>
@ -34,10 +68,24 @@
<div class="col-md-12"> <div class="col-md-12">
<div class="row g-1"> <div class="row g-1">
<div class="col-md-2 mb-1"> <div class="col-md-2 mb-1">
<button class="btn btn-outline-secondary btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送未発送</button> <form method="GET" style="display:inline;">
@if(request('filter_type') == 'unissued_toggle')
<button type="submit" class="btn btn-warning btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ未発送解除</button>
@else
<input type="hidden" name="filter_type" value="unissued_toggle">
<button type="submit" class="btn btn-outline-secondary btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送未発送</button>
@endif
</form>
</div> </div>
<div class="col-md-2 mb-1"> <div class="col-md-2 mb-1">
<button class="btn btn-outline-secondary btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送済み</button> <form method="GET" style="display:inline;">
@if(request('filter_type') == 'issued_toggle')
<button type="submit" class="btn btn-warning btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送済み解除</button>
@else
<input type="hidden" name="filter_type" value="issued_toggle">
<button type="submit" class="btn btn-outline-secondary btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送済み</button>
@endif
</form>
</div> </div>
</div> </div>
</div> </div>
@ -46,51 +94,87 @@
<div class="row mb-2"> <div class="row mb-2">
<div class="col-md-12 font-weight-bold mb-1">タグシリアルフィルター</div> <div class="col-md-12 font-weight-bold mb-1">タグシリアルフィルター</div>
<div class="col-md-12"> <div class="col-md-12">
<form method="GET" class="mb-0">
<div class="row align-items-center g-1"> <div class="row align-items-center g-1">
<div class="col-auto font-weight-bold" style="padding-right:4px;">タグシリアル</div> <div class="col-auto font-weight-bold" style="padding-right:4px;">タグシリアル</div>
<div class="col-auto" style="min-width:140px;"> <div class="col-auto" style="min-width:140px;">
<input type="text" class="form-control form-control-sm" style="font-size:0.85rem; padding:2px 6px;" placeholder="キーワード…"> <input type="text" name="tag_serial" value="{{ request('tag_serial') }}" class="form-control form-control-sm" style="font-size:0.85rem; padding:2px 6px;" placeholder="キーワード…">
</div> </div>
<div class="col-auto font-weight-bold" style="padding-right:4px; padding-left:8px;">タグシリアル64進</div> <div class="col-auto font-weight-bold" style="padding-right:4px; padding-left:8px;">タグシリアル64進</div>
<div class="col-auto" style="min-width:140px;"> <div class="col-auto" style="min-width:140px;">
<input type="text" class="form-control form-control-sm" style="font-size:0.85rem; padding:2px 6px;" placeholder="キーワード…"> <input type="text" name="tag_serial_64" value="{{ request('tag_serial_64') }}" class="form-control form-control-sm" style="font-size:0.85rem; padding:2px 6px;" placeholder="キーワード…">
</div> </div>
<div class="col-auto text-end" style="padding-left:8px;"> <div class="col-auto text-end" style="padding-left:8px;">
<button class="btn btn-warning btn-xs py-1 px-2 me-1" style="font-size:0.85rem; min-width:60px;">絞り込み</button> <button type="submit" class="btn btn-default btn-xs py-1 px-2 me-1" style="font-size:0.85rem; min-width:60px;">絞り込み</button>
<button class="btn btn-warning btn-xs py-1 px-2" style="font-size:0.85rem; min-width:60px;">全表示</button> <a href="{{ route('tagissue') }}" class="btn btn-default btn-xs py-1 px-2" style="font-size:0.85rem; min-width:60px;">全表示</a>
</div> </div>
</div> </div>
</form>
</div> </div>
</div> </div>
<!-- 4行目:タグ発送ステータス変更 --> <!-- 4行目:タグ発送ステータス変更 -->
<div class="row mb-2"> <div class="row mb-2">
<div class="col-md-12 font-weight-bold mb-1">タグ発送ステータス変更</div> <div class="col-md-12 font-weight-bold mb-1">タグ発送ステータス変更</div>
<div class="col-md-12"> <div class="col-md-12">
<form id="statusForm" method="POST" action="{{ route('tagissue.status') }}">
@csrf
<input type="hidden" name="action" id="statusAction" value="">
<div class="row g-1"> <div class="row g-1">
<div class="col-md-2 mb-1"> <div class="col-md-2 mb-1">
<button class="btn btn-outline-secondary btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送済み</button> <button type="button" class="btn btn-outline-secondary btn-xs w-100 py-1 px-2"
style="font-size:0.85rem;" onclick="handleStatusChange('to_issued')">タグ発送済み</button>
</div> </div>
<div class="col-md-2 mb-1"> <div class="col-md-2 mb-1">
<button class="btn btn-outline-secondary btn-xs w-100 py-1 px-2" style="font-size:0.85rem;">タグ発送未発送</button> <button type="button" class="btn btn-outline-secondary btn-xs w-100 py-1 px-2"
style="font-size:0.85rem;" onclick="handleStatusChange('to_unissued')">タグ未発送</button>
</div> </div>
<div class="col-md-8 mb-1"></div> <div class="col-md-8 mb-1"></div>
</div> </div>
</div> <div class="table-responsive mt-2">
</div>
</div>
</div>
<!-- データテーブル -->
<div class="table-responsive">
<table class="table table-bordered table-hover table-sm"> <table class="table table-bordered table-hover table-sm">
<thead class="thead-light"> <thead class="thead-light">
<tr> <tr>
<th style="width:30px; background-color"><input type="checkbox"></th> <th style="width:30px; background-color"><input type="checkbox"></th>
<th>キューID</th> <th>
<th>タグシリアル</th> <a href="{{ route('tagissue', array_merge(request()->all(), ['sort' => 'que_id', 'sort_type' => (request('sort') === 'que_id' && request('sort_type') === 'asc') ? 'desc' : 'asc'])) }}">
<th>タグシリアル64進</th> キューID
<th>タグ発送ステータス</th> @if(request('sort') === 'que_id')
<th>利用者名</th> <i class="fa fa-sort-{{ request('sort_type') }}"></i>
@endif
</a>
</th>
<th>
<a href="{{ route('tagissue', array_merge(request()->all(), ['sort' => 'user_tag_serial', 'sort_type' => (request('sort') === 'user_tag_serial' && request('sort_type') === 'asc') ? 'desc' : 'asc'])) }}">
タグシリアル
@if(request('sort') === 'user_tag_serial')
<i class="fa fa-sort-{{ request('sort_type') }}"></i>
@endif
</a>
</th>
<th>
<a href="{{ route('tagissue', array_merge(request()->all(), ['sort' => 'user_tag_serial_64', 'sort_type' => (request('sort') === 'user_tag_serial_64' && request('sort_type') === 'asc') ? 'desc' : 'asc'])) }}">
タグシリアル64進
@if(request('sort') === 'user_tag_serial_64')
<i class="fa fa-sort-{{ request('sort_type') }}"></i>
@endif
</a>
</th>
<th>
<a href="{{ route('tagissue', array_merge(request()->all(), ['sort' => 'user_tag_issue', 'sort_type' => (request('sort') === 'user_tag_issue' && request('sort_type') === 'asc') ? 'desc' : 'asc'])) }}">
タグ発送ステータス
@if(request('sort') === 'user_tag_issue')
<i class="fa fa-sort-{{ request('sort_type') }}"></i>
@endif
</a>
</th>
<th>
<a href="{{ route('tagissue', array_merge(request()->all(), ['sort' => 'user_name', 'sort_type' => (request('sort') === 'user_name' && request('sort_type') === 'asc') ? 'desc' : 'asc'])) }}">
利用者名
@if(request('sort') === 'user_name')
<i class="fa fa-sort-{{ request('sort_type') }}"></i>
@endif
</a>
</th>
<th>携帯電話番号</th> <th>携帯電話番号</th>
<th>自宅電話番号</th> <th>自宅電話番号</th>
<th>居住所:郵便番号</th> <th>居住所:郵便番号</th>
@ -102,13 +186,24 @@
<tbody> <tbody>
@foreach($users as $user) @foreach($users as $user)
<tr> <tr>
<td style="background-color:#faebd7;"><input type="checkbox"></td> <td style="background-color:#faebd7;">
<td>{{ $user->user_seq }}</td> <input type="checkbox" name="ids[]" value="{{ $user->user_id }}">
</td>
@php
$que = \App\Models\OperatorQue::where('user_id', $user->user_id)->first();
@endphp
<td>{{ $que ? $que->que_id : '' }}</td>
<td>{{ $user->user_tag_serial }}</td> <td>{{ $user->user_tag_serial }}</td>
<td>{{ $user->user_tag_serial_64 }}</td> <td>{{ $user->user_tag_serial_64 }}</td>
<td>{{ $user->user_tag_issue }}</td> <td>{{ $user->user_tag_issue }}</td>
<td> <td>
<a href="{{ route('user_info', ['seq' => $user->user_seq]) }}" target="_blank">{{ $user->user_name }}</a> @if(!empty($user->user_seq))
<a href="{{ route('user_edit', ['seq' => $user->user_seq]) }}" target="_blank">
{{ $user->user_name }}
</a>
@else
{{ $user->user_name }}
@endif
</td> </td>
<td>{{ $user->user_mobile }}</td> <td>{{ $user->user_mobile }}</td>
<td>{{ $user->user_homephone }}</td> <td>{{ $user->user_homephone }}</td>
@ -126,5 +221,49 @@
</div> </div>
</div> </div>
</div> </div>
</div> </form>
<script>
function handleStatusChange(actionType) {
var form = document.getElementById('statusForm');
document.getElementById('statusAction').value = actionType;
var checkboxes = document.querySelectorAll('input[name="ids[]"]:checked');
if (checkboxes.length === 0) {
alert('1件以上選択してください。');
return;
}
var ids = Array.from(checkboxes).map(cb => cb.value);
var ajaxType = (actionType === 'to_issued') ? 'issued' : 'unissued';
fetch('/tagissue/check-status', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: JSON.stringify({ ids: ids, type: ajaxType })
})
.then(response => response.json())
.then(data => {
if (ajaxType === 'issued' && data.alreadyIssued.length > 0) {
alert('以下のユーザーはすでにタグ発送済みです:\n' + data.alreadyIssued.join('\n'));
return;
}
if (ajaxType === 'unissued' && data.alreadyUnissued && data.alreadyUnissued.length > 0) {
alert('以下のユーザーはすでにタグ未発送です:\n' + data.alreadyUnissued.join('\n'));
return;
}
var confirmMsg = (ajaxType === 'issued') ? 'ステータスをタグ発送済に変更してよろしいですか?' : 'ステータスをタグ未発送に変更してよろしいですか?';
if (confirm(confirmMsg)) {
form.submit();
}
})
.catch(() => {
alert('ステータス確認に失敗しました。');
});
}
</script>
</div>
</div>
</div>
</div>
</div>
@endsection @endsection

View File

@ -265,7 +265,11 @@ Route::middleware('auth')->group(function () {
Route::get('/information', [InformationController::class, 'list'])->name('information'); Route::get('/information', [InformationController::class, 'list'])->name('information');
// タグ発行キュー処理、履歴表示 // タグ発行キュー処理、履歴表示
Route::get('/tagissue', [TagissueController::class, 'list'])->name('tagissue'); Route::get('/tagissue', [App\Http\Controllers\Admin\TagissueController::class, 'list'])->name('tagissue');
Route::post('/tagissue/status', [App\Http\Controllers\Admin\TagissueController::class, 'updateStatus'])->name('tagissue.status');
Route::post('/tagissue/check-status', [App\Http\Controllers\Admin\TagissueController::class, 'checkStatus']);
// タグ発行キュー宛名PDF印刷
Route::post('/tagissue/print-unissued-labels', [App\Http\Controllers\Admin\TagissueController::class, 'printUnissuedLabels'])->name('tagissue.print_labels');
// シール発行履歴 // シール発行履歴
Route::get('/seals', [SealsController::class, 'list'])->name('seals'); Route::get('/seals', [SealsController::class, 'list'])->name('seals');