[FEAT] 優化廣告與機台管理介面及效能

1. [廣告管理] 修復編輯素材時刪除按鈕顯示邏輯並優化預覽功能。
2. [廣告管理] 修正請求回傳格式為 JSON,解決 AJAX 解析錯誤。
3. [機台管理] 實作 Alpine.js 無感頁籤切換(機台列表與效期管理)。
4. [機台管理] 移除冗餘返回按鈕,改為動態標題與頁籤重設邏輯。
5. [機台管理] 統一後端查詢,減少切換分頁時的延遲感。
6. [商品管理] 支援商品圖片 WebP 自動轉換,並調整上傳大小限制 (10MB)。
7. [UI] 修正多個管理模組的 JS 時序競爭與 Preline HSSelect 重置問題。
This commit is contained in:
2026-04-01 13:01:45 +08:00
parent 2e49129d77
commit 953d6a41f3
14 changed files with 387 additions and 166 deletions

View File

@@ -135,18 +135,9 @@ window.machineApp = function(initialTab) {
<!-- Top Header & Actions -->
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div class="flex items-center gap-4">
<template x-if="tab === 'expiry' && viewMode === 'cabinet'">
<button @click="viewMode = 'fleet'; selectedMachine = null"
class="p-2 rounded-xl bg-white dark:bg-slate-800 text-slate-500 hover:bg-slate-50 dark:hover:bg-slate-700 transition-all border border-slate-200 dark:border-slate-700 shadow-sm">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15 19l-7-7 7-7" />
</svg>
</button>
</template>
<div>
<h1
<h1 x-text="tab === 'list' ? '{{ __('Machine List') }}' : '{{ __('Expiry Management') }}'"
class="text-3xl font-black text-slate-800 dark:text-white tracking-tight font-display transition-all duration-300">
{{ __('Machine List') }}
</h1>
<p class="text-sm font-bold text-slate-500 dark:text-slate-400 mt-1 uppercase tracking-widest">
{{ __('Manage your machine fleet and operational data') }}
@@ -158,19 +149,20 @@ window.machineApp = function(initialTab) {
<!-- Tabs Switcher (Standard Position) -->
<div
class="flex items-center gap-1 p-1.5 bg-slate-100 dark:bg-slate-900/50 rounded-2xl w-fit border border-slate-200/50 dark:border-slate-800/50">
<a href="{{ route('admin.machines.index', ['tab' => 'list']) }}"
class="px-8 py-3 rounded-xl text-sm font-black uppercase tracking-widest transition-all {{ $tab === 'list' ? 'bg-white dark:bg-slate-800 text-cyan-600 dark:text-cyan-400 shadow-sm shadow-cyan-500/10' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-200' }}">
<button @click="tab = 'list'; viewMode = 'fleet'; selectedMachine = null; window.history.replaceState(null, '', '?tab=list' + (new URLSearchParams(window.location.search).get('search') ? '&search=' + new URLSearchParams(window.location.search).get('search') : ''))"
:class="tab === 'list' ? 'bg-white dark:bg-slate-800 text-cyan-600 dark:text-cyan-400 shadow-sm shadow-cyan-500/10' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-200'"
class="px-8 py-3 rounded-xl text-sm font-black uppercase tracking-widest transition-all">
{{ __('Machine List') }}
</a>
<a href="{{ route('admin.machines.index', ['tab' => 'expiry']) }}"
class="px-8 py-3 rounded-xl text-sm font-black uppercase tracking-widest transition-all {{ $tab === 'expiry' ? 'bg-white dark:bg-slate-800 text-cyan-600 dark:text-cyan-400 shadow-sm shadow-cyan-500/10' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-200' }}">
</button>
<button @click="tab = 'expiry'; viewMode = 'fleet'; selectedMachine = null; window.history.replaceState(null, '', '?tab=expiry' + (new URLSearchParams(window.location.search).get('search') ? '&search=' + new URLSearchParams(window.location.search).get('search') : ''))"
:class="tab === 'expiry' ? 'bg-white dark:bg-slate-800 text-cyan-600 dark:text-cyan-400 shadow-sm shadow-cyan-500/10' : 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-200'"
class="px-8 py-3 rounded-xl text-sm font-black uppercase tracking-widest transition-all">
{{ __('Expiry Management') }}
</a>
</button>
</div>
@if($tab === 'list')
<!-- Main Card (Machine List Tab) -->
<div class="luxury-card rounded-3xl p-8 animate-luxury-in overflow-hidden mt-6">
<div x-show="tab === 'list'" class="luxury-card rounded-3xl p-8 animate-luxury-in overflow-hidden mt-6">
<!-- Filters Area -->
<div class="flex items-center justify-between mb-8">
<form method="GET" action="{{ route('admin.machines.index') }}" class="relative group">
@@ -340,7 +332,8 @@ window.machineApp = function(initialTab) {
{{ $machines->appends(request()->query())->links('vendor.pagination.luxury') }}
</div>
</div>
@elseif($tab === 'expiry')
<div x-show="tab === 'expiry'">
<!-- Expiry Management Tab Content -->
<div class="animate-luxury-in mt-6">
<!-- viewMode: fleet (機台列表概覽) -->
@@ -575,7 +568,7 @@ window.machineApp = function(initialTab) {
{{ $machines->appends(request()->query())->links('vendor.pagination.luxury') }}
</div>
</div>
@endif
</div>
<!-- Offcanvas Log Panel -->
<div x-show="showLogPanel" class="fixed inset-0 z-[100] overflow-hidden" style="display: none;"