diff --git a/app/Http/Controllers/Admin/MaintenanceController.php b/app/Http/Controllers/Admin/MaintenanceController.php index f4d25de..4e5e750 100644 --- a/app/Http/Controllers/Admin/MaintenanceController.php +++ b/app/Http/Controllers/Admin/MaintenanceController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers\Admin; use App\Http\Controllers\Controller; use App\Models\Machine\Machine; use App\Models\Machine\MaintenanceRecord; +use App\Models\System\Company; use App\Traits\ImageHandler; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; @@ -21,6 +22,9 @@ class MaintenanceController extends Controller { $this->authorize('viewAny', MaintenanceRecord::class); + $currentUser = auth()->user(); + $companyId = trim((string) $request->input('company_id', '')); + $query = MaintenanceRecord::with(['machine', 'user', 'company']) ->whereHas('machine') // 確保僅顯示該帳號「看得見」的機台紀錄,避開因權限隔離導致的 null 報錯 ->latest('maintenance_at'); @@ -38,9 +42,16 @@ class MaintenanceController extends Controller $query->where('category', $request->category); } - $records = $query->paginate(15)->withQueryString(); + if ($currentUser->isSystemAdmin() && $companyId !== '') { + $query->where('company_id', $companyId); + } - return view('admin.maintenance.index', compact('records')); + $records = $query->paginate(15)->withQueryString(); + $companies = $currentUser->isSystemAdmin() + ? Company::select('id', 'name', 'code')->orderBy('name')->get() + : collect(); + + return view('admin.maintenance.index', compact('records', 'companies')); } /** diff --git a/app/Http/Controllers/Admin/WarehouseController.php b/app/Http/Controllers/Admin/WarehouseController.php index 5ee1e9c..ccbe366 100644 --- a/app/Http/Controllers/Admin/WarehouseController.php +++ b/app/Http/Controllers/Admin/WarehouseController.php @@ -26,36 +26,54 @@ class WarehouseController extends Controller public function index(Request $request) { + $currentUser = Auth::user(); + $companyId = trim((string) $request->input('company_id', '')); + $search = $request->input('search'); + $type = $request->input('type'); + + $applyWarehouseFilters = function ($query) use ($currentUser, $companyId, $search, $type) { + if ($currentUser->isSystemAdmin() && $companyId !== '') { + $query->where('company_id', $companyId); + } + + if ($search) { + $query->where(function ($q) use ($search) { + $q->where('name', 'like', "%{$search}%") + ->orWhere('address', 'like', "%{$search}%"); + }); + } + + if ($type) { + $query->where('type', $type); + } + + return $query; + }; + $query = Warehouse::query() ->with(['company']) ->withCount('stocks as products_count') ->withSum('stocks as total_stock', 'quantity'); - if ($search = $request->input('search')) { - $query->where(function ($q) use ($search) { - $q->where('name', 'like', "%{$search}%") - ->orWhere('address', 'like', "%{$search}%"); - }); - } - - if ($request->filled('type')) { - $query->where('type', $request->input('type')); - } + $applyWarehouseFilters($query); $warehouses = $query->orderBy('type')->orderBy('name') ->paginate($request->input('per_page', 10)) ->withQueryString(); + $statsWarehouseQuery = fn() => $applyWarehouseFilters(Warehouse::query()); + $stats = [ - 'total' => Warehouse::count(), - 'main' => Warehouse::main()->count(), - 'branch' => Warehouse::branch()->count(), + 'total' => $statsWarehouseQuery()->count(), + 'main' => $statsWarehouseQuery()->main()->count(), + 'branch' => $statsWarehouseQuery()->branch()->count(), 'low_stock' => WarehouseStock::lowStock() - ->whereHas('warehouse', fn($q) => $q)->count(), + ->whereHas('warehouse', fn($q) => $applyWarehouseFilters($q)) + ->count(), ]; $companies = collect(); - if (Auth::user()->isSystemAdmin()) { + if ($currentUser->isSystemAdmin()) { $companies = \App\Models\System\Company::active()->orderBy('name')->get(); } @@ -149,23 +167,39 @@ class WarehouseController extends Controller public function inventory(Request $request) { $tab = $request->input('tab', 'stock'); - $warehouses = Warehouse::active()->orderBy('name')->get(); + $currentUser = Auth::user(); + $companyId = trim((string) $request->input('company_id', '')); + $applyCompanyFilter = fn($query) => $query->when( + $currentUser->isSystemAdmin() && $companyId !== '', + fn($q) => $q->where('company_id', $companyId) + ); + + $warehouses = $applyCompanyFilter(Warehouse::active()) + ->orderBy('name') + ->get(); + $companies = $currentUser->isSystemAdmin() + ? \App\Models\System\Company::active()->orderBy('name')->get() + : collect(); $isAjax = $request->ajax(); - $data = compact('warehouses', 'tab'); + $data = compact('warehouses', 'companies', 'tab'); // 1. Current Stocks (stock) if (!$isAjax || $tab === 'stock') { $warehouse_ids = $request->input('warehouse_ids'); - $inventory_warehouses = Warehouse::active() + $inventory_warehouses = $applyCompanyFilter(Warehouse::active()) ->when($warehouse_ids, fn($q) => $q->whereIn('id', (array)$warehouse_ids)) ->orderBy('name') - ->get(['id', 'name', 'type']); + ->get(['id', 'name', 'type', 'company_id']); $query = Product::with(['stocks' => function($q) { $q->select('id', 'product_id', 'warehouse_id', 'quantity', 'safety_stock'); }, 'translations']); + if ($currentUser->isSystemAdmin() && $companyId !== '') { + $query->where('company_id', $companyId); + } + if ($warehouse_ids) { $query->whereHas('stocks', fn($q) => $q->whereIn('warehouse_id', (array)$warehouse_ids)); } @@ -185,6 +219,10 @@ class WarehouseController extends Controller ->withCount('items') ->latest(); + if ($currentUser->isSystemAdmin() && $companyId !== '') { + $query->where('company_id', $companyId); + } + if ($request->filled('status')) { $query->where('status', $request->input('status')); } @@ -206,7 +244,10 @@ class WarehouseController extends Controller $data['stockInDefaultEnd'] = ''; } $data['orders'] = $query->paginate($request->input('per_page', 10), ['*'], 'order_page')->withQueryString(); - $data['stock_in_products'] = Product::with('translations')->orderBy('name')->get(['id', 'name', 'image_url', 'name_dictionary_key']); + $data['stock_in_products'] = Product::with('translations') + ->when($currentUser->isSystemAdmin() && $companyId !== '', fn($q) => $q->where('company_id', $companyId)) + ->orderBy('name') + ->get(['id', 'name', 'image_url', 'name_dictionary_key']); } // 3. Movement History (movements) @@ -215,6 +256,10 @@ class WarehouseController extends Controller ->orderBy('created_at', 'desc') ->orderBy('id', 'desc'); + if ($currentUser->isSystemAdmin() && $companyId !== '') { + $query->where('company_id', $companyId); + } + if ($request->filled('warehouse_id')) { $query->where('warehouse_id', $request->input('warehouse_id')); } @@ -397,10 +442,17 @@ class WarehouseController extends Controller public function transfers(Request $request) { + $currentUser = Auth::user(); + $companyId = trim((string) $request->input('company_id', '')); + $isSystemAdmin = $currentUser->isSystemAdmin(); + $query = TransferOrder::with(['fromWarehouse:id,name', 'toWarehouse:id,name', 'fromMachine:id,name,serial_no', 'creator:id,name']) ->withCount('items') ->latest(); + if ($isSystemAdmin && $companyId !== '') { + $query->where('company_id', $companyId); + } if ($request->filled('type')) { $query->where('type', $request->input('type')); } @@ -431,14 +483,22 @@ class WarehouseController extends Controller ]); } - $warehouses = Warehouse::active()->orderBy('name')->get(['id', 'name']); - $machines = Machine::orderBy('name')->get(['id', 'name', 'serial_no']); - $products = Product::with('translations')->orderBy('name')->get(['id', 'name', 'image_url', 'name_dictionary_key']); + $companies = $isSystemAdmin + ? \App\Models\System\Company::active()->orderBy('name')->get() + : collect(); + $applyCompanyFilter = fn($query) => $query->when( + $isSystemAdmin && $companyId !== '', + fn($q) => $q->where('company_id', $companyId) + ); + + $warehouses = $applyCompanyFilter(Warehouse::active())->orderBy('name')->get(['id', 'name']); + $machines = $applyCompanyFilter(Machine::query())->orderBy('name')->get(['id', 'name', 'serial_no']); + $products = $applyCompanyFilter(Product::with('translations'))->orderBy('name')->get(['id', 'name', 'image_url', 'name_dictionary_key']); $defaultStart = ''; $defaultEnd = ''; - return view('admin.warehouses.transfers', compact('orders', 'warehouses', 'machines', 'products', 'defaultStart', 'defaultEnd')); + return view('admin.warehouses.transfers', compact('orders', 'warehouses', 'machines', 'products', 'companies', 'defaultStart', 'defaultEnd')); } /** @@ -625,11 +685,19 @@ class WarehouseController extends Controller public function machineInventory(Request $request) { + $currentUser = Auth::user(); + $companyId = trim((string) $request->input('company_id', '')); + $isSystemAdmin = $currentUser->isSystemAdmin(); + $query = Machine::with(['slots' => fn($q) => $q->with('product:id,name,image_url')->orderByRaw('CAST(slot_no AS UNSIGNED) ASC')]) ->withCount('slots as total_slots') ->withSum('slots as total_stock', 'stock') ->withSum('slots as total_capacity', 'max_stock'); + if ($isSystemAdmin && $companyId !== '') { + $query->where('company_id', $companyId); + } + if ($search = $request->input('search')) { $query->where(function ($q) use ($search) { $q->where('name', 'like', "%{$search}%") @@ -650,7 +718,11 @@ class WarehouseController extends Controller ]); } - return view('admin.warehouses.machine-inventory', compact('machines')); + $companies = $isSystemAdmin + ? \App\Models\System\Company::active()->orderBy('name')->get() + : collect(); + + return view('admin.warehouses.machine-inventory', compact('machines', 'companies')); } @@ -718,10 +790,17 @@ class WarehouseController extends Controller public function replenishments(Request $request) { + $currentUser = Auth::user(); + $companyId = trim((string) $request->input('company_id', '')); + $isSystemAdmin = $currentUser->isSystemAdmin(); + $query = ReplenishmentOrder::with(['warehouse:id,name', 'machine:id,name,serial_no', 'assignee:id,name', 'creator:id,name']) ->withCount('items') ->latest(); + if ($isSystemAdmin && $companyId !== '') { + $query->where('company_id', $companyId); + } if ($request->filled('status')) { $query->where('status', $request->input('status')); } @@ -749,20 +828,30 @@ class WarehouseController extends Controller ]); } - $warehouses = Warehouse::active()->orderBy('name')->get(['id', 'name']); - $machines = Machine::orderBy('name')->get(['id', 'name', 'serial_no']); - $products = Product::with('translations')->orderBy('name')->get(['id', 'name', 'image_url', 'name_dictionary_key']); + $companies = $isSystemAdmin + ? \App\Models\System\Company::active()->orderBy('name')->get() + : collect(); + $applyCompanyFilter = fn($query) => $query->when( + $isSystemAdmin && $companyId !== '', + fn($q) => $q->where('company_id', $companyId) + ); + + $warehouses = $applyCompanyFilter(Warehouse::active())->orderBy('name')->get(['id', 'name']); + $machines = $applyCompanyFilter(Machine::query())->orderBy('name')->get(['id', 'name', 'serial_no']); + $products = $applyCompanyFilter(Product::with('translations'))->orderBy('name')->get(['id', 'name', 'image_url', 'name_dictionary_key']); $userQuery = \App\Models\System\User::where('status', 1)->orderBy('name'); - if (!Auth::user()->isSystemAdmin()) { - $userQuery->where('company_id', Auth::user()->company_id); + if (!$isSystemAdmin) { + $userQuery->where('company_id', $currentUser->company_id); + } elseif ($companyId !== '') { + $userQuery->where('company_id', $companyId); } $users = $userQuery->get(['id', 'name']); $defaultStart = ''; $defaultEnd = ''; - return view('admin.warehouses.replenishments', compact('orders', 'warehouses', 'machines', 'products', 'users', 'defaultStart', 'defaultEnd')); + return view('admin.warehouses.replenishments', compact('orders', 'warehouses', 'machines', 'products', 'users', 'companies', 'defaultStart', 'defaultEnd')); } /** @@ -1479,4 +1568,3 @@ class WarehouseController extends Controller return view('admin.warehouses.print.replenishment', compact('order', 'items')); } } - diff --git a/lang/en.json b/lang/en.json index a97c215..a732410 100644 --- a/lang/en.json +++ b/lang/en.json @@ -1064,6 +1064,7 @@ "Machine to Warehouse": "Machine to Warehouse", "Machine to Warehouse Return": "Machine to Warehouse Return", "Machine to warehouse returns": "Machine to warehouse returns", + "M2W": "M2W", "Machine updated successfully.": "Machine updated successfully.", "Machine-Specific Webhook": "Machine-Specific Webhook", "Machines": "Machines", @@ -1261,6 +1262,7 @@ "No pickup codes found": "No pickup codes found", "No product data matching search criteria": "No product data matching search criteria", "No product record found": "No product record found", + "No products found": "No products found", "No products found in this warehouse": "No products found in this warehouse", "No products found matching your criteria.": "No products found matching your criteria.", "No records found": "No records found", @@ -2227,6 +2229,7 @@ "Warehouse to Warehouse": "Warehouse to Warehouse", "Warehouse to Warehouse Transfer": "Warehouse to Warehouse Transfer", "Warehouse to warehouse transfers": "Warehouse to warehouse transfers", + "W2W": "W2W", "Warehouse updated successfully": "Warehouse updated successfully", "Warehouse updated successfully.": "Warehouse updated successfully.", "Warning": "Warning", diff --git a/lang/ja.json b/lang/ja.json index b2032d4..1c076fb 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -1064,6 +1064,7 @@ "Machine to Warehouse": "機器から倉庫", "Machine to Warehouse Return": "自販機から倉庫への返品", "Machine to warehouse returns": "機器から倉庫への返却", + "M2W": "機器から倉庫", "Machine updated successfully.": "機器が正常に更新されました。", "Machine-Specific Webhook": "機器専用 Webhook", "Machines": "機器管理", @@ -1261,6 +1262,7 @@ "No pickup codes found": "受取コードが見つかりません", "No product data matching search criteria": "検索条件に一致する商品データはありません", "No product record found": "商品記録が見つかりません", + "No products found": "商品が見つかりません", "No products found in this warehouse": "この倉庫に商品は見つかりません", "No products found matching your criteria.": "条件に一致する商品が見つかりません。", "No records found": "記録が見つかりません", @@ -2227,6 +2229,7 @@ "Warehouse to Warehouse": "倉庫から倉庫", "Warehouse to Warehouse Transfer": "倉庫間移動", "Warehouse to warehouse transfers": "倉庫から倉庫への在庫移動", + "W2W": "倉庫間", "Warehouse updated successfully": "倉庫が正常に更新されました", "Warehouse updated successfully.": "倉庫が正常に更新されました。", "Warning": "期限間近", diff --git a/lang/zh_TW.json b/lang/zh_TW.json index 39e84da..728130d 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -1064,6 +1064,7 @@ "Machine to Warehouse": "機台對倉庫", "Machine to Warehouse Return": "機台退庫至倉庫", "Machine to warehouse returns": "機台退回倉庫", + "M2W": "機對倉", "Machine updated successfully.": "機台更新成功。", "Machine-Specific Webhook": "機台專屬 Webhook", "Machines": "機台管理", @@ -1261,6 +1262,7 @@ "No pickup codes found": "找不到取貨碼", "No product data matching search criteria": "沒有符合搜尋條件的商品資料", "No product record found": "無商品紀錄", + "No products found": "未找到商品", "No products found in this warehouse": "此倉庫目前無商品庫存", "No products found matching your criteria.": "找不到符合條件的商品。", "No records found": "未找到相關紀錄", @@ -2227,6 +2229,7 @@ "Warehouse to Warehouse": "倉庫對倉庫", "Warehouse to Warehouse Transfer": "倉庫至倉庫調撥", "Warehouse to warehouse transfers": "倉庫對倉庫調撥", + "W2W": "倉對倉", "Warehouse updated successfully": "倉庫更新成功", "Warehouse updated successfully.": "倉庫已成功更新。", "Warning": "警告", diff --git a/resources/views/admin/machines/index.blade.php b/resources/views/admin/machines/index.blade.php index 1e0da8a..b35bd0c 100644 --- a/resources/views/admin/machines/index.blade.php +++ b/resources/views/admin/machines/index.blade.php @@ -467,7 +467,8 @@ @if(auth()->user()->isSystemAdmin())
+ :placeholder="__('All Companies')" + x-on:change="$el.closest('form').dispatchEvent(new Event('submit', { cancelable: true }))" />
@endif @@ -532,7 +533,7 @@ - @foreach ($machines as $machine) + @forelse ($machines as $machine) - @endforeach + @empty + + + + + + @endforelse
- @foreach ($machines as $machine) + @forelse ($machines as $machine)
@@ -823,11 +831,27 @@
- @endforeach + @empty +
+ + + + + +
+ @endforelse
- {{ $machines->appends(request()->query())->links('vendor.pagination.luxury') }} + @if($machines->total() > 0) + {{ $machines->appends(request()->query())->links('vendor.pagination.luxury') }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
diff --git a/resources/views/admin/machines/permissions.blade.php b/resources/views/admin/machines/permissions.blade.php index 33d69b5..4b62f1b 100644 --- a/resources/views/admin/machines/permissions.blade.php +++ b/resources/views/admin/machines/permissions.blade.php @@ -103,15 +103,7 @@ window.dispatchEvent(new CustomEvent('toast', { detail: { message: e.message, type: 'error' } })); }); } -}" @ajax:navigate.window.prevent="fetchPage($event.detail.url)" - @submit.prevent="if($event.target.method.toLowerCase() === 'get') { - const url = new URL($event.target.action, window.location.origin); - new FormData($event.target).forEach((value, key) => { - if(value.trim()) url.searchParams.set(key, value); - else url.searchParams.delete(key); - }); - fetchPage(url.pathname + url.search); - }"> +}" @ajax:navigate.window.prevent="fetchPage($event.detail.url)">
@@ -151,7 +143,15 @@
+ class="flex flex-wrap items-center gap-4 w-full md:w-auto" + @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); + ">
@@ -170,7 +170,8 @@ @if(auth()->user()->isSystemAdmin())
+ :placeholder="__('All Companies')" + x-on:change="$el.closest('form').dispatchEvent(new Event('submit', { cancelable: true }))" />
@endif @@ -186,7 +187,7 @@ $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); + const instance = window.HSSelect?.getInstance(s); if (instance) instance.setValue(' '); }); $el.closest('form').dispatchEvent(new Event('submit', { cancelable: true })); @@ -279,12 +280,15 @@ @empty -
- +
+ + d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" /> + + -

{{ __('No accounts found') }}

+

{{ __('No accounts found') }}

@@ -354,17 +358,26 @@
@empty
-
- - +
+ + + + -

{{ __('No accounts found') }}

+

{{ __('No accounts found') }}

@endforelse
- {{ $users_list->links('vendor.pagination.luxury') }} + @if($users_list->total() > 0) + {{ $users_list->appends(request()->query())->links('vendor.pagination.luxury') }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
@@ -529,4 +542,4 @@
-@endsection \ No newline at end of file +@endsection diff --git a/resources/views/admin/maintenance/index.blade.php b/resources/views/admin/maintenance/index.blade.php index bf2450d..ef16841 100644 --- a/resources/views/admin/maintenance/index.blade.php +++ b/resources/views/admin/maintenance/index.blade.php @@ -24,6 +24,14 @@ if (newContent) { document.querySelector('#ajax-content-container').innerHTML = newContent.innerHTML; window.history.pushState({}, '', url); + + const container = document.querySelector('#ajax-content-container'); + if (container && window.Alpine) { + Alpine.initTree(container); + } + if (window.HSStaticMethods && typeof window.HSStaticMethods.autoInit === 'function') { + setTimeout(() => window.HSStaticMethods.autoInit(), 100); + } } } catch (e) { console.error('AJAX Load Failed:', e); @@ -80,14 +88,21 @@
+ @click="if ($event.target.closest('a') && $event.target.closest('a').href && ($event.target.closest('a').href.includes('page=') || $event.target.closest('a').href.includes('search=') || $event.target.closest('a').href.includes('category=') || $event.target.closest('a').href.includes('company_id='))) { $event.preventDefault(); fetchPage($event.target.closest('a').href); }">
+ @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); + ">
@@ -106,7 +121,7 @@
+ x-on:change="$el.closest('form').dispatchEvent(new Event('submit', { cancelable: true }))" :hasSearch="false" class="luxury-select-sm"> @foreach(['Repair', 'Installation', 'Removal', 'Maintenance'] as $cat)
+ @if(auth()->user()->isSystemAdmin()) +
+ +
+ @endif +
@empty
-
- - +
+ + -

{{ __('No maintenance records found') }}

+

{{ __('No maintenance records found') }}

@endforelse
- {{ $records->links('vendor.pagination.luxury') }} + @if($records->total() > 0) + {{ $records->appends(request()->query())->links('vendor.pagination.luxury') }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
diff --git a/resources/views/admin/remote/stock.blade.php b/resources/views/admin/remote/stock.blade.php index 47fe11d..ca35ca0 100644 --- a/resources/views/admin/remote/stock.blade.php +++ b/resources/views/admin/remote/stock.blade.php @@ -9,6 +9,7 @@ selectedMachine: null, slots: [], viewMode: initialMachineId ? 'detail' : 'history', + displayMode: 'table', history: @js($history), loading: false, updating: false, @@ -251,17 +252,42 @@ }, getSlotColorClass(slot) { - if (!slot.expiry_date) return 'bg-slate-50/50 dark:bg-slate-800/50 text-slate-400 border-slate-200/60 dark:border-slate-700/50'; - const todayStr = new Date().toISOString().split('T')[0]; - const expiryStr = slot.expiry_date; - if (expiryStr < todayStr) { - return 'bg-rose-50/60 dark:bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-200 dark:border-rose-500/30 shadow-sm shadow-rose-500/5'; + const today = new Date().toISOString().split('T')[0]; + if (slot.expiry_date && slot.expiry_date < today) { + return 'bg-rose-50/60 dark:bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-200 dark:border-rose-500/30'; } - const diffDays = Math.round((new Date(expiryStr) - new Date(todayStr)) / 86400000); - if (diffDays <= 7) { - return 'bg-amber-50/60 dark:bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-500/30 shadow-sm shadow-amber-500/5'; + if (!slot.product || parseInt(slot.stock) === 0) { + return 'bg-slate-50/50 dark:bg-slate-800/50 text-slate-400 border-slate-200/60 dark:border-slate-700/50'; } - return 'bg-emerald-50/60 dark:bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-200 dark:border-emerald-500/30 shadow-sm shadow-emerald-500/5'; + if (slot.max_stock > 0 && parseInt(slot.stock) <= (parseInt(slot.max_stock) * 0.2)) { + return 'bg-amber-50/60 dark:bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-200 dark:border-amber-500/30'; + } + const maxStock = parseInt(slot.max_stock) || 10; + if (parseInt(slot.stock) > maxStock / 2) { + return 'bg-cyan-50/60 dark:bg-cyan-500/10 text-cyan-600 dark:text-cyan-400 border-cyan-200 dark:border-cyan-500/30'; + } + return 'bg-emerald-50/60 dark:bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-200 dark:border-emerald-500/30'; + }, + + getSlotCardClass(slot) { + const base = 'luxury-card p-6 rounded-[2rem] backdrop-blur-xl group hover:shadow-2xl transition-all duration-500 relative '; + const today = new Date().toISOString().split('T')[0]; + if (slot.expiry_date && slot.expiry_date < today) return base + 'bg-rose-500/[0.06] border-rose-500/20 dark:bg-rose-500/10 dark:border-rose-500/30 hover:shadow-rose-500/10'; + if (!slot.product || parseInt(slot.stock) === 0) return base + 'bg-slate-500/[0.06] border-slate-500/20 dark:bg-slate-500/10 dark:border-slate-500/30 hover:shadow-slate-500/10'; + if (slot.max_stock > 0 && parseInt(slot.stock) <= (parseInt(slot.max_stock) * 0.2)) return base + 'bg-amber-500/[0.06] border-amber-500/20 dark:bg-amber-500/10 dark:border-amber-500/30 hover:shadow-amber-500/10'; + const maxStock = parseInt(slot.max_stock) || 10; + if (parseInt(slot.stock) > maxStock / 2) return base + 'bg-cyan-500/[0.06] border-cyan-500/20 dark:bg-cyan-500/10 dark:border-cyan-500/30 hover:shadow-cyan-500/10'; + return base + 'bg-emerald-500/[0.04] border-emerald-500/10 dark:bg-emerald-500/[0.08] dark:border-emerald-500/25 hover:shadow-emerald-500/10'; + }, + + getSlotProgressClass(slot) { + const today = new Date().toISOString().split('T')[0]; + if (slot.expiry_date && slot.expiry_date < today) return 'bg-rose-500 shadow-[0_0_8px_rgba(244,63,94,0.4)]'; + if (!slot.product || parseInt(slot.stock) === 0) return 'bg-slate-400'; + if (slot.max_stock > 0 && parseInt(slot.stock) <= (parseInt(slot.max_stock) * 0.2)) return 'bg-amber-500 shadow-[0_0_8px_rgba(245,158,11,0.4)]'; + const maxStock = parseInt(slot.max_stock) || 10; + if (parseInt(slot.stock) > maxStock / 2) return 'bg-cyan-500 shadow-[0_0_8px_rgba(6,182,212,0.4)]'; + return 'bg-emerald-500 shadow-[0_0_8px_rgba(16,185,129,0.4)]'; }, getCommandBadgeClass(status) { @@ -546,8 +572,29 @@
- -
+ +
+
+ + +
+
@@ -558,22 +605,131 @@ {{ - __('Warning') }} -
-
- - {{ - __('Normal') }} + __('Low Stock') }}
-
+ +
+
+ +
+
+
+
+ {{ + __('Loading Cabinet...') }} +
+
+ + +
+
+ + +
+ +
+
+
+ + +
+ class="absolute inset-0 bg-white/60 dark:bg-slate-900/60 backdrop-blur-md z-20 flex items-center justify-center transition-all duration-500 rounded-[2.5rem]">
@@ -584,102 +740,124 @@
- -
+ + - -
+ +
+
diff --git a/resources/views/admin/warehouses/index.blade.php b/resources/views/admin/warehouses/index.blade.php index 871147d..d1cdac6 100644 --- a/resources/views/admin/warehouses/index.blade.php +++ b/resources/views/admin/warehouses/index.blade.php @@ -95,6 +95,15 @@ const currentContent = document.querySelector('#ajax-content-container'); if (newContent && currentContent) { currentContent.innerHTML = newContent.innerHTML; + if (window.Alpine) { + Alpine.initTree(currentContent); + } + } + + const newStats = doc.querySelector('#warehouse-stats-container'); + const currentStats = document.querySelector('#warehouse-stats-container'); + if (newStats && currentStats) { + currentStats.innerHTML = newStats.innerHTML; } window.history.pushState({}, '', url); @@ -148,7 +157,7 @@
{{-- Stats Cards --}} -
+

{{ __('Total Warehouses') }}

{{ $stats['total'] }}

@@ -174,7 +183,14 @@ {{-- Filters --}}
+ @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); + "> + @if(auth()->user()->isSystemAdmin()) +
+ +
+ @endif +
@empty -
- +
+
+ + + +

{{ __('No machines found') }}

+
@endforelse
- {{ $machines->links('vendor.pagination.luxury') }} + @if($machines->total() > 0) + {{ $machines->links('vendor.pagination.luxury') }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
diff --git a/resources/views/admin/warehouses/partials/tab-movements.blade.php b/resources/views/admin/warehouses/partials/tab-movements.blade.php index 1195a52..67f8586 100644 --- a/resources/views/admin/warehouses/partials/tab-movements.blade.php +++ b/resources/views/admin/warehouses/partials/tab-movements.blade.php @@ -3,6 +3,26 @@ @submit.prevent="handleFilterSubmit('movements')"> + @if(auth()->user()->isSystemAdmin()) +
+ +
+ @endif + {{-- 倉庫篩選 --}}
{ s.value = ' '; - const instance = window.HSSelect.getInstance(s); + const instance = window.HSSelect?.getInstance(s); if (instance) instance.setValue(' '); }); $el.closest('form').dispatchEvent(new CustomEvent('multi-select-reset', { bubbles: true })); @@ -167,12 +187,10 @@
-
- - - -
-

{{ __('No movement records found') }}

+ + + +

{{ __('No movement records found') }}

@@ -229,12 +247,24 @@
@empty -
- +
+
+ + + +

{{ __('No movement records found') }}

+
@endforelse
- {{ $movements->links('vendor.pagination.luxury') }} + @if($movements->total() > 0) + {{ $movements->links('vendor.pagination.luxury') }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
diff --git a/resources/views/admin/warehouses/partials/tab-stock-in.blade.php b/resources/views/admin/warehouses/partials/tab-stock-in.blade.php index 13d34b3..6a1603d 100644 --- a/resources/views/admin/warehouses/partials/tab-stock-in.blade.php +++ b/resources/views/admin/warehouses/partials/tab-stock-in.blade.php @@ -80,6 +80,18 @@
@endif + @if(auth()->user()->isSystemAdmin()) +
+ +
+ @endif + {{-- 搜尋 + 重置按鈕 --}}
@empty -
- +
+
+ + + +

{{ __('No stock-in orders found') }}

+
@endforelse
- {{ $orders->links('vendor.pagination.luxury', ['ajax_navigate_event' => 'ajax:navigate:stock-in']) }} + @if($orders->total() > 0) + {{ $orders->links('vendor.pagination.luxury', ['ajax_navigate_event' => 'ajax:navigate:stock-in']) }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
diff --git a/resources/views/admin/warehouses/partials/tab-stock.blade.php b/resources/views/admin/warehouses/partials/tab-stock.blade.php index cfba802..8f532ee 100644 --- a/resources/views/admin/warehouses/partials/tab-stock.blade.php +++ b/resources/views/admin/warehouses/partials/tab-stock.blade.php @@ -22,6 +22,22 @@ :placeholder="__('Filter by Warehouse Presence')" />
+ @if(auth()->user()->isSystemAdmin()) +
+ +
+ @endif +
@empty -
- +
+
+ + + +

{{ __('No products found') }}

+
@endforelse
-
{{ - $products->links('vendor.pagination.luxury') }}
- \ No newline at end of file +
+ @if($products->total() > 0) + {{ $products->links('vendor.pagination.luxury') }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif +
+ diff --git a/resources/views/admin/warehouses/partials/table-replenishments.blade.php b/resources/views/admin/warehouses/partials/table-replenishments.blade.php index e5b71c9..986a12f 100644 --- a/resources/views/admin/warehouses/partials/table-replenishments.blade.php +++ b/resources/views/admin/warehouses/partials/table-replenishments.blade.php @@ -115,7 +115,16 @@ @empty - {{ __('No replenishment orders found') }} + + +
+ + + +

{{ __('No replenishment orders found') }}

+
+ + @endforelse @@ -195,12 +204,24 @@ @empty
-

{{ __('No replenishment orders found') }}

+
+ + + +

{{ __('No replenishment orders found') }}

+
@endforelse
- {{ $orders->links('vendor.pagination.luxury', ['ajax_navigate_event' => 'ajax:navigate:replenishments']) }} + @if($orders->total() > 0) + {{ $orders->links('vendor.pagination.luxury', ['ajax_navigate_event' => 'ajax:navigate:replenishments']) }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
diff --git a/resources/views/admin/warehouses/partials/table-transfers.blade.php b/resources/views/admin/warehouses/partials/table-transfers.blade.php index 67a0084..53bb506 100644 --- a/resources/views/admin/warehouses/partials/table-transfers.blade.php +++ b/resources/views/admin/warehouses/partials/table-transfers.blade.php @@ -88,7 +88,16 @@ @empty - {{ __('No transfer orders found') }} + + +
+ + + +

{{ __('No transfer orders found') }}

+
+ + @endforelse @@ -173,12 +182,24 @@ @empty
-

{{ __('No transfer orders found') }}

+
+ + + +

{{ __('No transfer orders found') }}

+
@endforelse
- {{ $orders->links('vendor.pagination.luxury', ['ajax_navigate_event' => 'ajax:navigate:transfers']) }} + @if($orders->total() > 0) + {{ $orders->links('vendor.pagination.luxury', ['ajax_navigate_event' => 'ajax:navigate:transfers']) }} + @else +
+ {{ __('No records found') }} + 0 / 0 +
+ @endif
diff --git a/resources/views/admin/warehouses/replenishments.blade.php b/resources/views/admin/warehouses/replenishments.blade.php index cdfc5e4..7f3e16e 100644 --- a/resources/views/admin/warehouses/replenishments.blade.php +++ b/resources/views/admin/warehouses/replenishments.blade.php @@ -517,6 +517,8 @@ if (data.success && container) { container.outerHTML = data.html; this.$nextTick(() => { + const newContainer = document.getElementById('replenishments-table-container'); + if (newContainer && window.Alpine) Alpine.initTree(newContainer); if (window.HSStaticMethods) window.HSStaticMethods.autoInit(); }); window.history.pushState({}, '', targetUrl); @@ -533,6 +535,7 @@
{{-- Header --}} @@ -625,6 +628,18 @@
+ @if(auth()->user()->isSystemAdmin()) +
+ +
+ @endif + {{-- 開始時間 --}}
{ s.value = ' '; - const instance = window.HSSelect.getInstance(s); + const instance = window.HSSelect?.getInstance(s); if (instance) instance.setValue(' '); }); fetchTabData(); @@ -716,4 +731,4 @@ @include('admin.warehouses.partials.modal-replenishment-assign') @include('admin.warehouses.partials.modal-replenishment-status')
-@endsection \ No newline at end of file +@endsection diff --git a/resources/views/admin/warehouses/transfers.blade.php b/resources/views/admin/warehouses/transfers.blade.php index a09b8fe..e070b6e 100644 --- a/resources/views/admin/warehouses/transfers.blade.php +++ b/resources/views/admin/warehouses/transfers.blade.php @@ -109,6 +109,8 @@ container.outerHTML = data.html; // Re-init HSSelect or other Preline components if needed this.$nextTick(() => { + const newContainer = document.getElementById('transfers-table-container'); + if (newContainer && window.Alpine) Alpine.initTree(newContainer); if (window.HSStaticMethods) window.HSStaticMethods.autoInit(); }); @@ -392,6 +394,18 @@ + @if(auth()->user()->isSystemAdmin()) +
+ +
+ @endif + {{-- 開始時間 --}}
{ s.value = ' '; - const instance = window.HSSelect.getInstance(s); + const instance = window.HSSelect?.getInstance(s); if (instance) instance.setValue(' '); }); fetchTabData();