option('dry-run'); $userId = $this->option('user'); $limit = (int) $this->option('limit'); $this->info('开始检查土地状态与作物生长阶段的一致性...'); if ($dryRun) { $this->warn('运行在模拟模式,不会实际修改数据'); } try { // 获取需要修复的数据 $inconsistentData = $this->getInconsistentData($userId, $limit); if ($inconsistentData->isEmpty()) { $this->info('没有发现需要修复的数据'); return 0; } $this->info("发现 {$inconsistentData->count()} 条需要修复的数据"); // 按问题类型分组 $groupedData = $inconsistentData->groupBy('problem_type'); foreach ($groupedData as $problemType => $items) { $this->info("\n=== {$problemType} ({$items->count()} 条) ==="); if ($dryRun) { $this->displayProblems($items); } else { $this->fixProblems($items, $problemType); } } if (!$dryRun) { $this->info("\n修复完成!"); } return 0; } catch (\Exception $e) { $this->error("修复过程中发生错误: {$e->getMessage()}"); Log::error('土地状态修复失败', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return 1; } } /** * 获取状态不一致的数据 * * @param string|null $userId * @param int $limit * @return \Illuminate\Support\Collection */ private function getInconsistentData(?string $userId, int $limit): \Illuminate\Support\Collection { $query = DB::table('farm_land_users as fl') ->join('farm_crops as fc', 'fl.id', '=', 'fc.land_id') ->select([ 'fl.id as land_id', 'fl.user_id', 'fl.status as land_status', 'fc.id as crop_id', 'fc.growth_stage', 'fc.disasters' ]) ->whereNull('fc.deleted_at') // 排除软删除的作物 ->where(function ($query) { $query // 作物成熟但土地状态不是可收获 ->where(function ($q) { $q->where('fc.growth_stage', GROWTH_STAGE::MATURE->value) ->where('fl.status', '!=', LAND_STATUS::HARVESTABLE->value); }) // 作物枯萎但土地状态不是枯萎 ->orWhere(function ($q) { $q->where('fc.growth_stage', GROWTH_STAGE::WITHERED->value) ->where('fl.status', '!=', LAND_STATUS::WITHERED->value); }) // 作物未成熟但土地状态是可收获 ->orWhere(function ($q) { $q->whereNotIn('fc.growth_stage', [GROWTH_STAGE::MATURE->value, GROWTH_STAGE::WITHERED->value]) ->where('fl.status', LAND_STATUS::HARVESTABLE->value); }) // 作物未枯萎但土地状态是枯萎 ->orWhere(function ($q) { $q->where('fc.growth_stage', '!=', GROWTH_STAGE::WITHERED->value) ->where('fl.status', LAND_STATUS::WITHERED->value); }); }); if ($userId) { $query->where('fl.user_id', $userId); } $results = $query->limit($limit)->get(); // 添加问题类型标识 return $results->map(function ($item) { $item->problem_type = $this->getProblemType($item); $item->active_disasters_count = $this->countActiveDisasters($item->disasters); return $item; }); } /** * 获取问题类型 * * @param object $item * @return string */ private function getProblemType(object $item): string { if ($item->growth_stage == GROWTH_STAGE::MATURE->value && $item->land_status != LAND_STATUS::HARVESTABLE->value) { return '作物成熟但土地非可收获'; } if ($item->growth_stage == GROWTH_STAGE::WITHERED->value && $item->land_status != LAND_STATUS::WITHERED->value) { return '作物枯萎但土地非枯萎'; } if (!in_array($item->growth_stage, [GROWTH_STAGE::MATURE->value, GROWTH_STAGE::WITHERED->value]) && $item->land_status == LAND_STATUS::HARVESTABLE->value) { return '作物未成熟但土地可收获'; } if ($item->growth_stage != GROWTH_STAGE::WITHERED->value && $item->land_status == LAND_STATUS::WITHERED->value) { return '作物未枯萎但土地枯萎'; } return '其他不一致'; } /** * 统计活跃灾害数量 * * @param string|array|null $disasters * @return int */ private function countActiveDisasters($disasters): int { if (empty($disasters)) { return 0; } // 如果是字符串,解码为数组 if (is_string($disasters)) { $disasterArray = json_decode($disasters, true); if (!is_array($disasterArray)) { return 0; } } elseif (is_array($disasters)) { $disasterArray = $disasters; } else { return 0; } return count(array_filter($disasterArray, function ($disaster) { return ($disaster['status'] ?? '') === 'active'; })); } /** * 显示问题数据 * * @param \Illuminate\Support\Collection $items * @return void */ private function displayProblems(\Illuminate\Support\Collection $items): void { $headers = ['土地ID', '用户ID', '土地状态', '作物ID', '生长阶段', '活跃灾害数']; $rows = []; foreach ($items as $item) { $rows[] = [ $item->land_id, $item->user_id, $this->getLandStatusName($item->land_status), $item->crop_id, $this->getGrowthStageName($item->growth_stage), $item->active_disasters_count ]; } $this->table($headers, $rows); } /** * 修复问题数据 * * @param \Illuminate\Support\Collection $items * @param string $problemType * @return void */ private function fixProblems(\Illuminate\Support\Collection $items, string $problemType): void { $fixedCount = 0; $failedCount = 0; foreach ($items as $item) { try { DB::transaction(function () use ($item, $problemType) { $this->fixSingleItem($item, $problemType); }); $fixedCount++; $this->info("✓ 修复土地 {$item->land_id} (用户 {$item->user_id})"); } catch (\Exception $e) { $failedCount++; $this->error("✗ 修复土地 {$item->land_id} 失败: {$e->getMessage()}"); Log::error('单个土地状态修复失败', [ 'land_id' => $item->land_id, 'user_id' => $item->user_id, 'problem_type' => $problemType, 'error' => $e->getMessage() ]); } } $this->info("修复完成: 成功 {$fixedCount} 条,失败 {$failedCount} 条"); } /** * 修复单个数据项 * * @param object $item * @param string $problemType * @return void */ private function fixSingleItem(object $item, string $problemType): void { $land = FarmLand::lockForUpdate()->find($item->land_id); $crop = FarmCrop::lockForUpdate()->find($item->crop_id); if (!$land || !$crop) { throw new \Exception('土地或作物不存在'); } $newStatus = $this->calculateCorrectLandStatus($crop); if ($land->status != $newStatus) { $oldStatus = $land->status; $land->status = $newStatus; $land->updateHasCrop(); $land->save(); Log::info('土地状态修复', [ 'land_id' => $land->id, 'user_id' => $land->user_id, 'crop_id' => $crop->id, 'old_status' => $oldStatus, 'new_status' => $newStatus, 'growth_stage' => $crop->growth_stage, 'problem_type' => $problemType, 'active_disasters' => $this->countActiveDisasters($crop->disasters) ]); }else{ Log::info('土地状态无需修复', [ 'land_id' => $land->id, 'user_id' => $land->user_id, 'crop_id' => $crop->id, 'status' => $land->status, 'growth_stage' => $crop->growth_stage, 'problem_type' => $problemType, 'active_disasters' => $this->countActiveDisasters($crop->disasters) ]); } } /** * 计算正确的土地状态 * * @param FarmCrop $crop * @return int */ private function calculateCorrectLandStatus(FarmCrop $crop): int { // 根据作物生长阶段确定土地状态 switch ($crop->growth_stage) { case GROWTH_STAGE::MATURE: // 作物成熟,土地状态为可收获 return LAND_STATUS::HARVESTABLE->value; case GROWTH_STAGE::WITHERED: // 作物枯萎,土地状态为枯萎 return LAND_STATUS::WITHERED->value; default: // 其他阶段,检查是否有活跃灾害 $activeDisasters = $this->countActiveDisasters($crop->disasters); if ($activeDisasters > 0) { return LAND_STATUS::DISASTER->value; } else { return LAND_STATUS::PLANTING->value; } } } /** * 获取土地状态名称 * * @param int $status * @return string */ private function getLandStatusName(int $status): string { return match ($status) { LAND_STATUS::IDLE->value => '空闲', LAND_STATUS::PLANTING->value => '种植中', LAND_STATUS::DISASTER->value => '灾害', LAND_STATUS::HARVESTABLE->value => '可收获', LAND_STATUS::WITHERED->value => '枯萎', default => '未知' }; } /** * 获取生长阶段名称 * * @param int $stage * @return string */ private function getGrowthStageName(int $stage): string { return match ($stage) { GROWTH_STAGE::SEED->value => '种子期', GROWTH_STAGE::SPROUT->value => '发芽期', GROWTH_STAGE::GROWTH->value => '生长期', GROWTH_STAGE::FRUIT->value => '果实期', GROWTH_STAGE::MATURE->value => '成熟期', GROWTH_STAGE::WITHERED->value => '枯萎期', default => '未知' }; } }