Forráskód Böngészése

fix(farm): 修复作物种植、收获及相关操作的日志记录- 优化了日志记录的格式,统一了键值对的命名规范
- 添加了REWARD_SOURCE_TYPE的引用,用于物品来源标识
- 调整了部分变量命名,提高了代码可读性
- 修复了一些潜在的错误处理问题

notfff 6 hónapja
szülő
commit
5010372aa5

+ 152 - 148
app/Module/Farm/Logics/CropLogic.php

@@ -17,6 +17,7 @@ use App\Module\Farm\Models\FarmLand;
 use App\Module\Farm\Models\FarmSeed;
 use App\Module\Farm\Models\FarmSeedOutput;
 use App\Module\Farm\Models\FarmSowLog;
+use App\Module\Game\Enums\REWARD_SOURCE_TYPE;
 use App\Module\GameItems\Services\ItemService;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
@@ -28,6 +29,7 @@ use UCore\Dto\Res;
  */
 class CropLogic
 {
+
     /**
      * 获取作物信息
      *
@@ -47,8 +49,8 @@ class CropLogic
         } catch (\Exception $e) {
             Log::error('获取作物信息失败', [
                 'crop_id' => $cropId,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
 
             return null;
@@ -74,8 +76,8 @@ class CropLogic
         } catch (\Exception $e) {
             Log::error('获取土地作物信息失败', [
                 'land_id' => $landId,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
 
             return null;
@@ -121,26 +123,26 @@ class CropLogic
             $seedId = $seed->id;
 
             // 创建作物记录
-            $crop = new FarmCrop();
-            $crop->land_id = $landId;
-            $crop->user_id = $userId;
-            $crop->seed_id = $seedId;
-            $crop->plant_time = now();
-            $crop->growth_stage = GROWTH_STAGE::SEED->value;
-            $crop->stage_start_time = now(); // 设置当前阶段开始时间
-            $crop->stage_end_time = now()->addSeconds($seed->seed_time);
-            $crop->disasters = [];
-            $crop->fertilized = false;
-            $crop->last_disaster_check_time = null; // 初始化灾害检查时间
-            $crop->can_disaster = false; // 种子期不能产生灾害
+            $crop                           = new FarmCrop();
+            $crop->land_id                  = $landId;
+            $crop->user_id                  = $userId;
+            $crop->seed_id                  = $seedId;
+            $crop->plant_time               = now();
+            $crop->growth_stage             = GROWTH_STAGE::SEED->value;
+            $crop->stage_start_time         = now(); // 设置当前阶段开始时间
+            $crop->stage_end_time           = now()->addSeconds($seed->seed_time);
+            $crop->disasters                = [];
+            $crop->fertilized               = false;
+            $crop->last_disaster_check_time = null;  // 初始化灾害检查时间
+            $crop->can_disaster             = false; // 种子期不能产生灾害
             $crop->save();
 
             // 创建种植日志
-            $sowLog = new FarmSowLog();
-            $sowLog->user_id = $userId;
-            $sowLog->land_id = $landId;
-            $sowLog->crop_id = $crop->id;
-            $sowLog->seed_id = $seedId;
+            $sowLog           = new FarmSowLog();
+            $sowLog->user_id  = $userId;
+            $sowLog->land_id  = $landId;
+            $sowLog->crop_id  = $crop->id;
+            $sowLog->seed_id  = $seedId;
             $sowLog->sow_time = now();
             $sowLog->save();
 
@@ -153,15 +155,15 @@ class CropLogic
             event(new CropPlantedEvent($userId, $land, $crop));
 
             Log::info('作物种植成功', [
-                'user_id' => $userId,
-                'land_id' => $landId,
-                'seed_id' => $seedId,
-                'crop_id' => $crop->id,
+                'user_id'    => $userId,
+                'land_id'    => $landId,
+                'seed_id'    => $seedId,
+                'crop_id'    => $crop->id,
                 'sow_log_id' => $sowLog->id
             ]);
 
             return [
-                'crop' => CropInfoDto::fromModel($crop),
+                'crop'   => CropInfoDto::fromModel($crop),
                 'log_id' => $sowLog->id
             ];
         } catch (\Exception $e) {
@@ -172,8 +174,8 @@ class CropLogic
                 'user_id' => $userId,
                 'land_id' => $landId,
                 'seed_id' => $seedId,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
 
             return null;
@@ -234,44 +236,44 @@ class CropLogic
             if ($crop->final_output_item_id) {
                 $outputItemId = $crop->final_output_item_id;
                 // 获取对应的产出配置来确定数量范围
-                $outputInfo = $this->getOutputInfoByItemId($seed->id, $outputItemId);
+                $outputInfo   = $this->getOutputInfoByItemId($seed->id, $outputItemId);
                 $outputAmount = mt_rand($outputInfo['min_amount'], $outputInfo['max_amount']);
 
                 Log::info('使用发芽期确定的最终产出果实', [
-                    'crop_id' => $crop->id,
+                    'crop_id'              => $crop->id,
                     'final_output_item_id' => $outputItemId,
-                    'output_amount' => $outputAmount
+                    'output_amount'        => $outputAmount
                 ]);
             } else {
                 // 兼容旧数据:如果没有预设的最终产出果实ID,则随机选择
-                $outputInfo = $this->getRandomOutput($seed->id);
+                $outputInfo   = $this->getRandomOutput($seed->id);
                 $outputItemId = $outputInfo['item_id'];
                 $outputAmount = mt_rand($outputInfo['min_amount'], $outputInfo['max_amount']);
 
                 Log::warning('作物没有预设最终产出果实ID,使用随机选择', [
-                    'crop_id' => $crop->id,
-                    'seed_id' => $seed->id,
+                    'crop_id'               => $crop->id,
+                    'seed_id'               => $seed->id,
                     'random_output_item_id' => $outputItemId
                 ]);
             }
 
             // 创建收获记录
-            $harvestLog = new FarmHarvestLog();
-            $harvestLog->user_id = $userId;
-            $harvestLog->land_id = $landId;
-            $harvestLog->crop_id = $crop->id;
-            $harvestLog->seed_id = $seed->id;
+            $harvestLog                = new FarmHarvestLog();
+            $harvestLog->user_id       = $userId;
+            $harvestLog->land_id       = $landId;
+            $harvestLog->crop_id       = $crop->id;
+            $harvestLog->seed_id       = $seed->id;
             $harvestLog->output_amount = $outputAmount;
-            $harvestLog->harvest_time = now();
-            $harvestLog->created_at = now();
+            $harvestLog->harvest_time  = now();
+            $harvestLog->created_at    = now();
             $harvestLog->save();
 
             // 收获后作物进入枯萎期,而不是直接删除
-            $oldStage = $crop->growth_stage;
-            $crop->growth_stage = GROWTH_STAGE::WITHERED;
+            $oldStage               = $crop->growth_stage;
+            $crop->growth_stage     = GROWTH_STAGE::WITHERED;
             $crop->stage_start_time = now();
-            $crop->stage_end_time = null; // 枯萎期没有结束时间
-            $crop->fertilized = false; // 重置施肥状态
+            $crop->stage_end_time   = null;  // 枯萎期没有结束时间
+            $crop->fertilized       = false; // 重置施肥状态
             $crop->save();
 
             // 更新土地状态为枯萎状态
@@ -283,27 +285,27 @@ class CropLogic
             event(new CropGrowthStageChangedEvent($userId, $crop, $oldStage->value, GROWTH_STAGE::WITHERED->value));
 
 
-
-
             // 触发作物收获事件
             event(new CropHarvestedEvent($userId, $land, $crop, $harvestLog, $outputItemId, $outputAmount));
 
             Log::info('作物收获成功,进入枯萎期', [
-                'user_id' => $userId,
-                'land_id' => $landId,
-                'crop_id' => $crop->id,
-                'seed_id' => $seed->id,
+                'user_id'        => $userId,
+                'land_id'        => $landId,
+                'crop_id'        => $crop->id,
+                'seed_id'        => $seed->id,
                 'output_item_id' => $outputItemId,
-                'output_amount' => $outputAmount,
+                'output_amount'  => $outputAmount,
                 'harvest_log_id' => $harvestLog->id,
-                'old_stage' => $oldStage->value,
-                'new_stage' => GROWTH_STAGE::WITHERED->value,
-                'land_status' => LAND_STATUS::WITHERED->value
+                'old_stage'      => $oldStage->value,
+                'new_stage'      => GROWTH_STAGE::WITHERED->value,
+                'land_status'    => LAND_STATUS::WITHERED->value
             ]);
             // 物品入包
-            ItemService::addItem($userId, $outputItemId, $outputAmount,[
-                'source'=>'FarmHarve',
-                'FarmHarvestLog'=>$harvestLog->id
+            ItemService::addItem($userId, $outputItemId, $outputAmount, [
+                'source'         => REWARD_SOURCE_TYPE::FARM_HARVEST,
+                'source_type'    => REWARD_SOURCE_TYPE::FARM_HARVEST,
+                'source_id'      => $harvestLog->id,
+                'FarmHarvestLog' => $harvestLog->id
             ]);
 
 
@@ -315,8 +317,8 @@ class CropLogic
             Log::error('作物收获失败', [
                 'user_id' => $userId,
                 'land_id' => $landId,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
 
             return Res::error('');
@@ -355,30 +357,30 @@ class CropLogic
 
             // 根据 cropGrowthTime 参数减少当前阶段时间
             if ($crop->stage_end_time) {
-                $currentTime = now();
-                $endTime = $crop->stage_end_time;
+                $currentTime   = now();
+                $endTime       = $crop->stage_end_time;
                 $remainingTime = $currentTime->diffInSeconds($endTime, false);
 
                 if ($remainingTime > 0) {
                     // 确保减少的时间不超过剩余时间
                     $reducedTime = min($cropGrowthTime, $remainingTime);
                     // 使用copy()方法创建副本,避免修改原始对象
-                    $newEndTime = $endTime->copy()->subSeconds($reducedTime);
+                    $newEndTime           = $endTime->copy()->subSeconds($reducedTime);
                     $crop->stage_end_time = $newEndTime;
 
                     Log::info('化肥减少生长时间', [
-                        'crop_id' => $crop->id,
-                        'reduced_time' => $reducedTime,
+                        'crop_id'           => $crop->id,
+                        'reduced_time'      => $reducedTime,
                         'original_end_time' => $endTime->format('Y-m-d H:i:s'),
-                        'new_end_time' => $crop->stage_end_time->format('Y-m-d H:i:s'),
-                        'stage_start_time' => $crop->stage_start_time ? $crop->stage_start_time->format('Y-m-d H:i:s') : null
+                        'new_end_time'      => $crop->stage_end_time->format('Y-m-d H:i:s'),
+                        'stage_start_time'  => $crop->stage_start_time ? $crop->stage_start_time->format('Y-m-d H:i:s') : null
                     ]);
                     event(new CropGrowthStageChangedEvent($crop->user_id, $crop, $crop->growth_stage->value, $crop->growth_stage->value));
 
                 } else {
                     Log::warning('作物已经到达或超过结束时间,无法减少生长时间', [
-                        'crop_id' => $crop->id,
-                        'current_time' => $currentTime->format('Y-m-d H:i:s'),
+                        'crop_id'        => $crop->id,
+                        'current_time'   => $currentTime->format('Y-m-d H:i:s'),
                         'stage_end_time' => $endTime->format('Y-m-d H:i:s'),
                         'remaining_time' => $remainingTime
                     ]);
@@ -388,10 +390,10 @@ class CropLogic
             $crop->save();
 
             Log::info('使用化肥成功', [
-                'crop_id' => $crop->id,
-                'user_id' => $crop->user_id,
-                'land_id' => $crop->land_id,
-                'growth_stage' => $crop->growth_stage,
+                'crop_id'        => $crop->id,
+                'user_id'        => $crop->user_id,
+                'land_id'        => $crop->land_id,
+                'growth_stage'   => $crop->growth_stage,
                 'stage_end_time' => $crop->stage_end_time
             ]);
 
@@ -400,10 +402,10 @@ class CropLogic
             ]);
         } catch (\Exception $e) {
             Log::error('使用化肥失败', [
-                'crop_id' => $cropId,
+                'crop_id'          => $cropId,
                 'crop_growth_time' => $cropGrowthTime,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'            => $e->getMessage(),
+                'trace'            => $e->getTraceAsString()
             ]);
 
             return Res::error('使用化肥失败');
@@ -466,28 +468,28 @@ class CropLogic
 
             // 根据 crop_growth_time 参数减少当前阶段时间
             if ($crop->stage_end_time) {
-                $currentTime = now();
-                $endTime = $crop->stage_end_time;
+                $currentTime   = now();
+                $endTime       = $crop->stage_end_time;
                 $remainingTime = $currentTime->diffInSeconds($endTime, false);
 
                 if ($remainingTime > 0) {
                     // 确保减少的时间不超过剩余时间
                     $reducedTime = min($crop_growth_time, $remainingTime);
                     // 使用copy()方法创建副本,避免修改原始对象
-                    $newEndTime = $endTime->copy()->subSeconds($reducedTime);
+                    $newEndTime           = $endTime->copy()->subSeconds($reducedTime);
                     $crop->stage_end_time = $newEndTime;
 
                     Log::info('化肥减少生长时间', [
-                        'crop_id' => $crop->id,
-                        'reduced_time' => $reducedTime,
+                        'crop_id'           => $crop->id,
+                        'reduced_time'      => $reducedTime,
                         'original_end_time' => $endTime->toDateTimeString(),
-                        'new_end_time' => $crop->stage_end_time->toDateTimeString(),
-                        'stage_start_time' => $crop->stage_start_time->toDateTimeString()
+                        'new_end_time'      => $crop->stage_end_time->toDateTimeString(),
+                        'stage_start_time'  => $crop->stage_start_time->toDateTimeString()
                     ]);
                 } else {
                     Log::warning('作物已经到达或超过结束时间,无法减少生长时间', [
-                        'crop_id' => $crop->id,
-                        'current_time' => $currentTime->toDateTimeString(),
+                        'crop_id'        => $crop->id,
+                        'current_time'   => $currentTime->toDateTimeString(),
                         'stage_end_time' => $endTime->toDateTimeString(),
                         'remaining_time' => $remainingTime
                     ]);
@@ -497,22 +499,22 @@ class CropLogic
             $crop->save();
 
             Log::info('使用化肥成功', [
-                'user_id' => $userId,
-                'land_id' => $landId,
-                'crop_id' => $crop->id,
-                'growth_stage' => $crop->growth_stage,
+                'user_id'        => $userId,
+                'land_id'        => $landId,
+                'crop_id'        => $crop->id,
+                'growth_stage'   => $crop->growth_stage,
                 'stage_end_time' => $crop->stage_end_time
             ]);
 
-            return Res::success('',[
+            return Res::success('', [
                 'crop_id' => $crop->id,
             ]);
         } catch (\Exception $e) {
             Log::error('使用化肥失败', [
                 'user_id' => $userId,
                 'land_id' => $landId,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
 
             return Res::error('使用化肥失败');
@@ -552,14 +554,14 @@ class CropLogic
             }
 
             // 检查灾害是否存在
-            $disasters = $crop->disasters ?? [];
+            $disasters     = $crop->disasters ?? [];
             $disasterIndex = -1;
-            $disasterInfo = null;
+            $disasterInfo  = null;
 
             foreach ($disasters as $index => $disaster) {
                 if (($disaster['type'] ?? 0) == $disasterType && ($disaster['status'] ?? '') === 'active') {
                     $disasterIndex = $index;
-                    $disasterInfo = $disaster;
+                    $disasterInfo  = $disaster;
                     break;
                 }
             }
@@ -569,9 +571,9 @@ class CropLogic
             }
 
             // 更新灾害状态
-            $disasters[$disasterIndex]['status'] = 'cleared';
+            $disasters[$disasterIndex]['status']     = 'cleared';
             $disasters[$disasterIndex]['cleared_at'] = now()->toDateTimeString();
-            $crop->disasters = $disasters;
+            $crop->disasters                         = $disasters;
 
             // 检查是否还有其他活跃灾害
             $hasActiveDisaster = false;
@@ -603,20 +605,20 @@ class CropLogic
             event(new DisasterClearedEvent($userId, $crop, $disasterType, $disasterInfo));
 
             Log::info('灾害清理成功', [
-                'user_id' => $userId,
-                'land_id' => $landId,
-                'crop_id' => $crop->id,
+                'user_id'       => $userId,
+                'land_id'       => $landId,
+                'crop_id'       => $crop->id,
                 'disaster_type' => $disasterType
             ]);
 
             return true;
         } catch (\Exception $e) {
             Log::error('灾害清理失败', [
-                'user_id' => $userId,
-                'land_id' => $landId,
+                'user_id'       => $userId,
+                'land_id'       => $landId,
                 'disaster_type' => $disasterType,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'         => $e->getMessage(),
+                'trace'         => $e->getTraceAsString()
             ]);
 
             return false;
@@ -656,14 +658,14 @@ class CropLogic
             if (!$crop) {
                 // 如果没有作物但土地状态不是空闲,修正土地状态
                 $oldLandStatus = $land->status;
-                $land->status = LAND_STATUS::IDLE->value;
+                $land->status  = LAND_STATUS::IDLE->value;
                 $land->updateHasCrop();
                 $land->save();
 
                 // 记录状态变更信息,由调用方处理事件触发
                 Log::info('土地状态已修正', [
-                    'user_id' => $userId,
-                    'land_id' => $landId,
+                    'user_id'    => $userId,
+                    'land_id'    => $landId,
                     'old_status' => $oldLandStatus,
                     'new_status' => $land->status
                 ]);
@@ -685,9 +687,9 @@ class CropLogic
             // 记录状态变更信息,由调用方处理事件触发和事务提交
 
             Log::info('铲除作物成功', [
-                'user_id' => $userId,
-                'land_id' => $landId,
-                'crop_id' => $crop->id,
+                'user_id'    => $userId,
+                'land_id'    => $landId,
+                'crop_id'    => $crop->id,
                 'old_status' => $oldLandStatus,
                 'new_status' => $land->status
             ]);
@@ -697,8 +699,8 @@ class CropLogic
             Log::error('铲除作物失败', [
                 'user_id' => $userId,
                 'land_id' => $landId,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
 
             throw $e; // 重新抛出异常,由调用方处理事务回滚
@@ -741,10 +743,10 @@ class CropLogic
             $stageEndTime = $this->calculateStageEndTime($crop, $newStage);
 
             // 更新作物信息
-            $crop->growth_stage = $newStage;
+            $crop->growth_stage     = $newStage;
             $crop->stage_start_time = now(); // 设置新阶段的开始时间
-            $crop->stage_end_time = $stageEndTime;
-            $crop->fertilized = false; // 重置施肥状态
+            $crop->stage_end_time   = $stageEndTime;
+            $crop->fertilized       = false; // 重置施肥状态
 
             // 如果进入发芽期,必须确定最终产出果实ID
             if ($newStage === GROWTH_STAGE::SPROUT->value) {
@@ -753,28 +755,28 @@ class CropLogic
 
                     // 如果是神秘种子,使用土地影响逻辑
                     if ($seed && $seed->type == \App\Module\Farm\Enums\SEED_TYPE::MYSTERIOUS->value) {
-                        $land = $crop->land;
-                        $mysteryLogic = new \App\Module\Farm\Logics\MysterySeeLLogic();
+                        $land           = $crop->land;
+                        $mysteryLogic   = new \App\Module\Farm\Logics\MysterySeeLLogic();
                         $selectedOutput = $mysteryLogic->selectFinalOutput($seed->id, $land->land_type);
 
                         $crop->final_output_item_id = $selectedOutput['item_id'];
 
                         Log::info('神秘种子确定最终产出(基于土地影响)', [
-                            'crop_id' => $crop->id,
-                            'user_id' => $crop->user_id,
-                            'seed_id' => $seed->id,
-                            'land_type' => $land->land_type,
+                            'crop_id'              => $crop->id,
+                            'user_id'              => $crop->user_id,
+                            'seed_id'              => $seed->id,
+                            'land_type'            => $land->land_type,
                             'final_output_item_id' => $selectedOutput['item_id']
                         ]);
                     } else {
                         // 普通种子使用原有逻辑
-                        $outputInfo = $this->getRandomOutput($crop->seed_id);
+                        $outputInfo                 = $this->getRandomOutput($crop->seed_id);
                         $crop->final_output_item_id = $outputInfo['item_id'];
 
                         Log::info('作物进入发芽期,确定最终产出果实', [
-                            'crop_id' => $crop->id,
-                            'user_id' => $crop->user_id,
-                            'seed_id' => $crop->seed_id,
+                            'crop_id'              => $crop->id,
+                            'user_id'              => $crop->user_id,
+                            'seed_id'              => $crop->seed_id,
                             'final_output_item_id' => $crop->final_output_item_id
                         ]);
                     }
@@ -784,11 +786,11 @@ class CropLogic
             // 验证:如果进入成熟期但没有final_output_item_id,这是一个严重错误
             if ($newStage === GROWTH_STAGE::MATURE->value && !$crop->final_output_item_id) {
                 Log::error('严重错误:作物进入成熟期但没有确定最终产出果实ID', [
-                    'crop_id' => $crop->id,
-                    'user_id' => $crop->user_id,
-                    'seed_id' => $crop->seed_id,
+                    'crop_id'       => $crop->id,
+                    'user_id'       => $crop->user_id,
+                    'seed_id'       => $crop->seed_id,
                     'current_stage' => $oldStage,
-                    'new_stage' => $newStage
+                    'new_stage'     => $newStage
                 ]);
 
                 throw new \Exception("作物ID {$crop->id} 进入成熟期但没有确定最终产出果实ID,这是系统错误");
@@ -805,8 +807,8 @@ class CropLogic
                     $land->save();
 
                     Log::info('作物进入枯萎期,更新土地状态', [
-                        'crop_id' => $crop->id,
-                        'land_id' => $land->id,
+                        'crop_id'     => $crop->id,
+                        'land_id'     => $land->id,
                         'land_status' => LAND_STATUS::WITHERED->value
                     ]);
                 }
@@ -816,10 +818,10 @@ class CropLogic
             event(new CropGrowthStageChangedEvent($crop->user_id, $crop, $oldStage->value, $newStage));
 
             Log::info('作物生长阶段更新成功', [
-                'crop_id' => $cropId,
-                'user_id' => $crop->user_id,
-                'old_stage' => $oldStage,
-                'new_stage' => $newStage,
+                'crop_id'        => $cropId,
+                'user_id'        => $crop->user_id,
+                'old_stage'      => $oldStage,
+                'new_stage'      => $newStage,
                 'stage_end_time' => $stageEndTime
             ]);
 
@@ -827,8 +829,8 @@ class CropLogic
         } catch (\Exception $e) {
             Log::error('作物生长阶段更新失败', [
                 'crop_id' => $cropId,
-                'error' => $e->getMessage(),
-                'trace' => $e->getTraceAsString()
+                'error'   => $e->getMessage(),
+                'trace'   => $e->getTraceAsString()
             ]);
 
             return false;
@@ -859,15 +861,16 @@ class CropLogic
 
         // 使用阶段映射确定下一个阶段
         $stageMap = [
-            GROWTH_STAGE::SEED->value => GROWTH_STAGE::SPROUT->value,
-            GROWTH_STAGE::SPROUT->value => GROWTH_STAGE::GROWTH->value,
-            GROWTH_STAGE::GROWTH->value => GROWTH_STAGE::MATURE->value,
-            GROWTH_STAGE::MATURE->value => GROWTH_STAGE::WITHERED->value,
+            GROWTH_STAGE::SEED->value     => GROWTH_STAGE::SPROUT->value,
+            GROWTH_STAGE::SPROUT->value   => GROWTH_STAGE::GROWTH->value,
+            GROWTH_STAGE::GROWTH->value   => GROWTH_STAGE::MATURE->value,
+            GROWTH_STAGE::MATURE->value   => GROWTH_STAGE::WITHERED->value,
             GROWTH_STAGE::WITHERED->value => GROWTH_STAGE::WITHERED->value, // 枯萎期保持不变
         ];
 
         // 确保返回整数值
         $currentStageValue = is_object($currentStage) ? $currentStage->value : $currentStage;
+
         return $stageMap[$currentStageValue] ?? GROWTH_STAGE::WITHERED->value;
     }
 
@@ -928,7 +931,7 @@ class CropLogic
             $seed = FarmSeed::find($seedId);
 
             return [
-                'item_id' => $seed->item_id,
+                'item_id'    => $seed->item_id,
                 'min_amount' => $seed->min_output,
                 'max_amount' => $seed->max_output,
             ];
@@ -941,7 +944,7 @@ class CropLogic
         $defaultOutput = $outputs->firstWhere('is_default', true);
 
         // 随机选择产出
-        $random = mt_rand(1, 100);
+        $random                = mt_rand(1, 100);
         $cumulativeProbability = 0;
 
         foreach ($outputs as $output) {
@@ -949,7 +952,7 @@ class CropLogic
 
             if ($random <= $cumulativeProbability) {
                 return [
-                    'item_id' => $output->item_id,
+                    'item_id'    => $output->item_id,
                     'min_amount' => $output->min_amount,
                     'max_amount' => $output->max_amount,
                 ];
@@ -959,7 +962,7 @@ class CropLogic
         // 如果随机值超过了所有概率之和,使用默认产出
         if ($defaultOutput) {
             return [
-                'item_id' => $defaultOutput->item_id,
+                'item_id'    => $defaultOutput->item_id,
                 'min_amount' => $defaultOutput->min_amount,
                 'max_amount' => $defaultOutput->max_amount,
             ];
@@ -969,7 +972,7 @@ class CropLogic
         $firstOutput = $outputs->first();
 
         return [
-            'item_id' => $firstOutput->item_id,
+            'item_id'    => $firstOutput->item_id,
             'min_amount' => $firstOutput->min_amount,
             'max_amount' => $firstOutput->max_amount,
         ];
@@ -992,7 +995,7 @@ class CropLogic
 
         if ($targetOutput) {
             return [
-                'item_id' => $targetOutput->item_id,
+                'item_id'    => $targetOutput->item_id,
                 'min_amount' => $targetOutput->min_amount,
                 'max_amount' => $targetOutput->max_amount,
             ];
@@ -1002,9 +1005,10 @@ class CropLogic
         $seed = FarmSeed::find($seedId);
 
         return [
-            'item_id' => $itemId, // 使用传入的物品ID
+            'item_id'    => $itemId, // 使用传入的物品ID
             'min_amount' => $seed->min_output,
             'max_amount' => $seed->max_output,
         ];
     }
+
 }

+ 229 - 248
app/Module/Game/Enums/REWARD_SOURCE_TYPE.php

@@ -10,6 +10,7 @@ use UCore\Enum\EnumToString;
  */
 enum REWARD_SOURCE_TYPE: string
 {
+
     use EnumCore, EnumToString;
 
 
@@ -47,6 +48,10 @@ enum REWARD_SOURCE_TYPE: string
      */
     case CRAFT = 'craft';
 
+    /**
+     * 分解
+     */
+    case DISMANTLE = 'dismantle';
 
     // ==================== 农场系统 ====================
 
@@ -149,6 +154,11 @@ enum REWARD_SOURCE_TYPE: string
      */
     case URSPROMOTION_LEVEL = 'urs_promotion_level';
 
+    /**
+     * 推广奖励-种植
+     */
+    case URSPROMOTION_HAVEST = 'urs_promotion_harvest';
+
     // ==================== 竞技系统 ====================
 
     /**
@@ -210,7 +220,15 @@ enum REWARD_SOURCE_TYPE: string
      */
     case DEBUG = 'debug';
 
+    /**
+     * Mex购买
+     */
+    case MEX_BUY = 'mex_buy';
 
+    /**
+     * Mex卖出
+     */
+    case MEX_SELL = 'mex_sell';
     /**
      * 获取奖励来源类型名称
      *
@@ -243,345 +261,308 @@ enum REWARD_SOURCE_TYPE: string
     {
         $descriptions = [
             // 核心游戏玩法
-            self::TASK->value => [
-                'name' => '任务',
+            self::TASK->value                     => [
+                'name'        => '任务',
                 'description' => '完成任务获得的奖励',
-                'category' => 'gameplay',
-                'admin_link' => '/admin/tasks',
-                'icon' => '📋',
-                'priority' => 1
+                'category'    => 'gameplay',
+                'admin_link'  => '/admin/tasks',
+                'icon'        => '📋',
+                'priority'    => 1
             ],
-            self::ACTIVITY->value => [
-                'name' => '活动',
+            self::ACTIVITY->value                 => [
+                'name'        => '活动',
                 'description' => '参与活动获得的奖励',
-                'category' => 'event',
-                'admin_link' => '/admin/activities',
-                'icon' => '🎉',
-                'priority' => 2
+                'category'    => 'event',
+                'admin_link'  => '/admin/activities',
+                'icon'        => '🎉',
+                'priority'    => 2
             ],
-            self::ACHIEVEMENT->value => [
-                'name' => '成就',
+            self::ACHIEVEMENT->value              => [
+                'name'        => '成就',
                 'description' => '达成成就获得的奖励',
-                'category' => 'achievement',
-                'admin_link' => '/admin/achievements',
-                'icon' => '🏆',
-                'priority' => 3
+                'category'    => 'achievement',
+                'admin_link'  => '/admin/achievements',
+                'icon'        => '🏆',
+                'priority'    => 3
             ],
-            self::LEVEL->value => [
-                'name' => '等级',
+            self::LEVEL->value                    => [
+                'name'        => '等级',
                 'description' => '等级提升获得的奖励',
-                'category' => 'progression',
-                'admin_link' => '/admin/levels',
-                'icon' => '⬆️',
-                'priority' => 4
+                'category'    => 'progression',
+                'admin_link'  => '/admin/levels',
+                'icon'        => '⬆️',
+                'priority'    => 4
             ],
-            self::CHEST->value => [
-                'name' => '宝箱',
+            self::CHEST->value                    => [
+                'name'        => '宝箱',
                 'description' => '开启宝箱获得的奖励',
-                'category' => 'gameplay',
-                'admin_link' => '/admin/chests',
-                'icon' => '📦',
-                'priority' => 5
+                'category'    => 'gameplay',
+                'admin_link'  => '/admin/chests',
+                'icon'        => '📦',
+                'priority'    => 5
             ],
-            self::CRAFT->value => [
-                'name' => '合成',
+            self::CRAFT->value                    => [
+                'name'        => '合成',
                 'description' => '合成物品获得的奖励',
-                'category' => 'gameplay',
-                'admin_link' => '/admin/craft',
-                'icon' => '🔨',
-                'priority' => 6
+                'category'    => 'gameplay',
+                'admin_link'  => '/admin/craft',
+                'icon'        => '🔨',
+                'priority'    => 6
             ],
 
             // 农场系统
-            self::FARM_INIT->value => [
-                'name' => '农场初始化',
+            self::FARM_INIT->value                => [
+                'name'        => '农场初始化',
                 'description' => '农场初始化时获得的奖励',
-                'category' => 'farm',
-                'admin_link' => '/admin/farm',
-                'icon' => '🌱',
-                'priority' => 10
+                'category'    => 'farm',
+                'admin_link'  => '/admin/farm',
+                'icon'        => '🌱',
+                'priority'    => 10
             ],
-            self::FARM_HARVEST->value => [
-                'name' => '农场收获',
+            self::FARM_HARVEST->value             => [
+                'name'        => '农场收获',
                 'description' => '农场收获时获得的奖励',
-                'category' => 'farm',
-                'admin_link' => '/admin/farm',
-                'icon' => '🌾',
-                'priority' => 11
+                'category'    => 'farm',
+                'admin_link'  => '/admin/farm',
+                'icon'        => '🌾',
+                'priority'    => 11
             ],
-            self::FARM_PLANT->value => [
-                'name' => '农场种植',
+            self::FARM_PLANT->value               => [
+                'name'        => '农场种植',
                 'description' => '农场种植时获得的奖励',
-                'category' => 'farm',
-                'admin_link' => '/admin/farm',
-                'icon' => '🌿',
-                'priority' => 12
+                'category'    => 'farm',
+                'admin_link'  => '/admin/farm',
+                'icon'        => '🌿',
+                'priority'    => 12
             ],
-            self::FARM_UPGRADE->value => [
-                'name' => '农场升级',
+            self::FARM_UPGRADE->value             => [
+                'name'        => '农场升级',
                 'description' => '农场升级时获得的奖励',
-                'category' => 'farm',
-                'admin_link' => '/admin/farm',
-                'icon' => '🏡',
-                'priority' => 13
+                'category'    => 'farm',
+                'admin_link'  => '/admin/farm',
+                'icon'        => '🏡',
+                'priority'    => 13
             ],
-            self::LAND_REMOVE_CROP->value => [
-                'name' => '土地清理',
+            self::LAND_REMOVE_CROP->value         => [
+                'name'        => '土地清理',
                 'description' => '清理土地作物获得的奖励',
-                'category' => 'farm',
-                'admin_link' => '/admin/farm',
-                'icon' => '🧹',
-                'priority' => 14
+                'category'    => 'farm',
+                'admin_link'  => '/admin/farm',
+                'icon'        => '🧹',
+                'priority'    => 14
             ],
-            self::LAND_UNLOCK->value => [
-                'name' => '土地解锁',
+            self::LAND_UNLOCK->value              => [
+                'name'        => '土地解锁',
                 'description' => '解锁新土地获得的奖励',
-                'category' => 'farm',
-                'admin_link' => '/admin/farm',
-                'icon' => '🔓',
-                'priority' => 15
+                'category'    => 'farm',
+                'admin_link'  => '/admin/farm',
+                'icon'        => '🔓',
+                'priority'    => 15
             ],
 
             // 每日系统
-            self::SIGN_IN->value => [
-                'name' => '签到',
+            self::SIGN_IN->value                  => [
+                'name'        => '签到',
                 'description' => '每日签到获得的奖励',
-                'category' => 'daily',
-                'admin_link' => '/admin/sign-in',
-                'icon' => '✅',
-                'priority' => 20
+                'category'    => 'daily',
+                'admin_link'  => '/admin/sign-in',
+                'icon'        => '✅',
+                'priority'    => 20
             ],
-            self::DAILY_LOGIN->value => [
-                'name' => '每日登录',
+            self::DAILY_LOGIN->value              => [
+                'name'        => '每日登录',
                 'description' => '每日登录获得的奖励',
-                'category' => 'daily',
-                'admin_link' => '/admin/daily-login',
-                'icon' => '🌅',
-                'priority' => 21
+                'category'    => 'daily',
+                'admin_link'  => '/admin/daily-login',
+                'icon'        => '🌅',
+                'priority'    => 21
             ],
-            self::DAILY_TASK->value => [
-                'name' => '每日任务',
+            self::DAILY_TASK->value               => [
+                'name'        => '每日任务',
                 'description' => '完成每日任务获得的奖励',
-                'category' => 'daily',
-                'admin_link' => '/admin/daily-tasks',
-                'icon' => '📅',
-                'priority' => 22
+                'category'    => 'daily',
+                'admin_link'  => '/admin/daily-tasks',
+                'icon'        => '📅',
+                'priority'    => 22
             ],
 
             // 社交系统
-            self::INVITE_FRIEND->value => [
-                'name' => '邀请好友',
+            self::INVITE_FRIEND->value            => [
+                'name'        => '邀请好友',
                 'description' => '邀请好友获得的奖励',
-                'category' => 'social',
-                'admin_link' => '/admin/invite',
-                'icon' => '👥',
-                'priority' => 30
+                'category'    => 'social',
+                'admin_link'  => '/admin/invite',
+                'icon'        => '👥',
+                'priority'    => 30
             ],
-            self::FRIEND_INTERACTION->value => [
-                'name' => '好友互动',
+            self::FRIEND_INTERACTION->value       => [
+                'name'        => '好友互动',
                 'description' => '与好友互动获得的奖励',
-                'category' => 'social',
-                'admin_link' => '/admin/friends',
-                'icon' => '🤝',
-                'priority' => 31
+                'category'    => 'social',
+                'admin_link'  => '/admin/friends',
+                'icon'        => '🤝',
+                'priority'    => 31
             ],
-            self::TEAM_ACTIVITY->value => [
-                'name' => '团队活动',
+            self::TEAM_ACTIVITY->value            => [
+                'name'        => '团队活动',
                 'description' => '参与团队活动获得的奖励',
-                'category' => 'social',
-                'admin_link' => '/admin/teams',
-                'icon' => '👨‍👩‍👧‍👦',
-                'priority' => 32
+                'category'    => 'social',
+                'admin_link'  => '/admin/teams',
+                'icon'        => '👨‍👩‍👧‍👦',
+                'priority'    => 32
             ],
 
             // 商店系统
-            self::SHOP_PURCHASE->value => [
-                'name' => '商店购买',
+            self::SHOP_PURCHASE->value            => [
+                'name'        => '商店购买',
                 'description' => '商店购买时获得的奖励',
-                'category' => 'shop',
-                'admin_link' => '/admin/shop',
-                'icon' => '🛒',
-                'priority' => 40
+                'category'    => 'shop',
+                'admin_link'  => '/admin/shop',
+                'icon'        => '🛒',
+                'priority'    => 40
             ],
-            self::SHOP_CHECKIN->value => [
-                'name' => '商店签到',
+            self::SHOP_CHECKIN->value             => [
+                'name'        => '商店签到',
                 'description' => '商店签到获得的奖励',
-                'category' => 'shop',
-                'admin_link' => '/admin/shop',
-                'icon' => '🏪',
-                'priority' => 41
+                'category'    => 'shop',
+                'admin_link'  => '/admin/shop',
+                'icon'        => '🏪',
+                'priority'    => 41
             ],
 
             // 推广系统
-            self::URSPROMOTION_REWARD->value => [
-                'name' => 'URS推广奖励',
+            self::URSPROMOTION_REWARD->value      => [
+                'name'        => 'URS推广奖励',
                 'description' => 'URS推广系统发放的奖励',
-                'category' => 'promotion',
-                'admin_link' => '/admin/urs-promotion',
-                'icon' => '💰',
-                'priority' => 50
+                'category'    => 'promotion',
+                'admin_link'  => '/admin/urs-promotion',
+                'icon'        => '💰',
+                'priority'    => 50
             ],
-            self::URSPROMOTION_REGISTER->value => [
-                'name' => 'URS推广注册测试',
+            self::URSPROMOTION_REGISTER->value    => [
+                'name'        => 'URS推广注册测试',
                 'description' => 'URS推广系统注册测试奖励',
-                'category' => 'promotion',
-                'admin_link' => '/admin/urs-promotion',
-                'icon' => '🧪',
-                'priority' => 51
+                'category'    => 'promotion',
+                'admin_link'  => '/admin/urs-promotion',
+                'icon'        => '🧪',
+                'priority'    => 51
             ],
-            self::URSPROMOTION_LEVEL->value => [
-                'name' => '推广等级',
+            self::URSPROMOTION_LEVEL->value       => [
+                'name'        => '推广等级',
                 'description' => '推广等级提升获得的奖励',
-                'category' => 'promotion',
-                'admin_link' => '/admin/urs-promotion',
-                'icon' => '📈',
-                'priority' => 52
+                'category'    => 'promotion',
+                'admin_link'  => '/admin/urs-promotion',
+                'icon'        => '📈',
+                'priority'    => 52
             ],
 
             // 竞技系统
-            self::LEADERBOARD->value => [
-                'name' => '排行榜',
+            self::LEADERBOARD->value              => [
+                'name'        => '排行榜',
                 'description' => '排行榜排名奖励',
-                'category' => 'competition',
-                'admin_link' => '/admin/leaderboard',
-                'icon' => '🏅',
-                'priority' => 60
+                'category'    => 'competition',
+                'admin_link'  => '/admin/leaderboard',
+                'icon'        => '🏅',
+                'priority'    => 60
             ],
-            self::COMPETITION->value => [
-                'name' => '竞赛',
+            self::COMPETITION->value              => [
+                'name'        => '竞赛',
                 'description' => '参与竞赛获得的奖励',
-                'category' => 'competition',
-                'admin_link' => '/admin/competitions',
-                'icon' => '🏁',
-                'priority' => 61
+                'category'    => 'competition',
+                'admin_link'  => '/admin/competitions',
+                'icon'        => '🏁',
+                'priority'    => 61
             ],
-            self::TOURNAMENT->value => [
-                'name' => '锦标赛',
+            self::TOURNAMENT->value               => [
+                'name'        => '锦标赛',
                 'description' => '锦标赛获得的奖励',
-                'category' => 'competition',
-                'admin_link' => '/admin/tournaments',
-                'icon' => '🏆',
-                'priority' => 62
+                'category'    => 'competition',
+                'admin_link'  => '/admin/tournaments',
+                'icon'        => '🏆',
+                'priority'    => 62
             ],
 
             // 特殊系统
-            self::COMPENSATION->value => [
-                'name' => '补偿',
+            self::COMPENSATION->value             => [
+                'name'        => '补偿',
                 'description' => '系统补偿发放的奖励',
-                'category' => 'special',
-                'admin_link' => '/admin/compensations',
-                'icon' => '💝',
-                'priority' => 70
+                'category'    => 'special',
+                'admin_link'  => '/admin/compensations',
+                'icon'        => '💝',
+                'priority'    => 70
             ],
             self::MAINTENANCE_COMPENSATION->value => [
-                'name' => '维护补偿',
+                'name'        => '维护补偿',
                 'description' => '维护期间的补偿奖励',
-                'category' => 'special',
-                'admin_link' => '/admin/maintenance',
-                'icon' => '🔧',
-                'priority' => 71
+                'category'    => 'special',
+                'admin_link'  => '/admin/maintenance',
+                'icon'        => '🔧',
+                'priority'    => 71
             ],
-            self::FESTIVAL->value => [
-                'name' => '节日',
+            self::FESTIVAL->value                 => [
+                'name'        => '节日',
                 'description' => '节日活动获得的奖励',
-                'category' => 'special',
-                'admin_link' => '/admin/festivals',
-                'icon' => '🎊',
-                'priority' => 72
+                'category'    => 'special',
+                'admin_link'  => '/admin/festivals',
+                'icon'        => '🎊',
+                'priority'    => 72
             ],
-            self::LIMITED_EVENT->value => [
-                'name' => '限时活动',
+            self::LIMITED_EVENT->value            => [
+                'name'        => '限时活动',
                 'description' => '限时活动获得的奖励',
-                'category' => 'special',
-                'admin_link' => '/admin/limited-events',
-                'icon' => '⏰',
-                'priority' => 73
+                'category'    => 'special',
+                'admin_link'  => '/admin/limited-events',
+                'icon'        => '⏰',
+                'priority'    => 73
             ],
 
             // 系统管理
-            self::SYSTEM->value => [
-                'name' => '系统',
+            self::SYSTEM->value                   => [
+                'name'        => '系统',
                 'description' => '系统自动发放的奖励',
-                'category' => 'system',
-                'admin_link' => null,
-                'icon' => '⚙️',
-                'priority' => 90
+                'category'    => 'system',
+                'admin_link'  => null,
+                'icon'        => '⚙️',
+                'priority'    => 90
             ],
-            self::ADMIN_GRANT->value => [
-                'name' => '管理员发放',
+            self::ADMIN_GRANT->value              => [
+                'name'        => '管理员发放',
                 'description' => '管理员手动发放的奖励',
-                'category' => 'system',
-                'admin_link' => '/admin/manual-grants',
-                'icon' => '👨‍💼',
-                'priority' => 91
+                'category'    => 'system',
+                'admin_link'  => '/admin/manual-grants',
+                'icon'        => '👨‍💼',
+                'priority'    => 91
             ],
-            self::TEST->value => [
-                'name' => '测试',
+            self::TEST->value                     => [
+                'name'        => '测试',
                 'description' => '测试用途的奖励',
-                'category' => 'system',
-                'admin_link' => null,
-                'icon' => '🧪',
-                'priority' => 98
+                'category'    => 'system',
+                'admin_link'  => null,
+                'icon'        => '🧪',
+                'priority'    => 98
             ],
-            self::DEBUG->value => [
-                'name' => '调试',
+            self::DEBUG->value                    => [
+                'name'        => '调试',
                 'description' => '调试用途的奖励',
-                'category' => 'system',
-                'admin_link' => null,
-                'icon' => '🐛',
-                'priority' => 99
+                'category'    => 'system',
+                'admin_link'  => null,
+                'icon'        => '🐛',
+                'priority'    => 99
             ],
         ];
 
         return $descriptions[$type] ?? [
-            'name' => '未知',
+            'name'        => '未知',
             'description' => '未知来源类型',
-            'category' => 'unknown',
-            'admin_link' => null,
-            'icon' => '❓',
-            'priority' => 999
+            'category'    => 'unknown',
+            'admin_link'  => null,
+            'icon'        => '❓',
+            'priority'    => 999
         ];
     }
 
-    /**
-     * 根据分类获取奖励来源类型
-     *
-     * @param string $category 分类
-     * @return array
-     */
-    public static function getByCategory(string $category): array
-    {
-        $result = [];
-        foreach (self::getValueDescription() as $value => $name) {
-            $info = self::getTypeInfo($value);
-            if ($info['category'] === $category) {
-                $result[$value] = $name;
-            }
-        }
-        return $result;
-    }
 
-    /**
-     * 获取所有分类
-     *
-     * @return array
-     */
-    public static function getCategories(): array
-    {
-        return [
-            'gameplay' => '游戏玩法',
-            'event' => '活动事件',
-            'daily' => '每日系统',
-            'achievement' => '成就系统',
-            'progression' => '进度系统',
-            'farm' => '农场系统',
-            'social' => '社交系统',
-            'shop' => '商店系统',
-            'promotion' => '推广系统',
-            'competition' => '竞技系统',
-            'special' => '特殊活动',
-            'system' => '系统管理',
-            'unknown' => '未知类型'
-        ];
-    }
+
+
+
 }

+ 236 - 230
app/Module/GameItems/Logics/Item.php

@@ -21,6 +21,7 @@ use UCore\Dto\Res;
  */
 class Item
 {
+
     /**
      * 判断物品是否为宝箱
      *
@@ -81,138 +82,138 @@ class Item
 
         // 获取来源信息
         $sourceType = $options['source_type'] ?? null;
-        $sourceId = $options['source_id'] ?? null;
-            // 检查用户是否已有该物品且过期时间相同,并且未满堆叠(排除冻结的物品)
-            $userItem = ItemUser::where('user_id', $userId)
-                ->where('item_id', $itemId)
-                ->where(function ($query) use ($expireAt) {
-                    if ($expireAt === null) {
-                        $query->whereNull('expire_at');
-                    } else {
-                        $query->where('expire_at', $expireAt);
-                    }
-                })
-                ->whereNull('instance_id')
-                ->where('is_frozen', false) // 排除冻结的物品
-                ->where(function ($query) use ($item) {
-                    // 如果有最大堆叠限制,只查找未满的堆叠
-                    if ($item->max_stack > 0) {
-                        $query->where('quantity', '<', $item->max_stack);
-                    }
-                })
-                ->first();
-
-            $addedQuantity = $quantity;
-            $currentQuantity = 0;
-
-            if ($userItem) {
-                // 已有物品,增加数量
-                $currentQuantity = $userItem->quantity;
-                $newQuantity = $currentQuantity + $quantity;
-
-                // 检查最大堆叠限制
-                if ($item->max_stack > 0 && $newQuantity > $item->max_stack) {
-                    // 超过最大堆叠,先填满当前堆叠
-                    $canAddToCurrent = $item->max_stack - $currentQuantity;
-                    $userItem->quantity = $item->max_stack;
-                    $userItem->save();
-
-                    // 触发物品数量变更事件(更新现有堆叠)
-                    Event::dispatch(new ItemQuantityChanged(
-                        $userId,
-                        $itemId,
-                        null,
-                        $currentQuantity,
-                        $item->max_stack,
-                        $userItem->id,
-                        $options
-                    ));
-
-                    // 剩余数量递归添加到新堆叠
-                    $remainingQuantity = $quantity - $canAddToCurrent;
-                    if ($remainingQuantity > 0) {
-                        self::addNormalItem($userId, $itemId, $remainingQuantity, $options);
-                    }
-
-                    $addedQuantity = $quantity;
-                    $currentQuantity = $item->max_stack;
+        $sourceId   = $options['source_id'] ?? null;
+        // 检查用户是否已有该物品且过期时间相同,并且未满堆叠(排除冻结的物品)
+        $userItem = ItemUser::where('user_id', $userId)
+            ->where('item_id', $itemId)
+            ->where(function ($query) use ($expireAt) {
+                if ($expireAt === null) {
+                    $query->whereNull('expire_at');
                 } else {
-                    // 未超过最大堆叠,直接更新数量
-                    $oldQuantity = $userItem->quantity;
-                    $userItem->quantity = $newQuantity;
-                    $userItem->save();
-                    $currentQuantity = $newQuantity;
-
-                    // 触发物品数量变更事件
-                    Event::dispatch(new ItemQuantityChanged(
-                        $userId,
-                        $itemId,
-                        null,
-                        $oldQuantity,
-                        $newQuantity,
-                        $userItem->id,
-                        $options
-                    ));
+                    $query->where('expire_at', $expireAt);
                 }
-            } else {
-                // 没有该物品,创建新记录
-                $createQuantity = min($quantity, $item->max_stack > 0 ? $item->max_stack : $quantity);
-                $userItem = new ItemUser([
-                    'user_id' => $userId,
-                    'item_id' => $itemId,
-                    'quantity' => $createQuantity,
-                    'expire_at' => $expireAt,
-                ]);
+            })
+            ->whereNull('instance_id')
+            ->where('is_frozen', false) // 排除冻结的物品
+            ->where(function ($query) use ($item) {
+                // 如果有最大堆叠限制,只查找未满的堆叠
+                if ($item->max_stack > 0) {
+                    $query->where('quantity', '<', $item->max_stack);
+                }
+            })
+            ->first();
+
+        $addedQuantity   = $quantity;
+        $currentQuantity = 0;
+
+        if ($userItem) {
+            // 已有物品,增加数量
+            $currentQuantity = $userItem->quantity;
+            $newQuantity     = $currentQuantity + $quantity;
+
+            // 检查最大堆叠限制
+            if ($item->max_stack > 0 && $newQuantity > $item->max_stack) {
+                // 超过最大堆叠,先填满当前堆叠
+                $canAddToCurrent    = $item->max_stack - $currentQuantity;
+                $userItem->quantity = $item->max_stack;
                 $userItem->save();
 
-                // 触发物品数量变更事件(新增物品)
+                // 触发物品数量变更事件(更新现有堆叠)
                 Event::dispatch(new ItemQuantityChanged(
-                    $userId,
-                    $itemId,
-                    null,
-                    0, // 旧数量为0
-                    $createQuantity,
-                    $userItem->id,
-                    $options
-                ));
-
-                // 如果数量超过最大堆叠,递归添加剩余数量
-                if ($item->max_stack > 0 && $quantity > $item->max_stack) {
-                    $remainingQuantity = $quantity - $item->max_stack;
+                                    $userId,
+                                    $itemId,
+                                    null,
+                                    $currentQuantity,
+                                    $item->max_stack,
+                                    $userItem->id,
+                                    $options
+                                ));
+
+                // 剩余数量递归添加到新堆叠
+                $remainingQuantity = $quantity - $canAddToCurrent;
+                if ($remainingQuantity > 0) {
                     self::addNormalItem($userId, $itemId, $remainingQuantity, $options);
-                    $addedQuantity = $quantity; // 总添加数量
-                } else {
-                    $addedQuantity = $createQuantity;
                 }
 
-                $currentQuantity = $createQuantity;
+                $addedQuantity   = $quantity;
+                $currentQuantity = $item->max_stack;
+            } else {
+                // 未超过最大堆叠,直接更新数量
+                $oldQuantity        = $userItem->quantity;
+                $userItem->quantity = $newQuantity;
+                $userItem->save();
+                $currentQuantity = $newQuantity;
+
+                // 触发物品数量变更事件
+                Event::dispatch(new ItemQuantityChanged(
+                                    $userId,
+                                    $itemId,
+                                    null,
+                                    $oldQuantity,
+                                    $newQuantity,
+                                    $userItem->id,
+                                    $options
+                                ));
             }
+        } else {
+            // 没有该物品,创建新记录
+            $createQuantity = min($quantity, $item->max_stack > 0 ? $item->max_stack : $quantity);
+            $userItem       = new ItemUser([
+                                               'user_id'   => $userId,
+                                               'item_id'   => $itemId,
+                                               'quantity'  => $createQuantity,
+                                               'expire_at' => $expireAt,
+                                           ]);
+            $userItem->save();
+
+            // 触发物品数量变更事件(新增物品)
+            Event::dispatch(new ItemQuantityChanged(
+                                $userId,
+                                $itemId,
+                                null,
+                                0, // 旧数量为0
+                                $createQuantity,
+                                $userItem->id,
+                                $options
+                            ));
+
+            // 如果数量超过最大堆叠,递归添加剩余数量
+            if ($item->max_stack > 0 && $quantity > $item->max_stack) {
+                $remainingQuantity = $quantity - $item->max_stack;
+                self::addNormalItem($userId, $itemId, $remainingQuantity, $options);
+                $addedQuantity = $quantity; // 总添加数量
+            } else {
+                $addedQuantity = $createQuantity;
+            }
+
+            $currentQuantity = $createQuantity;
+        }
+
+        // 记录交易日志
+        self::logTransaction(
+            $userId,
+            $itemId,
+            null,
+            $addedQuantity,
+            TRANSACTION_TYPE::ACQUIRE,
+            $sourceType,
+            $sourceId,
+            $options['details'] ?? null,
+            $expireAt,
+            $options['ip_address'] ?? null,
+            $options['device_info'] ?? null
+        );
+
+        // 触发物品获取事件
+        Event::dispatch(new ItemAcquired($userId, $itemId, null, $addedQuantity, $options));
 
-            // 记录交易日志
-            self::logTransaction(
-                $userId,
-                $itemId,
-                null,
-                $addedQuantity,
-                TRANSACTION_TYPE::ACQUIRE,
-                $sourceType,
-                $sourceId,
-                $options['details'] ?? null,
-                $expireAt,
-                $options['ip_address'] ?? null,
-                $options['device_info'] ?? null
-            );
-
-            // 触发物品获取事件
-            Event::dispatch(new ItemAcquired($userId, $itemId, null, $addedQuantity, $options));
-
-            return [
-                'success' => true,
-                'item_id' => $itemId,
-                'quantity' => $addedQuantity,
-                'current_quantity' => $currentQuantity,
-                'user_item_id' => $userItem->id,
-            ];
+        return [
+            'success'          => true,
+            'item_id'          => $itemId,
+            'quantity'         => $addedQuantity,
+            'current_quantity' => $currentQuantity,
+            'user_item_id'     => $userItem->id,
+        ];
     }
 
     /**
@@ -247,66 +248,69 @@ class Item
 
         // 获取来源信息
         $sourceType = $options['source_type'] ?? null;
-        $sourceId = $options['source_id'] ?? null;
-            // 创建物品实例
-            $instance = new ItemInstance([
-                'item_id' => $itemId,
-                'name' => $options['name'] ?? $item->name,
-                'display_attributes' => $options['display_attributes'] ?? $item->display_attributes,
-                'numeric_attributes' => $options['numeric_attributes'] ?? $item->numeric_attributes,
-                'tradable' => $options['tradable'] ?? $item->tradable,
-                'is_bound' => $options['is_bound'] ?? false,
-                'bound_to' => $options['bound_to'] ?? null,
-                'bind_exp_time' => $options['bind_exp_time'] ?? null,
-                'expire_at' => $expireAt,
-            ]);
-            $instance->save();
-
-            // 关联到用户
-            $userItem = new ItemUser([
-                'user_id' => $userId,
-                'item_id' => $itemId,
-                'instance_id' => $instance->id,
-                'quantity' => 1, // 单独属性物品数量始终为1
-                'expire_at' => $expireAt,
-            ]);
-            $userItem->save();
+        $sourceId   = $options['source_id'] ?? null;
+        if(!$sourceType  || !$sourceId){
+            throw new Exception("物品 {$itemId} ,缺少来源类型.");
+        }
+        // 创建物品实例
+        $instance = new ItemInstance([
+                                         'item_id'            => $itemId,
+                                         'name'               => $options['name'] ?? $item->name,
+                                         'display_attributes' => $options['display_attributes'] ?? $item->display_attributes,
+                                         'numeric_attributes' => $options['numeric_attributes'] ?? $item->numeric_attributes,
+                                         'tradable'           => $options['tradable'] ?? $item->tradable,
+                                         'is_bound'           => $options['is_bound'] ?? false,
+                                         'bound_to'           => $options['bound_to'] ?? null,
+                                         'bind_exp_time'      => $options['bind_exp_time'] ?? null,
+                                         'expire_at'          => $expireAt,
+                                     ]);
+        $instance->save();
+
+        // 关联到用户
+        $userItem = new ItemUser([
+                                     'user_id'     => $userId,
+                                     'item_id'     => $itemId,
+                                     'instance_id' => $instance->id,
+                                     'quantity'    => 1, // 单独属性物品数量始终为1
+                                     'expire_at'   => $expireAt,
+                                 ]);
+        $userItem->save();
+
+        // 记录交易日志
+        self::logTransaction(
+            $userId,
+            $itemId,
+            $instance->id,
+            1,
+            TRANSACTION_TYPE::ACQUIRE,
+            $sourceType,
+            $sourceId,
+            $options['details'] ?? null,
+            $expireAt,
+            $options['ip_address'] ?? null,
+            $options['device_info'] ?? null
+        );
 
-            // 记录交易日志
-            self::logTransaction(
-                $userId,
-                $itemId,
-                $instance->id,
-                1,
-                TRANSACTION_TYPE::ACQUIRE,
-                $sourceType,
-                $sourceId,
-                $options['details'] ?? null,
-                $expireAt,
-                $options['ip_address'] ?? null,
-                $options['device_info'] ?? null
-            );
-
-            // 触发物品获取事件
-            Event::dispatch(new ItemAcquired($userId, $itemId, $instance->id, 1, $options));
+        // 触发物品获取事件
+        Event::dispatch(new ItemAcquired($userId, $itemId, $instance->id, 1, $options));
 
-            // 触发物品数量变更事件(新增物品)
-            Event::dispatch(new ItemQuantityChanged(
-                $userId,
-                $itemId,
-                $instance->id,
-                0, // 旧数量为0
-                1, // 新数量为1
-                $userItem->id,
-                $options
-            ));
-
-            return [
-                'success' => true,
-                'item_id' => $itemId,
-                'instance_id' => $instance->id,
-                'user_item_id' => $userItem->id,
-            ];
+        // 触发物品数量变更事件(新增物品)
+        Event::dispatch(new ItemQuantityChanged(
+                            $userId,
+                            $itemId,
+                            $instance->id,
+                            0, // 旧数量为0
+                            1, // 新数量为1
+                            $userItem->id,
+                            $options
+                        ));
+
+        return [
+            'success'      => true,
+            'item_id'      => $itemId,
+            'instance_id'  => $instance->id,
+            'user_item_id' => $userItem->id,
+        ];
     }
 
     /**
@@ -329,7 +333,7 @@ class Item
             ->whereNull('instance_id')
             ->where('is_frozen', false) // 只获取未冻结的物品
             ->where('quantity', '>', 0) // 确保数量大于0
-            ->orderBy('expire_at') // 优先消耗即将过期的物品
+            ->orderBy('expire_at')      // 优先消耗即将过期的物品
             ->get();
 
         // 检查物品数量是否足够
@@ -340,7 +344,7 @@ class Item
 
         // 获取来源信息
         $sourceType = $options['source_type'] ?? null;
-        $sourceId = $options['source_id'] ?? null;
+        $sourceId   = $options['source_id'] ?? null;
 
         // 开始消耗物品
         $remainingQuantity = $quantity;
@@ -351,9 +355,9 @@ class Item
 
             if ($userItem->quantity <= $remainingQuantity) {
                 // 当前堆叠数量不足,全部消耗
-                $consumedQuantity = $userItem->quantity;
+                $consumedQuantity  = $userItem->quantity;
                 $remainingQuantity -= $consumedQuantity;
-                $oldQuantity = $userItem->quantity;
+                $oldQuantity       = $userItem->quantity;
 
                 // 记录交易日志
                 self::logTransaction(
@@ -376,19 +380,19 @@ class Item
 
                 // 触发物品数量变更事件
                 Event::dispatch(new ItemQuantityChanged(
-                    $userId,
-                    $itemId,
-                    null,
-                    $oldQuantity,
-                    0,
-                    $userItem->id,
-                    $options
-                ));
+                                    $userId,
+                                    $itemId,
+                                    null,
+                                    $oldQuantity,
+                                    0,
+                                    $userItem->id,
+                                    $options
+                                ));
             } else {
                 // 当前堆叠数量足够,部分消耗
-                $consumedQuantity = $remainingQuantity;
-                $oldQuantity = $userItem->quantity;
-                $newQuantity = $oldQuantity - $consumedQuantity;
+                $consumedQuantity   = $remainingQuantity;
+                $oldQuantity        = $userItem->quantity;
+                $newQuantity        = $oldQuantity - $consumedQuantity;
                 $userItem->quantity = $newQuantity;
                 $userItem->save();
                 $remainingQuantity = 0;
@@ -410,14 +414,14 @@ class Item
 
                 // 触发物品数量变更事件
                 Event::dispatch(new ItemQuantityChanged(
-                    $userId,
-                    $itemId,
-                    null,
-                    $oldQuantity,
-                    $newQuantity,
-                    $userItem->id,
-                    $options
-                ));
+                                    $userId,
+                                    $itemId,
+                                    null,
+                                    $oldQuantity,
+                                    $newQuantity,
+                                    $userItem->id,
+                                    $options
+                                ));
             }
 
             // 触发物品消耗事件
@@ -425,9 +429,9 @@ class Item
         }
 
         return [
-            'success' => true,
-            'item_id' => $itemId,
-            'quantity' => $quantity,
+            'success'            => true,
+            'item_id'            => $itemId,
+            'quantity'           => $quantity,
             'remaining_quantity' => $totalQuantity - $quantity,
         ];
     }
@@ -459,7 +463,7 @@ class Item
 
         // 获取来源信息
         $sourceType = $options['source_type'] ?? null;
-        $sourceId = $options['source_id'] ?? null;
+        $sourceId   = $options['source_id'] ?? null;
 
         // 记录交易日志
         self::logTransaction(
@@ -487,10 +491,10 @@ class Item
         // 触发物品消耗事件
         Event::dispatch(new ItemConsumed($userId, $itemId, $instanceId, 1, $options));
 
-        return Res::success('',[
-            'item_id' => $itemId,
+        return Res::success('', [
+            'item_id'     => $itemId,
             'instance_id' => $instanceId,
-        ]) ;
+        ]);
     }
 
     /**
@@ -510,30 +514,32 @@ class Item
      * @return ItemTransactionLog
      */
     public static function logTransaction(
-        int $userId,
-        int $itemId,
-        ?int $instanceId,
-        int $quantity,
-        int $transactionType,
+        int     $userId,
+        int     $itemId,
+        ?int    $instanceId,
+        int     $quantity,
+        int     $transactionType,
         ?string $sourceType = null,
-        ?int $sourceId = null,
-        ?array $details = null,
+        ?int    $sourceId = null,
+        ?array  $details = null,
         ?string $expireAt = null,
         ?string $ipAddress = null,
         ?string $deviceInfo = null
-    ): ItemTransactionLog {
+    ): ItemTransactionLog
+    {
         return ItemTransactionLog::create([
-            'user_id' => $userId,
-            'item_id' => $itemId,
-            'instance_id' => $instanceId,
-            'quantity' => $quantity,
-            'transaction_type' => $transactionType,
-            'source_type' => $sourceType,
-            'source_id' => $sourceId,
-            'details' => $details,
-            'expire_at' => $expireAt,
-            'ip_address' => $ipAddress,
-            'device_info' => $deviceInfo,
-        ]);
+                                              'user_id'          => $userId,
+                                              'item_id'          => $itemId,
+                                              'instance_id'      => $instanceId,
+                                              'quantity'         => $quantity,
+                                              'transaction_type' => $transactionType,
+                                              'source_type'      => $sourceType,
+                                              'source_id'        => $sourceId,
+                                              'details'          => $details,
+                                              'expire_at'        => $expireAt,
+                                              'ip_address'       => $ipAddress,
+                                              'device_info'      => $deviceInfo,
+                                          ]);
     }
+
 }

+ 2 - 1
app/Module/GameItems/Services/DismantleService.php

@@ -2,6 +2,7 @@
 
 namespace App\Module\GameItems\Services;
 
+use App\Module\Game\Enums\REWARD_SOURCE_TYPE;
 use App\Module\GameItems\Models\Item;
 use App\Module\GameItems\Models\ItemDismantleRule;
 use App\Module\GameItems\Models\ItemDismantleLog;
@@ -95,7 +96,7 @@ class DismantleService
                 if ($resultQuantity > 0) {
                     // 添加物品到用户背包
                     $addResult = ItemService::addItem($userId, $resultItemId, $resultQuantity, [
-                        'source_type' => 'dismantle',
+                        'source_type' => REWARD_SOURCE_TYPE::DISMANTLE,
                         'source_id' => $rule->id,
                         'details' => [
                             'rule_id' => $rule->id,

+ 3 - 3
app/Module/GameItems/Tests/ItemFreezeTest.php

@@ -26,7 +26,7 @@ class ItemFreezeTest extends TestCase
     protected function setUp(): void
     {
         parent::setUp();
-        
+
         // 创建测试物品
         Item::create([
             'id' => $this->testItemId,
@@ -193,7 +193,7 @@ class ItemFreezeTest extends TestCase
      */
     public function testBatchFreezeItems()
     {
-        Helper::begin_tr();
+        Helper::check_tr();
 
         try {
             // 添加多种物品
@@ -259,7 +259,7 @@ class ItemFreezeTest extends TestCase
         try {
             // 添加物品并冻结
             ItemService::addItem($this->testUserId, $this->testItemId, 100);
-            
+
             ItemFreeze::freezeNormalItem(
                 $this->testUserId,
                 $this->testItemId,

+ 0 - 139
app/Module/GameItems/Tests/freeze_test_manual.php

@@ -1,139 +0,0 @@
-<?php
-
-/**
- * 手动测试冻结功能
- * 
- * 运行方式:php artisan tinker
- * 然后执行:include 'app/Module/GameItems/Tests/freeze_test_manual.php';
- */
-
-use App\Module\GameItems\Enums\FREEZE_REASON_TYPE;
-use App\Module\GameItems\Logics\ItemFreeze;
-use App\Module\GameItems\Models\Item;
-use App\Module\GameItems\Models\ItemUser;
-use App\Module\GameItems\Services\ItemService;
-use UCore\Db\Helper;
-
-echo "开始测试物品冻结功能...\n";
-
-try {
-    // 测试用户ID和物品ID
-    $testUserId = 9999;
-    $testItemId = 8888;
-
-    // 清理测试数据
-    ItemUser::where('user_id', $testUserId)->delete();
-    Item::where('id', $testItemId)->delete();
-
-    // 创建测试物品
-    $item = Item::create([
-        'id' => $testItemId,
-        'name' => '测试冻结物品',
-        'description' => '用于测试冻结功能',
-        'category_id' => 1,
-        'type' => 1,
-        'is_unique' => false,
-        'max_stack' => 100,
-        'sell_price' => 10,
-        'tradable' => true,
-        'dismantlable' => true,
-        'default_expire_seconds' => 0,
-    ]);
-
-    echo "✓ 创建测试物品成功: {$item->name}\n";
-
-    // 开始事务
-    Helper::begin_tr();
-
-    // 1. 测试添加物品
-    $result = ItemService::addItem($testUserId, $testItemId, 100);
-    echo "✓ 添加物品成功: 数量 {$result['quantity']}\n";
-
-    // 2. 验证可用数量
-    $availableQuantity = ItemService::getAvailableQuantity($testUserId, $testItemId);
-    echo "✓ 当前可用数量: {$availableQuantity}\n";
-
-    // 3. 测试冻结物品
-    $freezeResult = ItemService::freezeItem(
-        $testUserId,
-        $testItemId,
-        null,
-        30,
-        '测试冻结',
-        [
-            'reason_type' => FREEZE_REASON_TYPE::TRADE_ORDER->value,
-            'source_id' => 123,
-            'source_type' => 'test_order'
-        ]
-    );
-    echo "✓ 冻结物品成功: 冻结数量 {$freezeResult['frozen_quantity']}\n";
-
-    // 4. 验证冻结后的可用数量
-    $availableQuantity = ItemService::getAvailableQuantity($testUserId, $testItemId);
-    echo "✓ 冻结后可用数量: {$availableQuantity}\n";
-
-    // 5. 测试获取冻结物品列表
-    $frozenItems = ItemService::getFrozenItems($testUserId);
-    echo "✓ 冻结物品数量: {$frozenItems->count()}\n";
-
-    // 6. 测试消耗物品(应该只消耗未冻结的)
-    $consumeResult = ItemService::consumeItem($testUserId, $testItemId, null, 20);
-    echo "✓ 消耗物品成功: 消耗数量 {$consumeResult['quantity']}\n";
-
-    // 7. 验证消耗后的可用数量
-    $availableQuantity = ItemService::getAvailableQuantity($testUserId, $testItemId);
-    echo "✓ 消耗后可用数量: {$availableQuantity}\n";
-
-    // 8. 测试解冻物品
-    $freezeLogId = $freezeResult['frozen_items'][0]['freeze_log_id'];
-    $unfreezeResult = ItemService::unfreezeItem($freezeLogId);
-    echo "✓ 解冻物品成功: 解冻数量 {$unfreezeResult['unfrozen_quantity']}\n";
-
-    // 9. 验证解冻后的可用数量
-    $availableQuantity = ItemService::getAvailableQuantity($testUserId, $testItemId);
-    echo "✓ 解冻后可用数量: {$availableQuantity}\n";
-
-    // 10. 测试批量冻结
-    $batchItems = [
-        ['item_id' => $testItemId, 'quantity' => 20],
-    ];
-    $batchResult = ItemService::batchFreezeItems(
-        $testUserId,
-        $batchItems,
-        '批量测试冻结',
-        ['reason_type' => FREEZE_REASON_TYPE::SYSTEM_FREEZE->value]
-    );
-    echo "✓ 批量冻结成功: 冻结物品种类 {$batchResult['frozen_items_count']}\n";
-
-    // 11. 获取冻结统计
-    $statistics = ItemService::getFreezeStatistics($testUserId);
-    echo "✓ 冻结统计: 总冻结物品 {$statistics['total_frozen_items']} 个,总数量 {$statistics['total_frozen_quantity']}\n";
-
-    // 提交事务
-    Helper::commit_tr();
-
-    echo "\n🎉 所有测试通过!冻结功能工作正常。\n";
-
-    // 清理测试数据
-    ItemUser::where('user_id', $testUserId)->delete();
-    Item::where('id', $testItemId)->delete();
-    echo "✓ 清理测试数据完成\n";
-
-} catch (Exception $e) {
-    // 回滚事务
-    Helper::rollback_tr();
-    
-    echo "\n❌ 测试失败: " . $e->getMessage() . "\n";
-    echo "错误位置: " . $e->getFile() . ":" . $e->getLine() . "\n";
-    
-    // 清理测试数据
-    try {
-        ItemUser::where('user_id', $testUserId)->delete();
-        Item::where('id', $testItemId)->delete();
-        echo "✓ 清理测试数据完成\n";
-    } catch (Exception $cleanupError) {
-        echo "⚠️ 清理测试数据失败: " . $cleanupError->getMessage() . "\n";
-    }
-}
-
-echo "\n测试完成。\n";

+ 33 - 28
app/Module/Mex/Logic/MexAccountLogic.php

@@ -5,6 +5,7 @@ namespace App\Module\Mex\Logic;
 use App\Module\Fund\Services\FundService;
 use App\Module\Fund\Enums\FUND_TYPE;
 use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
+use App\Module\Game\Enums\REWARD_SOURCE_TYPE;
 use App\Module\GameItems\Services\ItemService;
 use App\Module\Mex\Logic\MexTransactionLogic;
 use App\Module\Mex\Logic\MexWarehouseLogic;
@@ -62,36 +63,38 @@ class MexAccountLogic
                 DB::rollBack();
                 return ['success' => false, 'message' => $checkResult->message];
             }
-            
+
             // 2. 从用户扣除物品
             $consumeResult = ItemService::consumeItem($userId, $itemId, null, $quantity, [
                 'reason' => 'mex_sell',
                 'order_id' => $orderId,
                 'remark' => "农贸市场卖出物品,订单ID:{$orderId}"
             ]);
-            
+
             if (!$consumeResult['success']) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '扣除用户物品失败:' . ($consumeResult['message'] ?? '未知错误')];
             }
-            
+
             // 3. 给仓库账户添加物品
             $addResult = ItemService::addItem(self::WAREHOUSE_USER_ID, $itemId, $quantity, [
                 'reason' => 'mex_warehouse_buy',
+                'source_type'    => REWARD_SOURCE_TYPE::MEX_BUY,
+                'source_id'      => $orderId,
                 'order_id' => $orderId,
                 'remark' => "农贸市场仓库收购物品,订单ID:{$orderId}"
             ]);
-            
+
             if (!$addResult['success']) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '仓库添加物品失败:' . ($addResult['message'] ?? '未知错误')];
             }
-            
+
             // 4. 从仓库账户转出资金给用户
             $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, $availableAccountType->value);
             $precision = $currencyType->getPrecision();
             $fundAmount = (int)bcmul($totalAmount, bcpow('10', $precision), 0); // 根据币种精度转换
-            
+
             $transferResult = $warehouseFundService->trade(
                 $userId,
                 $fundAmount,
@@ -99,19 +102,19 @@ class MexAccountLogic
                 $orderId,
                 "农贸市场卖出收款,订单ID:{$orderId}"
             );
-            
+
             if (is_string($transferResult)) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '资金转移失败:' . $transferResult];
             }
-            
+
             // 5. 更新仓库统计
             $warehouseResult = MexWarehouseLogic::addStock($itemId, $quantity, $totalAmount);
             if (!$warehouseResult) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '更新仓库统计失败'];
             }
-            
+
             // 6. 创建成交记录
             $transactionResult = MexTransactionLogic::createTransaction([
                 'sell_order_id' => $orderId,
@@ -125,14 +128,14 @@ class MexAccountLogic
                 'transaction_type' => TransactionType::USER_SELL,
                 'is_admin_operation' => false,
             ]);
-            
+
             if (!$transactionResult) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '创建成交记录失败'];
             }
-            
+
             DB::commit();
-            
+
             return [
                 'success' => true,
                 'message' => '卖出订单处理成功',
@@ -141,7 +144,7 @@ class MexAccountLogic
                 'item_consume' => $consumeResult,
                 'warehouse_add' => $addResult
             ];
-            
+
         } catch (\Exception $e) {
             DB::rollBack();
             Log::error('Mex卖出订单处理失败', [
@@ -152,7 +155,7 @@ class MexAccountLogic
                 'error' => $e->getMessage(),
                 'trace' => $e->getTraceAsString()
             ]);
-            
+
             return ['success' => false, 'message' => '系统错误:' . $e->getMessage()];
         }
     }
@@ -195,12 +198,12 @@ class MexAccountLogic
             $userFundService = new FundService($userId, $availableAccountType->value);
             $precision = $currencyType->getPrecision();
             $fundAmount = (int)bcmul($totalAmount, bcpow('10', $precision), 0); // 根据币种精度转换
-            
+
             if ($userFundService->balance() < $fundAmount) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '用户资金不足'];
             }
-            
+
             // 3. 从用户转出资金到仓库
             $transferResult = $userFundService->trade(
                 self::WAREHOUSE_USER_ID,
@@ -209,43 +212,45 @@ class MexAccountLogic
                 $orderId,
                 "农贸市场买入付款,订单ID:{$orderId}"
             );
-            
+
             if (is_string($transferResult)) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '资金转移失败:' . $transferResult];
             }
-            
+
             // 4. 从仓库扣除物品
             $consumeResult = ItemService::consumeItem(self::WAREHOUSE_USER_ID, $itemId, null, $quantity, [
                 'reason' => 'mex_warehouse_sell',
                 'order_id' => $orderId,
                 'remark' => "农贸市场仓库出售物品,订单ID:{$orderId}"
             ]);
-            
+
             if (!$consumeResult['success']) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '仓库扣除物品失败:' . ($consumeResult['message'] ?? '未知错误')];
             }
-            
+
             // 5. 给用户添加物品
             $addResult = ItemService::addItem($userId, $itemId, $quantity, [
                 'reason' => 'mex_buy',
+                'source_type'    => REWARD_SOURCE_TYPE::MEX_BUY,
+                'source_id'      => $orderId,
                 'order_id' => $orderId,
                 'remark' => "农贸市场买入物品,订单ID:{$orderId}"
             ]);
-            
+
             if (!$addResult['success']) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '用户添加物品失败:' . ($addResult['message'] ?? '未知错误')];
             }
-            
+
             // 6. 更新仓库统计
             $warehouseResult = MexWarehouseLogic::reduceStock($itemId, $quantity, $totalAmount);
             if (!$warehouseResult) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '更新仓库统计失败'];
             }
-            
+
             // 7. 创建成交记录
             $transactionResult = MexTransactionLogic::createTransaction([
                 'buy_order_id' => $orderId,
@@ -259,14 +264,14 @@ class MexAccountLogic
                 'transaction_type' => TransactionType::USER_BUY,
                 'is_admin_operation' => false,
             ]);
-            
+
             if (!$transactionResult) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '创建成交记录失败'];
             }
-            
+
             DB::commit();
-            
+
             return [
                 'success' => true,
                 'message' => '买入订单处理成功',
@@ -275,7 +280,7 @@ class MexAccountLogic
                 'item_consume' => $consumeResult,
                 'user_add' => $addResult
             ];
-            
+
         } catch (\Exception $e) {
             DB::rollBack();
             Log::error('Mex买入订单处理失败', [
@@ -286,7 +291,7 @@ class MexAccountLogic
                 'error' => $e->getMessage(),
                 'trace' => $e->getTraceAsString()
             ]);
-            
+
             return ['success' => false, 'message' => '系统错误:' . $e->getMessage()];
         }
     }

+ 2 - 0
app/Module/Mex/Logic/MexMatchLogic.php

@@ -2,6 +2,7 @@
 
 namespace App\Module\Mex\Logic;
 
+use App\Module\Game\Enums\REWARD_SOURCE_TYPE;
 use App\Module\Mex\Models\MexOrder;
 use App\Module\Mex\Models\MexWarehouse;
 use App\Module\Mex\Models\MexTransaction;
@@ -808,6 +809,7 @@ class MexMatchLogic
             // 添加物品到用户账户
             $result = ItemService::addItem($userId, $itemId, $quantity, [
                 'source' => 'mex_order',
+                'source_type'    => REWARD_SOURCE_TYPE::MEX_BUY,
                 'source_id' => $orderId,
                 'remark' => '用户买入物品撮合-物品转移',
             ]);

+ 4 - 3
app/Module/UrsPromotion/Listeners/CropHarvestedListener.php

@@ -3,12 +3,13 @@
 namespace App\Module\UrsPromotion\Listeners;
 
 use App\Module\Farm\Events\CropHarvestedEvent;
+use App\Module\Game\Enums\REWARD_SOURCE_TYPE;
 use App\Module\UrsPromotion\Services\UrsProfitService;
 use Illuminate\Support\Facades\Log;
 
 /**
  * Farm收获事件监听器
- * 
+ *
  * 监听Farm模块的作物收获事件,自动分发URS种植收益
  */
 class CropHarvestedListener
@@ -36,7 +37,7 @@ class CropHarvestedListener
             // 传递物品ID和数量,用于按比例发放物品奖励
             $profits = UrsProfitService::distributePlantingReward(
                 $event->userId,
-                'farm_harvest',
+                REWARD_SOURCE_TYPE::URSPROMOTION_HAVEST->valueString(),
                 $event->harvestLog->id,
                 $event->outputAmount,
                 $event->outputItemId
@@ -56,7 +57,7 @@ class CropHarvestedListener
                 'error' => $e->getMessage(),
                 'trace' => $e->getTraceAsString(),
             ]);
-            
+
             // 不抛出异常,避免影响Farm模块的正常流程
             // 收益分发失败不应该影响用户的收获操作
         }

+ 1 - 1
database/test/delete.sql

@@ -118,7 +118,7 @@ delete from kku_job_runs where 1=1;
 delete from  kku_item_users where user_id > 10000;
 delete from kku_item_user_recipes where user_id > 10000;
 delete from kku_item_user_output_counters where user_id > 10000;
-delete from kku_item_transaction_logs where user_id > 10000;
+delete from kku_item_transaction_logs where 1=1;
 
 # kku_item_recipes  不处理,配置项目,配方配置
 delete from kku_item_pity_times  where user_id > 10000;