diff --git a/app/Console/Commands/ListenMqttQueue.php b/app/Console/Commands/ListenMqttQueue.php index 1b541f5..d5b6ddd 100644 --- a/app/Console/Commands/ListenMqttQueue.php +++ b/app/Console/Commands/ListenMqttQueue.php @@ -95,6 +95,10 @@ class ListenMqttQueue extends Command $finalPayload = is_array($payload) ? $payload : ['raw_data' => $payload]; ProcessHeartbeat::dispatch($serialNo, $finalPayload); break; + case 'ambient_temp': + $finalPayload = is_array($payload) ? $payload : ['temperature' => $payload]; + \App\Jobs\Machine\ProcessAmbientTemp::dispatch($serialNo, $finalPayload); + break; case 'status': ProcessStatus::dispatch($serialNo, $payload); break; diff --git a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php index fa1dfc8..ad6a1b5 100644 --- a/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php +++ b/app/Http/Controllers/Admin/BasicSettings/MachineSettingController.php @@ -213,6 +213,7 @@ class MachineSettingController extends AdminController 'scan_pay_linepay_enabled' => 'boolean', 'shopping_cart_enabled' => 'boolean', 'cash_module_enabled' => 'boolean', + 'ambient_temp_monitoring_enabled' => 'boolean', 'machine_model_id' => 'required|exists:machine_models,id', 'payment_config_id' => 'nullable|exists:payment_configs,id', 'location' => 'nullable|string|max:255', @@ -333,6 +334,7 @@ class MachineSettingController extends AdminController 'welcome_gift_enabled', 'cash_module_enabled', 'member_system_enabled', + 'ambient_temp_monitoring_enabled', ]; $data = []; foreach ($allowedFields as $field) { @@ -361,6 +363,7 @@ class MachineSettingController extends AdminController 'welcome_gift_enabled', 'cash_module_enabled', 'member_system_enabled', + 'ambient_temp_monitoring_enabled', ]; if (!in_array($field, $allowedFields)) { diff --git a/app/Http/Controllers/Admin/MachineController.php b/app/Http/Controllers/Admin/MachineController.php index 4b6e017..235151f 100644 --- a/app/Http/Controllers/Admin/MachineController.php +++ b/app/Http/Controllers/Admin/MachineController.php @@ -43,10 +43,48 @@ class MachineController extends AdminController { $validated = $request->validate([ 'name' => 'required|string|max:255', + 'ambient_temp_setting' => 'nullable|integer', ]); $machine->update($validated); + if ($machine->wasChanged('ambient_temp_setting')) { + $newSetting = $machine->ambient_temp_setting; + + // 將先前未執行的同類型指令標記為 superseded (被取代) + \App\Models\Machine\RemoteCommand::where('machine_id', $machine->id) + ->where('command_type', 'ambient_temp_limit') + ->where('status', 'pending') + ->update([ + 'status' => 'superseded', + 'remark' => __('Superseded by new command'), + 'executed_at' => now(), + ]); + + // 建立新指令 + $command = \App\Models\Machine\RemoteCommand::create([ + 'machine_id' => $machine->id, + 'user_id' => auth()->id() ?: 1, + 'command_type' => 'ambient_temp_limit', + 'payload' => [ + 'temperature' => $newSetting !== null ? (int)$newSetting : null + ], + 'status' => 'pending', + 'remark' => $newSetting !== null + ? __('Temperature reaches :temp degrees, the fan will turn on', ['temp' => $newSetting]) + : __('Disabled ambient temperature monitoring') + ]); + + // 發送 MQTT 指令 + $mqttService = app(\App\Services\Machine\MqttService::class); + $mqttService->pushCommand( + $machine->serial_no, + $command->command_type, + $command->payload, + (string)$command->id + ); + } + return redirect()->route('admin.machines.index') ->with('success', __('Machine updated successfully.')); } @@ -267,4 +305,35 @@ class MachineController extends AdminController 'data' => $chartData ]); } + + /** + * AJAX: 取得機台環境溫度歷史紀錄 (供圖表使用) + */ + public function ambientTemperatureAjax(Request $request, Machine $machine) + { + $startDate = $request->get('start_date'); + $endDate = $request->get('end_date'); + + $logs = $machine->logs() + ->where('type', 'ambient_temp') + ->where('message', 'Ambient temperature reported: :temp°C') + ->when($startDate, function ($query, $start) { + return $query->where('created_at', '>=', str_replace('T', ' ', $start)); + }) + ->when($endDate, function ($query, $end) { + return $query->where('created_at', '<=', str_replace('T', ' ', $end)); + }) + ->oldest() + ->get(); + + $chartData = $logs->map(fn($log) => [ + 'x' => $log->created_at->getTimestamp() * 1000, + 'y' => (int) ($log->context['temp'] ?? 0), + ])->values()->toArray(); + + return response()->json([ + 'success' => true, + 'data' => $chartData + ]); + } } diff --git a/app/Http/Controllers/Admin/RemoteController.php b/app/Http/Controllers/Admin/RemoteController.php index 13b832c..9fceafc 100644 --- a/app/Http/Controllers/Admin/RemoteController.php +++ b/app/Http/Controllers/Admin/RemoteController.php @@ -139,7 +139,7 @@ class RemoteController extends Controller { $validated = $request->validate([ 'machine_id' => 'required|exists:machines,id', - 'command_type' => 'required|string|in:reboot,reboot_card,checkout,lock,unlock,change,dispense', + 'command_type' => 'required|string|in:reboot,reboot_card,checkout,lock,unlock,change,dispense,fanon,fanoff,fanauto', 'amount' => 'nullable|integer|min:0', 'slot_no' => 'nullable|string', 'note' => 'nullable|string|max:255', diff --git a/app/Jobs/Machine/ProcessAmbientTemp.php b/app/Jobs/Machine/ProcessAmbientTemp.php new file mode 100644 index 0000000..83d9133 --- /dev/null +++ b/app/Jobs/Machine/ProcessAmbientTemp.php @@ -0,0 +1,94 @@ +serialNo = $serialNo; + $this->payload = (array) $payload; + } + + /** + * Execute the job. + */ + public function handle(): void + { + $machine = Machine::withoutGlobalScopes()->where('serial_no', $this->serialNo)->first(); + + if (!$machine) { + Log::warning("MQTT Ambient Temp: Machine not found", ['serial_no' => $this->serialNo]); + return; + } + + // 環境溫度欄位更新 + // 支持機台傳送 payload 為 {"temperature": 25} 或 {"ambient_temp": 25} 等結構 + $temp = null; + if (isset($this->payload['temperature'])) { + $temp = (int) $this->payload['temperature']; + } elseif (isset($this->payload['ambient_temp'])) { + $temp = (int) $this->payload['ambient_temp']; + } elseif (isset($this->payload['raw_data'])) { + $temp = (int) $this->payload['raw_data']; + } + + if ($temp === null) { + Log::warning("MQTT Ambient Temp: Missing temperature field in payload", [ + 'serial_no' => $this->serialNo, + 'payload' => $this->payload + ]); + return; + } + + Log::debug("ProcessAmbientTemp: Ambient temperature reported for {$this->serialNo}: {$temp}"); + + $updateData = [ + 'ambient_temperature' => $temp, + ]; + + // 讀取最後一次記錄日誌的溫度與時間,避免頻繁寫入相同的溫度日誌 + $tempLogCacheKey = "machine:{$this->serialNo}:last_ambient_temp_log"; + $lastLogEntry = Cache::get($tempLogCacheKey); + + // 優先從快取取值,若無則從資料庫取 + $oldTemp = isset($lastLogEntry['value']) ? (int)$lastLogEntry['value'] : $machine->ambient_temperature; + + if ($temp !== (int)$oldTemp) { + Log::debug("ProcessAmbientTemp: Ambient temperature changed from {$oldTemp} to {$temp}. Triggering log."); + \App\Jobs\Machine\ProcessStateLog::dispatch( + $machine->id, + $machine->company_id, + "Ambient temperature reported: :temp°C", + 'info', + ['temp' => $temp], + 'ambient_temp' // type 欄位 + ); + } + + // 更新快取 (存活時間為 7 天) + Cache::put($tempLogCacheKey, [ + 'value' => $temp, + 'at' => now()->toDateTimeString() + ], 604800); + + $machine->update($updateData); + } +} diff --git a/app/Jobs/Machine/ProcessMachineEvent.php b/app/Jobs/Machine/ProcessMachineEvent.php index b6f0535..0a282ea 100644 --- a/app/Jobs/Machine/ProcessMachineEvent.php +++ b/app/Jobs/Machine/ProcessMachineEvent.php @@ -45,10 +45,10 @@ class ProcessMachineEvent implements ShouldQueue return; } - // 寫入機台狀態日誌,type 為 'status' 以便正確歸類顯示於「機台狀態」日誌中 + // 寫入環境溫度日誌,type 為 'ambient_temp' 以便正確歸類顯示於「環境溫度回傳」日誌中 $machine->logs()->create([ 'company_id' => $machine->company_id, - 'type' => 'status', // 忠實呈現於機台狀態中 + 'type' => 'ambient_temp', // 歸類至環境溫度回傳 'level' => 'info', 'message' => $event, // 例如 "fanon" 或 "fanoff" 'context' => $this->payload, diff --git a/app/Models/Machine/Machine.php b/app/Models/Machine/Machine.php index 526b1ba..378fcd6 100644 --- a/app/Models/Machine/Machine.php +++ b/app/Models/Machine/Machine.php @@ -70,6 +70,9 @@ class Machine extends Model 'current_page', 'door_status', 'temperature', + 'ambient_temperature', + 'ambient_temp_setting', + 'ambient_temp_monitoring_enabled', 'firmware_version', 'api_token', 'last_heartbeat_at', @@ -309,6 +312,9 @@ class Machine extends Model protected $casts = [ 'last_heartbeat_at' => 'datetime', 'temperature' => 'integer', + 'ambient_temperature' => 'integer', + 'ambient_temp_setting' => 'integer', + 'ambient_temp_monitoring_enabled' => 'boolean', 'welcome_gift_enabled' => 'boolean', 'is_spring_slot_1_10' => 'boolean', 'is_spring_slot_11_20' => 'boolean', diff --git a/config/api-docs.php b/config/api-docs.php index 190c65a..94009ef 100644 --- a/config/api-docs.php +++ b/config/api-docs.php @@ -540,6 +540,22 @@ return [ 'status' => 'online' ], ], + [ + 'name' => '機台環境溫度上報 (Ambient Temperature Report)', + 'slug' => 'mqtt-ambient-temp-report', + 'action' => 'PUB', + 'topic' => 'machine/{serial_no}/ambient_temp', + 'qos' => 1, + 'description' => '機台主動上報當前環境溫度。支援 temperature 或 ambient_temp 欄位上報。', + 'payload_parameters' => [ + 'temperature' => ['type' => 'integer', 'description' => '當前環境溫度值 (例如 28)'], + 'ambient_temp' => ['type' => 'integer', 'description' => '當前環境溫度值 (相容相應硬體參數)'], + ], + 'payload_example' => [ + 'temperature' => 28 + ], + ], + [ 'name' => '機台硬體事件上報 (Event)', 'slug' => 'mqtt-event', @@ -773,7 +789,7 @@ return [ 'qos' => 1, 'description' => '雲端主動下發的系統級別控制指令。包含重啟、設備鎖定解鎖、購物車結帳等無額外參數的指令。', 'payload_parameters' => [ - 'command' => ['type' => 'string', 'description' => '系統指令類型。支援:reboot (重啟機台), reboot_card (重啟刷卡機), checkout (購物車結帳), lock (設備鎖定), unlock (設備解鎖), update_ads (廣告同步), update_products (商品資料同步)'], + 'command' => ['type' => 'string', 'description' => '系統指令類型。支援:reboot (重啟機台), reboot_card (重啟刷卡機), checkout (購物車結帳), lock (設備鎖定), unlock (設備解鎖), update_ads (廣告同步), update_products (商品資料同步), fanon (開啟風扇), fanoff (關閉風扇), fanauto (風扇自動控制)'], 'command_id' => ['type' => 'string', 'description' => '指令唯一 ID'], 'payload' => ['type' => 'object', 'description' => '空物件 (無額外參數)'], ], @@ -784,6 +800,28 @@ return [ ], ], + [ + 'name' => '指令下發:環境溫度上限 (Ambient Temperature Upper Limit)', + 'slug' => 'mqtt-command-ambient-temp-limit', + 'action' => 'SUB', + 'topic' => 'machine/{serial_no}/command', + 'qos' => 1, + 'description' => '雲端主動下發「環境溫度上限」指令。指示機台更新環境溫度開啟風扇的閾值設定。', + 'payload_parameters' => [ + 'command' => ['type' => 'string', 'description' => '固定為 "ambient_temp_limit"'], + 'command_id' => ['type' => 'string', 'description' => '指令唯一 ID'], + 'payload' => ['type' => 'object', 'description' => '溫度設定參數'], + 'payload.temperature' => ['type' => 'integer', 'description' => '環境溫度上限閾值(可為 null 表示停用監測)'], + ], + 'payload_example' => [ + 'command' => 'ambient_temp_limit', + 'command_id' => '1122334455', + 'payload' => [ + 'temperature' => 28 + ] + ], + ], + [ 'name' => '指令執行回報 (Machine to Cloud)', 'slug' => 'mqtt-command-ack', diff --git a/database/migrations/2026_06_04_100930_add_ambient_temperature_and_setting_to_machines_table.php b/database/migrations/2026_06_04_100930_add_ambient_temperature_and_setting_to_machines_table.php new file mode 100644 index 0000000..affd750 --- /dev/null +++ b/database/migrations/2026_06_04_100930_add_ambient_temperature_and_setting_to_machines_table.php @@ -0,0 +1,33 @@ +integer('ambient_temperature')->nullable()->after('temperature')->comment('環境溫度'); + } + if (!Schema::hasColumn('machines', 'ambient_temp_setting')) { + $table->integer('ambient_temp_setting')->nullable()->after('ambient_temperature')->comment('環境溫度設定值'); + } + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('machines', function (Blueprint $table) { + $table->dropColumn(['ambient_temperature', 'ambient_temp_setting']); + }); + } +}; diff --git a/database/migrations/2026_06_04_110221_add_ambient_temp_monitoring_enabled_to_machines_table.php b/database/migrations/2026_06_04_110221_add_ambient_temp_monitoring_enabled_to_machines_table.php new file mode 100644 index 0000000..a37ea67 --- /dev/null +++ b/database/migrations/2026_06_04_110221_add_ambient_temp_monitoring_enabled_to_machines_table.php @@ -0,0 +1,30 @@ +boolean('ambient_temp_monitoring_enabled')->default(false)->after('ambient_temp_setting')->comment('是否啟用環境溫度監測'); + } + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('machines', function (Blueprint $table) { + $table->dropColumn('ambient_temp_monitoring_enabled'); + }); + } +}; diff --git a/database/seeders/RoleSeeder.php b/database/seeders/RoleSeeder.php index 6f46764..50859d9 100644 --- a/database/seeders/RoleSeeder.php +++ b/database/seeders/RoleSeeder.php @@ -58,8 +58,6 @@ class RoleSeeder extends Seeder 'menu.reservation', 'menu.special-permission', 'menu.special-permission.clear-stock', - 'menu.special-permission.apk-versions', - 'menu.special-permission.discord-notifications', 'menu.basic', 'menu.basic.machines', 'menu.basic.payment-configs', @@ -123,10 +121,6 @@ class RoleSeeder extends Seeder 'menu.reservation', 'menu.special-permission', 'menu.special-permission.clear-stock', - 'menu.special-permission.apk-versions', - 'menu.special-permission.discord-notifications', - 'menu.basic.discord-notifications', - 'menu.basic.apk-versions', ]); } } \ No newline at end of file diff --git a/lang/en.json b/lang/en.json index 0e8263f..40e204d 100644 --- a/lang/en.json +++ b/lang/en.json @@ -120,6 +120,13 @@ "All Warehouses": "All Warehouses", "All issues marked as resolved.": "All issues marked as resolved.", "All slots are fully stocked": "All slots are fully stocked", + "Ambient Temperature": "Ambient Temperature", + "Ambient Temperature Log": "Ambient Temperature Log", + "Ambient Temperature Monitoring": "Ambient Temperature Monitoring", + "Ambient Temperature Setting": "Ambient Temperature Setting", + "Ambient Temperature Trend": "Ambient Temperature Trend", + "Ambient Temperature Upper Limit": "Ambient Temperature Upper Limit", + "Ambient temperature reported: :temp°C": "Ambient temperature reported: :temp°C", "Amount": "Amount", "Amount / Payment": "Amount / Payment", "Amount Discount": "Amount Discount", @@ -236,6 +243,7 @@ "CASH": "CASH", "CREATE STOCK TRANSFERS BETWEEN WAREHOUSES AND MACHINE RETURNS": "CREATE STOCK TRANSFERS BETWEEN WAREHOUSES AND MACHINE RETURNS", "Calculate Replenishment": "Calculate Replenishment", + "Can be empty. If left blank, it means ambient temperature monitoring is disabled.": "Can be empty. If left blank, it means ambient temperature monitoring is disabled.", "Cancel": "Cancel", "Cancel Gift": "Cancel Gift", "Cancel Order": "Cancel Order", @@ -511,6 +519,7 @@ "Disable Product Confirmation": "Disable Product Confirmation", "Disable Warehouse": "Disable Warehouse", "Disabled": "Disabled", + "Disabled ambient temperature monitoring": "Disabled ambient temperature monitoring", "Disabling this customer will also disable all accounts under this customer. Are you sure you want to continue?": "Disabling this customer will also disable all accounts under this customer. Are you sure you want to continue?", "Discord Notifications": "Discord Notifications", "Discord Webhook URL": "Discord Webhook URL", @@ -632,6 +641,7 @@ "English": "English", "Ensure your account is using a long, random password to stay secure.": "Ensure your account is using a long, random password to stay secure.", "Enter ad material name": "Enter ad material name", + "Enter ambient temperature setting...": "Enter ambient temperature setting...", "Enter full address": "Enter full address", "Enter login ID": "Enter login ID", "Enter machine location": "Enter machine location", @@ -690,6 +700,10 @@ "Failed to send test notification.": "Failed to send test notification.", "Failed to send test notification. Please verify the Webhook URL.": "Failed to send test notification. Please verify the Webhook URL.", "Failed to update machine images: ": "Failed to update machine images: ", + "Fan Auto": "Fan Auto", + "Fan Controls": "Fan Controls", + "Fan Off": "Fan Off", + "Fan On": "Fan On", "Feature Settings": "Feature Settings", "Feature Toggles": "Feature Toggles", "Field": "Field", @@ -822,6 +836,7 @@ "Half Points Amount": "Half Points Amount", "Hardware & Network": "Hardware & Network", "Hardware & Slots": "Hardware & Slots", + "Hardware Peripheral Settings": "Hardware Peripheral Settings", "HashIV": "HashIV", "HashKey": "HashKey", "Heartbeat": "Heartbeat", @@ -1955,6 +1970,7 @@ "Temperature Limit": "Temperature Limit", "Temperature Restored": "Temperature Restored", "Temperature Trend": "Temperature Trend", + "Temperature reaches :temp degrees, the fan will turn on": "Temperature reaches :temp°C, the fan will turn on", "Temperature reported: :temp°C": "Temperature reported: :temp°C", "Temperature updated to :temp°C": "Temperature updated to :temp°C", "Tenant": "Tenant", @@ -2084,6 +2100,7 @@ "Update Product": "Update Product", "Update Settings": "Update Settings", "Update Welcome Gift": "Update Welcome Gift", + "Update ambient temperature setting to :temp°C": "Update ambient temperature setting to :temp°C", "Update existing role and permissions.": "Update existing role and permissions.", "Update failed": "Update failed", "Update identification for your asset": "Update identification for your asset", @@ -2098,6 +2115,7 @@ "Upload file or provide URL": "Upload file or provide URL", "Uploading new images will replace all existing images.": "Uploading new images will replace all existing images.", "Uploading...": "Uploading...", + "Upper limit; the fan will turn on when reached": "Upper limit; the fan will turn on when reached", "Usage Completed": "Usage Completed", "Usage Limit": "Usage Limit", "Usage Logs": "Usage Logs", @@ -2343,9 +2361,7 @@ "menu.sales.records": "Sales Records", "menu.sales.store-gifts": "Store Gifts", "menu.special-permission": "Special Permissions", - "menu.special-permission.apk-versions": "APK Versions", "menu.special-permission.clear-stock": "Clear Stock", - "menu.special-permission.discord-notifications": "Discord Notifications", "menu.warehouses": "Warehouse Management", "menu.warehouses.inventory": "Inventory Management", "menu.warehouses.machine-inventory": "Machine Inventory Overview", diff --git a/lang/ja.json b/lang/ja.json index c04b0d0..5856093 100644 --- a/lang/ja.json +++ b/lang/ja.json @@ -120,6 +120,13 @@ "All Warehouses": "すべての倉庫", "All issues marked as resolved.": "すべての問題が解決済みとしてマークされました。", "All slots are fully stocked": "すべてのスロットが補充完了しました", + "Ambient Temperature": "周囲温度", + "Ambient Temperature Log": "周囲温度ログ", + "Ambient Temperature Monitoring": "環境温度監視", + "Ambient Temperature Setting": "周囲温度設定", + "Ambient Temperature Trend": "周囲温度トレンド", + "Ambient Temperature Upper Limit": "環境温度上限", + "Ambient temperature reported: :temp°C": "環境温度受信: :temp°C", "Amount": "金額", "Amount / Payment": "金額 / 支払い", "Amount Discount": "金額割引", @@ -236,6 +243,7 @@ "CASH": "現金", "CREATE STOCK TRANSFERS BETWEEN WAREHOUSES AND MACHINE RETURNS": "倉庫間の移動または機器からの返品を作成", "Calculate Replenishment": "補充量を計算", + "Can be empty. If left blank, it means ambient temperature monitoring is disabled.": "空欄にすることができます。空欄の場合、周囲温度の監視は無効になります。", "Cancel": "キャンセル", "Cancel Gift": "ギフトをキャンセル", "Cancel Order": "注文キャンセル", @@ -511,6 +519,7 @@ "Disable Product Confirmation": "商品無効化確認", "Disable Warehouse": "倉庫無効化", "Disabled": "無効済み", + "Disabled ambient temperature monitoring": "環境温度監視を停止しました", "Disabling this customer will also disable all accounts under this customer. Are you sure you want to continue?": "顧客を無効にすると配下の全アカウントも無効になります。続行しますか?", "Discord Notifications": "Discord通知", "Discord Webhook URL": "Discord Webhook URL", @@ -632,6 +641,7 @@ "English": "英語", "Ensure your account is using a long, random password to stay secure.": "安全を保つため、長くランダムなパスワードを使用してください。", "Enter ad material name": "広告素材名を入力", + "Enter ambient temperature setting...": "周囲温度設定を入力してください...", "Enter full address": "完全な住所を入力", "Enter login ID": "ログインIDを入力してください", "Enter machine location": "機器の設置場所を入力してください", @@ -690,6 +700,10 @@ "Failed to send test notification.": "テスト通知の送信に失敗しました。", "Failed to send test notification. Please verify the Webhook URL.": "テスト通知の送信に失敗しました。Webhook URLを確認してください。", "Failed to update machine images: ": "機器画像の更新に失敗しました: ", + "Fan Auto": "ファン自動", + "Fan Controls": "ファン制御", + "Fan Off": "ファン停止", + "Fan On": "ファン起動", "Feature Settings": "機能設定", "Feature Toggles": "機能切り替え", "Field": "Field", @@ -822,6 +836,7 @@ "Half Points Amount": "ハーフポイント金額", "Hardware & Network": "ハードウェア・ネットワーク", "Hardware & Slots": "ハードウェア・スロット", + "Hardware Peripheral Settings": "ハードウェア周辺機器設定", "HashIV": "HashIV", "HashKey": "HashKey", "Heartbeat": "ハートビート", @@ -1955,6 +1970,7 @@ "Temperature Limit": "温度しきい値", "Temperature Restored": "温度正常復帰", "Temperature Trend": "温度傾向", + "Temperature reaches :temp degrees, the fan will turn on": "温度が :temp度 に達するとファンが作動します", "Temperature reported: :temp°C": "温度が報告されました: :temp°C", "Temperature updated to :temp°C": "温度が :temp°C に更新されました", "Tenant": "顧客 (テナント)", @@ -2084,6 +2100,7 @@ "Update Product": "商品更新", "Update Settings": "設定更新", "Update Welcome Gift": "ウェルカムギフトを更新", + "Update ambient temperature setting to :temp°C": "環境温度設定を :temp°C に更新しました", "Update existing role and permissions.": "既存のロールと権限設定を更新します。", "Update failed": "更新失敗", "Update identification for your asset": "資産の識別情報を更新", @@ -2098,6 +2115,7 @@ "Upload file or provide URL": "Upload file or provide URL", "Uploading new images will replace all existing images.": "新しい写真をアップロードすると、既存のすべての写真が置き換えられます。", "Uploading...": "アップロード中...", + "Upper limit; the fan will turn on when reached": "温度上限;この温度に達するとファンが作動します", "Usage Completed": "使用完了", "Usage Limit": "使用回数上限", "Usage Logs": "使用履歴", @@ -2343,9 +2361,7 @@ "menu.sales.records": "販売記録", "menu.sales.store-gifts": "来店ギフト", "menu.special-permission": "特別権限", - "menu.special-permission.apk-versions": "APKバージョン", "menu.special-permission.clear-stock": "在庫クリア", - "menu.special-permission.discord-notifications": "Discord通知", "menu.warehouses": "倉庫管理", "menu.warehouses.inventory": "在庫管理", "menu.warehouses.machine-inventory": "機器在庫概要", diff --git a/lang/zh_TW.json b/lang/zh_TW.json index 32e077e..e025f01 100644 --- a/lang/zh_TW.json +++ b/lang/zh_TW.json @@ -120,6 +120,13 @@ "All Warehouses": "所有倉庫", "All issues marked as resolved.": "所有異常已標記為已排除。", "All slots are fully stocked": "所有貨道已滿貨", + "Ambient Temperature": "環境溫度", + "Ambient Temperature Log": "環境溫度回傳", + "Ambient Temperature Monitoring": "環境溫度監測", + "Ambient Temperature Setting": "環境溫度設定", + "Ambient Temperature Trend": "環境溫度趨勢", + "Ambient Temperature Upper Limit": "環境溫度上限", + "Ambient temperature reported: :temp°C": "環境溫度回傳::temp°C", "Amount": "金額", "Amount / Payment": "金額 / 支付", "Amount Discount": "固定金額", @@ -236,6 +243,7 @@ "CASH": "CASH", "CREATE STOCK TRANSFERS BETWEEN WAREHOUSES AND MACHINE RETURNS": "建立倉庫間調撥或機台退庫單", "Calculate Replenishment": "計算補貨量", + "Can be empty. If left blank, it means ambient temperature monitoring is disabled.": "可留空,留空表示不啟用監控功能", "Cancel": "取消", "Cancel Gift": "取消此來店禮", "Cancel Order": "取消訂單", @@ -511,6 +519,7 @@ "Disable Product Confirmation": "停用商品確認", "Disable Warehouse": "停用倉庫", "Disabled": "已停用", + "Disabled ambient temperature monitoring": "已停用環境溫度監測", "Disabling this customer will also disable all accounts under this customer. Are you sure you want to continue?": "停用此客戶將會連帶停用該客戶下的所有帳號,確定要繼續嗎?", "Discord Notifications": "Discord通知", "Discord Webhook URL": "Discord Webhook 網址", @@ -632,6 +641,7 @@ "English": "英文", "Ensure your account is using a long, random password to stay secure.": "確保您的帳號使用了足夠強度的隨機密碼以維持安全。", "Enter ad material name": "輸入廣告素材名稱", + "Enter ambient temperature setting...": "請輸入環境溫度設定...", "Enter full address": "輸入完整地址", "Enter login ID": "請輸入登入帳號", "Enter machine location": "請輸入機台地點", @@ -690,6 +700,10 @@ "Failed to send test notification.": "發送測試通知失敗。", "Failed to send test notification. Please verify the Webhook URL.": "發送測試通知失敗,請確認 Webhook 網址。", "Failed to update machine images: ": "更新機台圖片失敗:", + "Fan Auto": "風扇自動", + "Fan Controls": "風扇控制", + "Fan Off": "關閉風扇", + "Fan On": "開啟風扇", "Feature Settings": "功能設定", "Feature Toggles": "功能開關", "Field": "欄位", @@ -822,6 +836,7 @@ "Half Points Amount": "半點數金額", "Hardware & Network": "硬體與網路", "Hardware & Slots": "硬體與貨道", + "Hardware Peripheral Settings": "硬體周邊設定", "HashIV": "HashIV", "HashKey": "HashKey", "Heartbeat": "心跳狀態", @@ -1955,6 +1970,7 @@ "Temperature Limit": "溫度限制", "Temperature Restored": "溫度恢復正常", "Temperature Trend": "溫度趨勢", + "Temperature reaches :temp degrees, the fan will turn on": "溫度達 :temp度 將開啟風扇", "Temperature reported: :temp°C": "回報溫度 : :temp°C", "Temperature updated to :temp°C": "溫度已更新為::temp°C", "Tenant": "客戶", @@ -2084,6 +2100,7 @@ "Update Product": "更新商品", "Update Settings": "更新設定", "Update Welcome Gift": "更新來店禮", + "Update ambient temperature setting to :temp°C": "更新環境溫度設定為 :temp°C", "Update existing role and permissions.": "更新現有角色與權限設定。", "Update failed": "更新失敗", "Update identification for your asset": "更新您的資產識別名稱", @@ -2098,6 +2115,7 @@ "Upload file or provide URL": "上傳檔案或提供連結", "Uploading new images will replace all existing images.": "上傳新照片將會取代所有現有照片。", "Uploading...": "上傳中...", + "Upper limit; the fan will turn on when reached": "溫度上限,達到此溫度時風扇將會開啟", "Usage Completed": "使用完成", "Usage Limit": "使用次數上限", "Usage Logs": "使用紀錄", @@ -2343,9 +2361,7 @@ "menu.sales.records": "銷售紀錄", "menu.sales.store-gifts": "來店禮", "menu.special-permission": "特殊權限", - "menu.special-permission.apk-versions": "APK版本", "menu.special-permission.clear-stock": "庫存清空", - "menu.special-permission.discord-notifications": "Discord通知", "menu.warehouses": "倉儲管理", "menu.warehouses.inventory": "庫存管理", "menu.warehouses.machine-inventory": "機台庫存概覽", diff --git a/resources/views/admin/basic-settings/machines/index.blade.php b/resources/views/admin/basic-settings/machines/index.blade.php index b3f3514..975f438 100644 --- a/resources/views/admin/basic-settings/machines/index.blade.php +++ b/resources/views/admin/basic-settings/machines/index.blade.php @@ -106,7 +106,8 @@ shopping_cart_enabled: machine.shopping_cart_enabled === true || machine.shopping_cart_enabled === 1 || machine.shopping_cart_enabled === '1', welcome_gift_enabled: machine.welcome_gift_enabled === true || machine.welcome_gift_enabled === 1 || machine.welcome_gift_enabled === '1', cash_module_enabled: machine.cash_module_enabled === true || machine.cash_module_enabled === 1 || machine.cash_module_enabled === '1', - member_system_enabled: machine.member_system_enabled === true || machine.member_system_enabled === 1 || machine.member_system_enabled === '1' + member_system_enabled: machine.member_system_enabled === true || machine.member_system_enabled === 1 || machine.member_system_enabled === '1', + ambient_temp_monitoring_enabled: machine.ambient_temp_monitoring_enabled === true || machine.ambient_temp_monitoring_enabled === 1 || machine.ambient_temp_monitoring_enabled === '1' }; this.showMachineSettingsModal = true; }, @@ -610,6 +611,29 @@ + + +