type != ITEM_TYPE::CHEST) { throw new Exception("物品 {$chestId} 不是宝箱类型"); } // 获取宝箱配置 $chestConfig = ItemChestConfig::with([ 'consumeGroup', 'rewardGroup', 'conditionGroup' ]) ->where('item_id', $chestId) ->where('is_active', true) ->first(); if (!$chestConfig) { throw new Exception("宝箱 {$chestId} 没有配置新系统或配置未激活"); } if (!$chestConfig->reward_group_id) { throw new Exception("宝箱 {$chestId} 没有配置奖励组"); } $allResults = []; // 第一步:先扣除消耗组(如果有消耗组配置,支持倍率) if ($chestConfig->consume_group_id) { $consumeResult = ConsumeService::executeConsume( $userId, $chestConfig->consume_group_id, REWARD_SOURCE_TYPE::CHEST, $chestId, true, // 检查消耗条件 $quantity // 使用开启数量作为倍率 ); if (!$consumeResult->success) { throw new Exception("消耗验证失败: " . $consumeResult->message); } } // 第二步:再扣除宝箱本身(一次性扣除所有宝箱) $chestConsumeResult = ItemService::consumeItem( $userId, $chestId, null, $quantity, [ 'source_type' => REWARD_SOURCE_TYPE::CHEST->value(), 'source_id' => $chestId, 'details' => [ 'quantity' => $quantity ], 'ip_address' => $options['ip_address'] ?? null, 'device_info' => $options['device_info'] ?? null, ] ); if (!$chestConsumeResult['success']) { throw new Exception("消耗宝箱失败: " . $chestConsumeResult['message']); } // 第三步:最后循环产出奖励 for ($i = 0; $i < $quantity; $i++) { // 发放奖励(支持保底机制) $rewardResult = RewardService::grantRewardWithPity( $userId, $chestConfig->reward_group_id, REWARD_SOURCE_TYPE::CHEST, $chestId, true // 启用保底机制 ); if (!$rewardResult->success) { throw new Exception("发放奖励失败: " . ($rewardResult->errorMessage ?? '未知错误')); } // 记录本次开启结果 $allResults[] = $rewardResult->items; } // 记录宝箱开启日志 $openLog = ItemChestOpenLog::create([ 'user_id' => $userId, 'chest_id' => $chestId, 'open_quantity' => $quantity, 'result_items' => $allResults, 'pity_triggered' => false, // V2版本暂不支持保底机制 'pity_content_id' => null, 'open_time' => now(), 'ip_address' => $options['ip_address'] ?? null, 'device_info' => $options['device_info'] ?? null, ]); return Res::success('成功', [ 'openLog' => $openLog->id ]); } /** * 获取宝箱内容预览 * * @param int $chestId 宝箱ID * @return array 宝箱内容预览 */ public static function getChestContentPreview(int $chestId): array { // 获取宝箱信息 $chest = Item::findOrFail($chestId); // 检查是否为宝箱类型 if ($chest->type != ITEM_TYPE::CHEST) { throw new Exception("物品 {$chestId} 不是宝箱类型"); } // 获取宝箱配置 $chestConfig = ItemChestConfig::with([ 'consumeGroup.consumeItems', 'rewardGroup.rewardItems', 'conditionGroup' ]) ->where('item_id', $chestId) ->where('is_active', true) ->first(); $preview = [ 'chest_id' => $chestId, 'chest_name' => $chest->name, 'version' => 'new', 'consume_group' => null, 'reward_group' => null, 'condition_group' => null, 'config_status' => $chestConfig ? 'active' : 'not_configured', ]; if (!$chestConfig) { return $preview; } // 获取消耗组信息 if ($chestConfig->consumeGroup) { $preview['consume_group'] = [ 'id' => $chestConfig->consumeGroup->id, 'name' => $chestConfig->consumeGroup->name, 'code' => $chestConfig->consumeGroup->code, 'description' => $chestConfig->consumeGroup->description, 'items' => $chestConfig->consumeGroup->consumeItems->map(function ($item) { return [ 'consume_type' => $item->consume_type, 'target_id' => $item->target_id, 'quantity' => $item->quantity, ]; })->toArray(), ]; } // 获取奖励组信息 if ($chestConfig->rewardGroup) { $preview['reward_group'] = [ 'id' => $chestConfig->rewardGroup->id, 'name' => $chestConfig->rewardGroup->name, 'code' => $chestConfig->rewardGroup->code, 'description' => $chestConfig->rewardGroup->description, 'is_random' => $chestConfig->rewardGroup->is_random, 'random_count' => $chestConfig->rewardGroup->random_count, 'reward_mode' => $chestConfig->rewardGroup->reward_mode, 'items' => $chestConfig->rewardGroup->rewardItems->map(function ($item) { return [ 'reward_type' => $item->reward_type, 'target_id' => $item->target_id, 'quantity' => $item->quantity, 'weight' => $item->weight, 'is_guaranteed' => $item->is_guaranteed, ]; })->toArray(), ]; } // 获取条件组信息 if ($chestConfig->conditionGroup) { $preview['condition_group'] = [ 'id' => $chestConfig->conditionGroup->id, 'name' => $chestConfig->conditionGroup->name, 'code' => $chestConfig->conditionGroup->code, 'description' => $chestConfig->conditionGroup->description, ]; } return $preview; } /** * 检查宝箱是否可以开启 * * @param int $userId 用户ID * @param int $chestId 宝箱ID * @param int $quantity 开启数量 * @return array 检查结果 */ public static function canOpenChest(int $userId, int $chestId, int $quantity = 1): array { try { // 获取宝箱信息 $chest = Item::findOrFail($chestId); // 检查是否为宝箱类型 if ($chest->type != ITEM_TYPE::CHEST) { return [ 'can_open' => false, 'message' => "物品 {$chestId} 不是宝箱类型", ]; } // 获取宝箱配置 $chestConfig = ItemChestConfig::with([ 'consumeGroup' ]) ->where('item_id', $chestId) ->where('is_active', true) ->first(); if (!$chestConfig) { return [ 'can_open' => false, 'message' => "宝箱 {$chestId} 没有配置新系统或配置未激活", ]; } // 检查是否配置了奖励组 if (!$chestConfig->reward_group_id) { return [ 'can_open' => false, 'message' => "宝箱 {$chestId} 没有配置奖励组", ]; } // 检查用户是否拥有足够的宝箱 $checkResult = ItemService::checkItemQuantity($userId, $chestId, $quantity); if (!$checkResult->success) { return [ 'can_open' => false, 'message' => $checkResult->message, ]; } // 检查消耗组(如果有,支持倍率检查) if ($chestConfig->consume_group_id) { $canConsume = ConsumeService::checkConsume($userId, $chestConfig->consume_group_id, $quantity); if (!$canConsume->success) { return [ 'can_open' => false, 'message' => "消耗验证失败: " . $canConsume->message, ]; } } return [ 'can_open' => true, 'message' => '可以开启', ]; } catch (Exception $e) { return [ 'can_open' => false, 'message' => "检查失败: " . $e->getMessage(), ]; } } }