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; } }