定期予約マスタ修正

This commit is contained in:
kin.rinzen 2026-01-28 17:52:43 +09:00
parent 466dc98e17
commit 2691c1f373
32 changed files with 4619 additions and 3554 deletions

View File

@ -1,275 +1,308 @@
<?php <?php
declare(strict_types=1);
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use App\Models\City;
use App\Http\Requests\ParkRequest;
use App\Models\Park;
use App\Utils;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator; use App\Http\Requests\ParkRequest;
use Response; use App\Models\City;
use App\Services\ParkService;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpFoundation\StreamedResponse;
class ParkController extends Controller class ParkController extends Controller
{ {
public function list(Request $request) public function __construct(
{ private readonly ParkService $parkService
$query = \DB::table('park as p') ) {
->leftJoin('city as c', 'p.city_id', '=', 'c.city_id')
->select([
'p.*',
'c.city_name',
]);
if ($request->filled('park_name')) {
$query->where('p.park_name', 'like', '%' . $request->input('park_name') . '%');
}
if ($request->filled('city_id')) {
$query->where('p.city_id', $request->input('city_id'));
}
if ($request->filled('sort')) {
$query->orderBy($request->input('sort'), $request->input('sort_type', 'asc'));
} else {
$query->orderBy('p.park_id', 'asc');
} }
$parks = $query->paginate(20); /**
$cities = \DB::table('city')->orderBy('city_id')->get(); * 一覧
*/
$sort = $request->input('sort', 'p.park_id'); public function index(ParkRequest $request)
$sort_type = $request->input('sort_type', 'asc');
return view('admin.parks.list', compact('parks', 'cities', 'sort', 'sort_type'));
}
public function add(Request $request)
{ {
$cities = \DB::table('city')->orderBy('city_id')->get(); $filters = $request->filters();
if ($request->isMethod('post')) { $parks = $this->parkService->paginate($filters, 20);
// バリデーション(必要な項目だけ例示) $cities = City::orderBy('city_id')->get();
$validated = $request->validate([
'city_id' => 'required|integer',
'park_name' => 'required|string|max:255',
// 他の項目も必要に応じて追加
]);
// 保存処理 $sort = $filters['sort'] ?? 'p.park_id';
$park = new \App\Models\Park(); $sort_type = $filters['sort_type'] ?? 'asc';
$park->fill($validated);
$park->operator_id = auth()->user()->ope_id ?? 1;
$park->save();
return redirect()->route('parks')->with('success', '新規登録に完了しました。'); return view('admin.parks.index', compact(
'parks',
'cities',
'sort',
'sort_type'
));
} }
return view('admin.parks.add', [ /**
'cities' => $cities, * 新規(画面)
]); */
} public function create()
public function edit(Request $request, $pk, $view = '')
{ {
$park = Park::find($pk); $cities = City::orderBy('city_id')->get();
if (empty($pk) || empty($park)) {
abort('404');
}
$data = $park->getAttributes();
$dataList = $this->getDataDropList();
$data = array_merge($data, $dataList);
if ($request->isMethod('POST') || $request->isMethod('PUT')) {
// ここをaddと同じバリデーションに変更
$validated = $request->validate([
'city_id' => 'required|integer',
'park_name' => 'required|string|max:255',
// 他の項目も必要に応じて追加
]);
\DB::transaction(function () use ($validated, &$type, $park) { return view('admin.parks.create', compact('cities'));
$park->fill($validated);
$park->save();
$type = true;
});
$request->session()->flash('success', __('更新に成功しました'));
return redirect()->route('parks');
}
if ($view != '') {
return view($view, $data);
}
return view('admin.parks.edit', [
'park' => $park,
'cities' => $dataList['cities'] ?? [],
// 必要な他の変数もここで渡す
]);
} }
public function delete(Request $request) /**
* 新規(登録)
*/
public function store(ParkRequest $request)
{ {
$arr_pk = $request->get('pk'); $operatorId = (int) (auth()->user()->ope_id ?? 1);
if ($arr_pk) {
if (Park::destroy($arr_pk)) { $payload = $request->payload();
return redirect()->route('parks')->with('success', __("削除が完了しました。"));
} else { // 駐輪場五十音を設定
return redirect()->route('parks')->with('error', __('削除に失敗しました。')); $payload['park_syllabary'] = $this->toSyllabaryGroup(
} $payload['park_ruby'] ?? null
} );
return redirect()->route('parks')->with('error', __('削除するユーザーを選択してください。'));
// 駐輪場五十音を設定してから Service に渡す
$this->parkService->create(
$payload,
$operatorId
);
return redirect()
->route('parks.index')
->with('success', __('新規登録に完了しました。'));
} }
public function info(Request $request, $id)
/**
* 編集(画面)
*/
public function edit(int $id)
{ {
return $this->edit($request, $id, 'admin.parks.info'); $record = $this->parkService->findOrFail($id);
$cities = City::orderBy('city_id')->get();
return view('admin.parks.edit', compact(
'record',
'cities'
));
} }
public function getDataDropList()
/**
* 編集(更新)
*/
public function update(ParkRequest $request, int $id)
{ {
$data['cities'] = City::orderBy('city_id')->get(); $park = $this->parkService->findOrFail($id);
return $data;
$operatorId = (int) (auth()->user()->ope_id ?? 1);
$payload = $request->payload();
// 駐輪場五十音を設定
$payload['park_syllabary'] = $this->toSyllabaryGroup(
$payload['park_ruby'] ?? null);
// 駐輪場五十音を設定してから Service に渡す
$this->parkService->update(
$park, $payload, $operatorId);
$this->parkService->update(
$park,
$request->payload(),
$operatorId
);
return redirect()
->route('parks.index')
->with('success', __('更新に成功しました。'));
} }
/**
* 削除(複数)
*/
public function destroy(Request $request)
{
$ids = (array) $request->input('pk', []);
public function export(Request $request) if (empty($ids)) {
{ return redirect()
->route('parks.index')
->with('error', __('削除するデータを選択してください。'));
}
$ok = $this->parkService->deleteByIds($ids);
return redirect()
->route('parks.index')
->with(
$ok ? 'success' : 'error',
$ok ? __('削除が完了しました。') : __('削除に失敗しました。')
);
}
/**
* CSV 出力
*/
public function export(): StreamedResponse
{
$columns = [ $columns = [
'駐輪場ID', '市区', '駐輪場名', '駐輪場ふりがな', '駐輪場五十音', '住所', '駐輪場ID','市区','駐輪場名','駐輪場ふりがな','駐輪場五十音','住所',
'閉設フラグ', '閉設日', '残警告チェックフラグ', '印字数', '最新キープアライブ', '閉設フラグ','閉設日','残警告チェックフラグ','印字数','最新キープアライブ',
'更新オペレータID', '更新期間開始日', '更新期間開始時', '更新期間終了日', '更新期間終了時', '更新オペレータID','更新期間開始日','更新期間開始時',
'駐輪開始期間', 'リマインダー種別', 'リマインダー時間', '契約後即利用許可', '更新期間終了日','更新期間終了時','駐輪開始期間',
'項目表示設定:性別', '項目表示設定:生年月日', '項目表示設定:防犯登録番号', 'リマインダー種別','リマインダー時間','契約後即利用許可',
'二点間距離', '駐車場座標(緯度)', '駐車場座標(経度)', '電話番号', '項目表示設定:性別','項目表示設定:生年月日','項目表示設定:防犯登録番号',
'駐輪場契約形態(定期)', '駐輪場契約形態(一時利用)', '車種制限', '手続方法', '支払方法', '二点間距離','駐車場座標(緯度)','駐車場座標(経度)','電話番号',
'利用可能時間制限フラグ', '利用可能時間(開始)', '利用可能時間(終了)', '駐輪場契約形態(定期)','駐輪場契約形態(一時利用)',
'常駐管理人フラグ', '常駐時間(開始)', '常駐時間(終了)', '車種制限','手続方法','支払方法',
'屋根フラグ', 'シール発行機フラグ', '駐輪場利用方法', '定期更新期間', '利用可能時間制限フラグ','利用可能時間(開始)','利用可能時間(終了)',
'空き待ち予約', '特記事項', '学生証確認種別', '常駐管理人フラグ','常駐時間(開始)','常駐時間(終了)',
'減免案内表示フラグ', '減免対象年齢', '減免案内表示開始月数', '年跨ぎ' '屋根フラグ','シール発行機フラグ','駐輪場利用方法',
'定期更新期間','空き待ち予約','特記事項','学生証確認種別',
'減免案内表示フラグ','減免対象年齢','減免案内表示開始月数','年跨ぎ',
]; ];
$dataExport = DB::table('park as p') $rows = $this->parkService->exportRows();
->select([
'p.park_id', 'p.city_id', 'p.park_name', 'p.park_ruby', 'p.park_syllabary', 'p.park_adrs',
'p.park_close_flag', 'p.park_day', 'p.alert_flag', 'p.print_number', 'p.keep_alive',
'p.operator_id', 'p.update_grace_period_start_date', 'p.update_grace_period_start_time',
'p.update_grace_period_end_date', 'p.update_grace_period_end_time',
'p.parking_start_grace_period', 'p.reminder_type', 'p.reminder_time', 'p.immediate_use_permit',
'p.gender_display_flag', 'p.bd_display_flag', 'p.securityreg_display_flag',
'p.distance_twopoints', 'p.park_latitude', 'p.park_longitude', 'p.park_tel',
'p.park_fixed_contract', 'p.park_temporary_contract', 'p.park_restriction',
'p.park_procedure', 'p.park_payment',
'p.park_available_time_flag', 'p.park_available_time_from', 'p.park_available_time_to',
'p.park_manager_flag', 'p.park_manager_resident_from', 'p.park_manager_resident_to',
'p.park_roof_flag', 'p.park_issuing_machine_flag', 'p.park_using_method',
'p.park_contract_renewal_term', 'p.park_reservation', 'p.park_reference',
'p.student_id_confirm_type', 'p.reduction_guide_display_flag', 'p.reduction_age',
'p.reduction_guide_display_start_month', 'p.overyear_flag'
])
->orderBy('p.park_id', 'asc')
->get();
$response = new StreamedResponse(function () use ($dataExport, $columns) { return response()->streamDownload(function () use ($rows, $columns) {
$stream = fopen('php://output', 'w'); $fp = fopen('php://output', 'w');
// Excel兼容 BOM
fwrite($stream, chr(0xEF) . chr(0xBB) . chr(0xBF));
fputcsv($stream, $columns);
foreach ($dataExport as $item) { fwrite($fp, "\xEF\xBB\xBF");
fputcsv($stream, [ fputcsv($fp, $columns);
$item->park_id, $item->city_id, $item->park_name, $item->park_ruby, $item->park_syllabary, $item->park_adrs,
$item->park_close_flag, $item->park_day, $item->alert_flag, $item->print_number, $item->keep_alive, foreach ($rows as $r) {
$item->operator_id, $item->update_grace_period_start_date, $item->update_grace_period_start_time, fputcsv($fp, [
$item->update_grace_period_end_date, $item->update_grace_period_end_time, $r->park_id,
$item->parking_start_grace_period, $item->reminder_type, $item->reminder_time, $item->immediate_use_permit, $r->city_id,
$item->gender_display_flag, $item->bd_display_flag, $item->securityreg_display_flag, $r->park_name,
$item->distance_twopoints, $item->park_latitude, $item->park_longitude, $item->park_tel, $r->park_ruby,
$item->park_fixed_contract, $item->park_temporary_contract, $item->park_restriction, $r->park_syllabary,
$item->park_procedure, $item->park_payment, $r->park_adrs,
$item->park_available_time_flag, $item->park_available_time_from, $item->park_available_time_to, $r->park_close_flag,
$item->park_manager_flag, $item->park_manager_resident_from, $item->park_manager_resident_to, $r->park_day,
$item->park_roof_flag, $item->park_issuing_machine_flag, $item->park_using_method, $r->alert_flag,
$item->park_contract_renewal_term, $item->park_reservation, $item->park_reference, $r->print_number,
$item->student_id_confirm_type, $item->reduction_guide_display_flag, $item->reduction_age, $r->keep_alive,
$item->reduction_guide_display_start_month, $item->overyear_flag $r->operator_id,
$r->update_grace_period_start_date,
$r->update_grace_period_start_time,
$r->update_grace_period_end_date,
$r->update_grace_period_end_time,
$r->parking_start_grace_period,
$r->reminder_type,
$r->reminder_time,
$r->immediate_use_permit,
$r->gender_display_flag,
$r->bd_display_flag,
$r->securityreg_display_flag,
$r->distance_twopoints,
$r->park_latitude,
$r->park_longitude,
$r->park_tel,
$r->park_fixed_contract,
$r->park_temporary_contract,
$r->park_restriction,
$r->park_procedure,
$r->park_payment,
$r->park_available_time_flag,
$r->park_available_time_from,
$r->park_available_time_to,
$r->park_manager_flag,
$r->park_manager_resident_from,
$r->park_manager_resident_to,
$r->park_roof_flag,
$r->park_issuing_machine_flag,
$r->park_using_method,
$r->park_contract_renewal_term,
$r->park_reservation,
$r->park_reference,
$r->student_id_confirm_type,
$r->reduction_guide_display_flag,
$r->reduction_age,
$r->reduction_guide_display_start_month,
$r->overyear_flag,
]); ]);
} }
fclose($stream); fclose($fp);
}); }, '駐輪場マスタ.csv', [
'Content-Type' => 'text/csv; charset=UTF-8',
$response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
$response->headers->set('Content-Disposition', 'attachment; filename="駐輪場マスタ.csv"');
$response->headers->set('Cache-Control', 'no-store, no-cache');
return $response;
}
public function import(Request $request)
{
$file = $request->file('file');
if (!empty($file)) {
$data = Utils::csvToArray($file);
$type = 1;
$msg = '';
$record = 0;
DB::beginTransaction();
try {
Park::query()->delete();
$col = 13;
foreach ($data as $key => $items) {
$record = $key + 2;
if (count($items) == $col) {
$row = new Park();
$row->park_id = $items[0];
$row->city_id = $items[1];
$row->park_name = $items[3];
$row->park_ruby = $items[4];
$row->park_syllabary = $items[5];
$row->park_adrs = $items[6];
$row->park_close_flag = $items[7];
$row->park_day = $items[9];
$row->alert_flag = $items[10];
$row->print_number = $items[11];
$row->keep_alive = $items[12];
if (!$row->save()) {
$type = 0;
$msg = '行:record型が一致しません。';
break;
}
} else {
$type = 0;
$msg = '行:record列数が一致しません。';
break;
}
}
} catch (\Exception $e) {
$msg = '行:record型が一致しません。';
$type = 0;
}
if ($type) {
DB::commit();
return redirect()->route('parks')->with('success', __('輸入成功'));
} else {
DB::rollBack();
return redirect()->route('parks')->with('error', __($msg, ['record' => $record]));
}
} else {
return redirect()->route('parks')->with('error', __('あなたはcsvファイルを選択していません。'));
}
}
public function checkDuplicate(\Illuminate\Http\Request $request)
{
$parkName = $request->input('park_name');
$duplicate = Park::where('park_name', $parkName)->first();
if ($duplicate) {
return response()->json([
'duplicate' => true,
'park_id' => $duplicate->park_id,
'park_name' => $duplicate->park_name,
]); ]);
} }
/**
* 重複チェックAJAX
*/
public function checkDuplicate(Request $request)
{
$parkName = (string) $request->input('park_name', '');
if ($parkName === '') {
return response()->json(['duplicate' => false]); return response()->json(['duplicate' => false]);
} }
$dup = $this->parkService->checkDuplicateByName($parkName);
if (!$dup) {
return response()->json(['duplicate' => false]);
}
return response()->json([
'duplicate' => true,
'park_id' => $dup->park_id,
'park_name' => $dup->park_name,
]);
}
private function toSyllabaryGroup(?string $ruby): ?string
{
$ruby = trim((string) $ruby);
if ($ruby === '') {
return null;
}
// 先取第1文字UTF-8
$first = mb_substr($ruby, 0, 1, 'UTF-8');
// 小书き/濁点などを正規化(必要最低限)
$map = [
'が'=>'か','ぎ'=>'き','ぐ'=>'く','げ'=>'け','ご'=>'こ',
'ざ'=>'さ','じ'=>'し','ず'=>'す','ぜ'=>'せ','ぞ'=>'そ',
'だ'=>'た','ぢ'=>'ち','づ'=>'つ','で'=>'て','ど'=>'と',
'ば'=>'は','び'=>'ひ','ぶ'=>'ふ','べ'=>'へ','ぼ'=>'ほ',
'ぱ'=>'は','ぴ'=>'ひ','ぷ'=>'ふ','ぺ'=>'へ','ぽ'=>'ほ',
'ぁ'=>'あ','ぃ'=>'い','ぅ'=>'う','ぇ'=>'え','ぉ'=>'お',
'ゃ'=>'や','ゅ'=>'ゆ','ょ'=>'よ','っ'=>'つ',
'ゎ'=>'わ',
];
$first = $map[$first] ?? $first;
// グループ判定(先頭文字で分類)
$groups = [
'あ' => ['あ','い','う','え','お'],
'か' => ['か','き','く','け','こ'],
'さ' => ['さ','し','す','せ','そ'],
'た' => ['た','ち','つ','て','と'],
'な' => ['な','に','ぬ','ね','の'],
'は' => ['は','ひ','ふ','へ','ほ'],
'ま' => ['ま','み','む','め','も'],
'や' => ['や','ゆ','よ'],
'ら' => ['ら','り','る','れ','ろ'],
'わ' => ['わ','を','ん'],
];
foreach ($groups as $head => $chars) {
if (in_array($first, $chars, true)) {
return $head;
}
}
// ひらがな以外(空/英数など)は null
return null;
}
} }

View File

@ -1,469 +1,118 @@
<?php <?php
declare(strict_types=1);
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use Illuminate\Support\Facades\Schema; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use App\Http\Requests\ReserveRequest;
use Illuminate\Support\Facades\DB; use App\Services\ReserveService;
use Illuminate\Support\Facades\Validator; use Illuminate\Http\RedirectResponse;
use App\Models\Park; use Illuminate\View\View;
use App\Models\PriceA;
use App\Models\PriceB;
use Illuminate\Support\Facades\Auth;
class ReservesController final class ReservesController extends Controller
{ {
public function __construct(
private readonly ReserveService $reserveService
) {
}
/** /**
* 予約一覧 * 予約一覧(検索・並び替え・ページング)
* - 基本表: reserver * Why: Controller を薄くし、検索条件・クエリ構築は Service に集約する。
* - 付加情報: useru, parkp
* - 画面変数: $list, $sort, $sort_type利用者マスタの書式に準拠
*
* reserve テーブルの主な列:
* reserve_id, contract_id, user_id, park_id, price_parkplaceid, psection_id,
* reserve_date, reserve_start, reserve_end, reserve_cancelday, valid_flag, ope_id など
* DDL dump の通り【turn12file6†L15-L37】
*/ */
public function list(Request $request) public function index(ReserveRequest $request): View
{ {
// ── 並び順(既定: reserve_id DESC────────────────────────────── $result = $this->reserveService->paginate($request->payload());
$sort = $request->input('sort', 'reserve_id');
$sortType = strtolower($request->input('sort_type', 'asc')) === 'desc' ? 'desc' : 'asc';
// ── 絞り込み(必要最低限:利用者/駐輪場/期間)────────────────── return view('admin.reserves.index', $result);
$userId = trim((string) $request->input('user_id', ''));
$parkId = trim((string) $request->input('park_id', ''));
$fromDt = $request->input('reserve_date_from', '');
$toDt = $request->input('reserve_date_to', '');
$keyword = trim((string) $request->input('keyword', '')); // 利用者名かな など
$validFlag = trim((string) $request->input('valid_flag', ''));
$mailSentFrom = $request->input('mail_sent_from', '');
$mailSentTo = $request->input('mail_sent_to', '');
$priceUnion = DB::query()->fromSub(function ($sub) {
$sub->from('price_a')
->select('price_parkplaceid', 'prine_name')
->unionAll(
DB::table('price_b')->select('price_parkplaceid', 'prine_name')
);
}, 'price_union');
// ── クエリ構築 ────────────────────────────────────────────────
$q = DB::table('reserve as r')
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
->leftJoin('psection as ps', 'ps.psection_id', '=', 'r.psection_id')
->leftJoin('ptype as pt', 'pt.ptype_id', '=', 'r.ptype_id')
->leftJoin('usertype as t', 't.user_categoryid', '=', 'r.user_categoryid')
->leftJoinSub($priceUnion, 'price_union', function ($join) {
$join->on('price_union.price_parkplaceid', '=', 'r.price_parkplaceid');
})
->select([
'r.reserve_id',
'r.contract_id',
'r.contract_created_at',
'r.user_id',
'r.park_id',
'r.price_parkplaceid',
'r.psection_id',
'r.reserve_date',
'r.reserve_start',
'r.reserve_end',
'r.reserve_reduction',
'r.reserve_auto_remind',
'r.reserve_manual_remind',
DB::raw('r.`800m_flag` as flag_800m'),
'r.reserve_cancelday',
'r.valid_flag',
'r.reserve_manual',
'r.reserve_notice',
'r.sent_date',
'r.reserve_order',
'r.valid_flag',
'r.ope_id',
'r.user_categoryid',
DB::raw('u.user_name as user_name'),
DB::raw('u.user_phonetic as user_phonetic'),
DB::raw('u.user_mobile as user_mobile'),
DB::raw('p.park_name as park_name'),
DB::raw('pt.ptype_subject as ptype_subject'),
DB::raw('ps.psection_subject as psection_subject'),
DB::raw('price_union.price_parkplaceid as display_price_parkplaceid'),
DB::raw('price_union.prine_name as display_prine_name'),
DB::raw('t.usertype_subject1 as usertype_subject1'),
DB::raw('t.usertype_subject2 as usertype_subject2'),
DB::raw('t.usertype_subject3 as usertype_subject3'),
]);
if ($userId !== '')
$q->where('r.user_id', 'like', "%{$userId}%");
if ($parkId !== '')
$q->where('r.park_id', '=', (int) $parkId);
if ($fromDt)
$q->whereDate('r.reserve_date', '>=', $fromDt);
if ($toDt)
$q->whereDate('r.reserve_date', '<=', $toDt);
if ($keyword !== '') {
$q->where(function ($w) use ($keyword) {
$w->where('u.user_name', 'like', "%{$keyword}%")
->orWhere('u.user_phonetic', 'like', "%{$keyword}%");
});
}
if (in_array($validFlag, ['0', '1'], true)) {
$q->where('r.valid_flag', '=', (int) $validFlag);
}
if ($mailSentFrom !== null && $mailSentFrom !== '') {
$q->where('r.sent_date', '>=', $mailSentFrom);
}
if ($mailSentTo !== null && $mailSentTo !== '') {
$q->where('r.sent_date', '<=', $mailSentTo);
} }
// ソート許可カラムJOIN 先も含む) /**
$sortable = [ * 新規(画面)
'reserve_id', * Why: プルダウン等の初期表示データ取得は Service に寄せる。
'contract_id', */
'contract_created_at', public function create(): View
'user_categoryid', {
'user_id', $form = $this->reserveService->getCreateForm();
'reserve_date',
'park_price_name',
'price_parkplaceid',
'psection_subject',
'ptype_subject',
'park_name',
'reserve_reduction',
'reserve_auto_remind',
'reserve_manual_remind',
'flag_800m',
'reserve_cancelday',
'valid_flag',
'sent_date',
'reserve_manual',
'reserve_notice',
'reserve_order',
];
if (!in_array($sort, $sortable, true)) {
$sort = 'reserve_id';
}
$sortMap = [ return view('admin.reserves.create', [
'reserve_id' => DB::raw('r.reserve_id'), 'record' => null,
'contract_id' => DB::raw('r.contract_id'),
'contract_created_at' => DB::raw('r.contract_created_at'),
'user_categoryid' => DB::raw('r.user_categoryid'),
'user_id' => DB::raw('r.user_id'),
'reserve_date' => DB::raw('r.reserve_date'),
'park_price_name' => DB::raw('price_union.prine_name'),
'price_parkplaceid' => DB::raw('r.price_parkplaceid'),
'psection_subject' => DB::raw('ps.psection_subject'),
'ptype_subject' => DB::raw('pt.ptype_subject'),
'park_name' => DB::raw('p.park_name'),
'reserve_reduction' => DB::raw('r.reserve_reduction'),
'reserve_auto_remind' => DB::raw('r.reserve_auto_remind'),
'reserve_manual_remind' => DB::raw('r.reserve_manual_remind'),
'flag_800m' => DB::raw('r.`800m_flag`'),
'reserve_cancelday' => DB::raw('r.reserve_cancelday'),
'valid_flag' => DB::raw('r.valid_flag'),
'sent_date' => DB::raw('r.sent_date'),
'reserve_manual' => DB::raw('r.reserve_manual'),
'reserve_notice' => DB::raw('r.reserve_notice'),
'reserve_order' => DB::raw('r.reserve_order'),
];
$sortColumn = $sortMap[$sort] ?? DB::raw('r.reserve_id');
$q->orderBy($sortColumn, $sortType);
$parkOptions = Park::query() // Blade: ($userTypes ?? []) as $id => $label 형태로 사용
->orderBy('park_id', 'asc') 'userTypes' => $form['userTypeOptions'] ?? [],
->pluck('park_name', 'park_id')
->toArray();
$list = $q->paginate(50); // Blade: ($parks ?? []) as $id => $label
'parks' => $form['parkOptions'] ?? [],
$placeIds = $list->getCollection() // Blade: ($prices ?? []) as $id => $label (prine_name 표시)
->pluck('price_parkplaceid') 'prices' => $form['priceOptions'] ?? [],
->filter()
->unique()
->values()
->all();
if (!empty($placeIds)) { // Blade: ($psections ?? []) as $id => $label
$priceNamesA = PriceA::query() 'psections' => $form['psectionOptions'] ?? [],
->whereIn('price_parkplaceid', $placeIds)
->pluck('prine_name', 'price_parkplaceid')
->toArray();
$priceNamesB = PriceB::query() // Blade: ($ptypes ?? []) as $id => $label
->whereIn('price_parkplaceid', $placeIds) 'ptypes' => $form['ptypeOptions'] ?? [],
->pluck('prine_name', 'price_parkplaceid')
->toArray();
// 駐輪場所名のマッピングprice_b で上書き)
$priceNames = array_replace($priceNamesA, $priceNamesB);
$list->setCollection(
$list->getCollection()->map(function ($row) use ($priceNames) {
$id = $row->price_parkplaceid ?? null;
$row->display_prine_name = ($id !== null && array_key_exists($id, $priceNames))
? $priceNames[$id]
: null;
return $row;
})
);
}
return view('admin.reserves.list', [
'list' => $list,
'sort' => $sort,
'sort_type' => $sortType,
// 入力保持
'user_id' => $userId,
'park_id' => $parkId,
'reserve_date_from' => $fromDt,
'reserve_date_to' => $toDt,
'keyword' => $keyword,
'valid_flag' => $validFlag,
'mail_sent_from' => $mailSentFrom,
'mail_sent_to' => $mailSentTo,
'parkOptions' => $parkOptions,
]); ]);
} }
/** /**
* 予約追加GET: 画面表示 / POST: 登録) * 新規(登録)
*/ */
public function add(Request $request) public function store(ReserveRequest $request): RedirectResponse
{ {
if ($request->isMethod('get')) { $this->reserveService->create($request->payload());
$userTypes = DB::table('usertype')
->orderBy('user_categoryid', 'asc')
->get([
'user_categoryid',
'usertype_subject1',
'usertype_subject2',
'usertype_subject3',
])
->map(function ($row) {
$labels = array_filter([
$row->usertype_subject1,
$row->usertype_subject2,
$row->usertype_subject3,
], fn ($v) => $v !== null && $v !== '');
$row->display_name = $labels ? implode('/', $labels) : '';
return $row;
});
$parks = Park::query() return redirect()
->orderBy('park_id', 'asc') ->route('reserves.index')
->get(['park_id', 'park_name']); ->with('success', __('登録を完了しました。'));
$priceA = PriceA::query()
->select('price_parkplaceid', 'prine_name')
->get();
$priceB = PriceB::query()
->select('price_parkplaceid', 'prine_name')
->get();
$priceOptions = $priceA->merge($priceB)
->sortBy('price_parkplaceid', SORT_NATURAL)
->unique('price_parkplaceid')
->values();
return view('admin.reserves.add', [
'userTypes' => $userTypes,
'parks' => $parks,
'priceOptions' => $priceOptions,
]);
}
// 予約の最低限バリデーション(必要に応じて追加)
$v = Validator::make($request->all(), [
'user_id' => ['required', 'integer'],
'park_id' => ['required', 'integer'],
'reserve_date' => ['nullable', 'date'],
'reserve_start' => ['nullable', 'date'],
'reserve_end' => ['nullable', 'date'],
], [], [
'user_id' => '利用者ID',
'park_id' => '駐輪場ID',
]);
if ($v->fails()) {
return back()->withErrors($v)->withInput();
}
$now = now();
$opeId = optional(Auth::user())->ope_id;
$nextReserveId = DB::transaction(function () {
$currentMax = DB::table('reserve')->max('reserve_id');
return $currentMax ? $currentMax + 1 : 1;
});
DB::table('reserve')->insert([
'reserve_id' => $nextReserveId,
'user_id' => (int) $request->input('user_id'),
'park_id' => (int) $request->input('park_id'),
'contract_id' => $request->input('contract_id'),
'price_parkplaceid' => $request->input('price_parkplaceid'),
'psection_id' => $request->input('psection_id'),
'reserve_date' => $request->input('reserve_date'),
'reserve_start' => $now,
'reserve_end' => $now,
'valid_flag' => $request->input('valid_flag'),
'ope_id' => $opeId,
'created_at' => $now,
'updated_at' => $now,
]);
return redirect()->route('reserves')->with('success', '予約を登録しました。');
} }
/** /**
* 予約削除 * 編集(画面)
*/ */
public function delete(Request $request) public function edit(int $reserveId): View
{ {
$form = $this->reserveService->getEditForm($reserveId);
$normalizeIds = function ($raw) { return view('admin.reserves.edit', [
'record' => $form['row'],
if (is_string($raw)) { 'userTypes' => $form['userTypeOptions'] ?? [],
$raw = explode(',', $raw); 'parks' => $form['parkOptions'] ?? [],
} 'prices' => $form['priceOptions'] ?? [],
if (is_array($raw) && count($raw) === 1 && is_string($raw[0]) && str_contains($raw[0], ',')) { 'psections' => $form['psectionOptions'] ?? [],
$raw = explode(',', $raw[0]); 'ptypes' => $form['ptypeOptions'] ?? [],
} ]);
$ids = array_map('intval', (array) $raw);
$ids = array_values(array_unique(array_filter($ids, fn($v) => $v > 0)));
return $ids;
};
if ($request->isMethod('get')) {
$ids = $normalizeIds($request->input('ids', []));
$rows = [];
if ($ids) {
$rows = DB::table('reserve as r')
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
->whereIn('r.reserve_id', $ids)
->select('r.*', 'u.user_name', 'p.park_name')
->get();
}
return view('admin.reserves.delete', compact('rows', 'ids'));
} }
if ($request->post('confirmed')) {
$ids = $normalizeIds($request->input('ids', [])); /**
if ($ids) { * 編集(更新)
$deleted = DB::table('reserve')->whereIn('reserve_id', $ids)->delete(); */
return redirect()->route('reserves')->with( public function update(ReserveRequest $request, int $reserveId): RedirectResponse
$deleted ? 'success' : 'warning', {
$deleted ? "{$deleted} 件を削除しました。" : '対象が見つかりませんでした。' $this->reserveService->update($reserveId, $request->payload());
return redirect()
->route('reserves.index')
->with('success', __('更新を完了しました。'));
}
/**
* 削除(複数削除 pk[]
*/
public function destroy(ReserveRequest $request): RedirectResponse
{
$payload = $request->payload();
$deleted = $this->reserveService->deleteMany($payload['ids'] ?? []);
return redirect()
->route('reserves.index')
->with(
$deleted > 0 ? 'success' : 'warning',
$deleted > 0 ? __(':count 件を削除しました。', ['count' => $deleted]) : __('削除対象がありません。')
); );
} }
}
return redirect()->route('reserves')->with('warning', '削除対象がありません。');
}
public function edit(Request $request, $reserve_id)
{
$id = (int) $reserve_id;
// 取得レコード無ければ404
$row = DB::table('reserve')->where('reserve_id', $id)->first();
if (!$row) {
abort(404);
}
// POST: 更新処理※reserveテーブルに確実にある列だけ更新
if ($request->isMethod('post')) {
$v = Validator::make($request->all(), [
'user_id' => ['required', 'integer'],
'park_id' => ['required', 'integer'],
'reserve_date' => ['nullable', 'date'],
'reserve_start' => ['nullable', 'date'],
'reserve_end' => ['nullable', 'date'],
], [], [
'user_id' => '利用者ID',
'park_id' => '駐輪場ID',
]);
if ($v->fails()) {
return back()->withErrors($v)->withInput();
}
$data = [
'contract_id' => $request->input('contract_id'),
'user_id' => (int) $request->input('user_id'),
'park_id' => (int) $request->input('park_id'),
'price_parkplaceid' => $request->input('price_parkplaceid'),
'psection_id' => $request->input('psection_id'),
'reserve_date' => $request->input('reserve_date'),
'reserve_start' => $request->input('reserve_start'),
'reserve_end' => $request->input('reserve_end'),
'valid_flag' => $request->input('valid_flag'),
'ope_id' => $request->input('ope_id'),
'updated_at' => now(),
];
DB::table('reserve')->where('reserve_id', $id)->update($data);
return redirect()->route('reserves')->with('success', '予約を更新しました。');
}
// GET: 編集画面表示用の各種プルダウン(存在するテーブルだけ読む)
$userOptions = DB::table('user')
->orderBy('user_id', 'asc')
->limit(5000)
->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id')
->toArray();
$parkOptions = DB::table('park')
->orderBy('park_id', 'asc')
->pluck('park_name', 'park_id')
->toArray();
$userTypeOptions = Schema::hasTable('usertype')
? DB::table('usertype')->orderBy('user_categoryid')
->pluck('print_name', 'user_categoryid')->toArray()
: [];
$parkplaceOptions = Schema::hasTable('price_parkplace')
? DB::table('price_parkplace')->orderBy('price_parkplaceid')
->pluck('price_parkplaceid', 'price_parkplaceid')->toArray()
: [];
$psectionOptions = Schema::hasTable('psection')
? DB::table('psection')->orderBy('psection_id')
->pluck(
Schema::hasColumn('psection', 'psection_name') ? 'psection_name' : 'psection_id',
'psection_id'
)->toArray()
: [];
$ptypeOptions = Schema::hasTable('ptype')
? DB::table('ptype')->orderBy('ptype_id')
->pluck(
Schema::hasColumn('ptype', 'ptype_name') ? 'ptype_name' : 'ptype_id',
'ptype_id'
)->toArray()
: [];
return view('admin.reserves.edit', compact(
'row',
'userOptions',
'parkOptions',
'userTypeOptions',
'parkplaceOptions',
'psectionOptions',
'ptypeOptions'
));
}
} }

View File

@ -2,20 +2,22 @@
namespace App\Http\Controllers\Admin; namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Http\Requests\UsertypeRequest; use App\Http\Requests\UsertypeRequest;
use App\Models\Usertype; use App\Models\Usertype;
use App\Utils; use App\Services\UsertypeService;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use Response;
class UsertypeController extends Controller class UsertypeController extends Controller
{ {
public function list(Request $request) public function __construct(
private readonly UsertypeService $service
) {}
public function index(Request $request)
{ {
$sort = $request->input('sort', 'user_categoryid'); // sort の許可値チェック
$sort = $request->query('sort', 'user_categoryid');
$allowSort = [ $allowSort = [
'user_categoryid', 'user_categoryid',
'sort_order', 'sort_order',
@ -28,315 +30,86 @@ class UsertypeController extends Controller
$sort = 'user_categoryid'; $sort = 'user_categoryid';
} }
$sortType = strtolower($request->input('sort_type', 'asc')); $sortType = strtolower($request->query('sort_type', 'asc'));
if (!in_array($sortType, ['asc', 'desc'], true)) { if (!in_array($sortType, ['asc', 'desc'], true)) {
$sortType = 'asc'; $sortType = 'asc';
} }
$action = $request->input('action'); $list = $this->service->paginateList(
if ($action === 'unlink') { $request->query('filter_sort_order'),
$request->merge([ $request->query('filter_usertype_subject1'),
'filter_sort_order' => '', $request->query('filter_usertype_subject2'),
'filter_usertype_subject1' => '', $request->query('filter_usertype_subject3'),
'filter_usertype_subject2' => '', $sort,
'filter_usertype_subject3' => '', $sortType
'page' => 1, );
]);
}
$inputs = [ return view('admin.usertypes.index', [
'isMethodPost' => $request->isMethod('post') ? 1 : 0, 'list' => $list,
'isExport' => 0,
'sort' => $sort, 'sort' => $sort,
'sort_type' => $sortType, 'sort_type' => $sortType,
'page' => (int) $request->get('page', 1), 'filter_sort_order' => $request->query('filter_sort_order', ''),
'action' => $action, 'filter_usertype_subject1' => $request->query('filter_usertype_subject1', ''),
]; 'filter_usertype_subject2' => $request->query('filter_usertype_subject2', ''),
'filter_usertype_subject3' => $request->query('filter_usertype_subject3', ''),
$filters = [ ]);
'filter_sort_order' => $request->input('filter_sort_order', ''),
'filter_usertype_subject1'=> $request->input('filter_usertype_subject1', ''),
'filter_usertype_subject2'=> $request->input('filter_usertype_subject2', ''),
'filter_usertype_subject3'=> $request->input('filter_usertype_subject3', ''),
];
$searchParams = array_merge($inputs, $filters);
$viewData = $searchParams;
$viewData['list'] = Usertype::search($searchParams);
if ($viewData['list']->total() > 0 && $viewData['page'] > $viewData['list']->lastPage()) {
return redirect()->route('usertypes');
} }
return view('admin.usertypes.list', $viewData);
}
public function add(Request $request) public function create()
{ {
// 画面に戻すための初期値 return view('admin.usertypes.create', [
$viewData = [ 'isEdit' => false,
'sort_order' => old('sort_order', ''), ]);
'usertype_subject1' => old('usertype_subject1', ''),
'usertype_subject2' => old('usertype_subject2', ''),
'usertype_subject3' => old('usertype_subject3', ''),
'print_name' => old('print_name', ''),
'usertype_money' => old('usertype_money', ''),
'usertype_remarks' => old('usertype_remarks', ''),
'isEdit' => 0,
'isInfo' => 0,
];
if ($request->isMethod('post')) {
// 入力値をまとめる
$inputs = [
'sort_order' => $request->input('sort_order'),
'usertype_subject1' => $request->input('usertype_subject1'),
'usertype_subject2' => $request->input('usertype_subject2'),
'usertype_subject3' => $request->input('usertype_subject3'),
'print_name' => $request->input('print_name'),
'usertype_money' => $request->input('usertype_money'),
'usertype_remarks' => $request->input('usertype_remarks'),
];
// バリデーションルール(最小限)
$rules = [
'sort_order' => 'required|integer',
'usertype_subject1' => 'required|string|max:10',
'usertype_subject2' => 'required|string|max:10',
'usertype_subject3' => 'nullable|string|max:10',
'print_name' => 'nullable|string|max:20',
'usertype_money' => 'nullable|string|max:10',
'usertype_remarks' => 'nullable|string|max:85',
];
$messages = [
'sort_order.required' => 'ソートオーダーは必須です。',
'sort_order.integer' => 'ソートオーダーは数値で入力してください。',
'usertype_subject1.required' => '分類名1は必須です。',
'usertype_subject2.required' => '分類名2は必須です。',
// 'print_name.required' => '印字名は必須です。',
];
$validator = Validator::make($inputs, $rules, $messages);
if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
} }
// 登録処理 public function store(UsertypeRequest $request)
$ok = false;
\DB::transaction(function () use ($inputs, &$ok) {
$new = new Usertype();
$new->fill($inputs);
$ok = $new->save();
});
if ($ok) {
return redirect()->route('usertypes')->with('success', '登録が完了しました。');
}
return back()->with('error', '登録に失敗しました。')->withInput();
}
// GET: 画面表示
return view('admin.usertypes.add', $viewData);
}
public function edit(Request $request, $id)
{ {
$record = Usertype::findOrFail($id); $this->service->create($request->validated());
$data = [ return redirect()
->route('usertypes.index')
->with('success', '登録が完了しました。');
}
public function edit(int $id)
{
$record = Usertype::query()->findOrFail($id);
return view('admin.usertypes.edit', [
'record' => $record, 'record' => $record,
'isEdit' => true, 'isEdit' => true,
'isInfo' => false,
];
if (method_exists($this, 'getDataDropList')) {
$data = array_merge($data, $this->getDataDropList());
}
// POST更新処理
if ($request->isMethod('POST')) {
$rules = [
'sort_order' => 'required|integer',
'usertype_subject1' => 'required|string|max:10',
'usertype_subject2' => 'required|string|max:10',
'usertype_subject3' => 'nullable|string|max:10',
'print_name' => 'nullable|string|max:20',
'usertype_money' => 'nullable|string|max:10',
'usertype_remarks' => 'nullable|string|max:85',
];
$messages = [
'sort_order.required' => 'ソートオーダーは必須です。',
'sort_order.integer' => 'ソートオーダーは数値で入力してください。',
'usertype_subject1.required' => '分類名1は必須です。',
'usertype_subject2.required' => '分類名2は必須です。',
'usertype_subject3.required' => '分類名3は必須です。',
];
$validator = Validator::make($request->all(), $rules, $messages);
if ($validator->fails()) {
return back()->withErrors($validator)->withInput();
}
\DB::transaction(function () use ($request, $record) {
$record->fill([
'sort_order' => $request->sort_order,
'usertype_subject1' => $request->usertype_subject1,
'usertype_subject2' => $request->usertype_subject2,
'usertype_subject3' => $request->usertype_subject3,
'print_name' => $request->print_name,
'usertype_money' => $request->usertype_money,
'usertype_remarks' => $request->usertype_remarks,
]);
$record->save();
});
return redirect()->route('usertypes')->with('success', '更新が完了しました。');
}
// GET画面表示
return view('admin.usertypes.edit', $data);
}
public function delete(Request $request)
{
// pk[] が無ければ ids[] を見る(両対応)
$arr_pk = $request->input('pk');
if (empty($arr_pk)) {
$arr_pk = $request->input('ids', []);
}
if (!is_array($arr_pk)) {
$arr_pk = [$arr_pk];
}
if (empty($arr_pk)) {
return redirect()->route('usertypes')->with('error', '削除対象を1件以上選択してください。');
}
if (Usertype::deleteByPk($arr_pk)) {
return redirect()->route('usertypes')->with('success', '削除が完了しました。');
}
return redirect()->route('usertypes')->with('error', '削除に失敗しました。');
}
public function info(Request $request, $id)
{
return $this->edit($request, $id, 'admin.usertypes.info');
}
public function getDataDropList()
{
$data = [];
return $data;
}
public function export(Request $request)
{
// ファイル名
$filename = '利用者分類マスタ_' . now()->format('YmdHis') . '.csv';
// 検索条件(一覧と同じ)
$inputs = [
'isMethodPost' => 0,
'isExport' => 1,
'sort' => $request->input('sort', ''),
'sort_type' => $request->input('sort_type', ''),
'filter_sort_order' => $request->input('filter_sort_order', ''),
'filter_usertype_subject1' => $request->input('filter_usertype_subject1', ''),
'filter_usertype_subject2' => $request->input('filter_usertype_subject2', ''),
'filter_usertype_subject3' => $request->input('filter_usertype_subject3', ''),
];
$dataExport = Usertype::search($inputs);
return response()->streamDownload(function () use ($dataExport) {
// Excel用 UTF-8 BOM
echo "\xEF\xBB\xBF";
// ヘッダー行
echo "利用者分類ID,ソートオーダー,分類名1,分類名2,分類名3,適用料率,備考\n";
// データ行
foreach ($dataExport as $item) {
echo implode(',', [
$item->user_categoryid,
$item->sort_order,
$item->usertype_subject1,
$item->usertype_subject2,
$item->usertype_subject3,
$item->usertype_money,
$item->usertype_remarks,
]) . "\n";
}
}, $filename, [
'Content-Type' => 'text/csv; charset=UTF-8',
]); ]);
} }
public function update(UsertypeRequest $request, int $id)
public function import(Request $request)
{ {
$file = $request->file('file'); $record = Usertype::query()->findOrFail($id);
if (!empty($file)) {
$data = Utils::csvToArray($file); $this->service->update($record, $request->validated());
$type = 1;
$msg = ''; return redirect()
$record = 0; ->route('usertypes.index')
DB::beginTransaction(); ->with('success', '更新が完了しました。');
try {
Usertype::query()->delete();
$col = 4;
foreach ($data as $key => $items) {
$record = $key + 2;
if (count($items) == $col) {
$row = new Usertype();
$row->user_categoryid = $items[0];
$row->print_name = $items[1];
$row->usertype_money = $items[2];
$row->usertype_remarks = $items[3];
if (!$row->save()) {
$type = 0;
$msg = '行:record型が一致しません。';
break;
}
} else {
$type = 0;
$msg = '行:record列数が一致しません。';
break;
}
}
} catch (\Exception $e) {
dd($e);
$msg = '行:record型が一致しません。';
$type = 0;
}
if ($type) {
DB::commit();
return redirect()->route('usertypes')->with('success', __('輸入成功'));
} else {
DB::rollBack();
return redirect()->route('usertypes')->with('error', __($msg, ['record' => $record]));
}
} else {
return redirect()->route('usertypes')->with('error', __('あなたはcsvファイルを選択していません。'));
}
} }
public function destroy(Request $request)
{
$ids = $request->input('pk', []);
if (!is_array($ids)) {
$ids = [$ids];
}
if ($ids === []) {
return redirect()
->route('usertypes.index')
->with('error', '削除対象を1件以上選択してください。');
}
Usertype::query()->whereIn('user_categoryid', $ids)->delete();
return redirect()
->route('usertypes.index')
->with('success', '削除が完了しました。');
}
} }

View File

@ -14,11 +14,31 @@ final class CityRequest extends FormRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'city_name' => ['required', 'string', 'max:20', 'regex:/^[^ -~。-゚]+$/u'], // 市区名:全角文字列 / 必須 / 1〜20文字
'print_layout' => ['required', 'string', 'max:255', 'regex:/^[A-Za-z0-9]+$/'], 'city_name' => [
'city_remarks' => ['nullable', 'string', 'max:255'], 'required',
'string',
'min:1',
'max:20',
'regex:/^[^ -~。-゚]+$/u',
],
// 印字レイアウトファイル:半角英数字 / 必須 / 1〜255文字
'print_layout' => [
'required',
'string',
'min:1',
'max:255',
'regex:/^[A-Za-z0-9]+$/',
],
// 備考:任意文字列 / 最大255
'city_remarks' => [
'nullable',
'string',
'max:255',
],
]; ];
} }

View File

@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ParkRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* add / edit 用的 validation
*/
public function rules(): array
{
if ($this->isMethod('post') || $this->isMethod('put')) {
return [
// 必須
'city_id' => ['required', 'integer'],
'park_name' => ['required', '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'],
// フラグ / 種別系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'], // 年跨ぎ
// 数値系
'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'], // 駐輪開始猶予期間
'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_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'], // 学生証確認種別
];
}
return [];
}
//
protected function prepareForValidation(): void
{
foreach ([
'park_available_time_from',
'park_available_time_to',
'park_manager_resident_from',
'park_manager_resident_to',
'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로 통일
}
}
}
/**
* add / edit payload
*/
public function payload(): array
{
return $this->validated();
}
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'),
];
}
}

View File

@ -0,0 +1,160 @@
<?php
declare(strict_types=1);
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
final class ReserveRequest extends FormRequest
{
public function rules(): array
{
$action = $this->routeAction();
if ($action === 'index') {
return [
'sort' => ['nullable', 'string'],
'sort_type' => ['nullable', 'in:asc,desc'],
'user_id' => ['nullable', 'string'],
'park_id' => ['nullable', 'integer'],
'reserve_date_from' => ['nullable', 'date'],
'reserve_date_to' => ['nullable', 'date'],
'keyword' => ['nullable', 'string'],
'valid_flag' => ['nullable', 'in:0,1'],
];
}
if ($action === 'destroy') {
return [
'ids' => ['required'],
];
}
if ($action === 'store') {
return [
'user_id' => ['required', 'integer'],
'park_id' => ['required', 'integer'],
'contract_id' => ['nullable', 'string'],
'price_parkplaceid' => ['nullable', 'integer'],
'psection_id' => ['nullable', 'integer'],
'reserve_date' => ['nullable', 'date'],
'valid_flag' => ['nullable', 'in:0,1'],
];
}
if ($action === 'update') {
return [
'user_id' => ['required', 'integer'],
'park_id' => ['required', 'integer'],
'contract_id' => ['nullable', 'string'],
'price_parkplaceid' => ['nullable', 'integer'],
'psection_id' => ['nullable', 'integer'],
'reserve_date' => ['nullable', 'date'],
'reserve_start' => ['nullable', 'date'],
'reserve_end' => ['nullable', 'date'],
'valid_flag' => ['nullable', 'in:0,1'],
'ope_id' => ['nullable', 'integer'],
];
}
// create/edit 등 “画面表示だけ” 는 검증 불필요
return [];
}
/**
* Why: Controller/Service 에서 공통으로 쓰는 입력 정규화.
*/
public function payload(): array
{
$action = $this->routeAction();
if ($action === 'index') {
return [
'sort' => (string) $this->input('sort', 'reserve_id'),
'sortType' => (string) $this->input('sort_type', 'asc'),
'userId' => trim((string) $this->input('user_id', '')),
'parkId' => $this->filled('park_id') ? (int) $this->input('park_id') : null,
'fromDt' => $this->input('reserve_date_from'),
'toDt' => $this->input('reserve_date_to'),
'keyword' => trim((string) $this->input('keyword', '')),
'validFlag' => $this->filled('valid_flag') ? (string) $this->input('valid_flag') : null,
];
}
if ($action === 'destroy') {
return [
'ids' => $this->normalizeIds($this->input('ids')),
];
}
if ($action === 'store' || $action === 'update') {
return [
'contractId' => $this->input('contract_id'),
'userCategoryId' => $this->filled('user_categoryid') ? (int) $this->input('user_categoryid') : null,
'contractCreatedAt' => $this->input('contract_created_at'),
'userId' => (int) $this->input('user_id'),
'parkId' => (int) $this->input('park_id'),
'priceParkplaceId' => $this->filled('price_parkplaceid') ? (int) $this->input('price_parkplaceid') : null,
'psectionId' => $this->filled('psection_id') ? (int) $this->input('psection_id') : null,
'ptypeId' => $this->filled('ptype_id') ? (int) $this->input('ptype_id') : null,
'reserveDate' => $this->input('reserve_date'),
'reserveStart' => $this->input('reserve_start'),
'reserveEnd' => $this->input('reserve_end'),
'reserveReduction' => $this->input('reserve_reduction'),
'reserveAutoRemind' => $this->input('reserve_auto_remind'),
'reserveManualRemind' => $this->input('reserve_manual_remind'),
'flag800m' => $this->filled('800m_flag') ? (int) $this->input('800m_flag') : null,
'reserveCancelday' => $this->input('reserve_cancelday'),
'validFlag' => $this->filled('valid_flag') ? (int) $this->input('valid_flag') : null,
'reserveManual' => $this->filled('reserve_manual') ? (int) $this->input('reserve_manual') : null,
'reserveNotice' => $this->input('reserve_notice'),
'sentDate' => $this->input('sent_date'),
'reserveOrder' => $this->filled('reserve_order') ? (int) $this->input('reserve_order') : null,
'reserveType' => $this->filled('reserve_type') ? (int) $this->input('reserve_type') : null,
'opeId' => $this->filled('ope_id') ? (int) $this->input('ope_id') : null,
];
}
return [];
}
private function routeAction(): string
{
// routes: reserves.index / reserves.store / reserves.update / reserves.destroy ...
$name = (string) $this->route()?->getName();
if ($name === '') {
return '';
}
$parts = explode('.', $name);
return (string) end($parts);
}
private function normalizeIds(mixed $raw): array
{
if (is_string($raw)) {
$raw = explode(',', $raw);
}
if (is_array($raw) && count($raw) === 1 && is_string($raw[0]) && str_contains($raw[0], ',')) {
$raw = explode(',', $raw[0]);
}
$ids = array_map('intval', (array) $raw);
$ids = array_values(array_unique(array_filter($ids, static fn (int $v): bool => $v > 0)));
return $ids;
}
}

View File

@ -0,0 +1,91 @@
<?php
declare(strict_types=1);
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
final class UsertypeRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
// ソートオーダー:数値 / 必須
'sort_order' => [
'required',
'integer',
],
// 分類名1文字列 / 必須 / 最大10文字
'usertype_subject1' => [
'required',
'string',
'min:1',
'max:10',
],
// 分類名2文字列 / 必須 / 最大10文字
'usertype_subject2' => [
'required',
'string',
'min:1',
'max:10',
],
// 分類名3文字列 / 任意 / 最大10文字
'usertype_subject3' => [
'nullable',
'string',
'max:10',
],
// 印字名:文字列 / 任意 / 最大20文字
'print_name' => [
'nullable',
'string',
'max:20',
],
// 適用料率:文字列 / 任意 / 最大10文字
'usertype_money' => [
'nullable',
'string',
'max:10',
],
// 備考:文字列 / 任意 / 最大85文字
'usertype_remarks' => [
'nullable',
'string',
'max:85',
],
];
}
public function messages(): array
{
return [
'sort_order.required' => 'ソートオーダーは必須です。',
'sort_order.integer' => 'ソートオーダーは数値で入力してください。',
'usertype_subject1.required' => '分類名1は必須です。',
'usertype_subject1.max' => '分類名1は10文字以内で入力してください。',
'usertype_subject2.required' => '分類名2は必須です。',
'usertype_subject2.max' => '分類名2は10文字以内で入力してください。',
'usertype_subject3.max' => '分類名3は10文字以内で入力してください。',
'print_name.max' => '印字名は20文字以内で入力してください。',
'usertype_money.max' => '適用料率は10文字以内で入力してください。',
'usertype_remarks.max' => '備考は85文字以内で入力してください。',
];
}
}

View File

@ -28,45 +28,55 @@ class Park extends Model
'alert_flag', // 残警告チェックフラグ 'alert_flag', // 残警告チェックフラグ
'print_number', // 印字数 'print_number', // 印字数
'keep_alive', // 最新キープアライブ 'keep_alive', // 最新キープアライブ
'renew_start_date', // 更新期間開始日
'renew_start_time', // 更新期間開始時 'update_grace_period_start_date', // 更新期間開始日
'renew_end_date', // 更新期間終了日 'update_grace_period_start_time', // 更新期間開始時
'renew_end_time', // 更新期間終了時 'update_grace_period_end_date', // 更新期間終了日
'parking_start_period', // 駐輪開始期間 'update_grace_period_end_time', // 更新期間終了時
'parking_start_grace_period', // 駐輪開始猶予期間
'reminder_type', // リマインダー種別 'reminder_type', // リマインダー種別
'reminder_time', // リマインダー時間 'reminder_time', // リマインダー時間
'immediate_use_after_contract', // 契約後即利用許可 'immediate_use_permit', // 契約後即利用許可
'display_gender', // 項目表示設定:性別 'gender_display_flag', // 項目表示設定:性別
'display_birthday', // 項目表示設定:生年月日 'bd_display_flag', // 項目表示設定:生年月日
'display_security_registration_number', // 項目表示設定:防犯登録番号 'securityreg_display_flag', // 項目表示設定:防犯登録番号
'distance_between_two_points', // 二点間距離 'distance_twopoints', // 二点間距離
'latitude', // 駐車場座標(緯度)
'longitude', // 駐車場座標(経度) 'park_latitude', // 駐車場座標(緯度)
'phone_number', // 電話番号 'park_longitude', // 駐車場座標(経度)
'contract_type_regular', // 駐輪場契約形態(定期) 'park_tel', // 電話番号
'contract_type_temporary', // 駐輪場契約形態(一時利用) 'park_fixed_contract', // 駐輪場契約形態(定期)
'vehicle_type_limit', // 車種制限 'park_temporary_contract', // 駐輪場契約形態(一時利用)
'procedure_method', // 手続方法 'park_restriction', // 車種制限
'payment_method', // 支払方法 'park_procedure', // 手続方法
'usage_time_limit_flag', // 利用可能時間制限フラグ 'park_payment', // 支払方法
'usage_time_start', // 利用可能時間(開始)
'usage_time_end', // 利用可能時間(終了) 'park_available_time_flag', // 利用可能時間制限フラグ
'resident_manager_flag', // 常駐管理人フラグ 'park_available_time_from', // 利用可能時間(開始)
'resident_time_start', // 常駐時間(開始) 'park_available_time_to', // 利用可能時間(終了)
'resident_time_end', // 常駐時間(終了) 'park_manager_flag', // 常駐管理人フラグ
'roof_flag', // 屋根フラグ 'park_manager_resident_from', // 常駐時間(開始)
'seal_issuing_machine_flag', // シール発行機フラグ 'park_manager_resident_to', // 常駐時間(終了)
'usage_method', // 駐輪場利用方法 'park_roof_flag', // 屋根フラグ
'periodic_update_period', // 定期更新期間
'waiting_reservation', // 空き待ち予約 'park_issuing_machine_flag', // シール発行機フラグ
'special_notes', // 特記事項 'park_using_method', // 駐輪場利用方法
'park_contract_renewal_term', // 定期更新期間
'park_reservation', // 空き待ち予約
'park_reference', // 特記事項
'student_id_confirmation_type', // 学生証確認種別 'student_id_confirmation_type', // 学生証確認種別
'reduction_guide_display_flag', // 減免案内表示フラグ 'reduction_guide_display_flag', // 減免案内表示フラグ
'reduction_target_age', // 減免対象年齢 'reduction_age', // 減免対象年齢
'reduction_guide_display_start_month', // 減免案内表示開始月数 'reduction_guide_display_start_month', // 減免案内表示開始月数
'cross_year', // 年跨ぎ 'overyear_flag', // 年跨ぎ
'reverse_use_general', // 逆利用一般 'inverse_use_flag1', // 逆利用一般
'reverse_use_student' // 逆利用学生 'inverse_use_flag2', // 逆利用学生
'parking_regulations_flag' // 駐輪規定フラグ
]; ];
public static function search($inputs) public static function search($inputs)

View File

@ -0,0 +1,199 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\Park;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
class ParkService
{
public function paginate(array $filters, int $perPage = 20): LengthAwarePaginator
{
$query = DB::table('park as p')
->leftJoin('city as c', 'p.city_id', '=', 'c.city_id')
->select([
'p.*',
'c.city_name',
]);
if (!empty($filters['park_name'])) {
$query->where('p.park_name', 'like', '%' . (string) $filters['park_name'] . '%');
}
if (!empty($filters['city_id'])) {
$query->where('p.city_id', (int) $filters['city_id']);
}
$sort = (string) ($filters['sort'] ?? '');
$sortType = (string) ($filters['sort_type'] ?? 'asc');
if ($sort === '') {
$sort = 'p.park_id';
}
$allowedSorts = [
'p.park_id',
'p.park_name',
'p.city_id',
'p.updated_at',
'c.city_name',
];
if (!in_array($sort, $allowedSorts, true)) {
$sort = 'p.park_id';
}
if (!in_array($sortType, ['asc', 'desc'], true)) {
$sortType = 'asc';
}
$query->orderBy($sort, $sortType);
return $query->paginate($perPage)->appends([
'park_name' => $filters['park_name'] ?? null,
'city_id' => $filters['city_id'] ?? null,
'sort' => $sort,
'sort_type' => $sortType,
]);
}
public function findOrFail(int $parkId): Park
{
$park = Park::find($parkId);
if (!$park) {
throw new ModelNotFoundException();
}
return $park;
}
public function create(array $payload, int $operatorId): Park
{
return DB::transaction(function () use ($payload, $operatorId) {
$park = new Park();
$park->fill($payload);
$park->operator_id = $operatorId;
$park->save();
return $park;
});
}
public function update(Park $park, array $payload, int $operatorId): Park
{
return DB::transaction(function () use ($park, $payload, $operatorId) {
$park->fill($payload);
$park->operator_id = $operatorId;
$park->save();
return $park;
});
}
public function deleteByIds(array $ids): bool
{
return (bool) Park::destroy($ids);
}
public function exportRows(): Collection
{
return DB::table('park as p')
->select([
'p.park_id',
'p.city_id',
'p.park_name',
'p.park_ruby',
'p.park_syllabary',
'p.park_adrs',
'p.park_close_flag',
'p.park_day',
'p.alert_flag',
'p.print_number',
'p.keep_alive',
'p.operator_id',
'p.update_grace_period_start_date',
'p.update_grace_period_start_time',
'p.update_grace_period_end_date',
'p.update_grace_period_end_time',
'p.parking_start_grace_period',
'p.reminder_type',
'p.reminder_time',
'p.immediate_use_permit',
'p.gender_display_flag',
'p.bd_display_flag',
'p.securityreg_display_flag',
'p.distance_twopoints',
'p.park_latitude',
'p.park_longitude',
'p.park_tel',
'p.park_fixed_contract',
'p.park_temporary_contract',
'p.park_restriction',
'p.park_procedure',
'p.park_payment',
'p.park_available_time_flag',
'p.park_available_time_from',
'p.park_available_time_to',
'p.park_manager_flag',
'p.park_manager_resident_from',
'p.park_manager_resident_to',
'p.park_roof_flag',
'p.park_issuing_machine_flag',
'p.park_using_method',
'p.park_contract_renewal_term',
'p.park_reservation',
'p.park_reference',
'p.student_id_confirm_type',
'p.reduction_guide_display_flag',
'p.reduction_age',
'p.reduction_guide_display_start_month',
'p.overyear_flag',
])
->orderBy('p.park_id', 'asc')
->get();
}
public function importCsv(UploadedFile $file): void
{
$data = \App\Utils::csvToArray($file);
DB::transaction(function () use ($data) {
Park::query()->delete();
$expectedCols = 13;
foreach ($data as $index => $items) {
if (count($items) !== $expectedCols) {
throw new \RuntimeException('列数が一致しません。line=' . ($index + 2));
}
$row = new Park();
$row->park_id = $items[0];
$row->city_id = $items[1];
$row->park_name = $items[3];
$row->park_ruby = $items[4];
$row->park_syllabary = $items[5];
$row->park_adrs = $items[6];
$row->park_close_flag = $items[7];
$row->park_day = $items[9];
$row->alert_flag = $items[10];
$row->print_number = $items[11];
$row->keep_alive = $items[12];
$row->save();
}
});
}
public function checkDuplicateByName(string $parkName): ?Park
{
return Park::where('park_name', $parkName)->first();
}
}

View File

@ -0,0 +1,510 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\Park;
use App\Models\Price;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use RuntimeException;
final class ReserveService
{
/**
* 一覧取得(検索+ページング)
* Why: Controller を薄くするため、クエリ構築をここに集約する。
*
* @return array{list: LengthAwarePaginator, sort: string, sort_type: string, user_id: string, park_id: ?int, reserve_date_from: mixed, reserve_date_to: mixed, keyword: string, valid_flag: ?string, parkOptions: array}
*/
public function paginate(array $payload): array
{
$sort = $this->normalizeSort((string) $payload['sort'], $this->sortableKeys());
$sortType = $this->normalizeSortType((string) $payload['sortType']);
$q = $this->baseQuery();
$this->applyFilters($q, $payload);
$this->applySort($q, $sort, $sortType);
$parkOptions = Park::query()
->orderBy('park_id', 'asc')
->pluck('park_name', 'park_id')
->toArray();
$list = $q->paginate(50);
$this->attachPriceNames($list);
return [
'list' => $list,
'sort' => $sort,
'sort_type' => $sortType,
'user_id' => (string) $payload['userId'],
'park_id' => $payload['parkId'],
'reserve_date_from' => $payload['fromDt'],
'reserve_date_to' => $payload['toDt'],
'keyword' => (string) $payload['keyword'],
'valid_flag' => $payload['validFlag'],
'parkOptions' => $parkOptions,
];
}
/**
* 新規画面用のプルダウンなど。
*/
public function getFormOptions(): array
{
$userTypes = DB::table('usertype')
->orderBy('user_categoryid', 'asc')
->get([
'user_categoryid',
'usertype_subject1',
'usertype_subject2',
'usertype_subject3',
])
->map(function (object $row): object {
$labels = array_filter([
$row->usertype_subject1,
$row->usertype_subject2,
$row->usertype_subject3,
], static fn ($v): bool => $v !== null && $v !== '');
$row->display_name = $labels ? implode('/', $labels) : '';
return $row;
});
$parks = Park::query()
->orderBy('park_id', 'asc')
->get(['park_id', 'park_name']);
$priceOptions = $this->getUnifiedPriceOptions();
return [
'userTypes' => $userTypes,
'parks' => $parks,
'priceOptions' => $priceOptions,
];
}
/**
* 新規画面用:プルダウン等
*/
public function getCreateForm(): array
{
$userOptions = DB::table('user')
->orderBy('user_id', 'asc')
->limit(5000)
->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id')
->toArray();
$parkOptions = DB::table('park')
->orderBy('park_id', 'asc')
->pluck('park_name', 'park_id')
->toArray();
$userTypeOptions = DB::table('usertype')
->orderBy('user_categoryid')
->select([
'user_categoryid',
DB::raw("
COALESCE(
NULLIF(TRIM(CONCAT_WS('/',
NULLIF(TRIM(usertype_subject1), ''),
NULLIF(TRIM(usertype_subject2), ''),
NULLIF(TRIM(usertype_subject3), '')
)), ''),
print_name
) AS label
")
])
->pluck('label', 'user_categoryid')
->toArray();
$priceOptions = Schema::hasTable('price')
? DB::table('price')
->orderBy('price_parkplaceid')
->pluck('prine_name', 'price_parkplaceid')
->toArray()
: [];
$psectionOptions = Schema::hasTable('psection')
? DB::table('psection')
->orderBy('psection_id')
->pluck(
Schema::hasColumn('psection', 'psection_subject') ? 'psection_subject' : 'psection_id',
'psection_id'
)
->toArray()
: [];
$ptypeOptions = Schema::hasTable('ptype')
? DB::table('ptype')
->orderBy('ptype_id')
->pluck(
Schema::hasColumn('ptype', 'ptype_subject') ? 'ptype_subject' : 'ptype_id',
'ptype_id'
)
->toArray()
: [];
return [
'userOptions' => $userOptions,
'parkOptions' => $parkOptions,
'userTypeOptions' => $userTypeOptions,
'priceOptions' => $priceOptions,
'psectionOptions' => $psectionOptions,
'ptypeOptions' => $ptypeOptions,
];
}
/**
* 編集画面用:対象レコード+プルダウン
*/
public function getEditForm(int $reserveId): array
{
$row = DB::table('reserve')->where('reserve_id', $reserveId)->first();
if ($row === null) {
abort(404);
}
$userOptions = DB::table('user')
->orderBy('user_id', 'asc')
->limit(5000)
->pluck(DB::raw("concat(user_id, ' ', user_name)"), 'user_id')
->toArray();
$parkOptions = DB::table('park')
->orderBy('park_id', 'asc')
->pluck('park_name', 'park_id')
->toArray();
$userTypeOptions = DB::table('usertype')
->orderBy('user_categoryid')
->select([
'user_categoryid',
DB::raw("
COALESCE(
NULLIF(TRIM(CONCAT_WS('/',
NULLIF(TRIM(usertype_subject1), ''),
NULLIF(TRIM(usertype_subject2), ''),
NULLIF(TRIM(usertype_subject3), '')
)), ''),
print_name
) AS label
")
])
->pluck('label', 'user_categoryid')
->toArray();
$priceOptions = Schema::hasTable('price')
? DB::table('price')
->orderBy('price_parkplaceid')
->pluck('prine_name', 'price_parkplaceid')
->toArray()
: [];
$psectionOptions = Schema::hasTable('psection')
? DB::table('psection')
->orderBy('psection_id')
->pluck(
Schema::hasColumn('psection', 'psection_subject') ? 'psection_subject' : 'psection_id',
'psection_id'
)
->toArray()
: [];
$ptypeOptions = Schema::hasTable('ptype')
? DB::table('ptype')
->orderBy('ptype_id')
->pluck(
Schema::hasColumn('ptype', 'ptype_subject') ? 'ptype_subject' : 'ptype_id',
'ptype_id'
)
->toArray()
: [];
return [
'row' => $row,
'userOptions' => $userOptions,
'parkOptions' => $parkOptions,
'userTypeOptions' => $userTypeOptions,
'priceOptions' => $priceOptions,
'psectionOptions' => $psectionOptions,
'ptypeOptions' => $ptypeOptions,
];
}
/**
* 更新
*/
public function update(int $reserveId, array $payload): void
{
$exists = DB::table('reserve')->where('reserve_id', $reserveId)->exists();
if (!$exists) {
abort(404);
}
$data = [
'user_categoryid' => $payload['userCategoryId'],
'contract_id' => $payload['contractId'],
'contract_created_at' => $payload['contractCreatedAt'],
'user_id' => $payload['userId'],
'park_id' => $payload['parkId'],
'price_parkplaceid' => $payload['priceParkplaceId'],
'psection_id' => $payload['psectionId'],
'ptype_id' => $payload['ptypeId'],
'reserve_date' => $payload['reserveDate'],
'reserve_start' => $payload['reserveStart'],
'reserve_end' => $payload['reserveEnd'],
'valid_flag' => $payload['validFlag'],
'reserve_reduction' => $payload['reserveReduction'],
'reserve_auto_remind' => $payload['reserveAutoRemind'],
'reserve_manual_remind' => $payload['reserveManualRemind'],
'800m_flag' => $payload['flag800m'],
'reserve_cancelday' => $payload['reserveCancelday'],
'reserve_manual' => $payload['reserveManual'],
'reserve_notice' => $payload['reserveNotice'],
'reserve_type' => $payload['reserveType'],
'sent_date' => $payload['sentDate'],
'reserve_order' => $payload['reserveOrder'],
'ope_id' => $payload['opeId'],
'updated_at' => now(),
];
DB::table('reserve')
->where('reserve_id', $reserveId)
->update($data);
}
/**
* 複数削除
*
* @return int 削除件数
*/
public function deleteMany(array $ids): int
{
if ($ids === []) {
return 0;
}
return (int) DB::table('reserve')
->whereIn('reserve_id', $ids)
->delete();
}
private function baseQuery(): Builder
{
return DB::table('reserve as r')
->leftJoin('user as u', 'u.user_id', '=', 'r.user_id')
->leftJoin('park as p', 'p.park_id', '=', 'r.park_id')
->leftJoin('psection as ps', 'ps.psection_id', '=', 'r.psection_id')
->leftJoin('ptype as pt', 'pt.ptype_id', '=', 'r.ptype_id')
->leftJoin('usertype as t', 't.user_categoryid', '=', 'r.user_categoryid')
->select([
'r.reserve_id',
'r.contract_id',
'r.contract_created_at',
'r.user_categoryid',
'r.user_id',
'r.park_id',
'r.price_parkplaceid',
'r.psection_id',
'r.ptype_id',
'r.reserve_date',
'r.reserve_reduction',
'r.reserve_auto_remind',
'r.reserve_manual_remind',
DB::raw('r.`800m_flag` as flag_800m'),
'r.reserve_cancelday',
'r.valid_flag',
'r.ope_id',
'r.reserve_manual',
'r.reserve_notice',
'r.sent_date',
'r.reserve_order',
'r.reserve_type',
DB::raw('u.user_name as user_name'),
DB::raw('p.park_name as park_name'),
DB::raw('ps.psection_subject as psection_subject'),
DB::raw('pt.ptype_subject as ptype_subject'),
DB::raw('t.usertype_subject1 as usertype_subject1'),
DB::raw('t.usertype_subject2 as usertype_subject2'),
DB::raw('t.usertype_subject3 as usertype_subject3'),
]);
}
private function applyFilters(Builder $q, array $payload): void
{
if ($payload['userId'] !== '') {
$q->where('r.user_id', 'like', '%' . $payload['userId'] . '%');
}
if ($payload['parkId'] !== null) {
$q->where('r.park_id', '=', $payload['parkId']);
}
if (!empty($payload['fromDt'])) {
$q->whereDate('r.reserve_date', '>=', $payload['fromDt']);
}
if (!empty($payload['toDt'])) {
$q->whereDate('r.reserve_date', '<=', $payload['toDt']);
}
if ($payload['keyword'] !== '') {
$keyword = $payload['keyword'];
$q->where(function (Builder $w) use ($keyword): void {
$w->where('u.user_name', 'like', '%' . $keyword . '%')
->orWhere('u.user_phonetic', 'like', '%' . $keyword . '%');
});
}
if (in_array($payload['validFlag'], ['0', '1'], true)) {
$q->where('r.valid_flag', '=', (int) $payload['validFlag']);
}
}
private function applySort(Builder $q, string $sort, string $sortType): void
{
$sortMap = [
'reserve_id' => DB::raw('r.reserve_id'),
'contract_id' => DB::raw('r.contract_id'),
'contract_created_at' => DB::raw('r.contract_created_at'), //
'user_categoryid' => DB::raw('r.user_categoryid'),
'user_id' => DB::raw('r.user_id'),
'reserve_date' => DB::raw('r.reserve_date'),
'park_name' => DB::raw('p.park_name'),
'price_parkplaceid' => DB::raw('r.price_parkplaceid'),
'psection_subject' => DB::raw('ps.psection_subject'),
'ptype_subject' => DB::raw('pt.ptype_subject'),
'reserve_reduction' => DB::raw('r.reserve_reduction'),
'reserve_auto_remind' => DB::raw('r.reserve_auto_remind'),
'reserve_manual_remind' => DB::raw('r.reserve_manual_remind'),
'flag_800m' => DB::raw('r.`800m_flag`'), //
'reserve_cancelday' => DB::raw('r.reserve_cancelday'),
'valid_flag' => DB::raw('r.valid_flag'),
'sent_date' => DB::raw('r.sent_date'),
'reserve_manual' => DB::raw('r.reserve_manual'),
'reserve_notice' => DB::raw('r.reserve_notice'),
'reserve_order' => DB::raw('r.reserve_order'),
'reserve_type' => DB::raw('r.reserve_type'), //
];
if (!isset($sortMap[$sort])) {
return;
}
$q->orderBy($sortMap[$sort], $sortType);
}
private function sortableKeys(): array
{
return [
'reserve_id',
'contract_id',
'contract_created_at',
'user_categoryid',
'user_id',
'reserve_date',
'park_name',
'price_parkplaceid',
'psection_subject',
'ptype_subject',
'reserve_reduction',
'reserve_auto_remind',
'reserve_manual_remind',
'flag_800m',
'reserve_cancelday',
'valid_flag',
'sent_date',
'reserve_manual',
'reserve_notice',
'reserve_order',
'reserve_type',
];
}
private function normalizeSort(string $sort, array $sortable): string
{
return in_array($sort, $sortable, true) ? $sort : 'reserve_id';
}
private function normalizeSortType(string $sortType): string
{
$sortType = strtolower($sortType);
return $sortType === 'desc' ? 'desc' : 'asc';
}
private function attachPriceNames(LengthAwarePaginator $list): void
{
$placeIds = $list->getCollection()
->pluck('price_parkplaceid')
->filter()
->unique()
->values()
->all();
if ($placeIds === []) {
return;
}
$priceNames = Price::query()
->whereIn('price_parkplaceid', $placeIds)
->pluck('prine_name', 'price_parkplaceid')
->toArray();
$list->setCollection(
$list->getCollection()->map(function (object $row) use ($priceNames): object {
$id = $row->price_parkplaceid ?? null;
$row->display_prine_name = ($id !== null && array_key_exists($id, $priceNames))
? $priceNames[$id]
: null;
return $row;
})
);
}
private function getUnifiedPriceOptions()
{
return Price::query()
->select('price_parkplaceid', 'prine_name')
->get()
->sortBy('price_parkplaceid', SORT_NATURAL)
->unique('price_parkplaceid')
->values();
}
}

View File

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace App\Services;
use App\Models\Usertype;
use App\Utils;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
final class UsertypeService
{
public function paginateList(
?string $sortOrder,
?string $subject1,
?string $subject2,
?string $subject3,
string $sort,
string $sortType
): LengthAwarePaginator {
$query = Usertype::query();
if ($sortOrder !== null && $sortOrder !== '') {
// sort_order は数値想定だが、まずは部分一致せず完全一致で
$query->where('sort_order', $sortOrder);
}
if ($subject1 !== null && $subject1 !== '') {
$query->where('usertype_subject1', 'like', '%' . $subject1 . '%');
}
if ($subject2 !== null && $subject2 !== '') {
$query->where('usertype_subject2', 'like', '%' . $subject2 . '%');
}
if ($subject3 !== null && $subject3 !== '') {
$query->where('usertype_subject3', 'like', '%' . $subject3 . '%');
}
$query->orderBy($sort, $sortType);
return $query->paginate(Utils::item_per_page);
}
public function create(array $validated): Usertype
{
return Usertype::create($this->payload($validated));
}
public function update(Usertype $usertype, array $validated): Usertype
{
$usertype->fill($this->payload($validated));
$usertype->save();
return $usertype;
}
private function payload(array $validated): array
{
return [
'sort_order' => $validated['sort_order'],
'usertype_subject1' => $validated['usertype_subject1'],
'usertype_subject2' => $validated['usertype_subject2'],
'usertype_subject3' => $validated['usertype_subject3'] ?? null,
'print_name' => $validated['print_name'] ?? null,
'usertype_money' => $validated['usertype_money'] ?? null,
'usertype_remarks' => $validated['usertype_remarks'] ?? null,
];
}
}

View File

@ -11,7 +11,6 @@
<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>
<!-- <li class="breadcrumb-item"><a href="javascript:void(0);">[東京都|〇〇駐輪場]</a></li> -->
<li class="breadcrumb-item active">オペレータマスタ</li> <li class="breadcrumb-item active">オペレータマスタ</li>
</ol> </ol>
</div> </div>
@ -32,6 +31,8 @@
<div class="container-fluid mb20"> <div class="container-fluid mb20">
<button type="button" class="btn btn-sm btn-default mr10" onclick="location.href='{{ route('opes_add') }}'">新規</button> <button type="button" class="btn btn-sm btn-default mr10" onclick="location.href='{{ route('opes_add') }}'">新規</button>
<button type="button" class="btn btn-sm btn-default mr10" id="delete">削除</button> <button type="button" class="btn btn-sm btn-default mr10" id="delete">削除</button>
<button type="button" class="btn btn-sm btn-default mr10" id="import">インポート</button>
<button type="button" class="btn btn-sm btn-default mr10" id="export">CSV出力</button>
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
{{ $list->appends(['sort' => $sort, 'sort_type' => $sort_type])->links('pagination') }} {{ $list->appends(['sort' => $sort, 'sort_type' => $sort_type])->links('pagination') }}

File diff suppressed because it is too large Load Diff

View File

@ -1,169 +0,0 @@
@extends('layouts.app')
@section('title', '駐輪場マスタ 新規')
@section('content')
<div class="container-fluid page-park py-3">
{{-- 成功メッセージ表示 --}}
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
{{-- パンくず --}}
<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>
{{-- 本体フォーム(白背景のカード) --}}
<form id="park-add-form" method="POST" action="{{ route('parks.store') }}" enctype="multipart/form-data"
class="card card-body form-card">
@csrf
@include('admin.parks._form')
<div class="form-footer mt-3 pt-2">
<button type="button" id="register-btn" class="btn btn-default">登録</button>
<a href="{{ route('parks') }}" class="btn btn-default">戻る</a>
</div>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<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/dist/jquery-confirm.min.js"></script>
@push('scripts')
<script>
$(function () {
$('#register-btn').off('click.parkConfirm').on('click.parkConfirm', function (e) {
e.preventDefault();
const form = document.getElementById('park-add-form');
const formData = new FormData(form);
const submit = function () {
fetch('{{ route('parks.check_duplicate') }}', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': '{{ csrf_token() }}'
},
body: formData
})
.then(response => response.json())
.then(data => {
if (data.duplicate) {
$.alert({
title: '重複エラー',
content: '登録内容に重複があります。<br>重複駐輪場ID' + data.park_id + '<br>駐輪場名:' + data.park_name
});
} else {
form.submit();
}
})
.catch(() => {
$.alert({
title: 'エラー',
content: '重複チェックに失敗しました。'
});
});
};
if ($.confirm) {
$.confirm({
title: '確認ダイアログ',
content: '登録してよろしいですか? はい/いいえ',
buttons: {
ok: {
text: 'はい',
btnClass: 'btn-primary',
action: function () {
form.requestSubmit();
}
},
いいえ: function () { }
}
});
} else if (window.confirm('登録してよろしいですか?')) {
form.requestSubmit();
}
});
});
</script>
@endpush
<style>
.page-park {
background: #f4f6f9;
}
.form-card {
border: 1px solid #e5e7eb;
box-shadow: 0 1px 1px rgba(0, 0, 0, .04)
}
.screen-toolbar {
display: flex;
justify-content: space-between;
align-items: center
}
.screen-toolbar .btn {
border-radius: 3px;
padding: .35rem .7rem
}
.screen-toolbar .btn-light {
background: #fff;
border: 1px solid #dcdfe3;
color: #333
}
.form-group {
margin-bottom: .6rem
}
.col-form-label {
padding-top: .55rem;
font-weight: 600
}
.req:after {
content: " *";
color: #dc3545
}
input.form-control,
select.form-control {
height: 34px;
padding: .25rem .5rem
}
textarea.form-control {
min-height: 72px
}
.img-thumbnail {
border: 1px dashed #d0d7de;
background: repeating-linear-gradient(45deg, #fafafa, #fafafa 8px, #f3f4f6 8px, #f3f4f6 16px)
}
.form-footer {
border-top: 1px dashed #e9ecef
}
</style>
@endsection

View File

@ -0,0 +1,54 @@
@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">
<a href="{{ route('parks.index') }}">駐輪場マスタ</a>
</li>
<li class="breadcrumb-item active">新規</li>
</ol>
</div>
</div>
</div>
</div>
<!-- Main content -->
<section class="content">
<div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<div class="card">
{{-- 新規登録フォーム --}}
<form id="form_add"
method="POST"
action="{{ route('parks.store') }}?back={{ urlencode(request()->get('back', request()->fullUrl())) }}"
enctype="multipart/form-data">
@csrf
@include('admin.parks._form', [
'isEdit' => false
])
</form>
</div>
</div>
</div>
</div>
</section>
@endsection

View File

@ -1,9 +1,9 @@
@extends('layouts.app') @extends('layouts.app')
@section('title', '駐輪場マスタ 編集') @section('title', '編集')
@section('content') @section('content')
{{-- パンくず --}} <!-- Content Header -->
<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">
@ -11,67 +11,50 @@
</div> </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">
<li class="breadcrumb-item"><a href="{{ route('parks') }}">駐輪場マスタ</a></li> <a href="{{ route('home') }}">ホーム</a>
</li>
<li class="breadcrumb-item">
<a href="{{ route('parks.index') }}">駐輪場マスタ</a>
</li>
<li class="breadcrumb-item active">編集</li> <li class="breadcrumb-item active">編集</li>
</ol> </ol>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{{-- 編集フォーム --}} <!-- Main content -->
<div class="card shadow"> <section class="content">
<form id="park-edit-form" method="POST" action="{{ route('parks.update', $park->park_id) }}" enctype="multipart/form-data"> <div class="container-fluid">
<div class="row">
<div class="col-lg-12">
<div class="card">
{{-- 編集フォーム --}}
<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 @csrf
@method('PUT')
<div class="card-header"> @include('admin.parks._form', [
{{-- ボタンエリア(上部) --}} 'record' => $record,
<div class="mt-2"> 'isEdit' => true
<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="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> </form>
</div> {{-- 削除フォームhidden --}}
<form id="form_delete" method="POST" action="{{ route('parks.destroy') }}" class="d-none">
@csrf
<input type="hidden" name="pk[]" value="{{ $record->park_id }}">
</form>
<!-- jQuery --> </div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> </div>
</div>
<!-- jQuery Confirm --> </div>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-confirm@3.3.4/css/jquery-confirm.min.css"> </section>
<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>
@endsection @endsection

View File

@ -0,0 +1,345 @@
@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>
{{-- 絞り込みフィルター --}}
<div class="card mb-3">
<div class="card-body">
<form method="GET" action="{{ route('parks.index') }}" id="filter-form">
<div class="row">
{{-- 駐輪場名 --}}
<div class="col-md-6">
<div class="form-group row mb-2">
<label class="col-md-4 col-form-label font-weight-bold">
駐輪場名
</label>
<div class="col-md-8">
<input type="text"
name="park_name"
class="form-control"
placeholder="キーワード..."
value="{{ request('park_name') }}">
</div>
</div>
</div>
{{-- 市区 --}}
<div class="col-md-6">
<div class="form-group row mb-2">
<label class="col-md-4 col-form-label font-weight-bold">
市区
</label>
<div class="col-md-8">
<select name="city_id" class="form-control">
<option value="">市町村を選択してください</option>
@foreach($cities as $city)
<option value="{{ $city->city_id }}"
@selected(request('city_id') == $city->city_id)>
{{ $city->city_name }}
</option>
@endforeach
</select>
</div>
</div>
</div>
</div>
{{-- ボタン --}}
<div class="mt-2">
<button type="submit" class="btn btn-success mr-2">
絞り込み
</button>
<a href="{{ route('parks.index') }}" class="btn btn-outline-secondary">
解除
</a>
</div>
</form>
</div>
</div>
{{-- 絞り込みフィルター --}}
<section class="content">
<div class="container-fluid">
{{-- 並び替え用 hidden --}}
<form method="GET" action="{{ route('parks.index') }}" 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>
{{-- ボタンエリア --}}
<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()) }}'">
新規
</button>
<button type="button" class="btn btn-sm btn-danger mr10" id="delete">
削除
</button>
</div>
{{-- ページネーション --}}
<div class="col-lg-12 px-0">
<div class="d-flex flex-column align-items-end mb-2 text-sm">
{{-- 件数表示(上) --}}
<div class="text-dark text-sm mb-1">
@if ($parks->total() > 0)
{{ $parks->total() }} 件中 {{ $parks->firstItem() }}{{ $parks->lastItem() }} 件を表示
@else
全0件
@endif
</div>
{{-- ページネーション(下) --}}
<div>
{{ $parks->appends([
'sort' => $sort ?? '',
'sort_type' => $sort_type ?? '',
] + request()->except('page'))->links('pagination') }}
</div>
</div>
</div>
{{-- フラッシュメッセージ --}}
<div class="col-lg-12 px-0">
@if(Session::has('success'))
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ Session::get('success') }}
</div>
@elseif(Session::has('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{!! Session::get('error') !!}
</div>
@endif
</div>
{{-- テーブル --}}
<div class="col-lg-12 mb20 px-0">
<div class="table-responsive">
<form id="form_delete" method="POST" action="{{ route('parks.destroy') }}">
@csrf
<table class="table table-bordered dataTable text-nowrap">
<thead class="thead-light">
<tr>
<th style="width:140px;">
<input type="checkbox"
class="js-check-all"
onclick="$('input[name*=\'pk\']').prop('checked', this.checked);">
</th>
<th class="sorting {{ ($sort ?? '') === 'p.park_id'
? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc')
: '' }}"
sort="p.park_id">
<span>駐輪場ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'c.city_name'
? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc')
: '' }}"
sort="c.city_name">
<span>市区</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'p.park_name'
? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc')
: '' }}"
sort="p.park_name">
<span>駐輪場名</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'p.park_ruby'
? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc')
: '' }}"
sort="p.park_ruby">
<span>駐輪場ふりがな</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'p.park_syllabary'
? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc')
: '' }}"
sort="p.park_syllabary">
<span>駐輪場五十音</span>
</th>
<th>住所</th>
<th>閉設状態</th>
<th>閉設日</th>
<th>価格メモ</th>
<th>残警告チェックフラグ</th>
<th>印字数</th>
<th>最新キープアライブ</th>
<th>更新期間開始日</th>
<th>更新期間開始時</th>
<th>更新期間終了日</th>
<th>更新期間終了時</th>
<th>駐輪開始期間</th>
<th>リマインダー種別</th>
<th>リマインダー時間</th>
<th>契約後即利用許可</th>
<th>項目表示設定:性別</th>
<th>項目表示設定:生年月日</th>
<th>項目表示設定:防犯登録番号</th>
<th>二点間距離</th>
<th>駐車場座標(緯度)</th>
<th>駐車場座標(経度)</th>
<th>電話番号</th>
<th>駐輪場契約形態(定期)</th>
<th>駐輪場契約形態(一時利用)</th>
<th>車種制限</th>
<th>手続方法</th>
<th>支払方法</th>
<th>利用時間制限フラグ</th>
<th>利用可能時間(開始)</th>
<th>利用可能時間(終了)</th>
<th>常駐管理人フラグ</th>
<th>常駐時間(開始)</th>
<th>常駐時間(終了)</th>
<th>屋根フラグ</th>
<th>シール機フラグ</th>
<th>駐輪場利用方法</th>
<th>定期更新期間</th>
<th>空き待ち予約</th>
<th>特記事項</th>
<th>学生証確認種別</th>
<th>減免案内表示フラグ</th>
<th>減免対象年齢</th>
<th>減免案内表示開始月数</th>
<th>年跨ぎ</th>
</tr>
</thead>
<tbody class="bg-white">
@foreach($parks as $park)
<tr>
<td style="background-color:#faebd7;">
<div class="d-flex align-items-center">
<input type="checkbox" name="pk[]" value="{{ $park->park_id }}">
<a href="{{ route('parks.edit', ['id' => $park->park_id]) }}?back={{ urlencode(request()->fullUrl()) }}"
class="btn btn-sm btn-outline-primary ml10">
編集
</a>
</div>
</td>
<td>{{ $park->park_id }}</td>
<td>{{ $park->city_name ?? '' }}</td>
<td>{{ $park->park_name ?? '' }}</td>
<td>{{ $park->park_ruby ?? '' }}</td>
<td>{{ $park->park_syllabary ?? '' }}</td>
<td>{{ $park->park_adrs ?? '' }}</td>
<td>{{ ($park->park_close_flag ?? 0) == 1 ? '閉設' : '営業中' }}</td>
<td>{{ $park->park_day ?? '' }}</td>
<td>{{ $park->price_memo ?? '' }}</td>
<td>{{ $park->alert_flag ?? '' }}</td>
<td>{{ $park->print_number ?? '' }}</td>
<td>{{ $park->keep_alive ?? '' }}</td>
<td>{{ $park->update_grace_period_start_date ?? '' }}</td>
<td>{{ substr($park->update_grace_period_start_time ?? '', 0, 5) }}</td>
<td>{{ $park->update_grace_period_end_date ?? '' }}</td>
<td>{{ substr($park->update_grace_period_end_time ?? '', 0, 5) }}</td>
<td>{{ $park->parking_start_grace_period ?? '' }}</td>
<td>
@switch($park->reminder_type ?? '')
@case(0) 毎日 @break
@case(1) 1日おき @break
@case(2) 2日おき @break
@default 未設定
@endswitch
</td>
<td>{{ $park->reminder_time ?? '' }}</td>
<td>{{ ($park->immediate_use_permit ?? 0) ? '許可する' : '許可しない' }}</td>
<td>{{ ($park->gender_display_flag ?? 0) ? '表示する' : '表示しない' }}</td>
<td>{{ ($park->bd_display_flag ?? 0) ? '表示する' : '表示しない' }}</td>
<td>{{ ($park->securityreg_display_flag ?? 0) ? '表示する' : '表示しない' }}</td>
<td>{{ $park->distance_twopoints ?? '' }}</td>
<td>{{ $park->park_latitude ?? '' }}</td>
<td>{{ $park->park_longitude ?? '' }}</td>
<td>{{ $park->park_tel ?? '' }}</td>
<td>{{ ($park->park_fixed_contract ?? 0) ? '定期利用可' : '定期利用不可' }}</td>
<td>{{ ($park->park_temporary_contract ?? 0) ? '一時利用可' : '一時利用不可' }}</td>
<td>{{ $park->park_restriction ?? '' }}</td>
<td>{{ $park->park_procedure ?? '' }}</td>
<td>{{ $park->park_payment ?? '' }}</td>
<td>{{ ($park->park_available_time_flag ?? 0) ? '制限あり' : '制限なし' }}</td>
<td>{{ substr($park->park_available_time_from ?? '', 0, 5) }}</td>
<td>{{ substr($park->park_available_time_to ?? '', 0, 5) }}</td>
<td>{{ ($park->park_manager_flag ?? 0) ? '常駐' : '非常駐' }}</td>
<td>{{ substr($park->park_manager_resident_from ?? '', 0, 5) }}</td>
<td>{{ substr($park->park_manager_resident_to ?? '', 0, 5) }}</td>
<td>{{ ($park->park_roof_flag ?? 0) ? '屋根あり' : '屋根なし' }}</td>
<td>{{ ($park->park_issuing_machine_flag ?? 0) ? 'あり' : 'なし' }}</td>
<td>{{ $park->park_using_method ?? '' }}</td>
<td>{{ $park->park_contract_renewal_term ?? '' }}</td>
<td>{{ $park->park_reservation ?? '' }}</td>
<td>{{ $park->park_reference ?? '' }}</td>
<td>
@switch($park->student_id_confirm_type ?? '')
@case('none') 確認しない @break
@case('year') 年1回 @break
@case('reissue') 再発行時 @break
@default 未設定
@endswitch
</td>
<td>{{ ($park->reduction_guide_display_flag ?? 0) ? '表示する' : '表示しない' }}</td>
<td>{{ $park->reduction_age ?? '' }}</td>
<td>{{ $park->reduction_guide_display_start_month ?? '' }}</td>
<td>{{ ($park->overyear_flag ?? 0) ? 'あり' : 'なし' }}</td>
</tr>
@endforeach
</tbody>
</table>
</form>
</div>
</div>
</div>
</section>
@endsection

View File

@ -1,222 +0,0 @@
@extends('layouts.app')
@section('content')
<div class="container-fluid pt-4">
{{-- フラッシュメッセージ --}}
@if(session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if(session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
<div class="d-flex justify-content-between align-items-center mb-3">
<h3 class="mb-0">駐輪場マスタ</h3>
<ol class="breadcrumb float-sm-right text-sm mb-0" style="background: #f8f9fa;">
<li class="breadcrumb-item"><a href="{{ url('/home') }}">ホーム</a></li>
<li class="breadcrumb-item active">駐輪場マスタ</li>
</ol>
</div>
<div class="card mb-2">
<div class="card-body pb-2">
<form method="GET" action="{{ route('parks') }}">
<div class="form-row">
<div class="form-group col-md-4">
<label class="mr-1">駐輪場名</label>
<input type="text" name="park_name" class="form-control" value="{{ request('park_name') }}"
placeholder="キーワード...">
</div>
<div class="form-group col-md-4">
<label class="mr-1">市区</label>
<select name="city_id" class="form-control">
<option value="">市町村を選択してください</option>
@foreach($cities as $city)
<option value="{{ $city->city_id }}" @if(request('city_id') == $city->city_id) selected
@endif>
{{ $city->city_name }}
</option>
@endforeach
</select>
</div>
<div class="form-group col-md-4 d-flex align-items-end">
<!-- 空白で高さを揃える -->
</div>
</div>
<button type="submit" class="btn btn-default mr-1">絞り込み</button>
<a href="{{ route('parks') }}" class="btn btn-default mr-2">解除</a>
</form>
</div>
</div>
<div class="form-row mt-2">
<div class="form-group col-md-6">
<a href="{{ route('parks.add') }}" class="btn btn-default mr-2">新規</a>
<a href="{{ route('parks.export') }}" class="btn btn-default mr-2">CSV出力</a>
<button type="button" id="delete" class="btn btn-default">削除</button>
</div>
</div>
<div class="table-responsive">
<form id="form_delete" method="POST" action="{{ route('parks.delete') }}">
@csrf
<table class="table table-bordered table-hover table-sm text-nowrap">
<thead class="thead-light">
<tr>
<th></th>
<th>駐輪場ID</th>
<th>市区</th>
<th>駐輪場名</th>
<th>駐輪場ふりがな</th>
<th>駐輪場五十音</th>
<th>住所</th>
<th>閉設フラグ</th>
<th>閉設日</th>
<th>残警告チェックフラグ</th>
<th>印字数</th>
<th>最新キープアライブ</th>
<th>更新オペレータID</th>
<th>更新期間開始日</th>
<th>更新期間開始時</th>
<th>更新期間終了日</th>
<th>更新期間終了時</th>
<th>駐輪開始期間</th>
<th>リマインダー種別</th>
<th>リマインダー時間</th>
<th>契約後即利用許可</th>
<th>項目表示設定:性別</th>
<th>項目表示設定:生年月日</th>
<th>項目表示設定:防犯登録番号</th>
<th>二点間距離</th>
<th>駐車場座標(緯度)</th>
<th>駐車場座標(経度)</th>
<th>電話番号</th>
<th>駐輪場契約形態(定期)</th>
<th>駐輪場契約形態(一時利用)</th>
<th>車種制限</th>
<th>手続方法</th>
<th>支払方法</th>
<th>利用可能時間制限フラグ</th>
<th>利用可能時間(開始)</th>
<th>利用可能時間(終了)</th>
<th>常駐管理人フラグ</th>
<th>常駐時間(開始)</th>
<th>常駐時間(終了)</th>
<th>屋根フラグ</th>
<th>シール発行機フラグ</th>
<th>駐輪場利用方法</th>
<th>定期更新期間</th>
<th>空き待ち予約</th>
<th>特記事項</th>
<th>学生証確認種別</th>
<th>減免案内表示フラグ</th>
<th>減免対象年齢</th>
<th>減免案内表示開始月数</th>
<th>年跨ぎ</th>
</tr>
</thead>
<tbody>
@foreach($parks as $park)
<tr>
<td style="background: #faebd7; white-space: nowrap;">
<input type="checkbox" name="pk[]" value="{{ $park->park_id }}" class="row_checkbox">
<a href="{{ route('parks.edit', ['id' => $park->park_id]) }}"
class="btn btn-sm btn-default ml10">編集</a>
</td>
<td class='sm-item text-left'><span>{{ $park->park_id }}</span></td>
<td class='sm-item text-right'><span>{{ $park->city_name }}</span></td>
<td class='sm-item text-right'><span>{{ $park->park_name }}</span></td>
<td class='sm-item text-right'><span>{{ $park->park_ruby }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_syllabary }}</span></td>
<td class='sm-item text-right'><span>{{ $park->park_adrs }}</span></td>
<td class='sm-item text-right'>
<span>
@if($park->park_close_flag == 1)
閉設
@else
営業中
@endif
</span>
</td>
<td class='sm-item text-right'><span>{{ $park->park_day }}</span></td>
<td class='sm-item text-left'><span>{{ $park->alert_flag }}</span></td>
<td class='sm-item text-left'><span>{{ $park->print_number }}</span></td>
<td class='sm-item text-left'><span>{{ $park->keep_alive }}</span></td>
<td class='sm-item text-left'><span>{{ $park->operator_id ?? '' }}</span></td>
<td class='sm-item text-left'><span>{{ $park->update_grace_period_start_date }}</span></td>
<td class='sm-item text-left'><span>{{ $park->update_grace_period_start_time }}</span></td>
<td class='sm-item text-left'><span>{{ $park->update_grace_period_end_date }}</span></td>
<td class='sm-item text-left'><span>{{ $park->update_grace_period_end_time }}</span></td>
<td class='sm-item text-left'><span>{{ $park->parking_start_grace_period }}</span></td>
<td class='sm-item text-left'>
@if($park->reminder_type === 0)
毎日
@elseif($park->reminder_type === 1)
1日おき
@elseif($park->reminder_type === 2)
2日おき
@else
未設定
@endif
</td>
<td class='sm-item text-left'><span>{{ $park->reminder_time }}</span></td>
<td class='sm-item text-left'>{{ $park->immediate_use_permit == 1 ? '許可する' : '許可しない' }}</td>
<td class='sm-item text-left'>{{ $park->gender_display_flag == 1 ? '表示する' : '表示しない' }}</td>
<td class='sm-item text-left'>{{ $park->bd_display_flag == 1 ? '表示する' : '表示しない' }}</td>
<td class='sm-item text-left'>{{ $park->securityreg_display_flag == 1 ? '表示する' : '表示しない' }}</td>
<td class='sm-item text-left'><span>{{ $park->distance_twopoints }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_latitude }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_longitude }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_tel }}</span></td>
<td class='sm-item text-left'>{{ $park->park_fixed_contract == 1 ? '定期利用可' : '定期利用不可' }}</td>
<td class='sm-item text-left'>{{ $park->park_temporary_contract == 1 ? '一時利用可' : '一時利用不可' }}</td>
<td class='sm-item text-left'><span>{{ $park->park_restriction }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_procedure }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_payment }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_available_time_flag }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_available_time_from }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_available_time_to }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_manager_flag }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_manager_resident_from }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_manager_resident_to }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_roof_flag }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_issuing_machine_flag }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_using_method }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_contract_renewal_term }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_reservation }}</span></td>
<td class='sm-item text-left'><span>{{ $park->park_reference }}</span></td>
<td class='sm-item text-left'><span>{{ $park->student_id_confirm_type }}</span></td>
<td class='sm-item text-left'><span>{{ $park->reduction_guide_display_flag }}</span></td>
<td class='sm-item text-left'><span>{{ $park->reduction_age }}</span></td>
<td class='sm-item text-left'><span>{{ $park->reduction_guide_display_start_month }}</span></td>
<td class='sm-item text-left'><span>{{ $park->overyear_flag }}</span></td>
</tr>
@endforeach
</tbody>
</table>
</form>
<div class="mt-3">
{{ $parks->appends(request()->except('page'))->links('pagination::bootstrap-4') }}
</div>
</div>
</div>
@endsection
@push('scripts')
<script>
// チェックボックス全選択
document.getElementById('check_all')?.addEventListener('change', function () {
document.querySelectorAll('.row_checkbox').forEach(cb => {
cb.checked = this.checked;
});
});
// jQuery fallbackもしjQueryが使われていれば
if (window.$) {
$('#check_all').on('change', function () {
$('.row_checkbox').prop('checked', this.checked);
});
}
</script>
@endpush

View File

@ -0,0 +1,535 @@
{{-- アラート(成功) --}}
@if(Session::has('success'))
<div class="alert alert-success alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{{ Session::get('success') }}
</div>
@endif
{{-- アラートエラーSession --}}
@if(Session::has('error'))
<div class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
{!! Session::get('error') !!}
</div>
@endif
{{-- アラート(任意エラー) --}}
@if(isset($errorMsg))
<div class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
@if(is_array($errorMsg))
<ul class="mb-0">
@foreach($errorMsg as $msg)
<li>{{ $msg }}</li>
@endforeach
</ul>
@else
{!! $errorMsg !!}
@endif
</div>
@endif
{{-- バリデーションエラー --}}
@if($errors->any())
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<h4><i class="icon fa fa-ban"></i> {{ __('入力内容に不備があります:') }}</h4>
<ul>
@foreach($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@php
// datetime-local 表示用 (YYYY-MM-DDTHH:MM)
$contractCreatedAtVal = old('contract_created_at');
if ($contractCreatedAtVal === null) {
$dt = $record->contract_created_at ?? null;
$contractCreatedAtVal = $dt ? \Carbon\Carbon::parse($dt)->format('Y-m-d\TH:i') : '';
}
$reserveDateVal = old('reserve_date');
if ($reserveDateVal === null) {
$dt = $record->reserve_date ?? null;
$reserveDateVal = $dt ? \Carbon\Carbon::parse($dt)->format('Y-m-d\TH:i') : '';
}
$sentDateVal = old('sent_date');
if ($sentDateVal === null) {
$dt = $record->sent_date ?? null;
$sentDateVal = $dt ? \Carbon\Carbon::parse($dt)->format('Y-m-d\TH:i') : '';
}
// 800m_flag は先頭が数字のため、プロパティアクセス不可の可能性あり
$flag800m = old('800m_flag', $record->{'800m_flag'} ?? '0');
// 手動通知
$manualFlag = old('reserve_manual', $record->reserve_manual ?? '0');
// 手動通知方法
$noticeMethod = old('reserve_notice', $record->reserve_notice ?? '');
@endphp
<div class="card-body">
<div class="row">
{{-- 定期予約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"
class="form-control form-control-lg bg-light"
value="{{ old('reserve_id', $record->reserve_id ?? '') }}"
readonly>
</div>
</div>
@endif
{{-- 定期契約ID --}}
<div class="form-group col-3">
<label>{{ __('定期契約ID') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="number"
name="contract_id"
class="form-control form-control-lg"
placeholder="{{ __('定期契約ID') }}"
value="{{ old('contract_id', $record->contract_id ?? '') }}">
</div>
</div>
{{-- 利用者分類IDuser_categoryid --}}
<div class="form-group col-3">
<label>{{ __('利用者分類') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<select name="user_categoryid" class="form-control form-control-lg">
<option value="">{{ __('全て') }}</option>
@foreach(($userTypes ?? []) as $id => $name)
<option value="{{ $id }}"
{{ (string)old('user_categoryid', $record->user_categoryid ?? '') === (string)$id ? 'selected' : '' }}>
{{ $name }}
</option>
@endforeach
</select>
</div>
</div>
{{-- 定期契約日時 --}}
<div class="form-group col-3">
<label>{{ __('定期契約日時') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="datetime-local"
name="contract_created_at"
class="form-control form-control-lg"
value="{{ $contractCreatedAtVal }}">
</div>
</div>
{{-- 利用者ID --}}
<div class="form-group col-3">
<label>{{ __('利用者ID') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="number"
name="user_id"
class="form-control form-control-lg"
placeholder="{{ __('利用者ID') }}"
value="{{ old('user_id', $record->user_id ?? '') }}">
</div>
</div>
{{-- 駐輪場ID --}}
<div class="form-group col-3">
<label class="form-label required">{{ __('駐輪場') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<select name="park_id" class="form-control form-control-lg">
<option value="">{{ __('全て') }}</option>
@foreach(($parks ?? []) as $parkId => $parkName)
<option value="{{ $parkId }}"
{{ (string)old('park_id', $record->park_id ?? '') === (string)$parkId ? 'selected' : '' }}>
{{ $parkName }}
</option>
@endforeach
</select>
</div>
</div>
{{-- 駐輪場所IDprice_parkplaceid --}}
<div class="form-group col-3">
<label>{{ __('駐輪場所ID') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<select name="price_parkplaceid" class="form-control form-control-lg">
<option value="">{{ __('全て') }}</option>
@foreach(($prices ?? []) as $id => $name)
<option value="{{ $id }}"
{{ (string)old('price_parkplaceid', $record->price_parkplaceid ?? '') === (string)$id ? 'selected' : '' }}>
{{ $name }}
</option>
@endforeach
</select>
</div>
</div>
{{-- 車種区分IDpsection_id --}}
<div class="form-group col-3">
<label>{{ __('車種区分ID') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<select name="psection_id" class="form-control form-control-lg">
<option value="">{{ __('全て') }}</option>
@foreach(($psections ?? []) as $psectionId => $psectionName)
<option value="{{ $psectionId }}"
{{ (string)old('psection_id', $record->psection_id ?? '') === (string)$psectionId ? 'selected' : '' }}>
{{ $psectionName }}
</option>
@endforeach
</select>
</div>
</div>
{{-- 駐輪分類IDptype_id --}}
<div class="form-group col-3">
<label class="form-label required">{{ __('駐輪分類ID') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<select name="ptype_id" class="form-control form-control-lg">
<option value="">{{ __('全て') }}</option>
@foreach(($ptypes ?? []) as $ptypeId => $ptypeName)
<option value="{{ $ptypeId }}"
{{ (string)old('ptype_id', $record->ptype_id ?? '') === (string)$ptypeId ? 'selected' : '' }}>
{{ $ptypeName }}
</option>
@endforeach
</select>
</div>
</div>
{{-- 予約日時 --}}
<div class="form-group col-3">
<label class="form-label required">{{ __('予約日時') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="datetime-local"
name="reserve_date"
class="form-control form-control-lg"
value="{{ $reserveDateVal }}">
</div>
</div>
{{-- 減免措置 --}}
<div class="form-group col-3">
<label>{{ __('減免措置') }}</label>
</div>
<div class="form-group col-9">
@php
// 初期表示:なし
$reductionFlag = old('reserve_reduction', $record->reserve_reduction ?? '0');
@endphp
<div class="row">
<div class="col-2 offset-1 form-check">
<label class="radio-inline mb-0">
<input type="radio"
name="reserve_reduction"
class="minimal"
value="1"
{{ (string)$reductionFlag === '1' ? 'checked' : '' }}>
{{ __('あり') }}
</label>
</div>
<div class="col-2 form-check">
<label class="radio-inline mb-0">
<input type="radio"
name="reserve_reduction"
class="minimal"
value="0"
{{ (string)$reductionFlag === '0' ? 'checked' : '' }}>
{{ __('なし') }}
</label>
</div>
</div>
</div>
{{-- 自動リマインド日 --}}
<div class="form-group col-3">
<label>{{ __('自動リマインド日') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="date"
name="reserve_auto_remind"
class="form-control form-control-lg"
value="{{ old('reserve_auto_remind', $record->reserve_auto_remind ?? '') }}">
</div>
</div>
{{-- 手動リマインド日 --}}
<div class="form-group col-3">
<label>{{ __('手動リマインド日') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="date"
name="reserve_manual_remind"
class="form-control form-control-lg"
value="{{ old('reserve_manual_remind', $record->reserve_manual_remind ?? '') }}">
</div>
</div>
<div class="form-group col-3">
<label>{{ __('800M以内フラグ') }}</label>
</div>
<div class="form-group col-9">
@php
$flag800m = old('800m_flag', $record->{'800m_flag'} ?? '0');
@endphp
<div class="row">
<div class="col-2 offset-1 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="800m_flag" class="minimal" value="1"
{{ (string)$flag800m === '1' ? 'checked' : '' }}>
{{ __('800M以内') }}
</label>
</div>
<div class="col-2 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="800m_flag" class="minimal" value="0"
{{ (string)$flag800m === '0' ? 'checked' : '' }}>
{{ __('800M以内ではない') }}
</label>
</div>
</div>
</div>
{{-- 解約日 --}}
<div class="form-group col-3">
<label>{{ __('解約日') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="date"
name="reserve_cancelday"
class="form-control form-control-lg"
value="{{ old('reserve_cancelday', $record->reserve_cancelday ?? '') }}">
</div>
</div>
{{-- 有効フラグ --}}
<div class="form-group col-3">
<label>{{ __('有効フラグ') }}</label>
</div>
<div class="form-group col-9">
@php
$validFlag = old('valid_flag', $record->valid_flag ?? '1'); // 初期:有効
@endphp
<div class="row">
<div class="col-2 offset-1 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="valid_flag" class="minimal" value="1"
{{ (string)$validFlag === '1' ? 'checked' : '' }}>
{{ __('有効') }}
</label>
</div>
<div class="col-2 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="valid_flag" class="minimal" value="0"
{{ (string)$validFlag === '0' ? 'checked' : '' }}>
{{ __('無効') }}
</label>
</div>
</div>
</div>
{{-- 手動通知 --}}
<div class="form-group col-3">
<label>{{ __('手動通知') }}</label>
</div>
<div class="form-group col-9">
@php
// 画面2の表示に合わせて初期は「メール通知(0)」
$manualFlag = old('reserve_manual', $record->reserve_manual ?? '0');
@endphp
<div class="row">
<div class="col-2 offset-1 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="reserve_manual" class="minimal" value="1"
{{ (string)$manualFlag === '1' ? 'checked' : '' }}>
{{ __('手動通知') }}
</label>
</div>
<div class="col-3 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="reserve_manual" class="minimal" value="0"
{{ (string)$manualFlag === '0' ? 'checked' : '' }}>
{{ __('メール通知') }}
</label>
</div>
</div>
</div>
{{-- 手動通知方法 --}}
<div class="form-group col-3">
<label>{{ __('手動通知方法') }}</label>
</div>
<div class="form-group col-9">
@php
// 初期:電話
$noticeMethod = old('reserve_notice', $record->reserve_notice ?? 'tel');
@endphp
<div class="row">
<div class="col-2 offset-1 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="reserve_notice" class="minimal" value="tel"
{{ (string)$noticeMethod === 'tel' ? 'checked' : '' }}>
{{ __('電話') }}
</label>
</div>
<div class="col-2 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="reserve_notice" class="minimal" value="post"
{{ (string)$noticeMethod === 'post' ? 'checked' : '' }}>
{{ __('郵送') }}
</label>
</div>
</div>
</div>
{{-- メール送信日時 --}}
<div class="form-group col-3">
<label>{{ __('メール送信日時') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="datetime-local"
name="sent_date"
class="form-control form-control-lg"
value="{{ $sentDateVal }}">
</div>
</div>
{{-- 空き待ち順 --}}
<div class="form-group col-3">
<label>{{ __('空き待ち順') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="number"
name="reserve_order"
class="form-control form-control-lg"
placeholder="{{ __('空き待ち順') }}"
min="0"
value="{{ old('reserve_order', $record->reserve_order ?? '') }}">
</div>
</div>
{{-- 予約区分(通常/仮) --}}
<div class="form-group col-3">
<label>{{ __('予約区分') }}</label>
</div>
<div class="form-group col-9">
@php
// 初期:通常予約
$reserveType = old('reserve_type', $record->reserve_type ?? '0');
@endphp
<div class="row">
<div class="col-2 offset-1 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="reserve_type" class="minimal" value="0"
{{ (string)$reserveType === '0' ? 'checked' : '' }}>
{{ __('通常予約') }}
</label>
</div>
<div class="col-2 form-check">
<label class="radio-inline mb-0">
<input type="radio" name="reserve_type" class="minimal" value="1"
{{ (string)$reserveType === '1' ? 'checked' : '' }}>
{{ __('仮予約') }}
</label>
</div>
</div>
</div>
<!-- {{-- オペレータID --}}
<div class="form-group col-3">
<label>{{ __('オペレータID') }}</label>
</div>
<div class="form-group col-9">
<div class="input-group">
<input type="number"
name="ope_id"
class="form-control form-control-lg"
placeholder="{{ __('オペレータID') }}"
value="{{ old('ope_id', $record->ope_id ?? '') }}">
</div>
</div> -->
</div>
{{-- 下部ボタン --}}
<div class="row mt-4">
<div class="form-group col-md-10 d-flex align-items-center gap-2 justify-content-start">
{{-- 登録ボタン --}}
@if(!empty($isEdit))
<button type="button" id="register_edit" class="btn btn-lg btn-success mr-2 js-confirm-submit">
{{ __('登録') }}
</button>
@else
<button type="button" id="register" class="btn btn-lg btn-success mr-2 register js-confirm-submit">
{{ __('登録') }}
</button>
@endif
{{-- 削除ボタン(編集時のみ表示) --}}
@if(!empty($isEdit))
<button type="button" id="delete_edit" class="btn btn-lg btn-danger js-inline-delete mr-2">
{{ __('削除') }}
</button>
@endif
{{-- 戻るボタン(一覧状態保持) --}}
<button type="button"
id="btn_back"
class="btn btn-lg btn-secondary mr-2"
data-back-url="{{ request('back') }}">
{{ __('戻る') }}
</button>
</div>
</div>
</div>

View File

@ -1,300 +0,0 @@
@extends('layouts.app')
@section('title', '定期予約登録')
@section('content')
<style>
/* 画面全体のフォント/サイズを統一(やや小さめ) */
.rv-add,
.rv-add .card,
.rv-add .form-control,
.rv-add .btn,
.rv-add .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-size: 13px;
line-height: 1.45;
}
/* 1行左ラベル右入力 */
.rv-add .field{display:flex;align-items:center;margin-bottom:.7rem;}
.rv-add .label{flex:0 0 170px;margin:0;color:#333;font-weight:600;white-space:nowrap;}
.rv-add .input{flex:1 1 auto;}
.rv-add .form-control{height:calc(2.0rem + 2px);padding:.25rem .5rem;}
.rv-add .help{color:#888;font-size:12px;}
</style>
<div class="rv-add">
{{-- パンくず&見出し --}}
<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('reserves') }}">定期予約マスタ</a></li>
<li class="breadcrumb-item active">新規</li>
</ol>
</div>
</div>
@if($errors->any())
<div class="alert alert-danger py-2 px-3 my-2">
<ul class="mb-0">
@foreach($errors->all() as $e)<li>{{ $e }}</li>@endforeach
</ul>
</div>
@endif
</div>
</div>
<section class="content">
<div class="container-fluid">
<div class="card">
<div class="card-header d-flex justify-content-start gap-2">
<button type="submit" class="btn btn-sm btn-default register js-confirm-submit">登録</button>
<a href="{{ route('reserves') }}" class="btn btn-sm btn-default ml-2">戻る</a>
</div>
<form id="rvAddForm" method="post" action="{{ route('reserves_add') }}">
@csrf
<div class="card-body">
{{-- 画面上部ID系 --}}
<div class="field">
<label class="label">定期契約ID</label>
<div class="input">
<input type="number" class="form-control" name="contract_id" value="{{ old('contract_id') }}" placeholder="定期契約ID">
</div>
</div>
<div class="field">
<label class="label">利用者分類ID</label>
<div class="input">
<select name="user_categoryid" class="form-control">
<option value="">全て</option>
@foreach($userTypes as $type)
<option value="{{ $type->user_categoryid }}"
{{ old('user_categoryid') == $type->user_categoryid ? 'selected' : '' }}>
{{ $type->display_name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">利用者登録日時</label>
<div class="input">
<input type="datetime-local" class="form-control" name="user_created_at" value="{{ old('user_created_at') }}">
</div>
</div>
{{-- 基本情報 --}}
<div class="field">
<label class="label">利用者ID <span class="text-danger">*</span></label>
<div class="input">
<input type="number" class="form-control" name="user_id" value="{{ old('user_id') }}" required placeholder="利用者ID">
</div>
</div>
<div class="field">
<label class="label">駐輪場ID <span class="text-danger">*</span></label>
<div class="input">
<select name="park_id" class="form-control" required>
<option value="">駐輪場ID</option>
@foreach($parks as $park)
<option value="{{ $park->park_id }}" {{ old('park_id') == $park->park_id ? 'selected' : '' }}>
{{ $park->park_name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">駐輪場所ID</label>
<div class="input">
<select name="price_parkplaceid" class="form-control">
<option value="">駐輪場所ID</option>
@foreach($priceOptions as $price)
<option value="{{ $price->price_parkplaceid }}" {{ old('price_parkplaceid') == $price->price_parkplaceid ? 'selected' : '' }}>
{{ $price->price_parkplaceid }} {{ $price->prine_name }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">車種区分ID</label>
<div class="input">
<input type="number" class="form-control" name="psection_id" value="{{ old('psection_id') }}" placeholder="車種区分ID">
</div>
</div>
<div class="field">
<label class="label">駐輪分類ID</label>
<div class="input">
<input type="number" class="form-control" name="ptype_id" value="{{ old('ptype_id') }}" placeholder="駐輪分類ID">
</div>
</div>
<div class="field">
<label class="label">予約日時</label>
<div class="input">
<input type="datetime-local" class="form-control" name="reserve_date" value="{{ old('reserve_date') }}" placeholder="yyyy/mm/dd hh:mm:ss">
</div>
</div>
{{-- ラジオ系 --}}
<div class="field">
<label class="label">減免措置</label>
<div class="input">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="reduction_flag" id="reduction1" value="1" {{ old('reduction_flag','0')==='1'?'checked':'' }}>
<label class="form-check-label" for="reduction1">あり</label>
</div>
<div class="form-check form-check-inline ml-3">
<input class="form-check-input" type="radio" name="reduction_flag" id="reduction0" value="0" {{ old('reduction_flag','0')==='0'?'checked':'' }}>
<label class="form-check-label" for="reduction0">なし</label>
</div>
</div>
</div>
{{-- リマインド --}}
<div class="field">
<label class="label">自動リマインド日</label>
<div class="input">
<input type="date" class="form-control" name="auto_remind_day" value="{{ old('auto_remind_day') }}" placeholder="yyyy/mm/dd">
</div>
</div>
<div class="field">
<label class="label">手動リマインド日</label>
<div class="input">
<input type="date" class="form-control" name="manual_remind_day" value="{{ old('manual_remind_day') }}" placeholder="yyyy/mm/dd">
</div>
</div>
<div class="field">
<label class="label">800M以内フラグ</label>
<div class="input">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="within_800m_flag" id="m800_1" value="1" {{ old('within_800m_flag','0')==='1'?'checked':'' }}>
<label class="form-check-label" for="m800_1">M以内</label>
</div>
<div class="form-check form-check-inline ml-3">
<input class="form-check-input" type="radio" name="within_800m_flag" id="m800_0" value="0" {{ old('within_800m_flag','0')==='0'?'checked':'' }}>
<label class="form-check-label" for="m800_0">M内ではない</label>
</div>
</div>
</div>
{{-- 期間・状態 --}}
<div class="field">
<label class="label">解約日</label>
<div class="input">
<input type="date" class="form-control" name="reserve_cancelday" value="{{ old('reserve_cancelday') }}" placeholder="yyyy/mm/dd">
</div>
</div>
<div class="field">
<label class="label">有効フラグ</label>
<div class="input">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="valid_flag" id="valid1" value="1" {{ old('valid_flag','1')==='1'?'checked':'' }}>
<label class="form-check-label" for="valid1">有効</label>
</div>
<div class="form-check form-check-inline ml-3">
<input class="form-check-input" type="radio" name="valid_flag" id="valid0" value="0" {{ old('valid_flag')==='0'?'checked':'' }}>
<label class="form-check-label" for="valid0">無効</label>
</div>
</div>
</div>
{{-- 通知 --}}
<div class="field">
<label class="label">手動通知</label>
<div class="input">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="manual_notice" id="mn1" value="1" {{ old('manual_notice','0')==='1'?'checked':'' }}>
<label class="form-check-label" for="mn1">手動通知</label>
</div>
<div class="form-check form-check-inline ml-3">
<input class="form-check-input" type="radio" name="manual_notice" id="mn2" value="2" {{ old('manual_notice')==='2'?'checked':'' }}>
<label class="form-check-label" for="mn2">メール通知</label>
</div>
</div>
</div>
<div class="field">
<label class="label">手動通知方法</label>
<div class="input">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="manual_notice_method" id="mm_tel" value="tel" {{ old('manual_notice_method','tel')==='tel'?'checked':'' }}>
<label class="form-check-label" for="mm_tel">電話</label>
</div>
<div class="form-check form-check-inline ml-3">
<input class="form-check-input" type="radio" name="manual_notice_method" id="mm_mail" value="post" {{ old('manual_notice_method')==='post'?'checked':'' }}>
<label class="form-check-label" for="mm_mail">郵送</label>
</div>
</div>
</div>
<div class="field">
<label class="label">空き待ちメール送信日時</label>
<div class="input">
<input type="datetime-local" class="form-control" name="waiting_mail_sent_at" value="{{ old('waiting_mail_sent_at') }}" placeholder="yyyy/mm/dd hh:mm:ss">
</div>
</div>
<div class="field">
<label class="label">空き待ち順</label>
<div class="input">
<input type="number" class="form-control" name="waiting_order" value="{{ old('waiting_order') }}" placeholder="空き待ち順">
</div>
</div>
<div class="mt-4 d-flex gap-2">
<button type="submit" class="btn btn-sm btn-default register js-confirm-submit">登録</button>
<a href="{{ route('reserves') }}" class="btn btn-sm btn-default ml-2">戻る</a>
</div>
</div>
</form>
</div>
</div>
</section>
</div>
@push('scripts')
<script>
(function ($) {
'use strict';
$(function () {
$(document).off('click.rvConfirm', '.js-confirm-submit').on('click.rvConfirm', '.js-confirm-submit', function (e) {
e.preventDefault();
const $button = $(this);
$.confirm({
title: '確認ダイアログ',
content: '!登録してよろしいですか? はい/いいえ',
buttons: {
yes: {
text: 'はい',
btnClass: 'btn-primary',
action: function () {
let $form = $button.closest('form');
if (!$form.length) {
const formId = $button.attr('form');
$form = formId ? $('#' + formId) : $('form').first();
}
$form.trigger('submit');
}
},
no: { text: 'いいえ' }
}
});
});
});
})(jQuery);
</script>
@endpush
@endsection

View File

@ -0,0 +1,38 @@
@extends('layouts.app')
@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('reserves.index') }}">定期予約マスタ</a></li>
<li class="breadcrumb-item active">新規</li>
</ol>
</div>
</div>
</div>
</div>
<section class="content">
<div class="container-fluid">
<div class="card">
<form method="POST" action="{{ route('reserves.store') }}">
@csrf
@include('admin.reserves._form', [
'isEdit' => false,
'record' => null,
'userTypes' => $userTypes ?? [],
'parks' => $parks ?? [],
'priceOptions' => $priceOptions ?? [],
])
</form>
</div>
</div>
</section>
@endsection

View File

@ -1,123 +0,0 @@
{{-- resources/views/admin/reserves/delete.blade.php --}}
@extends('layouts.app')
@section('title', '定期予約 削除確認')
@section('content')
@php
// === 削除対象IDを堅牢に収集$rows / $ids / request('ids') のいずれでも可)===
$collectedIds = [];
if (!empty($rows)) {
foreach ($rows as $r) { $collectedIds[] = (int)$r->reserve_id; }
} elseif (!empty($ids)) {
$collectedIds = array_map('intval', (array)$ids);
} else {
// クエリやPOSTで "ids" が来ている場合ids[]= / ids=1,2 どちらも吸収)
$raw = request()->input('ids', []);
if (is_string($raw)) $raw = explode(',', $raw);
$collectedIds = array_map('intval', (array)$raw);
}
$collectedIds = array_values(array_unique(array_filter($collectedIds, fn($v)=>$v>0)));
@endphp
<style>
/* 画面全体を小さめの文字で統一 */
.rs-del-page, .rs-del-page .card, .rs-del-page .btn, .rs-del-page table { font-size: 13px; }
</style>
<div class="rs-del-page">
{{-- ヘッダー / パンくず --}}
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6"><h1 class="m-0 text-dark">削除確認</h1></div>
<div class="col-sm-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('reserves') }}">定期予約マスタ</a></li>
<li class="breadcrumb-item active">削除確認</li>
</ol>
</div>
</div>
@if(count($collectedIds))
<div class="alert alert-warning mb-0">
選択した定期予約を<strong>削除</strong>します。この操作は取り消せません。よろしいですか?
</div>
@else
<div class="alert alert-danger mb-0">
削除対象が選択されていません。一覧に戻って、チェックボックスで対象を選択してください。
</div>
@endif
</div>
</div>
<section class="content">
<div class="container-fluid">
{{-- 対象一覧(可能なら情報を表示。$rows が無いときはIDのバッジだけ --}}
<div class="card">
<div class="card-header py-2">
<h3 class="card-title">削除対象</h3>
</div>
<div class="card-body p-2">
@if(!empty($rows) && count($rows))
<div class="table-responsive">
<table class="table table-bordered table-hover mb-2">
<thead>
<tr>
<th style="white-space:nowrap;">予約ID</th>
<th>定期契約ID</th>
<th>利用者名</th>
<th>駐輪場</th>
<th>予約日時</th>
</tr>
</thead>
<tbody>
@foreach($rows as $r)
<tr>
<td class="text-right">{{ $r->reserve_id }}</td>
<td class="text-right">{{ $r->contract_id ?? '' }}</td>
<td>{{ $r->user_name ?? '' }}</td>
<td>{{ $r->park_name ?? '' }}</td>
{{-- 実テーブル列名に合わせて reserve_date を使用 --}}
<td>{{ $r->reserve_date ?? '' }}</td>
</tr>
@endforeach
</tbody>
</table>
</div>
@elseif(count($collectedIds))
<p class="mb-2">
削除対象ID
@foreach($collectedIds as $id)
<span class="badge badge-secondary mr-1">{{ $id }}</span>
@endforeach
</p>
@else
<p class="text-muted mb-0">削除対象が取得できませんでした。</p>
@endif
</div>
</div>
{{-- 確認フォーム --}}
<form action="{{ route('reserves_delete') }}" method="post" class="mt-2">
@csrf
{{-- コントローラ側で「確認済み」を判定できるようにフラグを送る --}}
<input type="hidden" name="confirmed" value="1">
{{-- hidden に対象 ID を埋め込む --}}
@foreach($collectedIds as $id)
<input type="hidden" name="ids[]" value="{{ $id }}">
@endforeach
<a href="{{ route('reserves') }}" class="btn btn-default">キャンセル</a>
<button type="submit" class="btn btn-danger"
{{ count($collectedIds) ? '' : 'disabled' }}>
削除する
</button>
</form>
</div>
</section>
</div>
@endsection

View File

@ -1,421 +1,67 @@
{{-- resources/views/admin/reserves/edit.blade.php --}}
@extends('layouts.app') @extends('layouts.app')
@section('title', '定期予約マスタ - 編集') @section('title', '編集')
@section('content') @section('content')
<style> <div class="content-header">
.rv-edit,
.rv-edit .card,
.rv-edit .form-control,
.rv-edit .btn,
.rv-edit .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-size:13px;
line-height:1.45;
}
.rv-form .field{
display:flex;
align-items:center;
gap:1.25rem;
margin-bottom:.75rem;
}
.rv-form .label{
flex:0 0 180px;
margin:0;
color:#333;
font-weight:600;
white-space:nowrap;
}
.rv-form .label .req{
color:#e3342f;
margin-left:.35rem;
}
.rv-form .input{
flex:1 1 auto;
min-width:260px;
}
.rv-form .form-control{
height:calc(2.0rem + 2px);
padding:.25rem .5rem;
}
.rv-form .form-control[readonly],
.rv-form .form-control:disabled{
background:#f5f5f5;
color:#444;
}
.rv-form .radio-inline{
display:inline-flex;
align-items:center;
gap:.35rem;
margin-right:1.25rem;
}
.breadcrumb-inline{
white-space:nowrap;
color:#666;
}
.rv-edit .card-header{
display:flex;
justify-content:flex-start;
gap:.5rem;
padding:1rem 1.25rem;
border-bottom:1px solid #f1f1f1;
}
.rv-edit .card-footer{
background:#fff;
border-top:1px solid #f1f1f1;
display:flex;
justify-content:flex-start;
gap:.5rem;
padding:1rem 1.25rem;
}
@media (max-width: 576px){
.rv-form .field{
flex-direction:column;
align-items:flex-start;
}
.rv-form .label{
flex:none;
}
.rv-toolbar{
flex-direction:column;
align-items:stretch;
}
.rv-toolbar .btn{
width:100%;
}
}
</style>
@php
// 読み取り専用表示用:既存のオプションから名称を推定(コントローラを変更せず表示可能)
$userName = '';
if (!empty($row->user_id ?? null) && !empty($userOptions[$row->user_id] ?? null)) {
// $userOptions 形如 "12345 山田太郎" → 去掉开头ID只留名字
$userName = trim(preg_replace('/^\s*\d+\s*/', '', $userOptions[$row->user_id]));
}
$parkName = '';
if (!empty($row->park_id ?? null) && !empty($parkOptions[$row->park_id] ?? null)) {
$parkName = trim(preg_replace('/^\s*\d+\s*/', '', $parkOptions[$row->park_id]));
}
@endphp
<div class="rv-edit">
{{-- ヘッダ --}}
<div class="content-header">
<div class="container-fluid"> <div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-2"> <div class="row mb-2">
<div class="col-lg-6">
<h1 class="m-0 text-dark">編集</h1> <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>
<li class="breadcrumb-item"><a href="{{ route('reserves') }}">定期予約マスタ</a></li> <li class="breadcrumb-item"><a href="{{ route('reserves.index') }}">定期予約マスタ</a></li>
<li class="breadcrumb-item active">編集</li> <li class="breadcrumb-item active">編集</li>
</ol> </ol>
</div> </div>
</div> </div>
@if(session('success'))
<div class="alert alert-success py-2 px-3 my-2">{{ session('success') }}</div>
@endif
@if($errors->any())
<div class="alert alert-danger py-2 px-3 my-2">
<ul class="mb-0">@foreach($errors->all() as $e)<li>{{ $e }}</li>@endforeach</ul>
</div> </div>
@endif
</div>
</div>
{{-- 本体 --}}
<section class="content">
<div class="container-fluid">
<div class="card rv-form">
<div class="card-header">
<button type="submit" class="btn btn-default btn-sm js-confirm-submit" form="edit-form">登録</button>
<button type="button" id="btnDeleteTop" class="btn btn-default btn-sm">削除</button>
<a href="{{ route('reserves') }}" class="btn btn-default btn-sm">戻る</a>
</div>
{{-- GET と同一ルートで POST 更新 --}}
<form id="edit-form" method="post" action="{{ route('reserves_edit', ['reserve_id'=>$row->reserve_id]) }}">
@csrf
<div class="card-body">
<div class="field">
<label class="label">定期予約ID</label>
<div class="input">
<input type="text" class="form-control" value="{{ $row->reserve_id }}" readonly>
</div>
</div>
<div class="field">
<label class="label">定期契約ID</label>
<div class="input">
<input type="text" name="contract_id" class="form-control" placeholder="定期契約ID"
value="{{ old('contract_id', $row->contract_id ?? '') }}" readonly>
</div>
</div>
<div class="field">
<label class="label">定期契約日時</label>
<div class="input">
<input type="text" name="contract_created_at" class="form-control" placeholder="yyyy/mm/dd hh:mm:ss"
value="{{ old('contract_created_at', $row->contract_created_at ?? '') }}">
</div>
</div>
<div class="field">
<label class="label">利用者分類ID</label>
<div class="input">
<select name="user_categoryid" class="form-control">
<option value="">全て</option>
@foreach(($userTypeOptions ?? []) as $k => $v)
<option value="{{ $k }}" {{ (string)old('user_categoryid', $row->user_categoryid ?? '') === (string)$k ? 'selected' : '' }}>
{{ $v }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">利用者ID<span class="req">*</span></label>
<div class="input">
@php
$selectedUserId = old('user_id', $row->user_id ?? '');
$selectedUserLabel = $selectedUserId !== '' ? ($userOptions[$selectedUserId] ?? $selectedUserId) : '';
@endphp
<input type="text" class="form-control" value="{{ $selectedUserLabel }}" readonly>
<input type="hidden" name="user_id" value="{{ $selectedUserId }}">
</div>
</div>
<div class="field">
<label class="label">予約日時<span class="req">*</span></label>
<div class="input">
<input type="text" name="reserve_date" class="form-control" placeholder="yyyy/mm/dd hh:mm:ss"
value="{{ old('reserve_date', $row->reserve_date ?? '') }}">
</div>
</div>
<div class="field">
<label class="label">駐輪場ID<span class="req">*</span></label>
<div class="input">
<select name="park_id" class="form-control" required>
<option value="">選択してください</option>
@foreach(($parkOptions ?? []) as $k => $v)
<option value="{{ $k }}" {{ (string)old('park_id', $row->park_id ?? '') === (string)$k ? 'selected' : '' }}>
{{ $v }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">駐輪場所ID<span class="req">*</span></label>
<div class="input">
<select name="price_parkplaceid" class="form-control" required>
<option value="">選択してください</option>
@foreach(($parkplaceOptions ?? []) as $k => $v)
<option value="{{ $k }}" {{ (string)old('price_parkplaceid', $row->price_parkplaceid ?? '') === (string)$k ? 'selected' : '' }}>
{{ $v }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">車種区分ID</label>
<div class="input">
<select name="psection_id" class="form-control">
<option value="">選択してください</option>
@foreach(($psectionOptions ?? []) as $k => $v)
<option value="{{ $k }}" {{ (string)old('psection_id', $row->psection_id ?? '') === (string)$k ? 'selected' : '' }}>
{{ $v }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">駐輪分類ID</label>
<div class="input">
<select name="ptype_id" class="form-control">
<option value="">選択してください</option>
@foreach(($ptypeOptions ?? []) as $k => $v)
<option value="{{ $k }}" {{ (string)old('ptype_id', $row->ptype_id ?? '') === (string)$k ? 'selected' : '' }}>
{{ $v }}
</option>
@endforeach
</select>
</div>
</div>
<div class="field">
<label class="label">減免措置</label>
<div class="input">
@php $reduction = old('reduction', $row->reduction ?? ''); @endphp
<label class="radio-inline">
<input type="radio" name="reduction" value="1" {{ (string)$reduction === '1' ? 'checked' : '' }}> あり
</label>
<label class="radio-inline">
<input type="radio" name="reduction" value="0" {{ (string)$reduction === '0' ? 'checked' : '' }}> なし
</label>
</div>
</div>
<div class="field">
<label class="label">自動リマインド日</label>
<div class="input">
<input type="text" name="auto_remind_date" class="form-control" placeholder="yyyy/mm/dd"
value="{{ old('auto_remind_date', $row->auto_remind_date ?? '') }}">
</div>
</div>
<div class="field">
<label class="label">手動リマインド日</label>
<div class="input">
<input type="text" name="manual_remind_date" class="form-control" placeholder="yyyy/mm/dd"
value="{{ old('manual_remind_date', $row->manual_remind_date ?? '') }}">
</div>
</div>
<div class="field">
<label class="label">800M以内フラグ</label>
<div class="input">
@php $m800 = old('within_800m_flag', $row->within_800m_flag ?? ''); @endphp
<label class="radio-inline">
<input type="radio" name="within_800m_flag" value="1" {{ (string)$m800 === '1' ? 'checked' : '' }}> M以内
</label>
<label class="radio-inline">
<input type="radio" name="within_800m_flag" value="0" {{ (string)$m800 === '0' ? 'checked' : '' }}> M以内ではない
</label>
</div>
</div>
<div class="field">
<label class="label">解約日</label>
<div class="input">
<input type="text" name="contract_cancelday" class="form-control" placeholder="yyyy/mm/dd"
value="{{ old('contract_cancelday', $row->contract_cancelday ?? '') }}">
</div>
</div>
<div class="field">
<label class="label">有効フラグ</label>
<div class="input">
@php $valid = old('valid_flag', $row->valid_flag ?? ''); @endphp
<label class="radio-inline">
<input type="radio" name="valid_flag" value="1" {{ (string)$valid === '1' ? 'checked' : '' }}> 有効
</label>
<label class="radio-inline">
<input type="radio" name="valid_flag" value="0" {{ (string)$valid === '0' ? 'checked' : '' }}> 無効
</label>
</div>
</div>
<div class="field">
<label class="label">空き待ちメール送信日時</label>
<div class="input">
<input type="text" name="mail_sent_at" class="form-control" placeholder="yyyy/mm/dd hh:mm:ss"
value="{{ old('mail_sent_at', $row->mail_sent_at ?? '') }}">
</div>
</div>
<div class="field">
<label class="label">手動通知</label>
<div class="input">
@php $mnotice = old('manual_notice', $row->manual_notice ?? ''); @endphp
<label class="radio-inline">
<input type="radio" name="manual_notice" value="0" {{ (string)$mnotice === '0' ? 'checked' : '' }}> 手動通知
</label>
<label class="radio-inline">
<input type="radio" name="manual_notice" value="1" {{ (string)$mnotice === '1' ? 'checked' : '' }}> メール通知
</label>
</div>
</div>
<div class="field">
<label class="label">手動通知方法</label>
<div class="input">
@php $mhow = old('manual_notice_method', $row->manual_notice_method ?? ''); @endphp
<label class="radio-inline">
<input type="radio" name="manual_notice_method" value="tel" {{ $mhow === 'tel' ? 'checked' : '' }}> 電話
</label>
<label class="radio-inline">
<input type="radio" name="manual_notice_method" value="post" {{ $mhow === 'post' ? 'checked' : '' }}> 郵送
</label>
</div>
</div>
<div class="field">
<label class="label">空き待ち順</label>
<div class="input">
<input type="number" name="waitlist_order" class="form-control" min="0" step="1" placeholder="空き待ち順"
value="{{ old('waitlist_order', $row->waitlist_order ?? '') }}">
</div>
</div>
</div>
{{-- 下部操作(参照画面の下部にも登録/削除ボタンあり) --}}
<div class="card-footer">
<button type="submit" class="btn btn-default btn-sm js-confirm-submit">登録</button>
<button type="button" id="btnDeleteBottom" class="btn btn-default btn-sm">削除</button>
<a href="{{ route('reserves') }}" class="btn btn-default btn-sm">戻る</a>
</div>
</form>
{{-- 削除POSTconfirmed + ids[] --}}
<form id="del-form" method="post" action="{{ route('reserves_delete') }}" style="display:none;">
@csrf
<input type="hidden" name="confirmed" value="1">
<input type="hidden" name="ids[]" value="{{ $row->reserve_id }}">
</form>
</div>
</div>
</section>
</div> </div>
<script> <!-- Main content -->
(function(){ <section class="content">
var editForm = document.getElementById('edit-form'); <div class="container-fluid">
function handleSubmitConfirm(event){ <div class="row">
event.preventDefault(); <div class="col-lg-12">
var formAttr = this.getAttribute('form'); <div class="card">
var targetForm = this.form || (formAttr ? document.getElementById(formAttr) : editForm);
if (!targetForm) { return; }
var submitAction = function(){ targetForm.submit(); };
if (window.jQuery && typeof window.jQuery.confirm === 'function') { {{-- 編集フォーム --}}
window.jQuery.confirm({ <form id="form_edit"
title: '確認ダイアログ。', action="{{ route('reserves.update', ['reserve_id' => $record->reserve_id]) }}"
content: '!登録してよろしいですか? はい/いいえ', method="POST">
buttons: { @csrf
ok: { text: 'はい', btnClass: 'btn-primary', keys: ['enter'], action: submitAction },
いいえ: function () {} @include('admin.reserves._form', [
} 'isEdit' => true,
}); 'record' => $record,
} else if (window.confirm('!登録してよろしいですか? はい/いいえ')) { 'userTypes' => $userTypes ?? [],
submitAction(); 'parks' => $parks ?? [],
} 'priceOptions' => $priceOptions ?? [],
} 'prices' => $prices ?? [],
'psections' => $psections ?? [],
'ptypes' => $ptypes ?? [],
])
</form>
{{-- 削除フォーム(非表示) --}}
<form id="form_delete"
action="{{ route('reserves.destroy') }}"
method="POST"
style="display:none;">
@csrf
{{-- 複数削除仕様に合わせて pk[] --}}
<input type="hidden" name="pk[]" value="{{ $record->reserve_id }}">
</form>
</div>
</div>
</div>
</div>
</section>
<!-- /.content -->
var submitButtons = document.querySelectorAll('.js-confirm-submit');
Array.prototype.forEach.call(submitButtons, function(btn){
btn.addEventListener('click', handleSubmitConfirm);
});
function handleDelete(){
if(window.confirm('削除してよろしいですか? はい/いいえ')){
document.getElementById('del-form').submit();
}
}
var topBtn = document.getElementById('btnDeleteTop');
var bottomBtn = document.getElementById('btnDeleteBottom');
if(topBtn){ topBtn.addEventListener('click', handleDelete); }
if(bottomBtn){ bottomBtn.addEventListener('click', handleDelete); }
})();
</script>
@endsection @endsection

View File

@ -0,0 +1,493 @@
@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>
{{-- タイトル直下の注意文 --}}
<p class="text-muted text-sm mt-2 mb-0">
※この画面のデータは通常変更する必要はありません。
</p>
</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>
<!-- /.content-header -->
<section class="content">
<div class="container-fluid">
{{-- 並び替え用 hiddenusertypes と同型JS はここを submit --}}
<form method="GET" action="{{ route('reserves.index') }}" id="list-form">
<input type="hidden" name="sort" id="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" id="sort_type" value="{{ $sort_type ?? '' }}">
{{-- フィルタ条件(並び替え時に条件が消えないように hidden で保持) --}}
<input type="hidden" name="user_id" value="{{ request('user_id', $user_id ?? '') }}">
<input type="hidden" name="park_id" value="{{ request('park_id', $park_id ?? '') }}">
<input type="hidden" name="valid_flag" value="{{ request('valid_flag', $valid_flag ?? '') }}">
<input type="hidden" name="reserve_date_from" value="{{ request('reserve_date_from', $reserve_date_from ?? '') }}">
<input type="hidden" name="reserve_date_to" value="{{ request('reserve_date_to', $reserve_date_to ?? '') }}">
<input type="hidden" name="keyword" value="{{ request('keyword', $keyword ?? '') }}">
</form>
<!-- 絞り込みフィルター -->
<div class="col-lg-12 px-0">
<div class="card">
<div class="card-header">
<h3 class="card-title">絞り込みフィルター</h3>
</div>
<!-- 絞り込みフィルター -->
<div class="col-lg-12 px-0">
<div class="card-body">
<form action="{{ route('reserves.index') }}" method="GET" id="filter-form">
<input type="hidden" name="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" value="{{ $sort_type ?? '' }}">
<div class="row">
{{-- 左側 --}}
<div class="col-lg-6">
{{-- 利用者ID --}}
<div class="form-group row">
<label class="col-3 col-form-label font-weight-bold">利用者ID</label>
<div class="col-9">
<input type="text"
name="user_id"
class="form-control"
value="{{ request('user_id', $user_id ?? '') }}"
placeholder="123456">
</div>
</div>
{{-- 有効フラグ --}}
<div class="form-group row">
<label class="col-3 col-form-label font-weight-bold">有効フラグ</label>
<div class="col-9">
<select name="valid_flag" class="form-control">
<option value="">全て</option>
<option value="1" {{ (string)request('valid_flag', $valid_flag ?? '') === '1' ? 'selected' : '' }}>有効</option>
<option value="0" {{ (string)request('valid_flag', $valid_flag ?? '') === '0' ? 'selected' : '' }}>無効</option>
</select>
</div>
</div>
{{-- メール送信日時from〜to --}}
<div class="form-group row">
<label class="col-3 col-form-label font-weight-bold">メール送信日時</label>
<div class="col-9">
<div class="d-flex align-items-center">
<input type="datetime-local"
name="mail_sent_from"
class="form-control"
value="{{ request('mail_sent_from', $mail_sent_from ?? '') }}">
<span class="mx-2"></span>
<input type="datetime-local"
name="mail_sent_to"
class="form-control"
value="{{ request('mail_sent_to', $mail_sent_to ?? '') }}">
</div>
</div>
</div>
</div>
{{-- 右側 --}}
<div class="col-lg-6">
{{-- 駐輪場 --}}
<div class="form-group row">
<label class="col-3 col-form-label font-weight-bold">駐輪場</label>
<div class="col-9">
<select name="park_id" class="form-control">
<option value="">全て</option>
@foreach(($parkOptions ?? []) as $pid => $pname)
<option value="{{ $pid }}"
{{ (string)request('park_id', $park_id ?? '') === (string)$pid ? 'selected' : '' }}>
{{ $pname }}
</option>
@endforeach
</select>
</div>
</div>
{{-- ゾーンID --}}
<div class="form-group row">
<label class="col-3 col-form-label font-weight-bold">ゾーン名</label>
<div class="col-9">
<select name="zone_id" class="form-control">
<option value="">全て</option>
@foreach(($zoneOptions ?? []) as $zid => $zname)
<option value="{{ $zid }}"
{{ (string)request('zone_id', $zone_id ?? '') === (string)$zid ? 'selected' : '' }}>
{{ $zname }}
</option>
@endforeach
</select>
</div>
</div>
{{-- 予約区分 --}}
<div class="form-group row">
<label class="col-3 col-form-label font-weight-bold">予約区分</label>
<div class="col-9">
@php
$reserveType = (string)request('reserve_type', $reserve_type ?? '');
@endphp
<select name="reserve_type" class="form-control">
<option value="">全て</option>
<option value="0" {{ $reserveType === '0' ? 'selected' : '' }}>通常予約</option>
<option value="1" {{ $reserveType === '1' ? 'selected' : '' }}>仮予約</option>
</select>
</div>
</div>
</div>
</div>
{{-- ボタン(左寄せで同じ感じ) --}}
<div class="mt-2">
<button type="submit" class="btn btn-success mr-2">絞り込み</button>
<a href="{{ route('reserves.index') }}" class="btn btn-outline-secondary">解除</a>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- 絞り込みフィルター -->
{{-- ボタンエリアusertypes と同型) --}}
<div class="col-lg-12 mb-3 px-0">
<button type="button"
class="btn btn-sm btn-primary mr10"
onclick="location.href='{{ route('reserves.create') }}?back={{ urlencode(request()->fullUrl()) }}'">
新規
</button>
<button type="button" class="btn btn-sm btn-danger mr10" id="delete">削除</button>
{{-- CSV 出力が必要なら復活reserves.export がある場合のみ) --}}
@if(\Illuminate\Support\Facades\Route::has('reserves.export'))
<button type="submit" class="btn btn-sm btn-outline-success mr10" form="form_export">
CSV出力
</button>
@endif
<button type="submit" class="btn btn-sm btn-outline-success mr10" form="form_import">
インポート
</button>
</div>
{{-- ページネーション --}}
<div class="col-lg-12 px-0">
<div class="d-flex flex-column align-items-end mb-2 text-sm">
<div class="text-dark text-sm mb-1">
@if ($list->total() > 0)
{{ $list->total() }} 件中 {{ $list->firstItem() }}{{ $list->lastItem() }} 件を表示
@else
全0件
@endif
</div>
<div>
{{ $list->appends([
'sort' => $sort ?? '',
'sort_type' => $sort_type ?? '',
] + request()->except('page'))->links('pagination') }}
</div>
</div>
</div>
{{-- フラッシュメッセージ --}}
<div class="form col-lg-12 px-0">
@if(Session::has('success'))
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ Session::get('success') }}
</div>
@elseif(Session::has('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{!! Session::get('error') !!}
</div>
@elseif(isset($errorMsg))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{!! $errorMsg !!}
</div>
@endif
</div>
{{-- テーブル --}}
<div class="col-lg-12 mb20 px-0">
<div class="table-responsive">
<form id="form_delete" method="POST" action="{{ route('reserves.destroy') }}">
@csrf
<table class="table table-bordered dataTable text-nowrap">
<thead class="thead-light">
<tr>
<th style="width:140px;">
<input type="checkbox"
class="js-check-all"
onclick="$('input[name*=\'pk\']').prop('checked', this.checked);">
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_id' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_id">
<span>定期予約ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'contract_id' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="contract_id">
<span>定期契約ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'contract_created_at' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="contract_created_at">
<span>定期契約日時</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'user_categoryid' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="user_categoryid">
<span>利用者分類ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'user_id' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="user_id">
<span>利用者ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_date' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_date">
<span>予約日時</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'park_name' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="park_name">
<span>駐輪場ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'price_parkplaceid' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="price_parkplaceid">
<span>駐輪場所ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'psection_subject' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="psection_subject">
<span>車種区分ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'ptype_subject' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="ptype_subject">
<span>駐輪分類ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_reduction' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_reduction">
<span>減免措置</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_auto_remind' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_auto_remind">
<span>自動リマインド日</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_manual_remind' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_manual_remind">
<span>手動リマインド日</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'flag_800m' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="flag_800m">
<span>800M以内フラグ</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_cancelday' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_cancelday">
<span>解約日</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'valid_flag' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="valid_flag">
<span>有効フラグ</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'sent_date' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="sent_date">
<span>メール送信日時</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_manual' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_manual">
<span>手動通知</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_notice' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_notice">
<span>手動通知方法</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'reserve_order' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_order">
<span>空き待ち順</span>
</th>
{{-- ★追加:予約区分 --}}
<th class="sorting {{ ($sort ?? '') === 'reserve_type' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="reserve_type">
<span>予約区分</span>
</th>
</tr>
</thead>
<tbody class="bg-white">
@foreach ($list as $item)
@php
$subjects = array_values(array_filter([
$item->usertype_subject1 ?? '',
$item->usertype_subject2 ?? '',
$item->usertype_subject3 ?? '',
], static fn ($v): bool => $v !== ''));
$userTypeLabel = $subjects ? implode('/', $subjects) : '';
@endphp
<tr>
<td style="background-color:#faebd7;">
<div class="d-flex align-items-center">
<input type="checkbox" name="pk[]" value="{{ $item->reserve_id }}">
<a href="{{ route('reserves.edit', ['reserve_id' => $item->reserve_id]) }}?back={{ urlencode(request()->fullUrl()) }}"
class="btn btn-sm btn-outline-primary ml10">
編集
</a>
</div>
</td>
<td class="text-right">{{ $item->reserve_id }}</td> {{-- 定期予約ID --}}
<td class="text-right">{{ $item->contract_id ?? '' }}</td> {{-- 定期契約ID --}}
<td>{{ $item->contract_created_at ?? '' }}</td> {{-- 定期契約日時 --}}
<td class="text-right">{{ $item->user_categoryid ?? '' }}</td> {{-- 利用者分類ID --}}
<td>{{ trim(($item->user_id ?? '') . ' ' . ($item->user_name ?? '')) }}</td> {{-- 利用者ID --}}
<td>{{ $item->reserve_date ?? '' }}</td> {{-- 予約日時 --}}
<td>{{ $item->park_name ?? '' }}</td> {{-- 駐輪場ID --}}
<td>{{ $item->display_prine_name ?? '' }}</td> {{-- 駐輪場所ID --}}
<td>{{ $item->psection_subject ?? '' }}</td> {{-- 車種区分ID --}}
<td>{{ $item->ptype_subject ?? '' }}</td> {{-- 駐輪分類ID --}}
<td>
@if((string)($item->reserve_reduction ?? '') === '1')
あり
@elseif((string)($item->reserve_reduction ?? '') === '0')
なし
@else
{{ $item->reserve_reduction ?? '' }}
@endif
</td> {{-- 減免措置 --}}
<td>{{ $item->reserve_auto_remind ?? '' }}</td> {{-- 自動リマインド日 --}}
<td>{{ $item->reserve_manual_remind ?? '' }}</td> {{-- 手動リマインド日 --}}
<td>
@if((string)($item->flag_800m ?? '') === '1')
@elseif((string)($item->flag_800m ?? '') === '0')
×
@else
{{ $item->flag_800m ?? '' }}
@endif
</td> {{-- 800M以内フラグ --}}
<td>{{ $item->reserve_cancelday ?? '' }}</td> {{-- 解約日 --}}
<td>
@if((string)($item->valid_flag ?? '') === '1')
有効
@elseif((string)($item->valid_flag ?? '') === '0')
無効
@else
{{ $item->valid_flag ?? '' }}
@endif
</td> {{-- 有効フラグ --}}
<td>{{ $item->sent_date ?? '' }}</td> {{-- メール送信日時 --}}
<td>
@if((string)($item->reserve_manual ?? '') === '1')
手動
@elseif((string)($item->reserve_manual ?? '') === '0')
自動
@else
{{ $item->reserve_manual ?? '' }}
@endif
</td> {{-- 手動通知 --}}
<td>
@if((string)($item->reserve_notice ?? '') === 'tel')
電話
@elseif((string)($item->reserve_notice ?? '') === 'post')
郵送
@else
{{ $item->reserve_notice ?? '' }}
@endif
</td> {{-- 手動通知方法 --}}
<td class="text-right">{{ $item->reserve_order ?? '' }}</td> {{-- 空き待ち順 --}}
<td>
@if((string)($item->reserve_type ?? '') === '1')
仮予約
@elseif((string)($item->reserve_type ?? '') === '0')
通常予約
@else
{{ $item->reserve_type ?? '' }}
@endif
</td> {{-- ★予約区分 --}}
</tr>
@endforeach
</tbody>
</table>
</form>
</div>
</div>
{{-- CSVPOST のまま:ルートがある場合のみ) --}}
@if(\Illuminate\Support\Facades\Route::has('reserves.export'))
<form action="{{ route('reserves.export') }}" method="POST" id="form_export">
@csrf
<input type="hidden" name="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" value="{{ $sort_type ?? '' }}">
<input type="hidden" name="user_id" value="{{ request('user_id', $user_id ?? '') }}">
<input type="hidden" name="park_id" value="{{ request('park_id', $park_id ?? '') }}">
<input type="hidden" name="valid_flag" value="{{ request('valid_flag', $valid_flag ?? '') }}">
<input type="hidden" name="reserve_date_from" value="{{ request('reserve_date_from', $reserve_date_from ?? '') }}">
<input type="hidden" name="reserve_date_to" value="{{ request('reserve_date_to', $reserve_date_to ?? '') }}">
<input type="hidden" name="keyword" value="{{ request('keyword', $keyword ?? '') }}">
</form>
@endif
</div>
</section>
@endsection

View File

@ -1,347 +0,0 @@
@extends('layouts.app')
@section('title', '定期予約マスタ')
@section('content')
<style>
/* 画面全体のフォント/サイズを統一(やや小さめ) */
.rv-page,
.rv-page .card,
.rv-page .form-control,
.rv-page .btn,
.rv-page table,
.rv-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-size: 13px;
line-height: 1.45;
}
/* フィルター1行左ラベル右入力、を縦に積む */
.rv-filter .field{display:flex;align-items:center;margin-bottom:.6rem;}
.rv-filter .label{flex:0 0 170px;margin:0;color:#333;font-weight:600;white-space:nowrap;}
.rv-filter .input{flex:1 1 auto;min-width:220px;}
.rv-filter .form-control{height:calc(2.0rem + 2px);padding:.25rem .5rem;}
.rv-filter .inline-range{display:flex;gap:.5rem;align-items:center;}
.rv-filter .tilde{color:#666;}
/* 一覧テーブル:斑馬(ゼブラ)無し、やや詰め気味 */
.rv-table th,.rv-table td{padding:.35rem .5rem;font-size:12px;}
.rv-table thead th{white-space:nowrap;background:#eeeeee;}
.rv-table thead th.sortable{cursor:pointer;text-decoration:none;}
.rv-table thead th,
.rv-table thead th .sort-icon,
.rv-table thead th .sort-icon .up,
.rv-table thead th .sort-icon .down{
text-decoration:none !important;
}
.rv-table thead th.sorting_asc .sort-icon .up,
.rv-table thead th.sorting_desc .sort-icon .down{color:#000;}
.rv-table thead th .sort-icon{
display:inline-flex;
align-items:center;
flex-direction:row;
gap:2px;
font-size:11px;
color:#b5b5b5;
letter-spacing: -5px; /* ↑↓を詰める */
text-decoration: none; /* _削除 */
}
/* ツールバー:左にボタン群、右にページャ */
.rv-toolbar{display:flex;align-items:center;justify-content:space-between;gap:.75rem;flex-wrap:wrap;}
.rv-toolbar .btn+.btn{margin-left:.4rem;}
/* 操作セルの背景色(定期契約マスタと同じ雰囲気) */
.op-cell{background:#faebd7;}
</style>
<div class="rv-page">
{{-- パンくず・ヘッダ --}}
<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>
@if(session('success'))
<div class="alert alert-success py-2 px-3 my-2">{{ session('success') }}</div>
@endif
@if($errors->any())
<div class="alert alert-danger py-2 px-3 my-2">
<ul class="mb-0">
@foreach($errors->all() as $e)<li>{{ $e }}</li>@endforeach
</ul>
</div>
@endif
<p class="text-muted mb-0">※この画面では予約情報の検索・一括削除が行えます。</p>
</div>
</div>
<section class="content">
<div class="container-fluid">
{{-- 絞り込みフィルター(ここは前回どおり。必要に応じて調整可) --}}
<div class="card rv-filter">
<div class="card-header"><h3 class="card-title">絞り込みフィルター</h3></div>
<div class="card-body">
<form action="{{ route('reserves') }}" method="post" id="filter-form">
@csrf
<input type="hidden" name="sort" id="sort" value="{{ $sort }}">
<input type="hidden" name="sort_type" id="sort_type" value="{{ $sort_type }}">
<div class="row">
<div class="col-lg-6">
<div class="field">
<label class="label">利用者ID</label>
<div class="input">
<input type="text" class="form-control" name="user_id"
value="{{ $user_id ?? '' }}" placeholder="123456">
</div>
</div>
<div class="field">
<label class="label">有効フラグ</label>
<div class="input">
<select name="valid_flag" class="form-control">
<option value="">全て</option>
<option value="1" {{ (isset($valid_flag) && (string)$valid_flag==='1')?'selected':'' }}>有効</option>
<option value="0" {{ (isset($valid_flag) && (string)$valid_flag==='0')?'selected':'' }}>無効</option>
</select>
</div>
</div>
<div class="field">
<label class="label">メール送信日時</label>
<div class="input inline-range">
<input type="datetime-local" class="form-control" name="mail_sent_from"
value="{{ $mail_sent_from ?? '' }}">
<span class="tilde"></span>
<input type="datetime-local" class="form-control" name="mail_sent_to"
value="{{ $mail_sent_to ?? '' }}">
</div>
</div>
</div>
<div class="col-lg-6">
<div class="field">
<label class="label">駐輪場</label>
<div class="input">
<select name="park_id" class="form-control">
<option value="">全て</option>
@if(!empty($parkOptions) && is_iterable($parkOptions))
@foreach($parkOptions as $pid => $pname)
<option value="{{ $pid }}" {{ (isset($park_id) && (string)$park_id===(string)$pid)?'selected':'' }}>
{{ $pname }}
</option>
@endforeach
@endif
</select>
</div>
</div>
</div>
</div>
<div class="mt-2">
<button type="submit" class="btn btn-default">絞り込み</button>
<a href="{{ route('reserves') }}" class="btn btn-default">解除</a>
</div>
</form>
</div>
</div>
{{-- ツールバーボタン群、右ページャCSV出力→削除 --}}
<div class="rv-toolbar mb-2">
<div class="left">
<a href="{{ route('reserves_add') }}" class="btn btn-sm btn-default">新規</a>
<button type="button" class="btn btn-sm btn-default" id="btnBulkDel">削除</button>
</div>
<div class="right">
{{ $list->appends(['sort'=>$sort,'sort_type'=>$sort_type])->links('pagination') }}
</div>
</div>
{{-- 一覧テーブル(先頭列の並び替えを削除/操作列にチェック+編集) --}}
<div class="card">
<form id="bulkDeleteForm" method="post" action="{{ route('reserves_delete') }}">
@csrf
<input type="hidden" name="confirmed" value="1">
<div class="table-responsive">
<table class="table table-bordered table-hover rv-table mb-0 text-nowrap">
<thead>
@php
$currentSort = $sort ?? 'reserve_id';
$currentDir = strtolower($sort_type ?? 'asc');
if (!in_array($currentDir, ['asc','desc'], true)) { $currentDir = 'asc'; }
$sortClass = function(string $key) use ($currentSort, $currentDir) {
if ($currentSort === $key) {
return 'sortable sorting_' . $currentDir;
}
return 'sortable sorting';
};
$renderSortIcon = function() {
return '<span class="sort-icon"><span class="up">↑</span><span class="down">↓</span></span>';
};
@endphp
<tr>
<th style="width:140px;">
<input type="checkbox" id="chkAll">
<span class="ml-1"></span>
</th>
<th class="{{ $sortClass('reserve_id') }}" data-sort="reserve_id">定期予約ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('contract_id') }}" data-sort="contract_id">定期契約ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('contract_created_at') }}" data-sort="contract_created_at">定期契約日時 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('user_categoryid') }}" data-sort="user_categoryid">利用者分類ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('user_id') }}" data-sort="user_id">利用者ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_date') }}" data-sort="reserve_date">予約日時 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('park_price_name') }}" data-sort="park_price_name">駐輪場ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('price_parkplaceid') }}" data-sort="price_parkplaceid">駐輪場所ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('psection_subject') }}" data-sort="psection_subject">車種区分ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('ptype_subject') }}" data-sort="ptype_subject">駐輪分類ID {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_reduction') }}" data-sort="reserve_reduction">減免措置 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_auto_remind') }}" data-sort="reserve_auto_remind">自動リマインド日 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_manual_remind') }}" data-sort="reserve_manual_remind">手動リマインド日 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('flag_800m') }}" data-sort="flag_800m">800M以内フラグ {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_cancelday') }}" data-sort="reserve_cancelday">解約日 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('valid_flag') }}" data-sort="valid_flag">有効フラグ {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('sent_date') }}" data-sort="sent_date">メール送信日時 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_manual') }}" data-sort="reserve_manual">手動通知 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_notice') }}" data-sort="reserve_notice">手動通知方法 {!! $renderSortIcon() !!}</th>
<th class="{{ $sortClass('reserve_order') }}" data-sort="reserve_order">空き待ち順 {!! $renderSortIcon() !!}</th>
</tr>
</thead>
<tbody>
@foreach($list as $row)
<tr>
{{-- 操作セル--}}
<td class="op-cell">
<div class="d-flex align-items-center">
<input type="checkbox" class="mr-2 chkRow" name="ids[]" value="{{ $row->reserve_id }}">
<a href="{{ route('reserves_edit', ['reserve_id' => $row->reserve_id]) }}"
class="btn btn-sm btn-default">編集</a>
</div>
</td>
{{-- データ列(存在しないカラムは空文字で安全に表示) --}}
<td class="text-right">{{ $row->reserve_id }}</td> {{-- 定期予約ID --}}
<td class="text-right">{{ $row->contract_id ?? '' }}</td> {{-- 定期契約ID --}}
<td>{{ $row->contract_created_at ?? '' }}</td> {{-- 定期契約日時 --}}
<td>
@php
$subjects = array_values(array_filter([
$row->usertype_subject1 ?? '',
$row->usertype_subject2 ?? '',
$row->usertype_subject3 ?? '',
], fn($value) => $value !== ''));
@endphp
{{ $subjects ? implode('/', $subjects) : '' }}
</td> {{-- 利用者分類ID分類名// 表示) --}}
<td>{{ trim(($row->user_id ?? '') . ' ' . ($row->user_name ?? '')) }}</td> {{-- 利用者IDID 名字) --}}
<td>{{ $row->reserve_date ?? '' }}</td> {{-- 予約日時 --}}
<td>{{ trim($row->park_name ?? '') }}</td> {{-- 駐輪場ID --}}
<td>{{ $row->display_prine_name ?? '' }}</td> {{-- 駐輪場所ID --}}
<td>{{ $row->psection_subject ?? '' }}</td> {{-- 車種区分ID区分名を表示 --}}
<td>{{ $row->ptype_subject ?? '' }}</td> {{-- 駐輪分類IDptype_subject 表示 --}}
<td>{{ $row->reserve_reduction ?? '' }}</td> {{-- 減免措置 --}}
<td>{{ $row->reserve_auto_remind ?? '' }}</td> {{-- 自動リマインド日 --}}
<td>{{ $row->reserve_manual_remind ?? '' }}</td> {{-- 手動リマインド日 --}}
<td>{{ $row->flag_800m ?? '' }}</td> {{-- 800M以内フラグ --}}
<td>{{ $row->reserve_cancelday ?? '' }}</td> {{-- 解約日 --}}
<td>
@if((string)$row->valid_flag === '1')
有効
@elseif((string)$row->valid_flag === '0')
無効
@else
{{ $row->valid_flag ?? '' }}
@endif
</td> {{-- 有効フラグ --}}
<td>{{ $row->sent_date ?? '' }}</td> {{-- メール送信日時 --}}
<td>{{ $row->reserve_manual ?? '' }}</td> {{-- 手動通知 --}}
<td>{{ $row->reserve_notice ?? '' }}</td> {{-- 手動通知方法 --}}
<td class="text-right">{{ $row->reserve_order ?? '' }}</td> {{-- 空き待ち順 --}}
</tr>
@endforeach
</tbody>
</table>
</div>
</form>
</div>
{{-- 下側ページャ(右寄せ) --}}
<div class="d-flex justify-content-end mt-2">
{{ $list->appends(['sort'=>$sort,'sort_type'=>$sort_type])->links('pagination') }}
</div>
</div>
</section>
</div>
{{-- 一括削除のフロント処理jQuery不要 --}}
<script>
(function(){
var chkAll = document.getElementById('chkAll');
var chks = document.getElementsByClassName('chkRow');
var filterForm = document.getElementById('filter-form');
var sortInput = document.getElementById('sort');
var sortTypeInput = document.getElementById('sort_type');
// 全選択チェック
if (chkAll) {
chkAll.addEventListener('change', function(){
Array.prototype.forEach.call(chks, function(c){ c.checked = chkAll.checked; });
});
}
// 一括削除ボタン
var btn = document.getElementById('btnBulkDel');
var form = document.getElementById('bulkDeleteForm');
if (btn && form) {
btn.addEventListener('click', function(){
var any = false;
Array.prototype.forEach.call(chks, function(c){ if (c.checked) any = true; });
if (!any) { alert('削除対象の行を選択してください。'); return; }
var submitDelete = function () { form.submit(); };
if (window.jQuery && typeof window.jQuery.confirm === 'function') {
window.jQuery.confirm({
title: '確認ダイアログ。',
content: '削除してよろしいですか? はい/いいえ',
buttons: {
ok: {
text: 'はい',
btnClass: 'btn-primary',
keys: ['enter'],
action: submitDelete
},
いいえ: function () {}
}
});
} else if (confirm('削除してよろしいですか? はい/いいえ')) {
submitDelete();
}
});
}
var sortHeaders = document.querySelectorAll('th[data-sort]');
if (sortHeaders.length && filterForm && sortInput && sortTypeInput) {
Array.prototype.forEach.call(sortHeaders, function(th){
th.addEventListener('click', function(){
var key = th.getAttribute('data-sort');
if (!key) { return; }
var nextDir = 'asc';
if (sortInput.value === key) {
nextDir = sortTypeInput.value === 'asc' ? 'desc' : 'asc';
}
sortInput.value = key;
sortTypeInput.value = nextDir;
filterForm.submit();
});
});
}
})();
</script>
@endsection

View File

@ -1,4 +1,3 @@
{{-- アラート(成功) --}} {{-- アラート(成功) --}}
@if(Session::has('success')) @if(Session::has('success'))
<div class="alert alert-success alert-dismissible" role="alert"> <div class="alert alert-success alert-dismissible" role="alert">
@ -19,7 +18,15 @@
@if(isset($errorMsg)) @if(isset($errorMsg))
<div class="alert alert-danger alert-dismissible" role="alert"> <div class="alert alert-danger alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
@if(is_array($errorMsg))
<ul class="mb-0">
@foreach($errorMsg as $msg)
<li>{{ $msg }}</li>
@endforeach
</ul>
@else
{!! $errorMsg !!} {!! $errorMsg !!}
@endif
</div> </div>
@endif @endif
@ -40,7 +47,7 @@
<div class="row"> <div class="row">
{{-- 利用者分類ID編集時のみ表示 --}} {{-- 利用者分類ID編集時のみ表示 --}}
@if(!empty($isEdit) || !empty($isInfo)) @if(!empty($isEdit))
<div class="form-group col-3"> <div class="form-group col-3">
<label>{{ __('validation.attributes.user_categoryid') }}</label> <label>{{ __('validation.attributes.user_categoryid') }}</label>
</div> </div>
@ -96,7 +103,7 @@
</div> </div>
</div> </div>
{{-- 分類名3 --}} {{-- 分類名3(任意) --}}
<div class="form-group col-3"> <div class="form-group col-3">
<label class="form-label required">{{ __('分類名3') }}</label> <label class="form-label required">{{ __('分類名3') }}</label>
</div> </div>

View File

@ -13,7 +13,7 @@
<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>
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="{{ route('usertypes') }}">利用者分類マスタ</a> <a href="{{ route('usertypes.index') }}">利用者分類マスタ</a>
</li> </li>
<li class="breadcrumb-item active">新規</li> <li class="breadcrumb-item active">新規</li>
</ol> </ol>
@ -33,13 +33,12 @@
<form id="form_add" <form id="form_add"
method="post" method="post"
action="{{ route('usertype_add') }}" action="{{ route('usertypes.store') }}"
enctype="multipart/form-data"> enctype="multipart/form-data">
@csrf @csrf
@include('admin.usertypes._form', [ @include('admin.usertypes._form', [
'isEdit' => false, 'isEdit' => false
'isInfo' => false
]) ])
</form> </form>

View File

@ -13,7 +13,7 @@
<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>
<li class="breadcrumb-item"> <li class="breadcrumb-item">
<a href="{{ route('usertypes') }}">利用者分類マスタ</a> <a href="{{ route('usertypes.index') }}">利用者分類マスタ</a>
</li> </li>
<li class="breadcrumb-item active">編集</li> <li class="breadcrumb-item active">編集</li>
</ol> </ol>
@ -33,7 +33,7 @@
{{-- 編集フォーム --}} {{-- 編集フォーム --}}
<form id="form_edit" <form id="form_edit"
action="{{ route('usertype_edit', ['id' => $record->user_categoryid]) }}" action="{{ route('usertypes.update', ['id' => $record->user_categoryid]) }}"
method="POST" method="POST"
enctype="multipart/form-data"> enctype="multipart/form-data">
@csrf @csrf
@ -44,10 +44,9 @@
]) ])
</form> </form>
{{-- 削除フォーム(非表示) --}} {{-- 削除フォーム(非表示) --}}
<form id="form_delete" <form id="form_delete"
action="{{ route('usertypes_delete') }}" action="{{ route('usertypes.destroy') }}"
method="POST" method="POST"
style="display:none;"> style="display:none;">
@csrf @csrf

View File

@ -0,0 +1,260 @@
@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">
{{-- 並び替え用 hiddencity と同型JS はここを submit --}}
<form method="GET" action="{{ route('usertypes.index') }}" id="list-form">
<input type="hidden" name="sort" id="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" id="sort_type" value="{{ $sort_type ?? '' }}">
{{-- フィルタ条件(並び替え時に条件が消えないように hidden で保持) --}}
<input type="hidden" name="filter_sort_order" value="{{ request('filter_sort_order', $filter_sort_order ?? '') }}">
<input type="hidden" name="filter_usertype_subject1" value="{{ request('filter_usertype_subject1', $filter_usertype_subject1 ?? '') }}">
<input type="hidden" name="filter_usertype_subject2" value="{{ request('filter_usertype_subject2', $filter_usertype_subject2 ?? '') }}">
<input type="hidden" name="filter_usertype_subject3" value="{{ request('filter_usertype_subject3', $filter_usertype_subject3 ?? '') }}">
</form>
<!-- 絞り込みフィルター -->
<div class="col-lg-12 px-0">
<div class="card">
<div class="card-header">
<h3 class="card-title">絞り込みフィルター</h3>
</div>
<div class="card-body">
{{-- city と同じ GET 運用 --}}
<form action="{{ route('usertypes.index') }}" method="GET" id="filter-form">
{{-- 現在の並び順も 유지filter しても sort が消えない) --}}
<input type="hidden" name="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" value="{{ $sort_type ?? '' }}">
{{-- 1行目:ソートオーダー / 分類名1 / 分類名2 --}}
<div class="row mb-3">
<div class="col-md-4">
<div class="font-weight-bold mb-2">ソートオーダー</div>
<input type="text"
name="filter_sort_order"
class="form-control"
value="{{ request('filter_sort_order', $filter_sort_order ?? '') }}"
placeholder="123456">
</div>
<div class="col-md-4">
<div class="font-weight-bold mb-2">分類名1</div>
<input type="text"
name="filter_usertype_subject1"
class="form-control"
value="{{ request('filter_usertype_subject1', $filter_usertype_subject1 ?? '') }}"
placeholder="キーワード...">
</div>
<div class="col-md-4">
<div class="font-weight-bold mb-2">分類名2</div>
<input type="text"
name="filter_usertype_subject2"
class="form-control"
value="{{ request('filter_usertype_subject2', $filter_usertype_subject2 ?? '') }}"
placeholder="キーワード...">
</div>
</div>
{{-- 2行目分類名3 --}}
<div class="row mb-3">
<div class="col-md-4">
<div class="font-weight-bold mb-2">分類名3</div>
<input type="text"
name="filter_usertype_subject3"
class="form-control"
value="{{ request('filter_usertype_subject3', $filter_usertype_subject3 ?? '') }}"
placeholder="キーワード...">
</div>
</div>
{{-- ボタン --}}
<div class="mt-2">
<button type="submit" class="btn btn-success mr-2">
絞り込み
</button>
{{-- 解除sort/sort_type も初期化したいなら route('usertypes.index') のみにする) --}}
<a href="{{ route('usertypes.index') }}" class="btn btn-outline-secondary">
解除
</a>
</div>
</form>
</div>
</div>
</div>
<!-- 絞り込みフィルター -->
{{-- ボタンエリアcity と同型) --}}
<div class="col-lg-12 mb-3 px-0">
<button type="button"
class="btn btn-sm btn-primary mr10"
onclick="location.href='{{ route('usertypes.create') }}?back={{ urlencode(request()->fullUrl()) }}'">
新規
</button>
<button type="button" class="btn btn-sm btn-danger mr10" id="delete">削除</button>
<button type="submit" class="btn btn-sm btn-outline-success mr10" form="form_export">
CSV出力
</button>
</div>
{{-- ページネーションcity と同型) --}}
<div class="col-lg-12 px-0">
<div class="d-flex flex-column align-items-end mb-2 text-sm">
<div class="text-dark text-sm mb-1">
@if ($list->total() > 0)
{{ $list->total() }} 件中 {{ $list->firstItem() }}{{ $list->lastItem() }} 件を表示
@else
全0件
@endif
</div>
<div>
{{ $list->appends([
'sort' => $sort ?? '',
'sort_type' => $sort_type ?? '',
] + request()->except('page'))->links('pagination') }}
</div>
</div>
</div>
{{-- フラッシュメッセージcity と同型) --}}
<div class="form col-lg-12 px-0">
@if(Session::has('success'))
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ Session::get('success') }}
</div>
@elseif(Session::has('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{!! Session::get('error') !!}
</div>
@elseif(isset($errorMsg))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{!! $errorMsg !!}
</div>
@endif
</div>
{{-- テーブルcity と同型) --}}
<div class="col-lg-12 mb20 px-0">
<div class="table-responsive">
<form id="form_delete" method="POST" action="{{ route('usertypes.destroy') }}">
@csrf
<table class="table table-bordered dataTable text-nowrap">
<thead class="thead-light">
<tr>
<th style="width:140px;">
<input type="checkbox"
class="js-check-all"
onclick="$('input[name*=\'pk\']').prop('checked', this.checked);">
</th>
<th class="sorting {{ ($sort ?? '') === 'user_categoryid' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="user_categoryid">
<span>利用者分類ID</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'sort_order' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="sort_order">
<span>ソートオーダー</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'usertype_subject1' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="usertype_subject1">
<span>分類名1</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'usertype_subject2' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="usertype_subject2">
<span>分類名2</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'usertype_subject3' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="usertype_subject3">
<span>分類名3</span>
</th>
<th class="sorting {{ ($sort ?? '') === 'print_name' ? (($sort_type ?? '') === 'asc' ? 'sorting_asc' : 'sorting_desc') : '' }}"
sort="print_name">
<span>印字名</span>
</th>
<th><span>適用料率</span></th>
<th><span>備考</span></th>
</tr>
</thead>
<tbody class="bg-white">
@foreach ($list as $item)
<tr>
<td style="background-color:#faebd7;">
<div class="d-flex align-items-center">
<input type="checkbox" name="pk[]" value="{{ $item->user_categoryid }}">
<a href="{{ route('usertypes.edit', ['id' => $item->user_categoryid]) }}?back={{ urlencode(request()->fullUrl()) }}"
class="btn btn-sm btn-outline-primary ml10">
編集
</a>
</div>
</td>
<td>{{ $item->user_categoryid }}</td>
<td>{{ $item->sort_order }}</td>
<td>{{ $item->usertype_subject1 }}</td>
<td>{{ $item->usertype_subject2 }}</td>
<td>{{ $item->usertype_subject3 }}</td>
<td>{{ $item->print_name }}</td>
<td class="text-right">{{ $item->usertype_money }}</td>
<td>{{ $item->usertype_remarks }}</td>
</tr>
@endforeach
</tbody>
</table>
</form>
</div>
</div>
{{-- CSVPOST のまま) --}}
<form action="{{ route('usertypes.export') }}" method="POST" id="form_export">
@csrf
{{-- 現在の検索条件を引き継ぐなら hidden を足す(必要なら) --}}
<input type="hidden" name="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" value="{{ $sort_type ?? '' }}">
<input type="hidden" name="filter_sort_order" value="{{ request('filter_sort_order', $filter_sort_order ?? '') }}">
<input type="hidden" name="filter_usertype_subject1" value="{{ request('filter_usertype_subject1', $filter_usertype_subject1 ?? '') }}">
<input type="hidden" name="filter_usertype_subject2" value="{{ request('filter_usertype_subject2', $filter_usertype_subject2 ?? '') }}">
<input type="hidden" name="filter_usertype_subject3" value="{{ request('filter_usertype_subject3', $filter_usertype_subject3 ?? '') }}">
</form>
</div>
</section>
@endsection

View File

@ -1,259 +0,0 @@
@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">
<!-- 絞り込みフィルター -->
<div class="col-lg-12 px-0">
<div class="card">
<div class="card-header">
<h3 class="card-title">絞り込みフィルター</h3>
</div>
<div class="card-body">
<form action="{{ route('usertypes') }}" method="POST" id="list-form">
@csrf
<input type="hidden" name="sort" id="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" id="sort_type" value="{{ $sort_type ?? '' }}">
{{-- 1行目:ソートオーダー / 分類名1 / 分類名2ラベル上・入力下 --}}
<div class="row mb-3">
<div class="col-md-4">
<div class="font-weight-bold mb-2">ソートオーダー</div>
<input type="text"
name="filter_sort_order"
class="form-control"
value="{{ $filter_sort_order ?? '' }}"
placeholder="123456">
</div>
<div class="col-md-4">
<div class="font-weight-bold mb-2">分類名1</div>
<input type="text"
name="filter_usertype_subject1"
class="form-control"
value="{{ $filter_usertype_subject1 ?? '' }}"
placeholder="キーワード...">
</div>
<div class="col-md-4">
<div class="font-weight-bold mb-2">分類名2</div>
<input type="text"
name="filter_usertype_subject2"
class="form-control"
value="{{ $filter_usertype_subject2 ?? '' }}"
placeholder="キーワード...">
</div>
</div>
{{-- 2行目分類名3左寄せ、幅は1/3 --}}
<div class="row mb-3">
<div class="col-md-4">
<div class="font-weight-bold mb-2">分類名3</div>
<input type="text"
name="filter_usertype_subject3"
class="form-control"
value="{{ $filter_usertype_subject3 ?? '' }}"
placeholder="キーワード...">
</div>
</div>
{{-- ボタン --}}
<div class="mt-2">
<button type="submit" name="action" value="filter" class="btn btn-success mr-2">
絞り込み
</button>
<button type="submit" name="action" value="unlink" class="btn btn-outline-secondary">
解除
</button>
</div>
</form>
</div>
</div>
</div>
<!-- 絞り込みフィルター -->
{{-- 並び替え用 hidden --}}
<form action="{{ route('usertypes') }}" method="POST" id="list-form">
@csrf
<input type="hidden" name="sort" value="{{ $sort ?? '' }}">
<input type="hidden" name="sort_type" value="{{ $sort_type ?? '' }}">
</form>
{{-- ボタンエリア --}}
<div class="col-lg-12 mb-3">
<button type="button"
class="btn btn-sm btn-primary mr10"
onclick="location.href='{{ route('usertype_add') }}?back={{ urlencode(request()->fullUrl()) }}'">
新規
</button>
<button type="button" class="btn btn-sm btn-danger mr10" id="delete">削除</button>
<button type="submit" class="btn btn-sm btn-outline-success mr10" form="form_export">
CSV出力
</button>
</div>
{{-- ページネーション --}}
<div class="col-lg-12">
<div class="d-flex flex-column align-items-end mb-2 text-sm">
{{-- 件数表示(上) --}}
<div class="text-dark text-sm mb-1">
@if ($list->total() > 0)
{{ $list->total() }} 件中 {{ $list->firstItem() }}{{ $list->lastItem() }} 件を表示
@else
全0件
@endif
</div>
{{-- ページネーション(下) --}}
<div>
{{ $list->appends([
'sort' => $sort ?? '',
'sort_type' => $sort_type ?? ''
])->links('pagination') }}
</div>
</div>
</div>
{{-- ページネーション --}}
{{-- フラッシュメッセージ --}}
<div class="form col-lg-12">
@if(Session::has('success'))
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ Session::get('success') }}
</div>
@elseif(Session::has('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{!! Session::get('error') !!}
</div>
@elseif(isset($errorMsg))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">×</button>
{!! $errorMsg !!}
</div>
@endif
</div>
{{-- テーブル --}}
<div class="col-lg-12 mb20">
<div class="table-responsive">
<form action="{{ route('usertypes_delete') }}" method="POST" id="form_delete">
@csrf
<table class="table table-bordered dataTable text-nowrap">
<thead class="thead-light">
<tr>
{{-- チェック + 編集 --}}
<th style="width:140px;">
<input type="checkbox"
onclick="$('input[name*=\'pk\']').prop('checked', this.checked);">
</th>
<th class="sorting {{ $sort=='user_categoryid' ? ($sort_type=='asc'?'sorting_asc':'sorting_desc') : '' }}"
sort="user_categoryid">
<span>利用者分類ID</span>
</th>
<th class="sorting {{ $sort=='sort_order' ? ($sort_type=='asc'?'sorting_asc':'sorting_desc') : '' }}"
sort="sort_order">
<span>ソートオーダー</span>
</th>
<th class="sorting {{ $sort=='usertype_subject1' ? ($sort_type=='asc'?'sorting_asc':'sorting_desc') : '' }}"
sort="usertype_subject1">
<span>分類名1</span>
</th>
<th class="sorting {{ $sort=='usertype_subject2' ? ($sort_type=='asc'?'sorting_asc':'sorting_desc') : '' }}"
sort="usertype_subject2">
<span>分類名2</span>
</th>
<th class="sorting {{ $sort=='usertype_subject3' ? ($sort_type=='asc'?'sorting_asc':'sorting_desc') : '' }}"
sort="usertype_subject3">
<span>分類名3</span>
</th>
<th class="sorting {{ $sort=='print_name' ? ($sort_type=='asc'?'sorting_asc':'sorting_desc') : '' }}"
sort="print_name">
<span>印字名</span>
</th>
<th><span>適用料率</span></th>
<th><span>備考</span></th>
</tr>
</thead>
<tbody class="bg-white">
@foreach($list as $item)
<tr>
<td style="background-color:#faebd7;">
<div class="d-flex align-items-center">
<input type="checkbox" name="pk[]" value="{{ $item->user_categoryid }}">
<a href="{{ route('usertype_edit', ['id' => $item->user_categoryid]) }}?back={{ urlencode(request()->fullUrl()) }}"
class="btn btn-sm btn-outline-primary ml10">
編集
</a>
</div>
</td>
<td>{{ $item->user_categoryid }}</td>
<td>{{ $item->sort_order }}</td>
<td>{{ $item->usertype_subject1 }}</td>
<td>{{ $item->usertype_subject2 }}</td>
<td>{{ $item->usertype_subject3 }}</td>
<td>{{ $item->print_name }}</td>
<td class="text-right">{{ $item->usertype_money }}</td>
<td>{{ $item->usertype_remarks }}</td>
</tr>
@endforeach
<!-- @if($list->isEmpty())
<tr>
<td colspan="9" class="text-center text-muted">
データが存在しません。
</td>
</tr>
@endif -->
</tbody>
</table>
</form>
</div>
</div>
</div>
</section>
{{-- CSV --}}
<form action="{{ route('usertypes_export') }}" method="POST" id="form_export">
@csrf
</form>
@endsection

View File

@ -451,15 +451,15 @@
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href="{{ route('reserves') }}" <a href="{{ route('reserves.index') }}"
class="nav-link @if(app('router')->is('reserves')) active @endif"> class="nav-link {{ str_starts_with(Route::currentRouteName(), 'reserves.') ? 'active' : '' }}">
<span style="margin-left:20px;">定期予約マスタ</span> <span style="margin-left:20px;">定期予約マスタ</span>
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href="{{ route('usertypes') }}" <a href="{{ route('usertypes.index') }}"
class="nav-link @if(app('router')->is('usertypes')) active @endif"> class="nav-link {{ str_starts_with(Route::currentRouteName(), 'usertypes.') ? 'active' : '' }}">
<span style="margin-left:20px;">利用者分類マスタ</span> <span style="margin-left:20px;">利用者分類マスタ</span>
</a> </a>
</li> </li>
@ -504,17 +504,18 @@
<ul class="nav nav-treeview" <ul class="nav nav-treeview"
style="display: @if(in_array($current, $parkingRoutes)) block @else none @endif;"> style="display: @if(in_array($current, $parkingRoutes)) block @else none @endif;">
<li class="nav-item"> <li class="nav-item">
<a href="{{ route('parks') }}" <a href="{{ route('parks.index') }}"
class="nav-link @if($current === 'parks') active @endif"> class="nav-link @if($current === 'parks') active @endif">
<span style="margin-left:20px;">{{ __("駐輪場マスタ") }}</span> <span style="margin-left:20px;">{{ __("駐輪場マスタ") }}</span>
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href="{{ route('city') }}" <a href="{{ route('cities.index') }}"
class="nav-link @if($current === 'city') active @endif"> class="nav-link @if($current === 'cities') active @endif">
<span style="margin-left:20px;">{{ __("市区マスタ") }}</span> <span style="margin-left:20px;">{{ __('市区マスタ') }}</span>
</a> </a>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a href="{{ route('pricelist') }}" <a href="{{ route('pricelist') }}"
class="nav-link @if($current === 'pricelist') active @endif"> class="nav-link @if($current === 'pricelist') active @endif">

View File

@ -150,56 +150,78 @@ Route::middleware('auth')->group(function () {
Route::get('/pplace/export', [PplaceController::class, 'export'])->name('pplaces_export'); Route::get('/pplace/export', [PplaceController::class, 'export'])->name('pplaces_export');
// sou end // sou end
// ou start
// // 市区マスタ
// Route::match(['get', 'post'], '/city', [CityController::class, 'list'])->name('city');
// Route::match(['get', 'post'], '/city/add', [CityController::class, 'add'])->name('city_add');
// Route::match(['get', 'post'], '/city/edit/{id}', [CityController::class, 'edit'])->where(['id' => '[0-9]+'])->name('city_edit');
// 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');
// 市区マスタcities.* // 市区マスタcities.*
Route::prefix('cities')->group(function () { Route::prefix('cities')->group(function () {
// 一覧(画面) // 一覧(画面)
Route::get('/', [\App\Http\Controllers\Admin\CityController::class, 'index']) Route::get('/', [CityController::class, 'index'])
->name('cities.index'); ->name('cities.index');
// 新規(画面) // 新規(画面)
Route::get('/create', [\App\Http\Controllers\Admin\CityController::class, 'create']) Route::get('/create', [CityController::class, 'create'])
->name('cities.create'); ->name('cities.create');
// 新規(登録) // 新規(登録)
Route::post('/', [\App\Http\Controllers\Admin\CityController::class, 'store']) Route::post('/', [CityController::class, 'store'])
->name('cities.store'); ->name('cities.store');
// 編集(画面) // 編集(画面)
Route::get('/{id}/edit', [\App\Http\Controllers\Admin\CityController::class, 'edit']) Route::get('/{id}/edit', [CityController::class, 'edit'])
->whereNumber('id') ->whereNumber('id')
->name('cities.edit'); ->name('cities.edit');
// 編集(更新) // 編集(更新)
Route::post('/{id}', [\App\Http\Controllers\Admin\CityController::class, 'update']) Route::post('/{id}', [CityController::class, 'update'])
->whereNumber('id') ->whereNumber('id')
->name('cities.update'); ->name('cities.update');
// 削除(複数削除 pk[] // 削除(複数削除 pk[]
Route::post('/delete', [\App\Http\Controllers\Admin\CityController::class, 'destroy']) Route::post('/delete', [CityController::class, 'destroy'])
->name('cities.destroy'); ->name('cities.destroy');
}); });
// 駐輪場マスタparks.*
Route::prefix('parks')->group(function () {
// 一覧(画面)
Route::get('/', [ParkController::class, 'index'])
->name('parks.index');
// 新規(画面)
Route::get('/create', [ParkController::class, 'create'])
->name('parks.create');
// 新規(登録)
Route::post('/', [ParkController::class, 'store'])
->name('parks.store');
// 編集(画面)
Route::get('/{id}/edit', [ParkController::class, 'edit'])
->whereNumber('id')
->name('parks.edit');
// 編集(更新)
Route::post('/{id}', [ParkController::class, 'update'])
->whereNumber('id')
->name('parks.update');
// 削除(複数削除 pk[]
Route::post('/delete', [ParkController::class, 'destroy'])
->name('parks.destroy');
// CSV 出力(必要なら)
Route::post('/export', [ParkController::class, 'export'])
->name('parks.export');
// CSV 取込(必要なら)
Route::post('/import', [ParkController::class, 'import'])
->name('parks.import');
// 重複チェック(必要なら)
Route::post('/check-duplicate', [ParkController::class, 'checkDuplicate'])
->name('parks.check_duplicate');
});
// 駐輪場マスタ
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::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::match(['get', 'post'], '/admin/pricelist', [PriceListController::class, 'list'])->name('pricelist'); Route::match(['get', 'post'], '/admin/pricelist', [PriceListController::class, 'list'])->name('pricelist');
@ -262,21 +284,81 @@ Route::middleware('auth')->group(function () {
Route::match(['get', 'post'], '/regularcontracts/info/{contract_id}', [RegularContractController::class, 'info'])->where(['contract_id' => '[0-9]+'])->name('regularcontracts_info'); Route::match(['get', 'post'], '/regularcontracts/info/{contract_id}', [RegularContractController::class, 'info'])->where(['contract_id' => '[0-9]+'])->name('regularcontracts_info');
Route::match(['get', 'post'], '/regularcontracts/delete', [RegularContractController::class, 'delete'])->name('regularcontracts_delete'); Route::match(['get', 'post'], '/regularcontracts/delete', [RegularContractController::class, 'delete'])->name('regularcontracts_delete');
// 定期予約マスタ // 定期予約マスタreserves.*
Route::match(['get', 'post'], '/reserves', [ReservesController::class, 'list'])->name('reserves'); Route::prefix('reserves')->group(function () {
Route::match(['get', 'post'], '/reserves/add', [ReservesController::class, 'add'])->name('reserves_add');
Route::match(['get', 'post'], '/reserves/edit/{reserve_id}', [ReservesController::class, 'edit'])->name('reserves_edit'); // 一覧(画面)
Route::match(['get', 'post'], '/reserves/delete', [ReservesController::class, 'delete'])->name('reserves_delete'); Route::get('/', [ReservesController::class, 'index'])
Route::match(['get', 'post'], '/reserves/export', [ReservesController::class, 'export'])->name('reserves_export'); ->name('reserves.index');
// 新規(画面)
Route::get('/create', [ReservesController::class, 'create'])
->name('reserves.create');
// 新規(登録)
Route::post('/', [ReservesController::class, 'store'])
->name('reserves.store');
// 編集(画面)
Route::get('/{reserve_id}/edit', [ReservesController::class, 'edit'])
->whereNumber('reserve_id')
->name('reserves.edit');
// 編集(更新)
Route::post('/{reserve_id}', [ReservesController::class, 'update'])
->whereNumber('reserve_id')
->name('reserves.update');
// 削除(複数削除 pk[]
Route::post('/delete', [ReservesController::class, 'destroy'])
->name('reserves.destroy');
// エクスポート
Route::post('/export', [ReservesController::class, 'export'])
->name('reserves.export');
});
// 利用者分類マスタusertypes.*
Route::prefix('usertypes')->group(function () {
// 一覧(画面)
Route::get('/', [UsertypeController::class, 'index'])
->name('usertypes.index');
// 新規(画面)
Route::get('/create', [UsertypeController::class, 'create'])
->name('usertypes.create');
// 新規(登録)
Route::post('/', [UsertypeController::class, 'store'])
->name('usertypes.store');
// 編集(画面)
Route::get('/{id}/edit', [UsertypeController::class, 'edit'])
->whereNumber('id')
->name('usertypes.edit');
// 編集(更新)
Route::post('/{id}', [UsertypeController::class, 'update'])
->whereNumber('id')
->name('usertypes.update');
// 削除(複数削除 pk[]
Route::post('/delete', [UsertypeController::class, 'destroy'])
->name('usertypes.destroy');
// インポート
Route::post('/import', [UsertypeController::class, 'import'])
->name('usertypes.import');
// エクスポート
Route::post('/export', [UsertypeController::class, 'export'])
->name('usertypes.export');
});
// 利用者分類マスタ
Route::match(['get', 'post'], '/usertypes', [UsertypeController::class, 'list'])->name('usertypes');
Route::match(['get', 'post'], '/usertypes/add', [UsertypeController::class, 'add'])->name('usertype_add');
Route::match(['get', 'post'], '/usertypes/edit/{id}', [UsertypeController::class, 'edit'])->name('usertype_edit')->where(['id' => '[0-9]+']);
Route::match(['get', 'post'], '/usertypes/info/{id}', [UsertypeController::class, 'info'])->name('usertype_info')->where(['id' => '[0-9]+']);
Route::match(['get', 'post'], '/usertypes/delete', [UsertypeController::class, 'delete'])->name('usertypes_delete');
Route::match(['get', 'post'], '/usertypes/import', [UsertypeController::class, 'import'])->name('usertypes_import');
Route::match(['get', 'post'], '/usertypes/export', [UsertypeController::class, 'export'])->name('usertypes_export');