only(['branch', 'room_name', 'room_ip', 'email']); // 不記錄密碼 Log::info('Token Request Payload:', $data); // 1. 驗證帳密(登入用) $credentials = $request->only('email', 'password'); if (!Auth::attempt($credentials)) { return ApiResponse::unauthorized(); } // 2. 取得登入使用者 $user = Auth::user(); // 3. 產生或取得 Token if (empty($user->api_plain_token)) { $token = $user->createToken('pc-heartbeat')->plainTextToken; $user->api_plain_token = $token; $user->save(); } else { $token = $user->api_plain_token; } // 4. 驗證其他註冊欄位 $validated = $request->validated(); // branch_id, room_name, room_ip // 5. 找出對應包廂 $roomType = null; $roomName = null; // 從 room_name(例如 PC101, SVR01)中擷取 type 與 name if (preg_match('/^([A-Za-z]+)(\d+)$/', $validated['room_name'], $matches)) { $roomType = strtolower($matches[1]); // 'PC' → 'pc' $roomName = $matches[2]; // '101' } $branch=Branch::where('name',$validated['branch_name'])->first(); $room = Room::where('branch_id', $branch->id) ->where('name', $roomName) ->where('type', $roomType) ->first(); if (!$room) { return ApiResponse::error('找不到對應包廂'); } // 6. 更新包廂資訊 $room->internal_ip = $validated['room_ip']; $room->port = 1000; // 預設值 $room->is_online =1; $room->status = RoomStatus::Closed; $room->touch(); // 更新 updated_at $room->save(); // 7. 回傳 token 與包廂資料 return ApiResponse::success([ 'token' => $token, 'room' => $room, ]); } /** * @OA\Post( * path="/api/room/heartbeat", * summary="包廂心跳封包指令", * description="記錄設備連線狀況", * operationId="heartbeatRoomCommand", * tags={"Room Control"}, * security={{"Authorization":{}}}, * @OA\RequestBody( * required=true, * @OA\JsonContent(ref="#/components/schemas/ReceiveRoomStatusDataRequest") * ), * @OA\Response( * response=200, * description="成功傳送指令並回傳 TCP 回應", * @OA\JsonContent( * allOf={ * @OA\Schema(ref="#/components/schemas/ApiResponse"), * @OA\Schema( * @OA\Property(property="data", ref="#/components/schemas/MachineStatus") * ) * } * ) * ), * @OA\Response( * response=401, * description="Unauthorized", * @OA\JsonContent( * allOf={ * @OA\Schema(ref="#/components/schemas/ApiResponse"), * @OA\Schema( * @OA\Property(property="code", type="string", example="UNAUTHORIZED"), * @OA\Property(property="message", type="string", example="Unauthorized"), * @OA\Property(property="data", type="null") * ) * } * ) * ), * @OA\Parameter( * name="Accept", * in="header", * required=true, * @OA\Schema(type="string", default="application/json") * ) * ) */ public function StatusReport(ReceiveRoomStatusDataRequest $request) { $validated = $request->validated(); $roomType = null; $roomName = null; // 從 room_name(例如 PC101, SVR01)中擷取 type 與 name if (preg_match('/^([A-Za-z]+)(\d+)$/', $validated['hostname'], $matches)) { $roomType = strtolower($matches[1]); // 'PC' → 'pc' $roomName = $matches[2]; // '101' } $branch=Branch::where('name',$validated['branch_name'])->first(); $room = Room::where('branch_id', $branch->id) ->where('name', $roomName) ->where('type', $roomType) ->first(); // 決定 status 欄位值 $validated['status']= 'error'; if($room){ $validated['status']= 'online'; if($room->internal_ip != $validated['ip']){ $room->internal_ip = $validated['ip']; $validated['status']='error'; } $room->is_online=1; $room->touch(); // 更新 updated_at $room->save(); } return ApiResponse::success([ 'data' => MachineStatus::create($validated), ]); } /** * @OA\Post( * path="/api/room/sendSwitch", * summary="送出包廂控制指令", * description="依據傳入的 room_id 與 command,透過 TCP 傳送對應指令給包廂電腦。", * operationId="sendRoomSwitchCommand", * tags={"Room Control"}, * security={{"Authorization":{}}}, * @OA\RequestBody( * required=true, * @OA\JsonContent(ref="#/components/schemas/SendRoomSwitchCommandRequest") * ), * @OA\Response( * response=200, * description="成功傳送指令並回傳 TCP 回應", * @OA\JsonContent( * allOf={ * @OA\Schema(ref="#/components/schemas/ApiResponse"), * @OA\Schema( * @OA\Property(property="data", ref="#/components/schemas/Room") * ) * } * ) * ), * @OA\Response( * response=401, * description="Unauthorized", * @OA\JsonContent( * allOf={ * @OA\Schema(ref="#/components/schemas/ApiResponse"), * @OA\Schema( * @OA\Property(property="code", type="string", example="UNAUTHORIZED"), * @OA\Property(property="message", type="string", example="Unauthorized"), * @OA\Property(property="data", type="null") * ) * } * ) * ), * @OA\Parameter( * name="Accept", * in="header", * required=true, * @OA\Schema(type="string", default="application/json") * ) * ) */ public function sendSwitch(SendRoomSwitchCommandRequest $request): JsonResponse { $validated = $request->validated(); $branch = Branch::where('name',$validated['branch_name'])->first(); $room = Room::where([ ['branch_id', $branch->id], ['name', $validated['room_name']], ])->first(); if (!$branch) { return ApiResponse::error('分店不存在'); } if (empty($branch->external_ip) ) { return ApiResponse::error('分店未設定 外部URL'); } if (!$room) { return ApiResponse::error('房間不存在'); } if (empty($room->internal_ip) || empty($room->port)) { return ApiResponse::error('房間未設定 IP 或 Port'); } if ($room->status === RoomStatus::Error) { return ApiResponse::error('房間目前處於錯誤狀態,無法操作'); } $command = $validated['command']; $payload = [ 'branch_name' => $validated['branch_name'], 'room_name' => $validated['room_name'], 'command' => $command, 'started_at' => $validated['started_at'] ?? null, 'ended_at' => $validated['ended_at'] ?? null, ]; $user = \App\Models\User::find(2); $token = $user->api_plain_token; $api = new \App\Services\ApiClient(); $response = $api->setToken($token)->setBaseUrl($branch->external_ip)->post('/room/sendSwitch', $payload); if (!$response->successful()) { return ApiResponse::error('指令發送失敗:' . $response->body()); } return ApiResponse::success("命令已發送:$command"); } public function receiveSwitch(SendRoomSwitchCommandRequest $request): JsonResponse { $validated = $request->validated(); $branch = Branch::where('name',$validated['branch_name'])->first(); $room = Room::where([ ['branch_id', $branch->id], ['name', $validated['room_name']], ])->first(); if (!$branch) { return ApiResponse::error('分店不存在'); } if (!$room) { return ApiResponse::error('房間不存在'); } $room->status=$validated['command']; $room->started_at=$validated['started_at']; $room->ended_at=$validated['ended_at']; $room->save(); return ApiResponse::success($room); } }