PickService.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php
  2. namespace App\Module\Farm\Services;
  3. use App\Module\Farm\Logics\PickLogic;
  4. use App\Module\Farm\Validations\CropPickValidation;
  5. use App\Module\Farm\Dtos\PickResultDto;
  6. use App\Module\Farm\Dtos\PickInfoDto;
  7. use App\Module\Farm\Models\FarmCrop;
  8. use App\Module\Farm\Models\FarmCropLog;
  9. use Illuminate\Support\Facades\DB;
  10. use Illuminate\Support\Facades\Log;
  11. /**
  12. * 摘取服务类
  13. * 提供静态方法供其他模块调用
  14. */
  15. class PickService
  16. {
  17. /**
  18. * 摘取指定作物
  19. *
  20. * @param int $pickerId 摘取者用户ID
  21. * @param int $cropId 作物ID(摘取目标)
  22. * @param int $pickAmount 摘取数量
  23. * @param string $pickSource 摘取来源
  24. * @param int|null $sourceId 来源ID(可选)
  25. * @return PickResultDto
  26. * @throws \Exception
  27. */
  28. public static function pickCrop(int $pickerId, int $cropId, int $pickAmount, string $pickSource, ?int $sourceId = null): PickResultDto
  29. {
  30. // 验证摘取参数
  31. $validation = new CropPickValidation();
  32. $validation->pickerId = $pickerId;
  33. $validation->cropId = $cropId;
  34. $validation->pickAmount = $pickAmount;
  35. $validation->pickSource = $pickSource;
  36. $validation->sourceId = $sourceId;
  37. if (!$validation->validate()) {
  38. throw new \Exception($validation->getFirstError());
  39. }
  40. try {
  41. // return DB::transaction(function () use ($pickerId, $cropId, $pickAmount, $pickSource, $sourceId) {
  42. $pickLogic = new PickLogic();
  43. $result = $pickLogic->executePick($pickerId, $cropId, $pickAmount, $pickSource, $sourceId);
  44. Log::info('摘取服务调用成功', [
  45. 'picker_id' => $pickerId,
  46. 'crop_id' => $cropId,
  47. 'pick_amount' => $pickAmount,
  48. 'pick_source' => $pickSource,
  49. 'source_id' => $sourceId,
  50. 'result_log_id' => $result->pickLogId,
  51. ]);
  52. return $result;
  53. // });
  54. } catch (\Exception $e) {
  55. Log::error('摘取服务调用失败', [
  56. 'picker_id' => $pickerId,
  57. 'crop_id' => $cropId,
  58. 'pick_amount' => $pickAmount,
  59. 'pick_source' => $pickSource,
  60. 'source_id' => $sourceId,
  61. 'error' => $e->getMessage(),
  62. ]);
  63. throw $e;
  64. }
  65. }
  66. /**
  67. * 获取作物摘取信息
  68. *
  69. * @param int $cropId 作物ID
  70. * @return PickInfoDto|null
  71. */
  72. public static function getPickInfo(int $cropId): ?PickInfoDto
  73. {
  74. try {
  75. $pickLogic = new PickLogic();
  76. return $pickLogic->getPickInfo($cropId);
  77. } catch (\Exception $e) {
  78. Log::error('获取摘取信息失败', [
  79. 'crop_id' => $cropId,
  80. 'error' => $e->getMessage(),
  81. ]);
  82. return null;
  83. }
  84. }
  85. /**
  86. * 批量摘取多个作物
  87. *
  88. * @param int $pickerId 摘取者用户ID
  89. * @param array $cropRequests 摘取请求数组
  90. * @return array
  91. */
  92. public static function batchPickCrops(int $pickerId, array $cropRequests): array
  93. {
  94. try {
  95. return DB::transaction(function () use ($pickerId, $cropRequests) {
  96. $pickLogic = new PickLogic();
  97. $results = $pickLogic->batchPick($pickerId, $cropRequests);
  98. Log::info('批量摘取服务调用完成', [
  99. 'picker_id' => $pickerId,
  100. 'total_requests' => count($cropRequests),
  101. 'success_count' => count(array_filter($results, fn($r) => $r['success'])),
  102. 'failed_count' => count(array_filter($results, fn($r) => !$r['success'])),
  103. ]);
  104. return $results;
  105. });
  106. } catch (\Exception $e) {
  107. Log::error('批量摘取服务调用失败', [
  108. 'picker_id' => $pickerId,
  109. 'requests_count' => count($cropRequests),
  110. 'error' => $e->getMessage(),
  111. ]);
  112. throw $e;
  113. }
  114. }
  115. /**
  116. * 检查作物是否可以摘取
  117. *
  118. * @param int $cropId 作物ID
  119. * @return array 检查结果和详细原因
  120. */
  121. public static function canPickCrop(int $cropId): array
  122. {
  123. try {
  124. $crop = FarmCrop::find($cropId);
  125. if (!$crop) {
  126. return [
  127. 'can_pick' => false,
  128. 'reason' => '作物不存在',
  129. ];
  130. }
  131. $canPick = $crop->canBePicked();
  132. $reason = '';
  133. if (!$canPick) {
  134. if ($crop->growth_stage !== \App\Module\Farm\Enums\GROWTH_STAGE::MATURE) {
  135. $reason = '作物未成熟';
  136. } elseif ($crop->pickable_amount <= 0) {
  137. $reason = '没有可摘取数量';
  138. } elseif ($crop->pick_cooldown_end && now() < $crop->pick_cooldown_end) {
  139. $remainingTime = now()->diffInSeconds($crop->pick_cooldown_end);
  140. $reason = "正在冷却中,还需等待{$remainingTime}秒";
  141. } else {
  142. $reason = '不满足摘取条件';
  143. }
  144. }
  145. return [
  146. 'can_pick' => $canPick,
  147. 'reason' => $reason,
  148. 'pickable_amount' => $crop->pickable_amount,
  149. 'total_amount' => $crop->final_output_amount,
  150. 'picked_amount' => $crop->picked_amount,
  151. 'next_pick_time' => $crop->pick_cooldown_end,
  152. ];
  153. } catch (\Exception $e) {
  154. Log::error('检查摘取条件失败', [
  155. 'crop_id' => $cropId,
  156. 'error' => $e->getMessage(),
  157. ]);
  158. return [
  159. 'can_pick' => false,
  160. 'reason' => '检查失败: ' . $e->getMessage(),
  161. ];
  162. }
  163. }
  164. /**
  165. * 获取摘取历史记录
  166. *
  167. * @param int $userId 用户ID
  168. * @param string $type 查询类型:'picker'(摘取者) 或 'owner'(农场主)
  169. * @param int $limit 限制数量
  170. * @return array
  171. */
  172. public static function getPickHistory(int $userId, string $type = 'picker', int $limit = 50): array
  173. {
  174. try {
  175. $query = FarmCropLog::where('event_type', FarmCropLog::EVENT_PICKED)
  176. ->orderBy('created_at', 'desc')
  177. ->limit($limit);
  178. if ($type === 'picker') {
  179. // 查询作为摘取者的记录
  180. $query->whereJsonContains('event_data->picker_id', $userId);
  181. } else {
  182. // 查询作为农场主的记录
  183. $query->where('user_id', $userId);
  184. }
  185. $logs = $query->with(['crop', 'seed', 'land'])->get();
  186. return $logs->map(function ($log) {
  187. $eventData = $log->event_data ?? [];
  188. return [
  189. 'id' => $log->id,
  190. 'crop_id' => $log->crop_id,
  191. 'picker_id' => $eventData['picker_id'] ?? null,
  192. 'owner_id' => $log->user_id,
  193. 'pick_amount' => $eventData['pick_amount'] ?? 0,
  194. 'item_id' => $eventData['item_id'] ?? null,
  195. 'pick_source' => $eventData['pick_source'] ?? 'unknown',
  196. 'source_id' => $eventData['source_id'] ?? null,
  197. 'pick_time' => $log->created_at,
  198. 'crop_info' => $log->crop ? [
  199. 'seed_id' => $log->crop->seed_id,
  200. 'land_id' => $log->crop->land_id,
  201. ] : null,
  202. ];
  203. })->toArray();
  204. } catch (\Exception $e) {
  205. Log::error('获取摘取历史失败', [
  206. 'user_id' => $userId,
  207. 'type' => $type,
  208. 'error' => $e->getMessage(),
  209. ]);
  210. return [];
  211. }
  212. }
  213. }