first(); if (!$consumeGroup) { return [ 'success' => false, 'message' => "消耗组不存在: {$consumeGroupCode}" ]; } // 获取消耗组中的所有消耗项 $consumeItems = $consumeGroup->consumeItems; if ($consumeItems->isEmpty()) { return [ 'success' => true, 'message' => '消耗组中没有消耗项' ]; } // 检查每个消耗项 foreach ($consumeItems as $item) { $checkResult = self::checkConsumeItem($userId, $item); if (!$checkResult['success']) { return $checkResult; } } return [ 'success' => true, 'message' => '满足所有消耗条件' ]; } catch (\Exception $e) { Log::error('检查消耗条件失败', [ 'user_id' => $userId, 'consume_group' => $consumeGroupCode, 'error' => $e->getMessage() ]); return [ 'success' => false, 'message' => '检查消耗条件时发生错误: ' . $e->getMessage() ]; } } /** * 执行消耗 * * @param int $userId 用户ID * @param string|int $consumeGroupCode 消耗组编码或ID * @param string $source 消耗来源 * @param int $sourceId 消耗来源ID * @return array 执行结果,包含success字段表示是否成功,message字段表示错误信息 */ public static function executeConsume(int $userId, $consumeGroupCode, string $source, int $sourceId = 0): array { // 先检查是否满足消耗条件 $checkResult = self::checkConsume($userId, $consumeGroupCode); if (!$checkResult['success']) { return $checkResult; } try { // 获取消耗组 $consumeGroup = is_numeric($consumeGroupCode) ? GameConsumeGroup::find($consumeGroupCode) : GameConsumeGroup::where('code', $consumeGroupCode)->first(); // 获取消耗组中的所有消耗项 $consumeItems = $consumeGroup->consumeItems; // 开始事务 DB::beginTransaction(); // 执行每个消耗项 foreach ($consumeItems as $item) { $consumeResult = self::executeConsumeItem($userId, $item, $source, $sourceId); if (!$consumeResult['success']) { DB::rollBack(); return $consumeResult; } } // 提交事务 DB::commit(); return [ 'success' => true, 'message' => '消耗执行成功', 'consume_group' => [ 'id' => $consumeGroup->id, 'code' => $consumeGroup->code, 'name' => $consumeGroup->name ] ]; } catch (\Exception $e) { // 回滚事务 DB::rollBack(); Log::error('执行消耗失败', [ 'user_id' => $userId, 'consume_group' => $consumeGroupCode, 'source' => $source, 'source_id' => $sourceId, 'error' => $e->getMessage() ]); return [ 'success' => false, 'message' => '执行消耗时发生错误: ' . $e->getMessage() ]; } } /** * 检查单个消耗项 * * @param int $userId 用户ID * @param GameConsumeItem $consumeItem 消耗项 * @return array 检查结果 */ protected static function checkConsumeItem(int $userId, GameConsumeItem $consumeItem): array { switch ($consumeItem->consume_type) { case CONSUME_TYPE::ITEM->value: return self::checkItemConsume($userId, $consumeItem); case CONSUME_TYPE::CURRENCY->value: return self::checkCurrencyConsume($userId, $consumeItem); default: return [ 'success' => false, 'message' => "不支持的消耗类型: {$consumeItem->consume_type}" ]; } } /** * 执行单个消耗项 * * @param int $userId 用户ID * @param GameConsumeItem $consumeItem 消耗项 * @param string $source 消耗来源 * @param int $sourceId 消耗来源ID * @return array 执行结果 */ protected static function executeConsumeItem(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array { switch ($consumeItem->consume_type) { case CONSUME_TYPE::ITEM->value: return self::executeItemConsume($userId, $consumeItem, $source, $sourceId); case CONSUME_TYPE::CURRENCY->value: return self::executeCurrencyConsume($userId, $consumeItem, $source, $sourceId); case CONSUME_TYPE::FUND->value: return self::executeFundConsume($userId, $consumeItem, $source, $sourceId); default: return [ 'success' => false, 'message' => "不支持的消耗类型: {$consumeItem->consume_type}" ]; } } /** * 检查物品消耗 * * @param int $userId 用户ID * @param GameConsumeItem $consumeItem 消耗项 * @return array 检查结果 */ protected static function checkItemConsume(int $userId, GameConsumeItem $consumeItem): array { $itemId = $consumeItem->target_id; $quantity = $consumeItem->quantity; // 获取用户物品 $userItems = ItemService::getUserItems($userId, ['item_id' => $itemId]); // 计算用户拥有的物品总数 $totalQuantity = 0; foreach ($userItems as $userItem) { $totalQuantity += $userItem->quantity; } // 检查数量是否足够 if ($totalQuantity < $quantity) { return [ 'success' => false, 'message' => "物品数量不足,需要 {$quantity},实际 {$totalQuantity}", 'item_id' => $itemId, 'required' => $quantity, 'actual' => $totalQuantity ]; } return [ 'success' => true, 'message' => '物品数量足够' ]; } /** * 检查货币消耗 * * @param int $userId 用户ID * @param GameConsumeItem $consumeItem 消耗项 * @return array 检查结果 */ protected static function checkCurrencyConsume(int $userId, GameConsumeItem $consumeItem): array { $currencyId = $consumeItem->target_id; $amount = $consumeItem->quantity; // 获取用户货币账户 $account = FundLogic::get_account($userId, $currencyId); // 检查账户是否存在 if ($account === false) { return [ 'success' => false, 'message' => "用户没有该货币账户", 'currency_id' => $currencyId ]; } // 检查余额是否足够 if ($account->balance < $amount) { return [ 'success' => false, 'message' => "货币余额不足,需要 {$amount},实际 {$account->balance}", 'currency_id' => $currencyId, 'required' => $amount, 'actual' => $account->balance ]; } return [ 'success' => true, 'message' => '货币余额足够' ]; } /** * 执行物品消耗 * * @param int $userId 用户ID * @param GameConsumeItem $consumeItem 消耗项 * @param string $source 消耗来源 * @param int $sourceId 消耗来源ID * @return array 执行结果 */ protected static function executeItemConsume(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array { $itemId = $consumeItem->target_id; $quantity = $consumeItem->quantity; // 消耗物品 $result = ItemService::consumeItem($userId, $itemId, null, $quantity, [ 'source_type' => $source, 'source_id' => $sourceId, 'details' => [ 'consume_item_id' => $consumeItem->id, 'consume_group_id' => $consumeItem->group_id ] ]); if (!$result['success']) { return [ 'success' => false, 'message' => $result['message'] ?? '物品消耗失败', 'item_id' => $itemId, 'quantity' => $quantity ]; } return [ 'success' => true, 'message' => '物品消耗成功', 'item_id' => $itemId, 'quantity' => $quantity ]; } /** * 执行货币消耗 * * @param int $userId 用户ID * @param GameConsumeItem $consumeItem 消耗项 * @param string $source 消耗来源 * @param int $sourceId 消耗来源ID * @return array 执行结果 */ protected static function executeCurrencyConsume(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array { $currencyId = $consumeItem->target_id; $amount = -$consumeItem->quantity; // 负数表示消耗 // 构建备注 $remark = "消耗组:{$consumeItem->group_id},来源:{$source}"; if ($sourceId > 0) { $remark .= ",ID:{$sourceId}"; } // 消耗货币 $result = FundLogic::handle( $userId, $currencyId, $amount, FUND_LOG_TYPE::TRADE, // 使用TRADE类型,因为CONSUME可能不存在 $sourceId, $remark ); if ($result !== true) { return [ 'success' => false, 'message' => is_string($result) ? $result : '货币消耗失败', 'currency_id' => $currencyId, 'amount' => abs($amount) ]; } return [ 'success' => true, 'message' => '货币消耗成功', 'currency_id' => $currencyId, 'amount' => abs($amount) ]; } /** * 执行代币账户消耗 * * @param int $userId 用户ID * @param GameConsumeItem $consumeItem 消耗项 * @param string $source 消耗来源 * @param int $sourceId 消耗来源ID * @return array 执行结果 */ protected static function executeFundConsume(int $userId, GameConsumeItem $consumeItem, string $source, int $sourceId): array { $fundId = $consumeItem->target_id; $amount = -$consumeItem->quantity; // 负数表示消耗 // 构建备注 $remark = "消耗组:{$consumeItem->group_id},来源:{$source}"; if ($sourceId > 0) { $remark .= ",ID:{$sourceId}"; } try { // 消耗代币账户 $fundService = new \App\Module\Fund\Services\FundService($userId, $fundId); $result = $fundService->trade( 0, // 系统账户 abs($amount), // 正数金额 $source, $sourceId, $remark ); if (is_string($result)) { return [ 'success' => false, 'message' => $result, 'fund_id' => $fundId, 'amount' => abs($amount) ]; } return [ 'success' => true, 'message' => '代币账户消耗成功', 'fund_id' => $fundId, 'amount' => abs($amount) ]; } catch (\Exception $e) { return [ 'success' => false, 'message' => '代币账户消耗异常: ' . $e->getMessage(), 'fund_id' => $fundId, 'amount' => abs($amount) ]; } } }