json([ 'items' => $this->rideService->activeItems() ->map(fn (Ride $item) => $this->rideService->formatItem($item)) ->values(), 'current_ride' => $this->rideService->formatCurrentRide($user), 'purchases' => $this->rideService->purchaseRecords($user), 'user_jjb' => $user->jjb ?? 0, ]); } /** * 购买座驾并返回最新金币和当前座驾状态。 */ public function buy(BuyRideRequest $request): JsonResponse { $user = Auth::user(); $roomId = (int) $request->integer('room_id'); $room = Room::query()->findOrFail($roomId); if (! $room->canUserEnter($user) || ! $this->chatState->isUserInRoom($roomId, $user->username)) { return response()->json(['status' => 'error', 'message' => '请先进入当前房间后再购买座驾。'], 403); } $item = Ride::query()->findOrFail((int) $request->integer('item_id')); $result = $this->rideService->buy($user, $item, $roomId); if (! $result['ok']) { return response()->json(['status' => 'error', 'message' => $result['message']], 400); } $this->pushRidePurchaseNotice($user, $item, $roomId); return response()->json([ 'status' => 'success', 'message' => $result['message'], 'current_ride' => $result['current_ride'] ?? null, 'purchases' => $this->rideService->purchaseRecords($user->fresh()), 'jjb' => $user->fresh()->jjb, ]); } /** * 向当前房间广播座驾购买成功通知,方便其他用户快速打开座驾页面。 */ private function pushRidePurchaseNotice(User $user, Ride $item, int $roomId): void { $button = ''; $content = sprintf( '🚀 【座驾】 %s 购买了 %s,有效期 %d 天,排面已安排!%s', e($user->username), e($item->name), (int) $item->duration_days, $button, ); $message = [ 'id' => $this->chatState->nextMessageId($roomId), 'room_id' => $roomId, 'from_user' => '系统传音', 'to_user' => '大家', 'content' => $content, 'is_secret' => false, 'font_color' => '#0f766e', 'action' => 'ride_purchase', 'sent_at' => now()->toDateTimeString(), ]; // 购买通知需要写入房间消息缓存、实时广播并落库,刷新后仍可追溯。 $this->chatState->pushMessage($roomId, $message); broadcast(new MessageSent($roomId, $message)); SaveMessageJob::dispatch($message); } }