diff --git a/.agents/skills/ui-minimal-luxury/SKILL.md b/.agents/skills/ui-minimal-luxury/SKILL.md index c59a849..bab696e 100644 --- a/.agents/skills/ui-minimal-luxury/SKILL.md +++ b/.agents/skills/ui-minimal-luxury/SKILL.md @@ -330,13 +330,15 @@ description: 定義 Star Cloud 管理後台的「極簡奢華風」設計規範 > [!TIP] > 當遇到未定義的 UI 區塊時,優先參考 `admin.dashboard.blade.php` 的卡片與即時動態實作方式進行衍生。 -## 13. 加載指示器規範 (Loading Indicator Pattern) +## 13. AJAX 交互與加載規範 (AJAX Interactions & Loaders) -當使用 AJAX 進行局部頁面刷新或異步操作時,必須使用統一的「極奢華加載遮罩」。 +為了提供無刷新的 SPA 式流暢體驗,所有管理後台模組必須遵循統一的 AJAX 交互模式。 + +### 13.1 極奢華多環加載器 (Premium Multi-Ring Loader) +用於表格遮罩、局部更新或狀態切換。具備雙環旋轉與脈衝核心圖示。 -### 13.1 標準 HTML 結構 ```html - +
``` -### 13.2 設計要點 -1. **多重動畫**:結合 `animate-spin` (不同速度/方向) 與 `animate-pulse`,營造出高科技且細膩的層次感。 -2. **顏色規範**:主要使用 `cyan-500` 作為亮點,搭配 `slate` 系列的半透明背景。 -3. **字體細節**:文字使用極細小尺寸 (`text-[10px]`)、極粗字重 (`font-black`) 並大幅度拉開字距 (`tracking-[0.4em]`)。 -4. **背景質感**:使用 `backdrop-blur-[1px]` 與 `bg-white/40` (或 `dark:bg-slate-900/40`),確保遮罩具有玻璃質感但不完全阻斷視線。 -5. **防止閃爍**: 必須加上 `x-cloak` 配合對應的 CSS 樣式。 - -## 14. 頁面佈局與頁籤間距規範 (Page Layout & Tab Spacing) - -為了確保管理後台全站視覺的「高度整合感」與「緊湊性」,頁面頂部結構與頁籤導覽必須遵循以下間距規範。 - -### 14.1 核心佈局間距 (Core Spacing Scale) -- **根容器間距 (Root Space)**: 頂部 Header、Tabs 與內容區域之間的垂直間距統一使用 **`space-y-2`**。 -- **標題與描述 (Title & Subtitle)**: 描述文字應緊貼標題,使用 `mt-1`。 -- **頁籤外層間距 (Tabs Outer)**: 頁籤容器與 Header 之間應由根容器的 `space-y-2` 自然推開,不額外加 `mt`。 - -### 14.2 頁籤導覽樣式 (Tab Navigation Styles) -- **容器內距**: 使用 `p-1.5` 的圓角膠囊背景。 -- **按鈕內距**: 頁籤按鈕統一使用 **`px-8 py-3`**。 -- **內容間隙**: 頁籤下方內容區與頁籤列之間,建議不額外添加 `mt-6` 等大間距。若內容區域內部需要層次感,使用 `space-y-3` 即可。 - -### 14.3 實作範例結構 (Reference Structure) -```html -
- -
-
-

標題

-

描述文字

-
-
- - -
- - -
- - -
- -
-
-``` - -### 14.4 統計卡片間距 (Stats Grid Spacing) -- **網格間距**: 頂部統計卡片網格 (Grid) 建議使用 **`gap-4`** (16px),避免使用過大的 `gap-6` 或 `gap-8` 導致版面鬆散。 -- **卡片內距**: 統計卡片內部統一使用 `p-6`。 - -### 15. Premium AJAX Interactions & Loaders - -To maintain a seamless "SPA-like" experience without full-page reloads, all administrative modules must follow these AJAX patterns. - -#### 15.1 The Premium Multi-Ring Loader -Used for table overlays and state transitions. It features a dual-spin ring with a pulsing core icon. - -```html - -
- -
- -
- -
- -
- - - -
-
-

Syncing Data...

-
-``` - -#### 15.2 Standard fetchPage Pattern -All lists should implement the following `fetchPage` method in their `x-data` and wrap the dynamic content in `#ajax-content-container`. +### 13.2 標準 fetchPage 實作模式 +所有清單頁面應在 `x-data` 中實作 `fetchPage` 方法,並將動態內容包裹於 `#ajax-content-container` 中。 ```javascript async fetchPage(url) { @@ -470,7 +389,49 @@ async fetchPage(url) { } ``` -#### 15.3 Triggering AJAX Navigation -- **Forms**: Use `@submit.prevent="fetchPage($el.action + '?' + new URLSearchParams(new FormData($el)).toString())"`. -- **Selects**: Use `onchange="this.dispatchEvent(new CustomEvent('ajax:navigate', { detail: { url: ... }, bubbles: true }))"`. -- **Links/Pagination**: Use a delegated `@click` listener on the container or `@ajax:navigate.prevent.stop`. \ No newline at end of file +### 13.3 觸發 AJAX 導航 +- **搜尋表單**: 使用 `@submit.prevent="fetchPage($el.action + '?' + new URLSearchParams(new FormData($el)).toString())"`。 +- **下拉選單**: 使用 `onchange="this.dispatchEvent(new CustomEvent('ajax:navigate', { detail: { url: ... }, bubbles: true }))"`。 +- **分頁/連結**: 在容器上使用代理監聽,或直接調用 `fetchPage(url)`。 + +## 14. 頁面佈局與頁籤間距規範 (Page Layout & Tab Spacing) + +為了確保管理後台全站視覺的「高度整合感」與「緊湊性」,頁面頂部結構與頁籤導覽必須遵循以下間距規範。 + +### 14.1 核心佈局間距 (Core Spacing Scale) +- **根容器間距 (Root Space)**: 頂部 Header、Tabs 與內容區域之間的垂直間距統一使用 **`space-y-2`**。 +- **標題與描述 (Title & Subtitle)**: 描述文字應緊貼標題,使用 `mt-1`。 +- **頁籤外層間距 (Tabs Outer)**: 頁籤容器與 Header 之間應由根容器的 `space-y-2` 自然推開,不額外加 `mt`。 + +### 14.2 頁籤導覽樣式 (Tab Navigation Styles) +- **容器內距**: 使用 `p-1.5` 的圓角膠囊背景。 +- **按鈕內距**: 頁籤按鈕統一使用 **`px-8 py-3`**。 +- **內容間隙**: 頁籤下方內容區與頁籤列之間,建議不額外添加 `mt-6` 等大間距。若內容區域內部需要層次感,使用 `space-y-3` 即可。 + +### 14.3 實作範例結構 (Reference Structure) +```html +
+ +
+
+

標題

+

描述文字

+
+
+ + +
+ + +
+ + +
+ +
+
+``` + +### 14.4 統計卡片間距 (Stats Grid Spacing) +- **網格間距**: 頂部統計卡片網格 (Grid) 建議使用 **`gap-4`** (16px),避免使用過大的 `gap-6` 或 `gap-8` 導致版面鬆散。 +- **卡片內距**: 統計卡片內部統一使用 `p-6`。 \ No newline at end of file diff --git a/app/Http/Controllers/Admin/CompanyController.php b/app/Http/Controllers/Admin/CompanyController.php index 0a5389f..466b558 100644 --- a/app/Http/Controllers/Admin/CompanyController.php +++ b/app/Http/Controllers/Admin/CompanyController.php @@ -74,6 +74,13 @@ class CompanyController extends Controller if (isset($validated['settings'])) { $validated['settings']['enable_material_code'] = filter_var($validated['settings']['enable_material_code'] ?? false, FILTER_VALIDATE_BOOLEAN); $validated['settings']['enable_points'] = filter_var($validated['settings']['enable_points'] ?? false, FILTER_VALIDATE_BOOLEAN); + $validated['settings']['tax_invoice'] = filter_var($validated['settings']['tax_invoice'] ?? false, FILTER_VALIDATE_BOOLEAN); + $validated['settings']['card_terminal'] = filter_var($validated['settings']['card_terminal'] ?? false, FILTER_VALIDATE_BOOLEAN); + $validated['settings']['scan_pay_esun'] = filter_var($validated['settings']['scan_pay_esun'] ?? false, FILTER_VALIDATE_BOOLEAN); + $validated['settings']['scan_pay_linepay'] = filter_var($validated['settings']['scan_pay_linepay'] ?? false, FILTER_VALIDATE_BOOLEAN); + $validated['settings']['shopping_cart'] = filter_var($validated['settings']['shopping_cart'] ?? false, FILTER_VALIDATE_BOOLEAN); + $validated['settings']['welcome_gift'] = filter_var($validated['settings']['welcome_gift'] ?? false, FILTER_VALIDATE_BOOLEAN); + $validated['settings']['cash_module'] = filter_var($validated['settings']['cash_module'] ?? false, FILTER_VALIDATE_BOOLEAN); } DB::transaction(function () use ($validated) { @@ -217,6 +224,7 @@ class CompanyController extends Controller */ public function updateSettings(Request $request, Company $company) { + \Log::info('updateSettings payload:', $request->all()); $settings = $request->input('settings', []); $formattedSettings = [ diff --git a/config/api-docs.php b/config/api-docs.php index d8ed015..e3bc1f9 100644 --- a/config/api-docs.php +++ b/config/api-docs.php @@ -460,7 +460,7 @@ return [ 'description' => '當機台發生硬體故障(如卡貨、通訊中斷)時即時上報。', 'payload_parameters' => [ 'tid' => ['type' => 'integer', 'description' => '貨道編號或任務 ID'], - 'error_code' => ['type' => 'string', 'description' => '硬體錯誤代碼,詳見下方 B013 代碼表'], + 'error_code' => ['type' => 'string', 'description' => '硬體錯誤代碼 (如 0403 代表卡貨)'], ], 'payload_example' => [ 'tid' => 12, @@ -480,7 +480,7 @@ return [ 'amount' => ['type' => 'number', 'description' => '交易金額 (create/invoice 時使用)'], 'slot_no' => ['type' => 'string', 'description' => '出貨貨道號碼'], 'invoice_no' => ['type' => 'string', 'description' => '發票號碼 (action 為 invoice 時必填)'], - 'status' => ['type' => 'string', 'description' => '出貨結果狀態 (action 為 dispense 時必填,見狀態定義表)'], + 'status' => ['type' => 'string', 'description' => '出貨結果狀態 (action 為 dispense 時必填,如 success, failed)'], ], 'payload_example' => [ 'action' => 'create', @@ -596,7 +596,7 @@ return [ 'description' => '機台執行完雲端指令後的主動回報。此回報極為重要,雲端將依此決定交易是否完成或需進行庫存回滾。', 'payload_parameters' => [ 'command_id' => ['type' => 'string', 'description' => '對應下發時的指令 ID'], - 'result' => ['type' => 'string', 'description' => '執行結果,見狀態定義表'], + 'result' => ['type' => 'string', 'description' => '執行結果,僅接受: success 或 failed'], 'stock' => ['type' => 'integer', 'description' => '執行指令後的最終剩餘庫存 (選填,通常出貨指令需帶上)'], 'message' => ['type' => 'string', 'description' => '額外的錯誤訊息 (選填)'], ], @@ -608,39 +608,5 @@ return [ ] ] ] - ], - - 'status_definitions' => [ - [ - 'name' => 'B013: 硬體錯誤代碼 (MQTT Error Topic)', - 'description' => '當機台透過 machine/{serial_no}/error 上報時,error_code 欄位所使用的代碼。', - 'codes' => [ - ['code' => '0402', 'label' => '出貨成功', 'level' => 'info', 'description' => '商品成功掉落至取貨口。'], - ['code' => '0403', 'label' => '貨道卡貨', 'level' => 'error', 'description' => '馬達轉動異常或偵測到卡貨,需人工排除。'], - ['code' => '0202', 'label' => '貨道缺貨', 'level' => 'warning', 'description' => '偵測到實體貨道已無商品。'], - ['code' => '0412', 'label' => '昇降機上升異常', 'level' => 'error', 'description' => '昇降馬達無法正確到達指定位置。'], - ['code' => '0415', 'label' => '取貨門異常', 'level' => 'error', 'description' => '取貨門馬達損壞或感應器失效。'], - ['code' => '5402', 'label' => '取貨門未關', 'level' => 'warning', 'description' => '取貨逾時或門片未正確閉合。'], - ['code' => '5403', 'label' => '昇降系統故障', 'level' => 'error', 'description' => '昇降機通訊中斷或驅動板異常。'], - ] - ], - [ - 'name' => '交易與指令執行狀態 (Transaction & Command)', - 'description' => '用於 Transaction (dispense) 與 Command ACK 的執行結果判定。', - 'codes' => [ - ['code' => 'success', 'label' => '成功', 'description' => '動作執行圓滿完成。'], - ['code' => 'failed', 'label' => '失敗', 'description' => '動作執行失敗,雲端將視情況發起退款或記錄異常。'], - ['code' => '1', 'label' => '成功 (數字型態)', 'description' => '部分舊型指令或 B602 使用的成功代碼。'], - ['code' => '0', 'label' => '失敗 (數字型態)', 'description' => '部分舊型指令或 B602 使用的失敗代碼。'], - ] - ], - [ - 'name' => '機台連線狀態 (Connection Status)', - 'description' => '用於 machine/{serial_no}/status 主題,反映機台與 Broker 的連線情況。', - 'codes' => [ - ['code' => 'online', 'label' => '在線', 'description' => '機台已成功連線至 MQTT Broker。'], - ['code' => 'offline', 'label' => '離線', 'description' => '機台已斷開連線(通常由 LWT 遺囑訊息觸發)。'], - ] - ] ] ]; \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index a9dae4a..b458396 100644 --- a/lang/en.json +++ b/lang/en.json @@ -291,6 +291,7 @@ "e.g., Drinks": "e.g., Drinks", "e.g., Taipei Station": "e.g., Taipei Station", "e.g., お飲み物": "e.g., O-Nomimono", + "ESUN": "ESUN", "E.SUN QR Scan": "E.SUN QR Scan", "E.SUN QR Scan Settings Description": "E.SUN Bank QR Scan Payment Settings", "EASY_MERCHANT_ID": "EASY_MERCHANT_ID", @@ -315,6 +316,7 @@ "Edit Slot": "Edit Slot", "Edit Sub Account Role": "Edit Sub Account Role", "Email": "Email", + "Enabled Features": "Enabled Features", "Enable": "Enable", "Enable Material Code": "Enable Material Code", "Enable Points": "Enable Points", @@ -709,6 +711,7 @@ "Please select a slot": "Please select a slot", "PNG, JPG up to 2MB": "PNG, JPG up to 2MB", "PNG, JPG, WEBP up to 10MB": "PNG, JPG, WEBP up to 10MB", + "Points": "Points", "Point Rules": "Point Rules", "Point Settings": "Point Settings", "Points Rule": "Points Rule", diff --git a/lang/ja.json b/lang/ja.json index 3d786ad..e96f473 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -14,8 +14,16 @@ "Coin/Bill Acceptor": "コイン/紙幣機", "System settings updated successfully.": "システム設定が正常に更新されました。", "Update Settings": "設定を更新", + "Enabled Features": "有効な機能", "Material Code": "素材コード", "Points": "ポイント", + "Electronic Invoice": "電子翻訳", + "Card System": "カード決済システム", + "ESUN": "玉山銀行 (ESUN)", + "LinePay": "LinePay", + "Shopping Cart": "ショッピングカート", + "Welcome Gift": "登録特典", + "Cash Module": "現金決済モジュール", "Please enter configuration name": "設定名を入力してください", "Please select a company": "会社を選択してください", "Warehouse Management": "倉庫管理", diff --git a/lang/zh_TW.json b/lang/zh_TW.json index 00671b3..25622de 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -317,6 +317,8 @@ "Edit Slot": "編輯貨道", "Edit Sub Account Role": "編輯子帳號角色", "Email": "電子郵件", + "Emblem / Label": "標章 / 標籤", + "Enabled Features": "啟用功能", "Enable": "啟用", "Enable Material Code": "啟用物料編號", "Enable Points": "啟用點數規則", @@ -718,6 +720,7 @@ "PNG, JPG, WEBP up to 10MB": "支援 PNG, JPG, WEBP 格式,且不超過 10MB", "Point Rules": "點數規則", "Point Settings": "點數設定", + "Points": "點數功能", "Points Rule": "點數規則", "Points Settings": "點數設定", "Points toggle": "點數開關", @@ -1260,6 +1263,7 @@ "Card System": "刷卡機系統", "Credit Card / Contactless": "支援信用卡 / 感應支付", "Scan Pay": "掃碼支付", + "ESUN": "玉山銀行", "ESUN Scan Pay": "玉山掃碼支付", "LinePay": "LinePay", "Other Features": "其他功能", diff --git a/resources/views/admin/ads/index.blade.php b/resources/views/admin/ads/index.blade.php index d43eed8..984c33c 100644 --- a/resources/views/admin/ads/index.blade.php +++ b/resources/views/admin/ads/index.blade.php @@ -6,8 +6,17 @@ $baseRoute = 'admin.data-config.advertisements'; @endphp @section('content') -
-
+
+ +
+ +
+
+
+
+ + + +
+
+

{{ __('Loading Data') }}...

+
+
@@ -376,6 +407,7 @@ $baseRoute = 'admin.data-config.advertisements';
+ @keydown.escape.window="showLogPanel = false; showInventoryPanel = false" + @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); + }">
@@ -189,18 +203,15 @@
-

Syncing Data...

+

{{ __('Loading Data') }}...

+ :class="{ 'opacity-30 pointer-events-none transition-opacity duration-300': isLoadingTable }">
-
+ @@ -213,6 +224,7 @@ +
@@ -321,17 +333,17 @@
- {{ + {{ __('Normal') }}
- {{ + {{ __('Normal') }}
- {{ + {{ __('Normal') }}
@@ -433,7 +445,7 @@ {{ __('Machine Logs') }}
+ class="mt-2 flex flex-col sm:flex-row sm:items-center gap-1 sm:gap-2 text-[12px] sm:text-sm text-slate-500 dark:text-slate-400 font-bold uppercase tracking-widest overflow-hidden"> @@ -458,7 +470,7 @@
+ class="luxury-input text-[12px] h-9 sm:h-8 py-0 w-full sm:w-44 bg-white dark:bg-slate-800 border-slate-200 dark:border-slate-700">
+ class="luxury-input text-[12px] h-9 sm:h-8 py-0 w-full sm:w-44 bg-white dark:bg-slate-800 border-slate-200 dark:border-slate-700">
-

{{ __('Loading Data') }}...

+

{{ __('Loading Data') }}...

@@ -569,13 +581,13 @@ @@ -594,7 +606,7 @@ 'bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20': log.level === 'warning', 'bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-500/20': log.level === 'error' }" - class="inline-flex items-center px-2 py-0.5 rounded-md border text-[10px] font-black uppercase tracking-wider"> + class="inline-flex items-center px-2 py-0.5 rounded-md border text-[12px] font-black uppercase tracking-wider"> @@ -615,7 +627,7 @@ class="p-4 hover:bg-slate-50 dark:hover:bg-slate-800/30 transition-colors">
{{ + class="text-[12px] font-bold text-slate-400 dark:text-slate-500 uppercase tracking-widest">{{ __('No matching logs found') }}
@@ -666,9 +678,9 @@
- - / - + + / +
diff --git a/resources/views/admin/machines/utilization.blade.php b/resources/views/admin/machines/utilization.blade.php index 8003f05..594adc3 100644 --- a/resources/views/admin/machines/utilization.blade.php +++ b/resources/views/admin/machines/utilization.blade.php @@ -279,7 +279,7 @@ window.utilizationDashboard = function(initialMachines, initialStats) { -

Syncing Data...

+

{{ __('Loading Data') }}...

diff --git a/resources/views/vendor/pagination/luxury.blade.php b/resources/views/vendor/pagination/luxury.blade.php index 676f280..b7b9b91 100644 --- a/resources/views/vendor/pagination/luxury.blade.php +++ b/resources/views/vendor/pagination/luxury.blade.php @@ -43,7 +43,9 @@ @else - + @@ -67,7 +69,9 @@ {{-- Next Page Link --}} @if ($paginator->hasMorePages()) - +
+ class="px-6 py-4 text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] border-b border-slate-200 dark:border-slate-700 w-40"> {{ __('Timestamp') }} + class="px-6 py-4 text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] border-b border-slate-200 dark:border-slate-700 w-24 text-center"> {{ __('Level') }} + class="px-6 py-4 text-[12px] font-black text-slate-400 uppercase tracking-[0.2em] border-b border-slate-200 dark:border-slate-700"> {{ __('Message') }}