|
|
@@ -11,6 +11,7 @@ use App\Module\GameItems\Models\ItemChestConfig;
|
|
|
use Exception;
|
|
|
use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
+use UCore\Dto\Res;
|
|
|
|
|
|
/**
|
|
|
* 宝箱服务类 - 使用消耗组/奖励组系统
|
|
|
@@ -20,6 +21,7 @@ use Illuminate\Support\Facades\Log;
|
|
|
*/
|
|
|
class ChestService
|
|
|
{
|
|
|
+
|
|
|
/**
|
|
|
* 开启宝箱
|
|
|
*
|
|
|
@@ -30,7 +32,7 @@ class ChestService
|
|
|
* @return array 开启结果
|
|
|
* @throws Exception
|
|
|
*/
|
|
|
- public static function openChest(int $userId, int $chestId, int $quantity = 1, array $options = []): array
|
|
|
+ public static function openChest(int $userId, int $chestId, int $quantity = 1, array $options = []): Res
|
|
|
{
|
|
|
// 获取宝箱信息
|
|
|
$chest = Item::findOrFail($chestId);
|
|
|
@@ -41,7 +43,7 @@ class ChestService
|
|
|
}
|
|
|
|
|
|
// 获取宝箱配置
|
|
|
- $chestConfig = ItemChestConfig::with(['consumeGroup', 'rewardGroup', 'conditionGroup'])
|
|
|
+ $chestConfig = ItemChestConfig::with([ 'consumeGroup', 'rewardGroup', 'conditionGroup' ])
|
|
|
->where('item_id', $chestId)
|
|
|
->where('is_active', true)
|
|
|
->first();
|
|
|
@@ -54,103 +56,84 @@ class ChestService
|
|
|
throw new Exception("宝箱 {$chestId} 没有配置奖励组");
|
|
|
}
|
|
|
|
|
|
- // 开始事务
|
|
|
- DB::beginTransaction();
|
|
|
- try {
|
|
|
- $allResults = [];
|
|
|
- $totalCosts = [];
|
|
|
-
|
|
|
- // 循环开启每个宝箱
|
|
|
- for ($i = 0; $i < $quantity; $i++) {
|
|
|
- // 验证并扣除消耗(如果有消耗组配置)
|
|
|
- if ($chestConfig->consume_group_id) {
|
|
|
- $consumeResult = ConsumeService::executeConsume(
|
|
|
- $userId,
|
|
|
- $chestConfig->consume_group_id,
|
|
|
- "开启宝箱",
|
|
|
- $chestId
|
|
|
- );
|
|
|
-
|
|
|
- if (!$consumeResult->success) {
|
|
|
- throw new Exception("消耗验证失败: " . $consumeResult->message);
|
|
|
- }
|
|
|
-
|
|
|
- // 记录消耗详情
|
|
|
- $totalCosts = array_merge($totalCosts, $consumeResult->data ?? []);
|
|
|
- }
|
|
|
-
|
|
|
- // 消耗宝箱本身
|
|
|
- $consumeResult = ItemService::consumeItem(
|
|
|
- $userId,
|
|
|
- $chestId,
|
|
|
- null,
|
|
|
- 1,
|
|
|
- [
|
|
|
- 'source_type' => 'chest_open',
|
|
|
- 'source_id' => $chestId,
|
|
|
- 'details' => ['quantity' => 1],
|
|
|
- 'ip_address' => $options['ip_address'] ?? null,
|
|
|
- 'device_info' => $options['device_info'] ?? null,
|
|
|
- ]
|
|
|
- );
|
|
|
|
|
|
- if (!$consumeResult['success']) {
|
|
|
- throw new Exception("消耗宝箱失败: " . $consumeResult['message']);
|
|
|
- }
|
|
|
+ $allResults = [];
|
|
|
+ $totalCosts = [];
|
|
|
|
|
|
- // 发放奖励(支持保底机制)
|
|
|
- $rewardResult = RewardService::grantRewardWithPity(
|
|
|
+ // 循环开启每个宝箱
|
|
|
+ for ($i = 0; $i < $quantity; $i++) {
|
|
|
+ // 验证并扣除消耗(如果有消耗组配置)
|
|
|
+ if ($chestConfig->consume_group_id) {
|
|
|
+ $consumeResult = ConsumeService::executeConsume(
|
|
|
$userId,
|
|
|
- $chestConfig->reward_group_id,
|
|
|
- 'chest_open',
|
|
|
- $chestId,
|
|
|
- true // 启用保底机制
|
|
|
+ $chestConfig->consume_group_id,
|
|
|
+ "开启宝箱",
|
|
|
+ $chestId
|
|
|
);
|
|
|
|
|
|
- if (!$rewardResult->success) {
|
|
|
- throw new Exception("发放奖励失败: " . ($rewardResult->errorMessage ?? '未知错误'));
|
|
|
+ if (!$consumeResult->success) {
|
|
|
+ throw new Exception("消耗验证失败: " . $consumeResult->message);
|
|
|
}
|
|
|
|
|
|
- // 记录本次开启结果
|
|
|
- $allResults[] = $rewardResult->items;
|
|
|
+ // 记录消耗详情
|
|
|
+ $totalCosts = array_merge($totalCosts, $consumeResult->data ?? []);
|
|
|
}
|
|
|
|
|
|
- // 记录宝箱开启日志
|
|
|
- $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,
|
|
|
- ]);
|
|
|
-
|
|
|
- DB::commit();
|
|
|
+ // 消耗宝箱本身
|
|
|
+ $consumeResult = ItemService::consumeItem(
|
|
|
+ $userId,
|
|
|
+ $chestId,
|
|
|
+ null,
|
|
|
+ 1,
|
|
|
+ [
|
|
|
+ 'source_type' => 'chest_open',
|
|
|
+ 'source_id' => $chestId,
|
|
|
+ 'details' => [ 'quantity' => 1 ],
|
|
|
+ 'ip_address' => $options['ip_address'] ?? null,
|
|
|
+ 'device_info' => $options['device_info'] ?? null,
|
|
|
+ ]
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!$consumeResult['success']) {
|
|
|
+ throw new Exception("消耗宝箱失败: " . $consumeResult['message']);
|
|
|
+ }
|
|
|
|
|
|
- return [
|
|
|
- 'success' => true,
|
|
|
- 'chest_id' => $chestId,
|
|
|
- 'quantity' => $quantity,
|
|
|
- 'results' => $allResults,
|
|
|
- 'costs' => $totalCosts,
|
|
|
- 'log_id' => $openLog->id,
|
|
|
- 'version' => 'new',
|
|
|
- ];
|
|
|
+ // 发放奖励(支持保底机制)
|
|
|
+ $rewardResult = RewardService::grantRewardWithPity(
|
|
|
+ $userId,
|
|
|
+ $chestConfig->reward_group_id,
|
|
|
+ 'chest_open',
|
|
|
+ $chestId,
|
|
|
+ true // 启用保底机制
|
|
|
+ );
|
|
|
+
|
|
|
+ if (!$rewardResult->success) {
|
|
|
+ throw new Exception("发放奖励失败: " . ($rewardResult->errorMessage ?? '未知错误'));
|
|
|
+ }
|
|
|
|
|
|
- } catch (Exception $e) {
|
|
|
- DB::rollBack();
|
|
|
- Log::error('宝箱开启失败', [
|
|
|
- 'user_id' => $userId,
|
|
|
- 'chest_id' => $chestId,
|
|
|
- 'quantity' => $quantity,
|
|
|
- 'error' => $e->getMessage(),
|
|
|
- 'trace' => $e->getTraceAsString()
|
|
|
- ]);
|
|
|
- throw $e;
|
|
|
+ // 记录本次开启结果
|
|
|
+ $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
|
|
|
+ ]);
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -170,19 +153,22 @@ class ChestService
|
|
|
}
|
|
|
|
|
|
// 获取宝箱配置
|
|
|
- $chestConfig = ItemChestConfig::with(['consumeGroup.consumeItems', 'rewardGroup.rewardItems', 'conditionGroup'])
|
|
|
+ $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,
|
|
|
+ 'chest_id' => $chestId,
|
|
|
+ 'chest_name' => $chest->name,
|
|
|
+ 'version' => 'new',
|
|
|
+ 'consume_group' => null,
|
|
|
+ 'reward_group' => null,
|
|
|
'condition_group' => null,
|
|
|
- 'config_status' => $chestConfig ? 'active' : 'not_configured',
|
|
|
+ 'config_status' => $chestConfig ? 'active' : 'not_configured',
|
|
|
];
|
|
|
|
|
|
if (!$chestConfig) {
|
|
|
@@ -192,15 +178,15 @@ class ChestService
|
|
|
// 获取消耗组信息
|
|
|
if ($chestConfig->consumeGroup) {
|
|
|
$preview['consume_group'] = [
|
|
|
- 'id' => $chestConfig->consumeGroup->id,
|
|
|
- 'name' => $chestConfig->consumeGroup->name,
|
|
|
- 'code' => $chestConfig->consumeGroup->code,
|
|
|
+ 'id' => $chestConfig->consumeGroup->id,
|
|
|
+ 'name' => $chestConfig->consumeGroup->name,
|
|
|
+ 'code' => $chestConfig->consumeGroup->code,
|
|
|
'description' => $chestConfig->consumeGroup->description,
|
|
|
- 'items' => $chestConfig->consumeGroup->consumeItems->map(function ($item) {
|
|
|
+ 'items' => $chestConfig->consumeGroup->consumeItems->map(function ($item) {
|
|
|
return [
|
|
|
'consume_type' => $item->consume_type,
|
|
|
- 'target_id' => $item->target_id,
|
|
|
- 'quantity' => $item->quantity,
|
|
|
+ 'target_id' => $item->target_id,
|
|
|
+ 'quantity' => $item->quantity,
|
|
|
];
|
|
|
})->toArray(),
|
|
|
];
|
|
|
@@ -209,19 +195,19 @@ class ChestService
|
|
|
// 获取奖励组信息
|
|
|
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,
|
|
|
+ '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) {
|
|
|
+ '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,
|
|
|
+ 'reward_type' => $item->reward_type,
|
|
|
+ 'target_id' => $item->target_id,
|
|
|
+ 'quantity' => $item->quantity,
|
|
|
+ 'weight' => $item->weight,
|
|
|
'is_guaranteed' => $item->is_guaranteed,
|
|
|
];
|
|
|
})->toArray(),
|
|
|
@@ -231,9 +217,9 @@ class ChestService
|
|
|
// 获取条件组信息
|
|
|
if ($chestConfig->conditionGroup) {
|
|
|
$preview['condition_group'] = [
|
|
|
- 'id' => $chestConfig->conditionGroup->id,
|
|
|
- 'name' => $chestConfig->conditionGroup->name,
|
|
|
- 'code' => $chestConfig->conditionGroup->code,
|
|
|
+ 'id' => $chestConfig->conditionGroup->id,
|
|
|
+ 'name' => $chestConfig->conditionGroup->name,
|
|
|
+ 'code' => $chestConfig->conditionGroup->code,
|
|
|
'description' => $chestConfig->conditionGroup->description,
|
|
|
];
|
|
|
}
|
|
|
@@ -259,12 +245,12 @@ class ChestService
|
|
|
if ($chest->type != ITEM_TYPE::CHEST) {
|
|
|
return [
|
|
|
'can_open' => false,
|
|
|
- 'message' => "物品 {$chestId} 不是宝箱类型",
|
|
|
+ 'message' => "物品 {$chestId} 不是宝箱类型",
|
|
|
];
|
|
|
}
|
|
|
|
|
|
// 获取宝箱配置
|
|
|
- $chestConfig = ItemChestConfig::with(['consumeGroup'])
|
|
|
+ $chestConfig = ItemChestConfig::with([ 'consumeGroup' ])
|
|
|
->where('item_id', $chestId)
|
|
|
->where('is_active', true)
|
|
|
->first();
|
|
|
@@ -272,7 +258,7 @@ class ChestService
|
|
|
if (!$chestConfig) {
|
|
|
return [
|
|
|
'can_open' => false,
|
|
|
- 'message' => "宝箱 {$chestId} 没有配置新系统或配置未激活",
|
|
|
+ 'message' => "宝箱 {$chestId} 没有配置新系统或配置未激活",
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -280,7 +266,7 @@ class ChestService
|
|
|
if (!$chestConfig->reward_group_id) {
|
|
|
return [
|
|
|
'can_open' => false,
|
|
|
- 'message' => "宝箱 {$chestId} 没有配置奖励组",
|
|
|
+ 'message' => "宝箱 {$chestId} 没有配置奖励组",
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -289,7 +275,7 @@ class ChestService
|
|
|
if (!$checkResult->success) {
|
|
|
return [
|
|
|
'can_open' => false,
|
|
|
- 'message' => $checkResult->message,
|
|
|
+ 'message' => $checkResult->message,
|
|
|
];
|
|
|
}
|
|
|
|
|
|
@@ -299,21 +285,22 @@ class ChestService
|
|
|
if (!$canConsume->success) {
|
|
|
return [
|
|
|
'can_open' => false,
|
|
|
- 'message' => "消耗验证失败: " . $canConsume->message,
|
|
|
+ 'message' => "消耗验证失败: " . $canConsume->message,
|
|
|
];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return [
|
|
|
'can_open' => true,
|
|
|
- 'message' => '可以开启',
|
|
|
+ 'message' => '可以开启',
|
|
|
];
|
|
|
|
|
|
} catch (Exception $e) {
|
|
|
return [
|
|
|
'can_open' => false,
|
|
|
- 'message' => "检查失败: " . $e->getMessage(),
|
|
|
+ 'message' => "检查失败: " . $e->getMessage(),
|
|
|
];
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
}
|