| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- <?php
- namespace App\Module\Farm\Logics;
- use App\Module\Farm\Models\FarmCrop;
- use App\Module\Farm\Models\FarmCropLog;
- use App\Module\Farm\Dtos\PickResultDto;
- use App\Module\Farm\Dtos\PickInfoDto;
- use App\Module\Farm\Events\CropPickedEvent;
- use App\Module\GameItems\Services\ItemService;
- use Carbon\Carbon;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- /**
- * 摘取逻辑类
- * 处理作物摘取的核心业务逻辑
- */
- class PickLogic
- {
- /**
- * 执行摘取操作的核心方法
- *
- * @param int $pickerId 摘取者ID
- * @param int $cropId 作物ID
- * @param int $pickAmount 摘取数量
- * @param string $pickSource 摘取来源
- * @param int|null $sourceId 来源ID
- * @return PickResultDto
- * @throws \Exception
- */
- public function executePick(int $pickerId, int $cropId, int $pickAmount, string $pickSource, ?int $sourceId = null): PickResultDto
- {
- // 事务检查确保在事务中执行
- if (!DB::transactionLevel()) {
- throw new \Exception('摘取操作必须在数据库事务中执行');
- }
- // 验证摘取状态 - 直接验证而不使用验证器
- $crop = FarmCrop::find($cropId);
- if (!$crop) {
- throw new \Exception('作物不存在');
- }
- // 检查作物是否处于成熟期
- if ($crop->growth_stage !== \App\Module\Farm\Enums\GROWTH_STAGE::MATURE) {
- throw new \Exception('作物未成熟,无法摘取');
- }
- // 检查是否有最终产出
- if ($crop->final_output_amount <= 0) {
- throw new \Exception('作物没有产出,无法摘取');
- }
-
-
-
- // 检查摘取数量是否大于0
- if ($pickAmount <= 0) {
- throw new \Exception('摘取数量必须大于0');
- }
- // 计算摘取比例
- $pickRatio = $pickAmount / $crop->final_output_amount;
- // 获取冷却时间配置
- $cooldownSeconds = $crop->seed->pick_cooldown_seconds ?? 1800; // 默认30分钟
- // 更新作物的摘取相关字段
- $crop->picked_amount += $pickAmount;
- $crop->final_output_amount -= $pickAmount;
- $crop->last_pick_time = now();
- $crop->pick_cooldown_end = now()->addSeconds($cooldownSeconds);
- $crop->save();
- // 记录摘取事件到作物日志
- $eventData = [
- 'picker_id' => $pickerId,
- 'pick_amount' => $pickAmount,
- 'remaining_amount' => $crop->pickable_amount,
- 'pick_ratio' => $pickRatio,
- 'pick_source' => $pickSource,
- 'source_id' => $sourceId,
- 'item_id' => $crop->final_output_item_id,
- 'total_picked' => $crop->picked_amount,
- 'cooldown_end' => $crop->pick_cooldown_end->toDateTimeString(),
- 'ip_address' => request()->ip(),
- 'user_agent' => request()->userAgent(),
- 'growth_stage' => $crop->growth_stage->value,
- 'land_type' => $crop->land->land_type ?? 1,
- ];
- $cropLog = FarmCropLog::logPicked(
- $crop->user_id,
- $crop->land_id,
- $crop->id,
- $crop->seed_id,
- $eventData
- );
- // 给摘取者添加物品到背包
- ItemService::addItem($pickerId, $crop->final_output_item_id, $pickAmount, [
- 'source_type' => $pickSource,
- 'source_id' => $sourceId,
- 'details' => [
- 'crop_id' => $cropId,
- 'pick_amount' => $pickAmount,
- 'pick_ratio' => $pickRatio,
- ],
- 'ip_address' => request()->ip(),
- 'device_info' => request()->userAgent(),
- ]);
- // 触发摘取事件
- event(new CropPickedEvent(
- $pickerId,
- $crop->user_id,
- $crop->land_id,
- $crop->id,
- $crop->final_output_item_id,
- $pickAmount,
- $crop->final_output_amount,
- $crop->pickable_amount,
- $pickSource,
- $sourceId,
- $crop->land,
- $crop,
- $cropLog
- ));
- // 记录操作日志
- Log::info('作物摘取成功', [
- 'picker_id' => $pickerId,
- 'crop_id' => $cropId,
- 'pick_amount' => $pickAmount,
- 'pick_source' => $pickSource,
- 'source_id' => $sourceId,
- 'crop_log_id' => $cropLog->id,
- ]);
- // 返回摘取结果DTO
- return PickResultDto::fromPickOperation([
- 'crop_id' => $crop->id,
- 'item_id' => $crop->final_output_item_id,
- 'pick_amount' => $pickAmount,
- 'remaining_amount' => $crop->pickable_amount,
- 'pick_ratio' => $pickRatio,
- 'pick_time' => $crop->last_pick_time,
- 'pick_source' => $pickSource,
- 'source_id' => $sourceId,
- 'pick_log_id' => $cropLog->id,
- 'can_pick_again' => $crop->pickable_amount > 0,
- 'next_pick_time' => $crop->pick_cooldown_end,
- ]);
- }
- /**
- * 获取作物摘取信息
- *
- * @param int $cropId 作物ID
- * @return PickInfoDto|null
- */
- public function getPickInfo(int $cropId): ?PickInfoDto
- {
- $crop = FarmCrop::find($cropId);
- if (!$crop) {
- return null;
- }
- return PickInfoDto::fromCrop($crop);
- }
- /**
- * 批量摘取多个作物
- *
- * @param int $pickerId 摘取者ID
- * @param array $cropRequests 摘取请求数组
- * @return array
- */
- public function batchPick(int $pickerId, array $cropRequests): array
- {
- $results = [];
- foreach ($cropRequests as $request) {
- try {
- $result = $this->executePick(
- $pickerId,
- $request['crop_id'],
- $request['amount'],
- $request['source'],
- $request['source_id'] ?? null
- );
-
- $results[] = [
- 'success' => true,
- 'crop_id' => $request['crop_id'],
- 'result' => $result,
- ];
- } catch (\Exception $e) {
- $results[] = [
- 'success' => false,
- 'crop_id' => $request['crop_id'],
- 'error' => $e->getMessage(),
- ];
-
- Log::warning('批量摘取失败', [
- 'picker_id' => $pickerId,
- 'crop_id' => $request['crop_id'],
- 'error' => $e->getMessage(),
- ]);
- }
- }
- return $results;
- }
- }
|