[FEAT] 於機台管理與機台設定頁面新增公司篩選功能
1. 於機台管理 (MachineController 與 index.blade.php) 為系統管理員新增公司篩選下拉選單,並支援分頁參數與 AJAX 查詢。 2. 於機台設定頁面中的機台列表 (tab-machines.blade.php) 與系統設定列表 (tab-system-settings.blade.php) 新增公司篩選器。 3. 在 MachineSettingController 傳遞公司列表資料至視圖,以便支援公司篩選。 4. 修正重置按鈕,使其能正確清除 Preline HSSelect 的選取狀態並重新載入資料。
This commit is contained in:
parent
9a59186cd4
commit
e414396b0c
@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin\BasicSettings;
|
||||
use App\Http\Controllers\Admin\AdminController;
|
||||
use App\Models\Machine\Machine;
|
||||
use App\Models\Machine\MachineModel;
|
||||
use App\Models\System\Company;
|
||||
use App\Models\System\PaymentConfig;
|
||||
use App\Traits\ImageHandler;
|
||||
use Illuminate\Http\Request;
|
||||
@ -28,6 +29,23 @@ class MachineSettingController extends AdminController
|
||||
$per_page = $request->input('per_page', 10);
|
||||
$search = $request->input('search');
|
||||
$isAjax = $request->boolean('_ajax');
|
||||
$currentUser = auth()->user();
|
||||
$companyId = trim((string) $request->input('company_id', ''));
|
||||
|
||||
$applyMachineFilters = function ($query) use ($search, $currentUser, $companyId) {
|
||||
if ($search) {
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('serial_no', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
if ($currentUser->isSystemAdmin() && $companyId !== '') {
|
||||
$query->where('company_id', $companyId);
|
||||
}
|
||||
|
||||
return $query;
|
||||
};
|
||||
|
||||
// AJAX 模式:只查當前 Tab 的搜尋/分頁結果
|
||||
if ($isAjax) {
|
||||
@ -38,23 +56,13 @@ class MachineSettingController extends AdminController
|
||||
switch ($tab) {
|
||||
case 'machines':
|
||||
$machineQuery = Machine::query()->with(['machineModel', 'paymentConfig', 'company']);
|
||||
if ($search) {
|
||||
$machineQuery->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('serial_no', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
$applyMachineFilters($machineQuery);
|
||||
$machines = $machineQuery->latest()->paginate($per_page)->withQueryString();
|
||||
break;
|
||||
|
||||
case 'system_settings':
|
||||
$machineQuery = Machine::query()->with(['company']);
|
||||
if ($search) {
|
||||
$machineQuery->where(function ($q) use ($search) {
|
||||
$q->where('name', 'like', "%{$search}%")
|
||||
->orWhere('serial_no', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
$applyMachineFilters($machineQuery);
|
||||
$machines = $machineQuery->latest()->paginate($per_page)->withQueryString();
|
||||
break;
|
||||
|
||||
@ -76,15 +84,15 @@ class MachineSettingController extends AdminController
|
||||
->orWhere('username', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
if ($request->filled('company_id')) {
|
||||
$userQuery->where('company_id', $request->company_id);
|
||||
if ($currentUser->isSystemAdmin() && $companyId !== '') {
|
||||
$userQuery->where('company_id', $companyId);
|
||||
}
|
||||
$users_list = $userQuery->latest()->paginate($per_page)->withQueryString();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
$companies = \App\Models\System\Company::select('id', 'name', 'code')->get();
|
||||
$companies = Company::select('id', 'name', 'code')->orderBy('name')->get();
|
||||
|
||||
$tabView = match($tab) {
|
||||
'models' => 'admin.basic-settings.machines.partials.tab-models',
|
||||
@ -98,9 +106,14 @@ class MachineSettingController extends AdminController
|
||||
}
|
||||
|
||||
// SSR 模式:一次查好全部三個 Tab 的首頁資料(供 x-show 即時切換)
|
||||
$machines = Machine::query()
|
||||
->with(['machineModel', 'paymentConfig', 'company'])
|
||||
->latest()->paginate($per_page)->withQueryString();
|
||||
$machineQuery = Machine::query()
|
||||
->with(['machineModel', 'paymentConfig', 'company']);
|
||||
|
||||
if (in_array($tab, ['machines', 'system_settings'], true)) {
|
||||
$applyMachineFilters($machineQuery);
|
||||
}
|
||||
|
||||
$machines = $machineQuery->latest()->paginate($per_page)->withQueryString();
|
||||
|
||||
$models_list = MachineModel::query()
|
||||
->withCount('machines')
|
||||
@ -114,7 +127,7 @@ class MachineSettingController extends AdminController
|
||||
// 基礎下拉資料 (用於新增/編輯機台的彈窗)
|
||||
$models = MachineModel::select('id', 'name')->get();
|
||||
$paymentConfigs = PaymentConfig::select('id', 'name')->get();
|
||||
$companies = \App\Models\System\Company::select('id', 'name', 'code')->get();
|
||||
$companies = Company::select('id', 'name', 'code')->orderBy('name')->get();
|
||||
|
||||
return view('admin.basic-settings.machines.index', compact(
|
||||
'machines',
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Machine\Machine;
|
||||
use App\Models\System\Company;
|
||||
use App\Services\Machine\MachineService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
@ -16,8 +17,10 @@ class MachineController extends AdminController
|
||||
public function index(Request $request): View
|
||||
{
|
||||
$per_page = $request->input('per_page', 10);
|
||||
$companyId = trim((string) $request->input('company_id', ''));
|
||||
|
||||
$query = Machine::query();
|
||||
$currentUser = auth()->user();
|
||||
|
||||
// 搜尋:名稱或序號
|
||||
if ($search = $request->input('search')) {
|
||||
@ -27,13 +30,21 @@ class MachineController extends AdminController
|
||||
});
|
||||
}
|
||||
|
||||
if ($currentUser->isSystemAdmin() && $companyId !== '') {
|
||||
$query->where('company_id', $companyId);
|
||||
}
|
||||
|
||||
// 預加載統計資料
|
||||
$machines = $query->orderBy("last_heartbeat_at", "desc")
|
||||
->orderBy("id", "desc")
|
||||
->paginate($per_page)
|
||||
->withQueryString();
|
||||
|
||||
return view('admin.machines.index', compact('machines'));
|
||||
$companies = $currentUser->isSystemAdmin()
|
||||
? Company::select('id', 'name', 'code')->orderBy('name')->get()
|
||||
: collect();
|
||||
|
||||
return view('admin.machines.index', compact('machines', 'companies'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -5,9 +5,10 @@
|
||||
tab: '{{ $tab }}',
|
||||
tabLoading: false,
|
||||
machineSearch: '',
|
||||
machineCompanyId: @js(request('company_id')),
|
||||
modelSearch: '',
|
||||
permissionSearch: '',
|
||||
permissionCompanyId: '{{ request('company_id') }}',
|
||||
permissionCompanyId: @js(request('company_id')),
|
||||
isUpdatingSetting: false,
|
||||
async toggleSystemSetting(machineId, field, value) {
|
||||
if (this.isUpdatingSetting) return;
|
||||
@ -287,7 +288,10 @@
|
||||
const search = searchMap[tabName] || '';
|
||||
let qs = `tab=${tabName}&_ajax=1`;
|
||||
if (search) qs += `&search=${encodeURIComponent(search)}`;
|
||||
if (tabName === 'permissions' && this.permissionCompanyId) qs += `&company_id=${this.permissionCompanyId}`;
|
||||
const machineCompanyId = (this.machineCompanyId || '').trim();
|
||||
const permissionCompanyId = (this.permissionCompanyId || '').trim();
|
||||
if ((tabName === 'machines' || tabName === 'system_settings') && machineCompanyId) qs += `&company_id=${machineCompanyId}`;
|
||||
if (tabName === 'permissions' && permissionCompanyId) qs += `&company_id=${permissionCompanyId}`;
|
||||
if (extraQuery) qs += extraQuery;
|
||||
|
||||
// 同步 URL(不含 _ajax)
|
||||
@ -1669,4 +1673,4 @@
|
||||
<script>
|
||||
|
||||
</script>
|
||||
@endsection
|
||||
@endsection
|
||||
|
||||
@ -19,6 +19,14 @@
|
||||
class="luxury-input py-2.5 pl-11 pr-4 block w-full sm:w-72 text-sm font-bold">
|
||||
</div>
|
||||
|
||||
@if(auth()->user()->isSystemAdmin())
|
||||
<div class="w-full sm:w-72">
|
||||
<x-searchable-select id="machine-company-filter-machines" name="company_filter" :options="$companies" :selected="request('company_id')"
|
||||
:placeholder="__('All Companies')"
|
||||
x-on:change="machineCompanyId = $event.target.value; searchInTab('machines')" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center gap-2 ml-auto sm:ml-0">
|
||||
{{-- 搜尋按鈕 --}}
|
||||
<button type="button" @click="searchInTab('machines')"
|
||||
@ -31,7 +39,16 @@
|
||||
|
||||
{{-- 重置按鈕 --}}
|
||||
<button type="button"
|
||||
@click="machineSearch = ''; searchInTab('machines')"
|
||||
@click="
|
||||
machineSearch = '';
|
||||
machineCompanyId = '';
|
||||
const select = document.getElementById('machine-company-filter-machines');
|
||||
if (select) {
|
||||
select.value = ' ';
|
||||
window.HSSelect?.getInstance(select)?.setValue(' ');
|
||||
}
|
||||
searchInTab('machines');
|
||||
"
|
||||
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">
|
||||
@ -268,5 +285,5 @@
|
||||
</div>
|
||||
|
||||
<div class="mt-8 border-t border-slate-100/50 dark:border-slate-800/50 pt-6">
|
||||
{{ $machines->appends(['tab' => 'machines'])->links('vendor.pagination.luxury') }}
|
||||
{{ $machines->appends(['tab' => 'machines', 'search' => request('search'), 'company_id' => request('company_id')])->links('vendor.pagination.luxury') }}
|
||||
</div>
|
||||
|
||||
@ -15,17 +15,18 @@
|
||||
class="luxury-input py-2.5 pl-11 pr-4 block w-full sm:w-72 text-sm font-bold">
|
||||
</div>
|
||||
|
||||
@if(auth()->user()->isSystemAdmin())
|
||||
<!-- Company Filter -->
|
||||
<div class="w-full sm:w-72">
|
||||
<x-searchable-select
|
||||
x-model="permissionCompanyId"
|
||||
@change="searchInTab('system_settings')"
|
||||
:placeholder="__('所有公司')">
|
||||
@foreach ($companies as $company)
|
||||
<option value="{{ $company->id }}">{{ $company->name }}</option>
|
||||
@endforeach
|
||||
</x-searchable-select>
|
||||
id="machine-company-filter-system-settings"
|
||||
name="company_filter"
|
||||
:options="$companies"
|
||||
:selected="request('company_id')"
|
||||
x-on:change="machineCompanyId = $event.target.value; searchInTab('system_settings')"
|
||||
:placeholder="__('All Companies')" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center gap-2 ml-auto sm:ml-0">
|
||||
{{-- 搜尋按鈕 --}}
|
||||
@ -39,7 +40,16 @@
|
||||
|
||||
{{-- 重置按鈕 --}}
|
||||
<button type="button"
|
||||
@click="machineSearch = ''; permissionCompanyId = ''; searchInTab('system_settings')"
|
||||
@click="
|
||||
machineSearch = '';
|
||||
machineCompanyId = '';
|
||||
const select = document.getElementById('machine-company-filter-system-settings');
|
||||
if (select) {
|
||||
select.value = ' ';
|
||||
window.HSSelect?.getInstance(select)?.setValue(' ');
|
||||
}
|
||||
searchInTab('system_settings');
|
||||
"
|
||||
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">
|
||||
|
||||
@ -438,10 +438,70 @@
|
||||
:class="{ 'opacity-30 pointer-events-none transition-opacity duration-300': isLoadingTable }">
|
||||
|
||||
{{-- Filters --}}
|
||||
<x-search-bar :action="route('admin.machines.index')" :value="request('search')"
|
||||
:placeholder="__('Search machines...')">
|
||||
<form method="GET" action="{{ route('admin.machines.index') }}"
|
||||
class="flex flex-wrap items-center gap-3 sm:gap-4 mb-8"
|
||||
@submit.prevent="
|
||||
const url = new URL($el.action, window.location.origin);
|
||||
new FormData($el).forEach((value, key) => {
|
||||
if (value.trim()) url.searchParams.set(key, value);
|
||||
else url.searchParams.delete(key);
|
||||
});
|
||||
fetchPage(url.pathname + url.search);
|
||||
">
|
||||
<input type="hidden" name="tab" value="list">
|
||||
</x-search-bar>
|
||||
|
||||
<div class="relative group flex-1 sm:flex-none">
|
||||
<span class="absolute inset-y-0 left-0 flex items-center pl-4 pointer-events-none z-10">
|
||||
<svg class="h-4 w-4 text-slate-400 group-focus-within:text-cyan-500 transition-colors"
|
||||
viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
||||
</svg>
|
||||
</span>
|
||||
<input type="text" name="search" value="{{ request('search') }}"
|
||||
placeholder="{{ __('Search machines...') }}"
|
||||
class="luxury-input py-2.5 pl-11 pr-4 block w-full sm:w-72 text-sm font-bold">
|
||||
</div>
|
||||
|
||||
@if(auth()->user()->isSystemAdmin())
|
||||
<div class="w-full sm:w-72">
|
||||
<x-searchable-select name="company_id" :options="$companies" :selected="request('company_id')"
|
||||
:placeholder="__('All Companies')" />
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="flex items-center gap-2 ml-auto sm:ml-0">
|
||||
<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>
|
||||
|
||||
<button type="button"
|
||||
@click="
|
||||
$el.closest('form').querySelectorAll('input[type=text]').forEach(i => i.value = '');
|
||||
$el.closest('form').querySelectorAll('select').forEach(s => {
|
||||
s.value = ' ';
|
||||
const instance = window.HSSelect?.getInstance(s);
|
||||
if (instance) instance.setValue(' ');
|
||||
});
|
||||
$el.closest('form').dispatchEvent(new Event('submit', { cancelable: true }));
|
||||
"
|
||||
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>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Desktop Table View -->
|
||||
<div class="hidden xl:block overflow-x-auto pb-4">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user