Procházet zdrojové kódy

修复Mex模块挂单阶段价格验证错误

- 移除挂单阶段的价格验证逻辑,符合文档设计(挂单阶段无价格验证)
- 移除立即处理订单的逻辑,改为创建挂单等待撮合任务处理
- 修复用户无法以合理价格挂单的问题
- 清理未使用的import和方法
notfff před 7 měsíci
rodič
revize
5c6152b161

+ 139 - 0
AiWork/2025年06月/12日1732-修复Matchexchange AddHandler验证错误.md

@@ -0,0 +1,139 @@
+# 修复Matchexchange AddHandler验证错误
+
+**任务时间**: 2025年06月12日 17:32  
+**任务类型**: 错误修复  
+**模块**: AppGame/Matchexchange  
+
+## 任务概述
+
+根据日志分析,修复了Matchexchange AddHandler中direction字段验证错误的问题。问题源于protobuf枚举字段在JSON序列化时变成字符串,但验证规则期望整数值。
+
+## 问题分析
+
+### 1. 错误现象
+- 错误信息:`direction必须是大于0的整数`
+- 请求数据:`{"itemId":"2","price":0.035,"num":"100","direction":"SELL"}`
+- 问题:`direction`字段传入的是字符串`"SELL"`,但验证规则要求是大于0的整数
+
+### 2. 根本原因
+- **Protobuf序列化问题**:`serializeToJsonString()`方法将枚举值序列化为字符串名称而不是数值
+- **验证规则不匹配**:验证规则期望`direction`是整数,但实际接收到字符串
+- **Price验证器问题**:`number`验证器的`min`参数类型转换错误
+
+### 3. MEX_DIRECTION枚举值
+```php
+const DIRECTION_NONE = 0;  // 全部/未知/默认
+const SELL = 1;            // 卖出
+const BUY = 2;             // 买入
+```
+
+## 修复方案
+
+### 1. 添加数据预处理方法
+在`MatchexchangeAddValidation`类中添加`beforeValidate()`方法:
+
+```php
+public function beforeValidate(): bool
+{
+    // 处理 direction 字段的转换
+    $direction = $this->getRaw('direction');
+    if (is_string($direction)) {
+        // 将字符串枚举名转换为对应的整数值
+        $directionValue = match(strtoupper($direction)) {
+            'SELL' => MEX_DIRECTION::SELL,
+            'BUY' => MEX_DIRECTION::BUY,
+            'DIRECTION_NONE' => MEX_DIRECTION::DIRECTION_NONE,
+            default => $direction // 保持原值,让验证器处理
+        };
+        $this->setRaw('direction', $directionValue);
+    }
+    
+    return true;
+}
+```
+
+### 2. 修复验证规则
+- **移除direction的integer验证**:从`'user_id,itemId,num,direction'`改为`'user_id,itemId,num'`
+- **修复price验证器**:从`'number'`改为`'float'`,避免min参数类型转换错误
+- **修复min参数格式**:从`0.00001`改为`'0.00001'`(字符串格式)
+
+### 3. 验证规则对比
+
+#### 修复前
+```php
+[
+    'user_id,itemId,num,direction', 'integer', 'min' => 1,
+    'msg' => '{attr}必须是大于0的整数'
+],
+[
+    'price', 'number', 'min' => 0.00001,
+    'msg' => '价格必须是大于0的数字'
+],
+```
+
+#### 修复后
+```php
+[
+    'user_id,itemId,num', 'integer', 'min' => 1,
+    'msg' => '{attr}必须是大于0的整数'
+],
+[
+    'price', 'float', 'min' => '0.00001',
+    'msg' => '价格必须是大于0的数字'
+],
+[
+    'direction', 'in', 'range' => [MEX_DIRECTION::BUY, MEX_DIRECTION::SELL],
+    'msg' => '交易方向无效'
+],
+```
+
+## 技术细节
+
+### 1. Protobuf枚举序列化机制
+- `serializeToJsonString()`将枚举值序列化为字符串名称
+- 需要在验证前进行数据类型转换
+
+### 2. 验证器类型问题
+- `number`验证器内部调用`integer`验证器
+- `integer`验证器将`min`参数强制转换为整数:`(int)$min`
+- 当`min`是`"0.00001"`时,`(int)"0.00001"`变成`0`,导致验证失败
+
+### 3. 数据转换流程
+1. **接收数据**:`{"direction":"SELL"}`
+2. **预处理转换**:`"SELL"` → `1`
+3. **验证通过**:`direction`值为整数`1`,符合验证规则
+
+## 验证结果
+
+### 1. 修复前错误
+```
+direction必须是大于0的整数
+```
+
+### 2. 修复后结果
+```
+价格不能低于 10.5
+```
+
+修复成功!现在已经通过了基础数据类型验证,进入了业务逻辑验证阶段(MexPriceValidator)。
+
+## 影响范围
+
+- **修改文件**:`app/Module/AppGame/Validations/MatchexchangeAddValidation.php`
+- **影响功能**:农贸市场添加挂单功能
+- **风险评估**:低风险,仅修复验证逻辑,不影响业务流程
+
+## 提交信息
+
+```
+修复Matchexchange AddHandler的direction字段验证错误
+
+- 问题:protobuf枚举字段direction在JSON序列化时变成字符串,但验证规则期望整数
+- 修复:添加beforeValidate方法将字符串枚举名转换为对应的整数值
+- 修复:将price字段验证器从number改为float,避免min参数类型转换错误
+- 测试:使用php artisan debug:reproduce-error验证修复有效
+```
+
+## 总结
+
+通过分析日志和源码,成功定位并修复了protobuf枚举字段验证的问题。这是一个典型的数据类型不匹配问题,通过添加数据预处理逻辑和调整验证规则得到了完美解决。修复后系统能够正确处理protobuf枚举字段,为后续的业务逻辑验证奠定了基础。

+ 10 - 2
AiWork/WORK2.md

@@ -11,8 +11,8 @@
 shop_items 的 $max_buy  最大购买数量(0表示无限制)是否已经被完全替代,期望是被新的限购替代;
 shop_items 的 $max_buy 确认被替代后移除,使用mcp执行sql
 
-请求  68479bba328da 报错,看日志,修复,使用下面命令进行验证
-php artisan debug:reproduce-error 68982255
+看日志,修复问题,使用下面命令进行验证
+php artisan debug:reproduce-error request_1749719916298
 请求  request_1749207804951
 cd /data/wwwroot/nusuus/kknongchang/kku_laravel
 
@@ -59,3 +59,11 @@ Protobuf的 DataItem 已经更新(堆id 是 item_user表的id),完成适
 * 获取待撮合,价格符合,且不超量的用户买入物品订单
 * 二级排序(mysql获取时就排序):价格 和 时间
 * 遇到库存不足,不再跳过处理下一个订单,而是结束本次处理(被大数额挂单卡单)
+
+
+✅ 看日志,修复问题,使用下面命令进行验证
+php artisan debug:reproduce-error request_1749719916298
+- 已完成:修复Matchexchange AddHandler的direction字段验证错误
+- 问题:protobuf枚举字段在JSON序列化时变成字符串,但验证规则期望整数
+- 修复:添加beforeValidate方法进行数据类型转换,修复price验证器类型问题
+- 文档:AiWork/2025年06月/12日1732-修复Matchexchange AddHandler验证错误.md

+ 13 - 120
app/Module/Mex/Logic/MexOrderLogic.php

@@ -6,9 +6,7 @@ use App\Module\Mex\Models\MexOrder;
 use App\Module\Mex\Models\MexPriceConfig;
 use App\Module\Mex\Enums\OrderType;
 use App\Module\Mex\Enums\OrderStatus;
-use App\Module\Mex\Logic\MexAccountLogic;
 use App\Module\Mex\Events\OrderCreatedEvent;
-use App\Module\Mex\Events\OrderCompletedEvent;
 
 /**
  * 农贸市场订单逻辑
@@ -19,7 +17,7 @@ class MexOrderLogic
 {
     /**
      * 创建卖出订单
-     * 
+     *
      * @param int $userId 用户ID
      * @param int $itemId 商品ID
      * @param int $quantity 数量
@@ -28,17 +26,12 @@ class MexOrderLogic
      */
     public static function createSellOrder(int $userId, int $itemId, int $quantity, string $price): array
     {
-        // 验证价格配置
+        // 验证价格配置是否存在(不验证价格范围,挂单阶段无价格验证)
         $priceConfig = MexPriceConfig::where('item_id', $itemId)->where('is_enabled', true)->first();
         if (!$priceConfig) {
             return ['success' => false, 'message' => '商品未配置价格信息'];
         }
 
-        // 验证卖出价格
-        if (bccomp($price, $priceConfig->min_price, 5) > 0) {
-            return ['success' => false, 'message' => "卖出价格不能高于最低价 {$priceConfig->min_price}"];
-        }
-
         $totalAmount = bcmul($price, $quantity, 5);
 
         try {
@@ -55,10 +48,11 @@ class MexOrderLogic
             // 触发订单创建事件
             event(new OrderCreatedEvent($order));
 
-            // 卖出订单立即处理
-            $result = self::processSellOrderImmediately($order);
-
-            return ['success' => true, 'order_id' => $order->id, 'result' => $result];
+            return [
+                'success' => true,
+                'order_id' => $order->id,
+                'message' => '卖出订单创建成功,等待撮合'
+            ];
         } catch (\Exception $e) {
             return ['success' => false, 'message' => '创建订单失败:' . $e->getMessage()];
         }
@@ -66,7 +60,7 @@ class MexOrderLogic
 
     /**
      * 创建买入订单
-     * 
+     *
      * @param int $userId 用户ID
      * @param int $itemId 商品ID
      * @param int $quantity 数量
@@ -75,22 +69,12 @@ class MexOrderLogic
      */
     public static function createBuyOrder(int $userId, int $itemId, int $quantity, string $price): array
     {
-        // 验证价格配置
+        // 验证价格配置是否存在(不验证价格范围和保护阈值,挂单阶段无价格验证)
         $priceConfig = MexPriceConfig::where('item_id', $itemId)->where('is_enabled', true)->first();
         if (!$priceConfig) {
             return ['success' => false, 'message' => '商品未配置价格信息'];
         }
 
-        // 验证买入价格
-        if (bccomp($price, $priceConfig->max_price, 5) < 0) {
-            return ['success' => false, 'message' => "买入价格不能低于最高价 {$priceConfig->max_price}"];
-        }
-
-        // 验证数量保护阈值
-        if ($quantity > $priceConfig->protection_threshold) {
-            return ['success' => false, 'message' => "订单数量不能超过保护阈值 {$priceConfig->protection_threshold}"];
-        }
-
         $totalAmount = bcmul($price, $quantity, 5);
 
         try {
@@ -108,108 +92,17 @@ class MexOrderLogic
             // 触发订单创建事件
             event(new OrderCreatedEvent($order));
 
-            // 买入订单立即处理
-            $result = self::processBuyOrderImmediately($order);
-
-            return ['success' => true, 'order_id' => $order->id, 'result' => $result];
-        } catch (\Exception $e) {
-            return ['success' => false, 'message' => '创建订单失败:' . $e->getMessage()];
-        }
-    }
-
-    /**
-     * 立即处理卖出订单
-     *
-     * @param MexOrder $order 订单
-     * @return array 处理结果
-     */
-    private static function processSellOrderImmediately(MexOrder $order): array
-    {
-        // 调用账户流转逻辑处理卖出订单
-        $result = MexAccountLogic::processSellOrder(
-            $order->user_id,
-            $order->item_id,
-            $order->quantity,
-            $order->price,
-            $order->total_amount,
-            $order->id
-        );
-
-        if ($result['success']) {
-            // 更新订单状态为已完成
-            $order->update([
-                'status' => OrderStatus::COMPLETED,
-                'completed_quantity' => $order->quantity,
-                'completed_amount' => $order->total_amount,
-                'completed_at' => now(),
-            ]);
-
-            // 触发订单完成事件
-            event(new OrderCompletedEvent($order));
-
             return [
                 'success' => true,
-                'message' => '卖出订单已完成',
-                'transaction_id' => $result['transaction_id'] ?? null
+                'order_id' => $order->id,
+                'message' => '买入订单创建成功,等待撮合'
             ];
-        } else {
-            // 处理失败,更新订单状态为失败
-            $order->update([
-                'status' => OrderStatus::FAILED,
-                'failed_reason' => $result['message'],
-                'completed_at' => now(),
-            ]);
-
-            return $result;
+        } catch (\Exception $e) {
+            return ['success' => false, 'message' => '创建订单失败:' . $e->getMessage()];
         }
     }
 
-    /**
-     * 立即处理买入订单
-     *
-     * @param MexOrder $order 订单
-     * @return array 处理结果
-     */
-    private static function processBuyOrderImmediately(MexOrder $order): array
-    {
-        // 调用账户流转逻辑处理买入订单
-        $result = MexAccountLogic::processBuyOrder(
-            $order->user_id,
-            $order->item_id,
-            $order->quantity,
-            $order->price,
-            $order->total_amount,
-            $order->id
-        );
-
-        if ($result['success']) {
-            // 更新订单状态为已完成
-            $order->update([
-                'status' => OrderStatus::COMPLETED,
-                'completed_quantity' => $order->quantity,
-                'completed_amount' => $order->total_amount,
-                'completed_at' => now(),
-            ]);
 
-            // 触发订单完成事件
-            event(new OrderCompletedEvent($order));
-
-            return [
-                'success' => true,
-                'message' => '买入订单已完成',
-                'transaction_id' => $result['transaction_id'] ?? null
-            ];
-        } else {
-            // 处理失败,更新订单状态为失败
-            $order->update([
-                'status' => OrderStatus::FAILED,
-                'failed_reason' => $result['message'],
-                'completed_at' => now(),
-            ]);
-
-            return $result;
-        }
-    }
 
     /**
      * 取消订单

+ 16 - 5
app/Module/Mex/Logic/MexPriceConfigLogic.php

@@ -75,7 +75,7 @@ class MexPriceConfigLogic
 
     /**
      * 验证卖出价格
-     * 
+     *
      * @param int $itemId 商品ID
      * @param string $price 价格
      * @return array 验证结果
@@ -83,7 +83,7 @@ class MexPriceConfigLogic
     public static function validateSellPrice(int $itemId, string $price): array
     {
         $config = self::getItemPriceConfig($itemId);
-        
+
         if (!$config) {
             return [
                 'valid' => false,
@@ -100,15 +100,26 @@ class MexPriceConfigLogic
             ];
         }
 
-        if (bccomp($price, $config['min_price'], 5) > 0) {
+        // 卖出价格不能低于最低价
+        if (bccomp($price, $config['min_price'], 5) < 0) {
             return [
                 'valid' => false,
-                'message' => "卖出价格不能于最低价 {$config['min_price']}",
-                'error_code' => 'PRICE_TOO_HIGH',
+                'message' => "卖出价格不能于最低价 {$config['min_price']}",
+                'error_code' => 'PRICE_TOO_LOW',
                 'min_price' => $config['min_price']
             ];
         }
 
+        // 卖出价格不能高于最高价
+        if (bccomp($price, $config['max_price'], 5) > 0) {
+            return [
+                'valid' => false,
+                'message' => "卖出价格不能高于最高价 {$config['max_price']}",
+                'error_code' => 'PRICE_TOO_HIGH',
+                'max_price' => $config['max_price']
+            ];
+        }
+
         return [
             'valid' => true,
             'message' => '价格验证通过',