|
|
@@ -0,0 +1,237 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Module\Farm\Services;
|
|
|
+
|
|
|
+use App\Module\Farm\Logics\PickLogic;
|
|
|
+use App\Module\Farm\Validations\CropPickValidation;
|
|
|
+use App\Module\Farm\Dtos\PickResultDto;
|
|
|
+use App\Module\Farm\Dtos\PickInfoDto;
|
|
|
+use App\Module\Farm\Models\FarmCrop;
|
|
|
+use App\Module\Farm\Models\FarmCropLog;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
+use Illuminate\Support\Facades\Log;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 摘取服务类
|
|
|
+ * 提供静态方法供其他模块调用
|
|
|
+ */
|
|
|
+class PickService
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 摘取指定作物
|
|
|
+ *
|
|
|
+ * @param int $pickerId 摘取者用户ID
|
|
|
+ * @param int $cropId 作物ID(摘取目标)
|
|
|
+ * @param int $pickAmount 摘取数量
|
|
|
+ * @param string $pickSource 摘取来源
|
|
|
+ * @param int|null $sourceId 来源ID(可选)
|
|
|
+ * @return PickResultDto
|
|
|
+ * @throws \Exception
|
|
|
+ */
|
|
|
+ public static function pickCrop(int $pickerId, int $cropId, int $pickAmount, string $pickSource, ?int $sourceId = null): PickResultDto
|
|
|
+ {
|
|
|
+ // 验证摘取参数
|
|
|
+ $validation = new CropPickValidation();
|
|
|
+ $validation->pickerId = $pickerId;
|
|
|
+ $validation->cropId = $cropId;
|
|
|
+ $validation->pickAmount = $pickAmount;
|
|
|
+ $validation->pickSource = $pickSource;
|
|
|
+ $validation->sourceId = $sourceId;
|
|
|
+
|
|
|
+ if (!$validation->validate()) {
|
|
|
+ throw new \Exception($validation->getFirstError());
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ return DB::transaction(function () use ($pickerId, $cropId, $pickAmount, $pickSource, $sourceId) {
|
|
|
+ $pickLogic = new PickLogic();
|
|
|
+ $result = $pickLogic->executePick($pickerId, $cropId, $pickAmount, $pickSource, $sourceId);
|
|
|
+
|
|
|
+ Log::info('摘取服务调用成功', [
|
|
|
+ 'picker_id' => $pickerId,
|
|
|
+ 'crop_id' => $cropId,
|
|
|
+ 'pick_amount' => $pickAmount,
|
|
|
+ 'pick_source' => $pickSource,
|
|
|
+ 'source_id' => $sourceId,
|
|
|
+ 'result_log_id' => $result->pickLogId,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $result;
|
|
|
+ });
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('摘取服务调用失败', [
|
|
|
+ 'picker_id' => $pickerId,
|
|
|
+ 'crop_id' => $cropId,
|
|
|
+ 'pick_amount' => $pickAmount,
|
|
|
+ 'pick_source' => $pickSource,
|
|
|
+ 'source_id' => $sourceId,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取作物摘取信息
|
|
|
+ *
|
|
|
+ * @param int $cropId 作物ID
|
|
|
+ * @return PickInfoDto|null
|
|
|
+ */
|
|
|
+ public static function getPickInfo(int $cropId): ?PickInfoDto
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ $pickLogic = new PickLogic();
|
|
|
+ return $pickLogic->getPickInfo($cropId);
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('获取摘取信息失败', [
|
|
|
+ 'crop_id' => $cropId,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 批量摘取多个作物
|
|
|
+ *
|
|
|
+ * @param int $pickerId 摘取者用户ID
|
|
|
+ * @param array $cropRequests 摘取请求数组
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function batchPickCrops(int $pickerId, array $cropRequests): array
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ return DB::transaction(function () use ($pickerId, $cropRequests) {
|
|
|
+ $pickLogic = new PickLogic();
|
|
|
+ $results = $pickLogic->batchPick($pickerId, $cropRequests);
|
|
|
+
|
|
|
+ Log::info('批量摘取服务调用完成', [
|
|
|
+ 'picker_id' => $pickerId,
|
|
|
+ 'total_requests' => count($cropRequests),
|
|
|
+ 'success_count' => count(array_filter($results, fn($r) => $r['success'])),
|
|
|
+ 'failed_count' => count(array_filter($results, fn($r) => !$r['success'])),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return $results;
|
|
|
+ });
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('批量摘取服务调用失败', [
|
|
|
+ 'picker_id' => $pickerId,
|
|
|
+ 'requests_count' => count($cropRequests),
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ throw $e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查作物是否可以摘取
|
|
|
+ *
|
|
|
+ * @param int $cropId 作物ID
|
|
|
+ * @return array 检查结果和详细原因
|
|
|
+ */
|
|
|
+ public static function canPickCrop(int $cropId): array
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ $crop = FarmCrop::find($cropId);
|
|
|
+ if (!$crop) {
|
|
|
+ return [
|
|
|
+ 'can_pick' => false,
|
|
|
+ 'reason' => '作物不存在',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ $canPick = $crop->canBePicked();
|
|
|
+ $reason = '';
|
|
|
+
|
|
|
+ if (!$canPick) {
|
|
|
+ if ($crop->growth_stage !== \App\Module\Farm\Enums\GROWTH_STAGE::MATURE) {
|
|
|
+ $reason = '作物未成熟';
|
|
|
+ } elseif ($crop->pickable_amount <= 0) {
|
|
|
+ $reason = '没有可摘取数量';
|
|
|
+ } elseif ($crop->pick_cooldown_end && now() < $crop->pick_cooldown_end) {
|
|
|
+ $remainingTime = now()->diffInSeconds($crop->pick_cooldown_end);
|
|
|
+ $reason = "正在冷却中,还需等待{$remainingTime}秒";
|
|
|
+ } else {
|
|
|
+ $reason = '不满足摘取条件';
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'can_pick' => $canPick,
|
|
|
+ 'reason' => $reason,
|
|
|
+ 'pickable_amount' => $crop->pickable_amount,
|
|
|
+ 'total_amount' => $crop->final_output_amount,
|
|
|
+ 'picked_amount' => $crop->picked_amount,
|
|
|
+ 'next_pick_time' => $crop->pick_cooldown_end,
|
|
|
+ ];
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('检查摘取条件失败', [
|
|
|
+ 'crop_id' => $cropId,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [
|
|
|
+ 'can_pick' => false,
|
|
|
+ 'reason' => '检查失败: ' . $e->getMessage(),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取摘取历史记录
|
|
|
+ *
|
|
|
+ * @param int $userId 用户ID
|
|
|
+ * @param string $type 查询类型:'picker'(摘取者) 或 'owner'(农场主)
|
|
|
+ * @param int $limit 限制数量
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ public static function getPickHistory(int $userId, string $type = 'picker', int $limit = 50): array
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ $query = FarmCropLog::where('event_type', FarmCropLog::EVENT_PICKED)
|
|
|
+ ->orderBy('created_at', 'desc')
|
|
|
+ ->limit($limit);
|
|
|
+
|
|
|
+ if ($type === 'picker') {
|
|
|
+ // 查询作为摘取者的记录
|
|
|
+ $query->whereJsonContains('event_data->picker_id', $userId);
|
|
|
+ } else {
|
|
|
+ // 查询作为农场主的记录
|
|
|
+ $query->where('user_id', $userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ $logs = $query->with(['crop', 'seed', 'land'])->get();
|
|
|
+
|
|
|
+ return $logs->map(function ($log) {
|
|
|
+ $eventData = $log->event_data ?? [];
|
|
|
+ return [
|
|
|
+ 'id' => $log->id,
|
|
|
+ 'crop_id' => $log->crop_id,
|
|
|
+ 'picker_id' => $eventData['picker_id'] ?? null,
|
|
|
+ 'owner_id' => $log->user_id,
|
|
|
+ 'pick_amount' => $eventData['pick_amount'] ?? 0,
|
|
|
+ 'item_id' => $eventData['item_id'] ?? null,
|
|
|
+ 'pick_source' => $eventData['pick_source'] ?? 'unknown',
|
|
|
+ 'source_id' => $eventData['source_id'] ?? null,
|
|
|
+ 'pick_time' => $log->created_at,
|
|
|
+ 'crop_info' => $log->crop ? [
|
|
|
+ 'seed_id' => $log->crop->seed_id,
|
|
|
+ 'land_id' => $log->crop->land_id,
|
|
|
+ ] : null,
|
|
|
+ ];
|
|
|
+ })->toArray();
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ Log::error('获取摘取历史失败', [
|
|
|
+ 'user_id' => $userId,
|
|
|
+ 'type' => $type,
|
|
|
+ 'error' => $e->getMessage(),
|
|
|
+ ]);
|
|
|
+
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|