Bladeren bron

feat(farm): 添加灾害统计功能并优化土地详情展示

- 在土地统计中增加灾害统计部分,显示各类灾害的数量和减产比例
- 在土地详情表格中添加灾害情况列,展示每块土地的灾害信息
- 新增 DisasterService 类,用于获取灾害相关数据
- 优化代码结构,移除重复的灾害类型定义
notfff 7 maanden geleden
bovenliggende
commit
a6d1b7611c

+ 28 - 32
app/Module/Farm/Commands/GenerateDisastersCommand.php

@@ -9,6 +9,7 @@ use App\Module\Farm\Enums\LAND_STATUS;
 use App\Module\Farm\Events\DisasterGeneratedEvent;
 use App\Module\Farm\Models\FarmCrop;
 use App\Module\Farm\Models\FarmGodBuff;
+use App\Module\Farm\Services\DisasterService;
 use Illuminate\Console\Command;
 use Illuminate\Support\Facades\Log;
 
@@ -39,62 +40,57 @@ class GenerateDisastersCommand extends Command
     public function handle()
     {
         $this->info('开始生成作物灾害...');
-        
+
         try {
             // 获取处于发芽期或生长期的作物
             $crops = FarmCrop::whereIn('growth_stage', [GROWTH_STAGE::SPROUT, GROWTH_STAGE::GROWTH])
                 ->get();
-            
+
             $this->info("找到 {$crops->count()} 个可能受灾的作物");
-            
+
             $generatedCount = 0;
-            
+
             foreach ($crops as $crop) {
                 $userId = $crop->user_id;
                 $land = $crop->land;
                 $seed = $crop->seed;
-                
+
                 // 跳过已经有灾害的土地
                 if ($land->status === LAND_STATUS::DISASTER) {
                     continue;
                 }
-                
+
                 // 获取种子的灾害抵抗属性
                 $disasterResistance = $seed->disaster_resistance ?? [];
-                
+
                 // 获取土地的灾害抵抗属性
                 $landDisasterResistance = $land->landType->disaster_resistance ?? 0;
-                
+
                 // 检查用户是否有有效的神灵加持
                 $activeBuffs = FarmGodBuff::where('user_id', $userId)
                     ->where('expire_time', '>', now())
                     ->pluck('buff_type')
                     ->toArray();
-                
+
                 // 灾害类型及其基础概率
-                $disasterTypes = [
-                    DISASTER_TYPE::DROUGHT => 0.1, // 干旱
-                    DISASTER_TYPE::PEST => 0.1,    // 虫害
-                    DISASTER_TYPE::WEED => 0.1,    // 杂草
-                ];
-                
+                $disasterTypes = DisasterService::getAllDisasters();
                 // 随机选择一种灾害类型
                 $randomDisasterType = array_rand($disasterTypes);
                 $baseProb = $disasterTypes[$randomDisasterType];
-                
+
                 // 计算最终概率,考虑种子抵抗、土地抵抗和神灵加持
                 $seedResistance = $disasterResistance[$this->getDisasterKey($randomDisasterType)] ?? 0;
                 $finalProb = $baseProb - $seedResistance - $landDisasterResistance;
-                
+
                 // 如果有对应的神灵加持,则不生成该类型的灾害
                 $buffType = DISASTER_TYPE::getPreventBuffType($randomDisasterType);
                 if ($buffType && in_array($buffType, $activeBuffs)) {
                     $finalProb = 0;
                 }
-                
+
                 // 确保概率在有效范围内
                 $finalProb = max(0, min(1, $finalProb));
-                
+
                 // 随机决定是否生成灾害
                 if (mt_rand(1, 100) <= $finalProb * 100) {
                     // 生成灾害
@@ -103,48 +99,48 @@ class GenerateDisastersCommand extends Command
                         'generated_at' => now()->toDateTimeString(),
                         'status' => 'active'
                     ];
-                    
+
                     // 更新作物灾害信息
                     $disasters = $crop->disasters ?? [];
                     $disasters[] = $disasterInfo;
                     $crop->disasters = $disasters;
-                    
+
                     // 更新土地状态为灾害
                     $land->status = LAND_STATUS::DISASTER;
-                    
+
                     // 保存更改
                     $crop->save();
                     $land->save();
-                    
+
                     // 触发灾害生成事件
                     event(new DisasterGeneratedEvent($userId, $crop, $randomDisasterType, $disasterInfo));
-                    
+
                     $generatedCount++;
-                    
+
                     $this->info("作物 ID: {$crop->id}, 用户 ID: {$userId}, 灾害类型: {$randomDisasterType}");
                 }
             }
-            
+
             $this->info("成功生成 {$generatedCount} 个作物灾害");
-            
+
             Log::info('作物灾害生成成功', [
                 'total' => $crops->count(),
                 'generated' => $generatedCount
             ]);
-            
+
             return 0;
         } catch (\Exception $e) {
             $this->error('作物灾害生成失败: ' . $e->getMessage());
-            
+
             Log::error('作物灾害生成失败', [
                 'error' => $e->getMessage(),
                 'trace' => $e->getTraceAsString()
             ]);
-            
+
             return 1;
         }
     }
-    
+
     /**
      * 获取灾害类型对应的键名
      *
@@ -158,7 +154,7 @@ class GenerateDisastersCommand extends Command
             DISASTER_TYPE::PEST => 'pest',
             DISASTER_TYPE::WEED => 'weed',
         ];
-        
+
         return $keys[$disasterType] ?? '';
     }
 }

+ 1 - 0
app/Module/Farm/Enums/DISASTER_TYPE.php

@@ -7,6 +7,7 @@ use UCore\Enum\EnumToInt;
 
 /**
  * 灾害类型枚举
+ * Disaster Type
  */
 enum DISASTER_TYPE: int
 {

+ 23 - 20
app/Module/Farm/Listeners/CalculateHarvestOutputListener.php

@@ -6,6 +6,7 @@ use App\Module\Farm\Enums\BUFF_TYPE;
 use App\Module\Farm\Events\CropHarvestedEvent;
 
 
+use App\Module\Farm\Services\DisasterService;
 use Illuminate\Support\Facades\Log;
 
 /**
@@ -26,9 +27,9 @@ class CalculateHarvestOutputListener
     public function handle(CropHarvestedEvent $event)
     {
         try {
-            $crop = $event->crop;
-            $land = $event->land;
-            $seed = $crop->seed;
+            $crop         = $event->crop;
+            $land         = $event->land;
+            $seed         = $crop->seed;
             $outputAmount = $event->outputAmount;
 
             // 获取土地的产量加成
@@ -40,7 +41,7 @@ class CalculateHarvestOutputListener
              */
             $farmUser = $crop->user;
 //            dd($farmUser,$crop);
-            $houseConfig = $farmUser->houseConfig;
+            $houseConfig      = $farmUser->houseConfig;
             $houseOutputBonus = $houseConfig->output_bonus ?? 0;
 
             // 检查是否有丰收之神加持
@@ -50,12 +51,13 @@ class CalculateHarvestOutputListener
                 ->exists();
 
             // 计算灾害减产
+            $dJian           = DisasterService::getAllDisasters();
             $disasterPenalty = 0;
             if (!empty($crop->disasters)) {
                 foreach ($crop->disasters as $disaster) {
                     if (($disaster['status'] ?? '') === 'active') {
-                        // 每个灾害减产5%
-                        $disasterPenalty += 0.05;
+                        // 递加减产比例
+                        $disasterPenalty += $dJian[$disaster];
                     }
                 }
             }
@@ -77,33 +79,33 @@ class CalculateHarvestOutputListener
                 $maxPossibleAmount = $seed->max_output;
                 $maxPossibleAmount = (int)($maxPossibleAmount * (1 + $landOutputBonus));
                 $maxPossibleAmount = (int)($maxPossibleAmount * (1 + $houseOutputBonus));
-                $finalAmount = max($finalAmount, $maxPossibleAmount);
+                $finalAmount       = max($finalAmount, $maxPossibleAmount);
             }
 
             // 确保产量不超过全局最高产量
             $globalMaxOutput = 3000;
-            $finalAmount = min($finalAmount, $globalMaxOutput);
+            $finalAmount     = min($finalAmount, $globalMaxOutput);
 
             // 如果有灾害,确保产量不超过灾害时最高产量
             if ($disasterPenalty > 0) {
                 $disasterMaxOutput = 2000;
-                $finalAmount = min($finalAmount, $disasterMaxOutput);
+                $finalAmount       = min($finalAmount, $disasterMaxOutput);
             }
 
             // 更新收获记录的产出数量
-            $harvestLog = $event->harvestLog;
+            $harvestLog                = $event->harvestLog;
             $harvestLog->output_amount = $finalAmount;
             $harvestLog->save();
 
             Log::info('收获产出计算成功', [
-                'user_id' => $event->userId,
-                'crop_id' => $crop->id,
-                'land_id' => $land->id,
-                'seed_id' => $seed->id,
-                'original_amount' => $outputAmount,
-                'final_amount' => $finalAmount,
-                'land_bonus' => $landOutputBonus,
-                'house_bonus' => $houseOutputBonus,
+                'user_id'          => $event->userId,
+                'crop_id'          => $crop->id,
+                'land_id'          => $land->id,
+                'seed_id'          => $seed->id,
+                'original_amount'  => $outputAmount,
+                'final_amount'     => $finalAmount,
+                'land_bonus'       => $landOutputBonus,
+                'house_bonus'      => $houseOutputBonus,
                 'disaster_penalty' => $disasterPenalty,
                 'has_harvest_buff' => $hasHarvestBuff
             ]);
@@ -111,9 +113,10 @@ class CalculateHarvestOutputListener
             Log::error('收获产出计算失败', [
                 'user_id' => $event->userId,
                 'crop_id' => $event->crop->id ?? null,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
         }
     }
+
 }

+ 2 - 5
app/Module/Farm/Listeners/GenerateDisasterListener.php

@@ -9,6 +9,7 @@ use App\Module\Farm\Events\CropGrowthStageChangedEvent;
 use App\Module\Farm\Events\DisasterGeneratedEvent;
 
 
+use App\Module\Farm\Services\DisasterService;
 use Illuminate\Support\Facades\Log;
 
 /**
@@ -51,11 +52,7 @@ class GenerateDisasterListener
                 ->toArray();
 
             // 灾害类型及其基础概率
-            $disasterTypes = [
-                DISASTER_TYPE::DROUGHT->valueInt() => 0.1, // 干旱
-                DISASTER_TYPE::PEST->valueInt() => 0.1,    // 虫害
-                DISASTER_TYPE::WEED->valueInt() => 0.1,    // 杂草
-            ];
+            $disasterTypes =DisasterService::getRate();
 
             // 随机选择一种灾害类型
             $randomDisasterType = array_rand($disasterTypes);

+ 2 - 5
app/Module/Farm/Logics/DisasterLogic.php

@@ -10,6 +10,7 @@ use App\Module\Farm\Enums\LAND_STATUS;
 use App\Module\Farm\Events\DisasterGeneratedEvent;
 use App\Module\Farm\Models\FarmCrop;
 use App\Module\Farm\Models\FarmGodBuff;
+use App\Module\Farm\Services\DisasterService;
 use Illuminate\Support\Collection;
 use Illuminate\Support\Facades\Log;
 
@@ -129,11 +130,7 @@ class DisasterLogic
                 ->toArray();
 
             // 灾害类型及其基础概率
-            $disasterTypes = [
-                DISASTER_TYPE::DROUGHT => 0.1, // 干旱
-                DISASTER_TYPE::PEST => 0.1,    // 虫害
-                DISASTER_TYPE::WEED => 0.1,    // 杂草
-            ];
+            $disasterTypes =DisasterService::getAllDisasters();
 
             // 随机选择一种灾害类型
             $randomDisasterType = array_rand($disasterTypes);

+ 43 - 0
app/Module/Farm/Services/DisasterService.php

@@ -0,0 +1,43 @@
+<?php
+
+namespace App\Module\Farm\Services;
+
+use App\Module\Farm\Enums\DISASTER_TYPE;
+
+class DisasterService
+{
+
+    /**
+     * 获取所有灾害 减产比例
+     *
+     * @return float[]
+     */
+    public static function getAllDisasters()
+    {
+        $disasterTypes = [
+            DISASTER_TYPE::DROUGHT->valueInt() => 0.05, // 干旱
+            DISASTER_TYPE::PEST->valueInt()    => 0.05,    // 虫害
+            DISASTER_TYPE::WEED->valueInt()    => 0.05,    // 杂草
+        ];
+
+        return $disasterTypes;
+    }
+
+    /**
+     * 获取灾害 产生比例
+     *
+     * @return float[]
+     */
+    public static function getRate()
+    {
+        $disasterTypes = [
+            DISASTER_TYPE::DROUGHT->valueInt() => 0.9, // 干旱
+            DISASTER_TYPE::PEST->valueInt()    => 0.9,    // 虫害
+            DISASTER_TYPE::WEED->valueInt()    => 0.9,    // 杂草
+        ];
+
+        return $disasterTypes;
+
+    }
+
+}

+ 133 - 22
app/Module/Game/AdminControllers/FarmUserSummaryController.php

@@ -2,12 +2,14 @@
 
 namespace App\Module\Game\AdminControllers;
 
+use App\Module\Farm\Enums\DISASTER_TYPE;
 use App\Module\Farm\Enums\GROWTH_STAGE;
 use App\Module\Farm\Models\FarmCrop;
 use App\Module\Farm\Models\FarmGodBuff;
 use App\Module\Farm\Models\FarmHouseConfig;
 use App\Module\Farm\Models\FarmLand;
 use App\Module\Farm\Models\FarmUser;
+use App\Module\Farm\Services\DisasterService;
 use App\Module\Fund\Models\FundModel;
 use App\Module\Fund\Services\AccountService;
 use App\Module\GameItems\Enums\ITEM_TYPE;
@@ -65,18 +67,18 @@ class FarmUserSummaryController extends AdminController
     {
         // 记录请求信息
         \Illuminate\Support\Facades\Log::info('访问农场用户信息汇总', [
-            'user_id' => $userId,
-            'referer' => request()->header('referer'),
+            'user_id'    => $userId,
+            'referer'    => request()->header('referer'),
             'user_agent' => request()->header('user-agent'),
-            'ip' => request()->ip(),
-            'url' => request()->fullUrl(),
+            'ip'         => request()->ip(),
+            'url'        => request()->fullUrl(),
         ]);
 
         // 查找用户
         $user = User::find($userId);
         if (!$user) {
             admin_error('错误', "用户 {$userId} 不存在");
-            \Illuminate\Support\Facades\Log::warning('访问不存在的用户', ['user_id' => $userId]);
+            \Illuminate\Support\Facades\Log::warning('访问不存在的用户', [ 'user_id' => $userId ]);
 
             return redirect()->route('dcat.admin.farm-user-summary');
         }
@@ -85,7 +87,7 @@ class FarmUserSummaryController extends AdminController
         $farmUser = FarmUser::where('user_id', $userId)->first();
         if (!$farmUser) {
             admin_warning('提示', "用户 {$userId} 没有农场信息");
-            \Illuminate\Support\Facades\Log::info('用户没有农场信息', ['user_id' => $userId]);
+            \Illuminate\Support\Facades\Log::info('用户没有农场信息', [ 'user_id' => $userId ]);
             // 不重定向,继续显示用户信息,只是提示没有农场信息
         }
 
@@ -216,11 +218,32 @@ class FarmUserSummaryController extends AdminController
         // 土地状态统计
         $landStatusStats = $lands->groupBy('status')->map->count();
 
-        // 创建土地类型和状态的统计表格
+        // 灾害统计
+        $disasterStats = [
+            1 => 0, // 干旱
+            2 => 0, // 虫害
+            3 => 0, // 杂草
+        ];
+
+        // 统计活跃的灾害
+        foreach ($lands as $land) {
+            if ($land->crop && !empty($land->crop->disasters)) {
+                foreach ($land->crop->disasters as $disaster) {
+                    if (($disaster['status'] ?? '') === 'active') {
+                        $type = $disaster['type'] ?? 0;
+                        if (isset($disasterStats[$type])) {
+                            $disasterStats[$type]++;
+                        }
+                    }
+                }
+            }
+        }
+
+        // 创建土地类型、状态和灾害的统计表格
         $statsContent = '<div class="row">';
 
         // 土地类型统计
-        $statsContent .= '<div class="col-md-6">';
+        $statsContent .= '<div class="col-md-4">';
         $statsContent .= '<h5>土地类型统计</h5>';
         $statsContent .= '<table class="table table-sm table-bordered">';
         $statsContent .= '<thead><tr><th>土地类型</th><th>数量</th></tr></thead>';
@@ -243,7 +266,7 @@ class FarmUserSummaryController extends AdminController
         $statsContent .= '</tbody></table></div>';
 
         // 土地状态统计
-        $statsContent .= '<div class="col-md-6">';
+        $statsContent .= '<div class="col-md-4">';
         $statsContent .= '<h5>土地状态统计</h5>';
         $statsContent .= '<table class="table table-sm table-bordered">';
         $statsContent .= '<thead><tr><th>土地状态</th><th>数量</th></tr></thead>';
@@ -262,31 +285,64 @@ class FarmUserSummaryController extends AdminController
             $statsContent .= "<tr><td>{$statusName}</td><td>{$count}</td></tr>";
         }
 
+        $statsContent .= '</tbody></table></div>';
+
+        // 灾害统计
+        $statsContent .= '<div class="col-md-4">';
+        $statsContent .= '<h5>灾害统计</h5>';
+        $statsContent .= '<table class="table table-sm table-bordered">';
+        $statsContent .= '<thead><tr><th>灾害类型</th><th>数量</th><th>减产比例</th></tr></thead>';
+        $statsContent .= '<tbody>';
+
+        $disasterNames  = DISASTER_TYPE::getAll();
+        $totalDisasters = 0;
+        $d              = DisasterService::getAllDisasters();
+        foreach ($disasterStats as $typeId => $count) {
+            $typeName       = $disasterNames[$typeId] ?? "未知灾害{$typeId}";
+            $penalty        = $d[$typeId];
+            $totalDisasters += $count;
+
+            $statsContent .= "<tr><td>{$typeName}</td><td>{$count}</td><td>{$penalty}</td></tr>";
+        }
+
+        // 添加总计行
+        $totalPenalty = $totalDisasters > 0 ? ($totalDisasters * 5) . '%' : '0%';
+        $statsContent .= "<tr class='table-info'><td><strong>总计</strong></td><td>{$totalDisasters}</td><td>{$totalPenalty}</td></tr>";
+
         $statsContent .= '</tbody></table></div>';
         $statsContent .= '</div>';
 
         // 创建土地详情表格
-        $headers = [  'ID','位置', '土地类型', '状态', '种植作物', '种植时间', '生长阶段', '本阶段开始时间', '本阶段结束时间' ];
+        $headers = [
+            'ID', '位置', '土地类型', '状态', '种植作物', '种植时间', '生长阶段', '本阶段开始时间', '本阶段结束时间',
+            '灾害情况'
+        ];
         $rows    = [];
 
         foreach ($lands as $land) {
             $landType = $land->landType ? $land->landType->name : "类型{$land->land_type}";
             $status   = $landStatusNames[$land->status] ?? "状态{$land->status}";
 
-            $crop        = $land->crop;
-            $cropInfo    = '无';
-            $plantTime   = '';
-            $growthStage = '';
+            $crop           = $land->crop;
+            $cropInfo       = '无';
+            $plantTime      = '';
+            $growthStage    = '';
             $stageStartTime = '';
-            $stageEndTime = '';
+            $stageEndTime   = '';
+            $disasterInfo   = '无';
 
             if ($crop) {
-                $seedName    = $crop->seed ? $crop->seed->name : "种子{$crop->seed_id}";
-                $cropInfo    = $seedName;
-                $plantTime   = $crop->plant_time;
-                $growthStage = $this->getGrowthStageName($crop->growth_stage);
+                $seedName       = $crop->seed ? $crop->seed->name : "种子{$crop->seed_id}";
+                $cropInfo       = $seedName;
+                $plantTime      = $crop->plant_time;
+                $growthStage    = $this->getGrowthStageName($crop->growth_stage);
                 $stageStartTime = $crop->stage_start_time;
-                $stageEndTime = $crop->stage_end_time;
+                $stageEndTime   = $crop->stage_end_time;
+
+                // 处理灾害信息
+                if (!empty($crop->disasters)) {
+                    $disasterInfo = $this->formatDisasterInfo($crop->disasters);
+                }
             }
 
             $rows[] = [
@@ -299,6 +355,7 @@ class FarmUserSummaryController extends AdminController
                 $growthStage,
                 $stageStartTime,
                 $stageEndTime,
+                $disasterInfo,
             ];
         }
 
@@ -347,6 +404,7 @@ class FarmUserSummaryController extends AdminController
         try {
             $stageNames = GROWTH_STAGE::getAll();
             $stageValue = $stage->value;
+
             return $stageNames[$stageValue] ?? "阶段{$stageValue}";
         } catch (\Throwable) {
             return "错误阶段";
@@ -435,12 +493,65 @@ class FarmUserSummaryController extends AdminController
         try {
             $typeNames = ITEM_TYPE::getValueDescription();
             $typeValue = $type->value;
+
             return $typeNames[$typeValue] ?? "类型{$typeValue}";
         } catch (\Throwable) {
             return "错误类型";
         }
     }
 
+    /**
+     * 格式化灾害信息
+     *
+     * @param array $disasters 灾害数组
+     * @return string 格式化后的灾害信息
+     */
+    protected function formatDisasterInfo(array $disasters): string
+    {
+        if (empty($disasters)) {
+            return '无';
+        }
+
+        $result = [];
+
+        foreach ($disasters as $disaster) {
+            $type   = $disaster['type'] ?? 0;
+            $status = $disaster['status'] ?? 'inactive';
+
+            // 获取灾害类型名称
+            $typeName = DISASTER_TYPE::getName($type);
+
+            // 灾害状态
+            $statusText = $status === 'active' ? '<span class="badge badge-danger">活跃</span>' : '<span class="badge badge-secondary">已处理</span>';
+
+            // 灾害开始时间
+            $startTime = isset($disaster['start_time']) ? date('Y-m-d H:i:s', $disaster['start_time']) : '未知';
+
+            // 灾害结束时间(如果有)
+            $endTime = '';
+            if (isset($disaster['end_time']) && $disaster['end_time'] > 0) {
+                $endTime = date('Y-m-d H:i:s', $disaster['end_time']);
+            }
+
+            // 减产比例
+            $penalty = isset($disaster['penalty']) ? ($disaster['penalty'] * 100) . '%' : '5%';
+
+            // 组合灾害信息
+            $disasterInfo = "<div><strong>{$typeName}</strong>: {$statusText}</div>";
+            $disasterInfo .= "<div>开始: {$startTime}</div>";
+
+            if ($endTime) {
+                $disasterInfo .= "<div>结束: {$endTime}</div>";
+            }
+
+            $disasterInfo .= "<div>减产: {$penalty}</div>";
+
+            $result[] = $disasterInfo;
+        }
+
+        return implode('<hr style="margin: 5px 0;">', $result);
+    }
+
     /**
      * 代币信息卡片
      *
@@ -466,8 +577,8 @@ class FarmUserSummaryController extends AdminController
         foreach ($funds as $fund) {
             try {
                 $fundIdValue = $fund->fund_id->value();
-                $fundName = $fundNames[$fundIdValue] ?? "账户{$fundIdValue}";
-                $balance = $fund->balance;
+                $fundName    = $fundNames[$fundIdValue] ?? "账户{$fundIdValue}";
+                $balance     = $fund->balance;
 
                 $rows[] = [
                     $fundIdValue,