| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- <?php
- namespace App\Module\Farm\Commands;
- use App\Module\Farm\Enums\LAND_STATUS;
- use App\Module\Farm\Models\FarmLand;
- use Illuminate\Console\Command;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Log;
- /**
- * 修复已铲除作物的土地状态命令
- *
- * 修复没有作物(has_crop为0)但土地状态不是空闲的问题
- * php artisan farm:fix-removed-crop-land-status --dry-run
- */
- class FixRemovedCropLandStatusCommand extends Command
- {
- /**
- * 命令签名
- *
- * @var string
- */
- protected $signature = 'farm:fix-removed-crop-land-status
- {--dry-run : 仅显示需要修复的数据,不执行修复}
- {--user= : 指定用户ID,只修复该用户的数据}
- {--limit=100 : 每批处理的数量}';
- /**
- * 命令描述
- *
- * @var string
- */
- protected $description = '修复没有作物(has_crop为0)但土地状态不是空闲的问题';
- /**
- * 执行命令
- *
- * @return int
- */
- public function handle(): int
- {
- $dryRun = $this->option('dry-run');
- $userId = $this->option('user');
- $limit = (int) $this->option('limit');
- $this->info('开始检查没有作物但土地状态不是空闲的问题...');
- if ($dryRun) {
- $this->warn('运行在模拟模式,不会实际修改数据');
- }
- try {
- // 获取需要修复的数据
- $problematicLands = $this->getProblematicLands($userId, $limit);
- if ($problematicLands->isEmpty()) {
- $this->info('没有发现需要修复的数据');
- return 0;
- }
- $this->info("发现 {$problematicLands->count()} 条需要修复的土地");
- if ($dryRun) {
- $this->displayProblems($problematicLands);
- } else {
- $this->fixProblems($problematicLands);
- }
- if (!$dryRun) {
- $this->info("\n修复完成!");
- }
- return 0;
- } catch (\Exception $e) {
- $this->error("修复过程中发生错误: {$e->getMessage()}");
- Log::error('已铲除作物土地状态修复失败', [
- 'error' => $e->getMessage(),
- 'trace' => $e->getTraceAsString()
- ]);
- return 1;
- }
- }
- /**
- * 获取有问题的土地数据
- * 查找没有作物(has_crop为0)但土地状态不是空闲的情况
- *
- * @param string|null $userId
- * @param int $limit
- * @return \Illuminate\Support\Collection
- */
- private function getProblematicLands(?string $userId, int $limit): \Illuminate\Support\Collection
- {
- // 查找has_crop为0但状态不是空闲的土地
- $query = DB::table('farm_land_users')
- ->select([
- 'id as land_id',
- 'user_id',
- 'status as land_status',
- 'has_crop'
- ])
- ->where('has_crop', 0) // has_crop为0(没有作物)
- ->where('status', '!=', LAND_STATUS::IDLE->value) // 状态不是空闲
- ->when($userId, function ($query, $userId) {
- return $query->where('user_id', $userId);
- })
- ->limit($limit);
- $results = $query->get();
- // 添加问题类型标识和额外信息
- return $results->map(function ($item) {
- // 检查是否有未删除的作物(用于验证has_crop字段的正确性)
- $activeCrops = DB::table('farm_crops')
- ->where('land_id', $item->land_id)
- ->whereNull('deleted_at')
- ->count();
- // 检查是否有软删除的作物
- $deletedCrops = DB::table('farm_crops')
- ->where('land_id', $item->land_id)
- ->whereNotNull('deleted_at')
- ->count();
- $item->active_crops_count = $activeCrops;
- $item->deleted_crops_count = $deletedCrops;
- $item->problem_type = $this->getProblemType($item);
- return $item;
- });
- }
- /**
- * 获取问题类型
- *
- * @param object $item
- * @return string
- */
- private function getProblemType(object $item): string
- {
- if ($item->active_crops_count > 0) {
- return 'has_crop为0但实际有活跃作物';
- } else {
- return 'has_crop为0且状态非空闲';
- }
- }
- /**
- * 显示问题数据
- *
- * @param \Illuminate\Support\Collection $items
- * @return void
- */
- private function displayProblems(\Illuminate\Support\Collection $items): void
- {
- // 按问题类型分组显示
- $groupedData = $items->groupBy('problem_type');
- foreach ($groupedData as $problemType => $problemItems) {
- $this->info("\n=== {$problemType} ({$problemItems->count()} 条) ===");
- $headers = ['土地ID', '用户ID', '当前土地状态', 'has_crop', '活跃作物数', '软删除作物数'];
- $rows = [];
- foreach ($problemItems as $item) {
- $rows[] = [
- $item->land_id,
- $item->user_id,
- $this->getLandStatusName($item->land_status),
- $item->has_crop ? '是' : '否',
- $item->active_crops_count,
- $item->deleted_crops_count
- ];
- }
- $this->table($headers, $rows);
- }
- }
- /**
- * 修复问题数据
- *
- * @param \Illuminate\Support\Collection $items
- * @return void
- */
- private function fixProblems(\Illuminate\Support\Collection $items): void
- {
- $fixedCount = 0;
- $failedCount = 0;
- foreach ($items as $item) {
- try {
- DB::transaction(function () use ($item) {
- $this->fixSingleLand($item);
- });
-
- $fixedCount++;
- $this->info("✓ 修复土地 {$item->land_id} (用户 {$item->user_id}) - {$item->problem_type}");
-
- } 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' => $item->problem_type,
- 'error' => $e->getMessage()
- ]);
- }
- }
- $this->info("修复完成: 成功 {$fixedCount} 条,失败 {$failedCount} 条");
- }
- /**
- * 修复单个土地
- *
- * @param object $item
- * @return void
- */
- private function fixSingleLand(object $item): void
- {
- $land = FarmLand::lockForUpdate()->find($item->land_id);
- if (!$land) {
- throw new \Exception('土地不存在');
- }
- $oldStatus = $land->status;
- $oldHasCrop = $land->has_crop;
- // 如果has_crop为0但状态不是空闲,将状态设置为空闲
- $land->status = LAND_STATUS::IDLE->value;
- $land->updateHasCrop(); // 这会根据状态更新has_crop字段
- $land->save();
- Log::info('修复has_crop为0但状态非空闲的土地', [
- 'land_id' => $land->id,
- 'user_id' => $land->user_id,
- 'active_crops_count' => $item->active_crops_count,
- 'deleted_crops_count' => $item->deleted_crops_count,
- 'old_status' => $oldStatus,
- 'new_status' => $land->status,
- 'old_has_crop' => $oldHasCrop,
- 'new_has_crop' => $land->has_crop,
- 'problem_type' => $item->problem_type
- ]);
- }
- /**
- * 获取土地状态名称
- *
- * @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 => '未知'
- };
- }
- }
|