feat(app-ui): UI組合編輯/機台設定 也加每頁筆數+搜尋+分頁

抽共用元件 x-app-list-controls(3頁共用);bundles 依名稱、machines 依名稱/序號搜尋 paginate

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
terrylee 2026-07-16 10:38:44 +08:00
parent 4d5d42f4cb
commit f43772fa99
7 changed files with 68 additions and 27 deletions

View File

@ -99,11 +99,19 @@ class UiElementController extends Controller
// 頁籤二UI 組合編輯
// ==================================================================
public function bundles()
public function bundles(Request $request)
{
$bundles = UiBundle::orderBy('id')->get();
$perPage = (int) $request->input('per_page', 10);
$perPage = in_array($perPage, [10, 25, 50, 100], true) ? $perPage : 10;
$search = trim((string) $request->input('search', ''));
return view('admin.app.ui-bundles.index', compact('bundles'));
$query = UiBundle::orderBy('id');
if ($search !== '') {
$query->where('name', 'like', "%{$search}%");
}
$bundles = $query->paginate($perPage)->withQueryString();
return view('admin.app.ui-bundles.index', compact('bundles', 'perPage', 'search'));
}
public function storeBundle(Request $request)
@ -186,16 +194,28 @@ class UiElementController extends Controller
public function machines(Request $request)
{
$machines = Machine::orderBy('name')->paginate(20);
$bundles = UiBundle::orderBy('name')->get();
$perPage = (int) $request->input('per_page', 25);
$perPage = in_array($perPage, [10, 25, 50, 100], true) ? $perPage : 25;
$search = trim((string) $request->input('search', ''));
// 現有綁定名稱對照
$query = Machine::orderBy('name');
if ($search !== '') {
$query->where(function ($q) use ($search) {
$q->where('name', 'like', "%{$search}%")
->orWhere('serial_no', 'like', "%{$search}%");
});
}
$machines = $query->paginate($perPage)->withQueryString();
$bundles = UiBundle::orderBy('name')->get();
$bundleNames = $bundles->pluck('name', 'id');
return view('admin.app.ui-machines.index', [
'machines' => $machines,
'bundles' => $bundles,
'bundleNames' => $bundleNames,
'perPage' => $perPage,
'search' => $search,
]);
}

View File

@ -2350,6 +2350,8 @@
"No data": "No data",
"entries": "entries",
"Search name or category...": "Search name or category...",
"Search name...": "Search name...",
"Search machine or serial...": "Search machine or serial...",
"Back": "Back",
"Rename": "Rename",
"Content Settings": "Content Settings",

View File

@ -2351,6 +2351,8 @@
"No data": "無資料",
"entries": "筆",
"Search name or category...": "搜尋名稱或類別…",
"Search name...": "搜尋名稱…",
"Search machine or serial...": "搜尋機台名稱或序號…",
"Back": "返回",
"Rename": "重新命名",
"Content Settings": "內容設定",

View File

@ -9,6 +9,8 @@
</button>
</x-app-tabs>
<x-app-list-controls :route="route('admin.app.ui-bundles')" :perPage="$perPage" :search="$search" :placeholder="__('Search name...')" />
<div class="overflow-x-auto">
<table class="min-w-full bg-white dark:bg-gray-800 rounded-lg overflow-hidden">
<thead class="bg-gray-100 dark:bg-gray-700">
@ -48,6 +50,10 @@
</table>
</div>
<div class="mt-4">
{{ $bundles->links() }}
</div>
{{-- 新增組合 Modal --}}
<div x-show="showCreate" x-cloak class="fixed inset-0 z-50 overflow-y-auto" @keydown.escape.window="showCreate = false">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:p-0">

View File

@ -9,27 +9,7 @@
</button>
</x-app-tabs>
{{-- 控制列:每頁筆數 + 搜尋 --}}
<form method="GET" action="{{ route('admin.app.ui-elements') }}" class="flex flex-wrap items-center justify-between gap-3 mb-4">
<div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
<span>{{ __('Show') }}</span>
<select name="per_page" onchange="this.form.submit()" class="luxury-input py-1.5 px-2 text-sm w-auto">
@foreach([10, 25, 50, 100] as $n)
<option value="{{ $n }}" {{ $perPage === $n ? 'selected' : '' }}>{{ $n }}</option>
@endforeach
</select>
<span>{{ __('entries') }}</span>
</div>
<div class="flex items-center gap-2">
<input type="text" name="search" value="{{ $search }}" placeholder="{{ __('Search name or category...') }}" class="luxury-input py-2 px-3 text-sm sm:w-72">
<button type="submit" class="p-2.5 rounded-xl bg-cyan-500 text-white hover:bg-cyan-600 shadow-lg shadow-cyan-500/25 transition-all active:scale-95" title="{{ __('Search') }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /></svg>
</button>
<a href="{{ route('admin.app.ui-elements') }}" class="p-2.5 rounded-xl bg-slate-100 dark:bg-slate-800 text-slate-500 hover:bg-slate-200 dark:hover:bg-slate-700 transition-all active:scale-95" title="{{ __('Reset') }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" /></svg>
</a>
</div>
</form>
<x-app-list-controls :route="route('admin.app.ui-elements')" :perPage="$perPage" :search="$search" :placeholder="__('Search name or category...')" />
<div class="overflow-x-auto">
<table class="min-w-full bg-white dark:bg-gray-800 rounded-lg overflow-hidden">

View File

@ -4,6 +4,8 @@
<div class="px-6 py-8">
<x-app-tabs active="machines" />
<x-app-list-controls :route="route('admin.app.ui-machines')" :perPage="$perPage" :search="$search" :placeholder="__('Search machine or serial...')" />
<div class="overflow-x-auto">
<table class="min-w-full bg-white dark:bg-gray-800 rounded-lg overflow-hidden">
<thead class="bg-gray-100 dark:bg-gray-700">

View File

@ -0,0 +1,29 @@
{{-- APP UI元素設定 列表控制列:每頁筆數下拉(左)+ 搜尋欄/重置(右)。一般 GET 表單(非 AJAX
用法:<x-app-list-controls :route="route('admin.app.ui-elements')" :perPage="$perPage" :search="$search" :placeholder="__('...')" /> --}}
@props([
'route' => '',
'perPage' => 10,
'search' => '',
'placeholder' => '',
])
<form method="GET" action="{{ $route }}" class="flex flex-wrap items-center justify-between gap-3 mb-4">
<div class="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
<span>{{ __('Show') }}</span>
<select name="per_page" onchange="this.form.submit()" class="luxury-input py-1.5 px-2 text-sm w-auto">
@foreach([10, 25, 50, 100] as $n)
<option value="{{ $n }}" {{ (int)$perPage === $n ? 'selected' : '' }}>{{ $n }}</option>
@endforeach
</select>
<span>{{ __('entries') }}</span>
</div>
<div class="flex items-center gap-2">
<input type="text" name="search" value="{{ $search }}" placeholder="{{ $placeholder ?: __('Search...') }}" class="luxury-input py-2 px-3 text-sm sm:w-72">
<button type="submit" class="p-2.5 rounded-xl bg-cyan-500 text-white hover:bg-cyan-600 shadow-lg shadow-cyan-500/25 transition-all active:scale-95" title="{{ __('Search') }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" /></svg>
</button>
<a href="{{ $route }}" class="p-2.5 rounded-xl bg-slate-100 dark:bg-slate-800 text-slate-500 hover:bg-slate-200 dark:hover:bg-slate-700 transition-all active:scale-95" title="{{ __('Reset') }}">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5"><path stroke-linecap="round" stroke-linejoin="round" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" /></svg>
</a>
</div>
</form>