BUG 包廂控制畫面開不啟來問題

加入驗証包廂是否在線
20250605
This commit is contained in:
allen.yan 2025-06-05 11:15:24 +08:00
parent ae6742575d
commit 13b5e3e3e1
6 changed files with 112 additions and 37 deletions

View File

@ -0,0 +1,49 @@
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Models\Room;
use App\Models\MachineStatus;
use App\Enums\RoomStatus;
use Carbon\Carbon;
use App\Services\MachineStatusForwarder;
class CheckRoomOnlineStatus extends Command
{
protected $signature = 'rooms:check-online-status';
protected $description = 'Check if each room has recent MachineStatus data, mark offline if outdated';
public function handle()
{
$now = Carbon::now();
$threshold = $now->subMinutes(10);
// 所有房間
$rooms = Room::with('branch')->where('is_online',1)->get();
foreach ($rooms as $room) {
// 找出最近的一筆 MachineStatus 資料(比對 hostname 和 branch_name
$latestStatus = MachineStatus::where('hostname', $room->type->value.$room->name)
//->where('branch_name', optional($room->branch)->name)
->latest('created_at')
->first();
if (!$latestStatus || $latestStatus->created_at < $threshold) {
$room->is_online = false;
$room->status = RoomStatus::Error;
$room->save();
$response = (new MachineStatusForwarder($rooms->branch->external_ip, "/api/room/receiveSwitch", [
"branch_name"=>$rooms->branch->name,
"room_name"=>$rooms->type->value.$rooms->name,
"command" =>"error",
]))->forward();
$this->info("Room [{$room->name}] marked as offline (no recent MachineStatus)");
}
}
return 0;
}
}

View File

@ -8,6 +8,7 @@ use App\Http\Requests\ReceiveRoomStatusDataRequest;
use App\Services\TcpSocketClient; use App\Services\TcpSocketClient;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use App\Services\MachineStatusForwarder;
use App\Services\ApiClient; use App\Services\ApiClient;
use App\Models\User; use App\Models\User;
use App\Models\Branch; use App\Models\Branch;
@ -201,8 +202,7 @@ class RoomControlController extends Controller
$room->save(); $room->save();
} }
$this->receiveRequest($branch->external_ip,"/api/room/heartbeat", $validated); $response = (new MachineStatusForwarder($branch->external_ip, "/api/room/heartbeat", $validated))->forward();
return ApiResponse::success([ return ApiResponse::success([
'data' => MachineStatus::create($validated), 'data' => MachineStatus::create($validated),
@ -311,36 +311,7 @@ class RoomControlController extends Controller
$room->started_at=$validated['started_at']; $room->started_at=$validated['started_at'];
$room->ended_at=$validated['ended_at']; $room->ended_at=$validated['ended_at'];
$room->save(); $room->save();
$this->receiveRequest($branch->external_ip,"/api/room/receiveSwitch",$validated); $response = (new MachineStatusForwarder($branch->external_ip, "/api/room/receiveSwitch", $validated))->forward();
return $validated['command']==='error' ? ApiResponse::error('機房控制失敗') : ApiResponse::success($room); return $validated['command']==='error' ? ApiResponse::error('機房控制失敗') : ApiResponse::success($room);
} }
function receiveRequest(string $externalUrl,string $endpoint, array $validated){
$response=null;
$parsed = parse_url($externalUrl);
$hostParts = explode('.', $parsed['host']);
if (count($hostParts) >= 3) {
$mainDomain = implode('.', array_slice($hostParts, 1));
} else {
$mainDomain = $parsed['host'];
}
$mainDomainUrl= $parsed['scheme'] . '://' . $mainDomain;
$user = User::find(2);
if ($user && $user->api_plain_token) {
$client = (new ApiClient($mainDomainUrl, $user->api_plain_token));
$response = $client->post($endpoint, $validated);
Log::info('✅ Machine status forwarded', [
'endpoint' => $endpoint,
'request' => $validated,
'status' => $response->status(),
'body' => $response->json(),
]);
} else {
Log::warning("🔒 User with ID {$userId} not found or missing token");
}
return $response;
}
} }

View File

@ -28,7 +28,7 @@ class RoomDetailModal extends Component
{ {
$room = Room::find($roomId); $room = Room::find($roomId);
$this->room_name=$room->type->value . $room->name; $this->room_name=$room->type->value . $room->name;
$this->branch = Branch::find($this->room->branch_id); $this->branch = Branch::find($room->branch_id);
$this->showModal = true; $this->showModal = true;
} }
public function closeModal() public function closeModal()

View File

@ -0,0 +1,54 @@
<?php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Facades\Log;
use Illuminate\Http\Client\Response;
use App\Services\ApiClient;
class MachineStatusForwarder
{
protected string $externalUrl;
protected string $endpoint;
protected array $validated;
protected ?User $user = null;
public function __construct(string $externalUrl, string $endpoint, array $validated)
{
$this->externalUrl = $externalUrl;
$this->endpoint = $endpoint;
$this->validated = $validated;
}
public function forward(): ?Response
{
$response = null;
$parsed = parse_url($this->externalUrl);
$hostParts = explode('.', $parsed['host']);
$mainDomain = count($hostParts) >= 3
? implode('.', array_slice($hostParts, 1))
: $parsed['host'];
$mainDomainUrl = "{$parsed['scheme']}://{$mainDomain}";
$this->user = User::find(2); // 或用 dependency injection 把 User 帶進來
if ($this->user && $this->user->api_plain_token) {
$client = new ApiClient($mainDomainUrl, $this->user->api_plain_token);
$response = $client->post($this->endpoint, $this->validated);
Log::info('✅ Machine status forwarded', [
'endpoint' => $this->endpoint,
'request' => $this->validated,
'status' => $response->status(),
'body' => $response->json(),
]);
} else {
Log::warning("🔒 User with ID 2 not found or missing token");
}
return $response;
}
}

View File

@ -13,7 +13,7 @@
</button> </button>
</x-slot> </x-slot>
<x-slot name="title"> <x-slot name="title">
{{ $room->name ?? '未選擇' }}包廂設定 {{ $room_name ?? '未選擇' }}包廂設定
</x-slot> </x-slot>
<div class="grid grid-cols-3 gap-4 mb-4"> <div class="grid grid-cols-3 gap-4 mb-4">
<x-wireui:button wire:click="startNotify" >開機</x-wireui:button> <x-wireui:button wire:click="startNotify" >開機</x-wireui:button>

View File

@ -3,11 +3,12 @@
use Illuminate\Foundation\Inspiring; use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Artisan;
Artisan::command('inspire', function () { //Artisan::command('inspire', function () {
$this->comment(Inspiring::quote()); // $this->comment(Inspiring::quote());
})->purpose('Display an inspiring quote'); //})->purpose('Display an inspiring quote');
Schedule::command('app:clear-machine-statuses')->dailyAt('12:00'); // 每天凌晨 12:10 執行 Schedule::command('app:clear-machine-statuses')->dailyAt('12:00'); // 每天凌晨 12:10 執行
Schedule::command('rooms:check-online-status')->everyMinute(); //每分驗証
//首次部署或有新增命令時)建立或更新任務排程 Crontab //首次部署或有新增命令時)建立或更新任務排程 Crontab
// 檢查是否已有下列 crontab 設定crontab -e // 檢查是否已有下列 crontab 設定crontab -e
//分鐘 小時 日 月 星期 指令 //分鐘 小時 日 月 星期 指令