Просмотр исходного кода

Mex模块增加多币种适配功能,默认钻石币种

- 完善FundLogic类,增加完整的币种与账户类型映射关系
- 为订单表和成交记录表添加currency_type字段,默认值为2(钻石)
- 更新MexOrder和MexTransaction模型,支持币种字段
- 修改MexAccountLogic类,支持币种参数传递和动态账户类型选择
- 更新MexTransactionLogic的createTransaction方法,支持币种字段
- 根据币种精度动态计算资金转换倍数,提高精度处理准确性
- 更新SQL生成文件,保持数据库结构同步
notfff 7 месяцев назад
Родитель
Сommit
dd91e2f618

+ 2 - 0
AiWork/记忆习惯.md

@@ -82,6 +82,8 @@
 - Mex模块撮合算法设计原则:大额订单应该卡住小额订单,这是业务需求而非要避免的问题
 - Mex模块中系统总量守恒验证不可用,因为交易期间会产生新的物品和资金,总量会发生变化
 - Mex模块的买入/卖出应该分为两个独立的任务处理,流程图也需要分开设计
+- Mex模块需要支持多币种适配功能,默认币种为钻石,通过FundLogic类管理币种与账户类型的映射关系
+- Mex模块多币种适配:订单表和成交记录表增加currency_type字段,FundLogic提供币种映射,MexAccountLogic支持币种参数传递
 
 ### GameItem模块
 - GameItem模块需要实现物品冻结功能,用于匹配交易过程中卖出物品时的状态管理

+ 2 - 0
app/Module/Mex/Databases/GenerateSql/mex_orders.sql

@@ -8,6 +8,7 @@ CREATE TABLE `kku_mex_orders` (
   `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '订单ID,主键',
   `user_id` bigint NOT NULL COMMENT '用户ID',
   `item_id` int NOT NULL COMMENT '商品ID,关联物品表',
+  `currency_type` int NOT NULL DEFAULT 2 COMMENT '币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石',
   `order_type` enum('BUY','SELL') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单类型:BUY买入,SELL卖出',
   `quantity` int NOT NULL COMMENT '订单数量',
   `price` decimal(15,5) NOT NULL COMMENT '订单价格,支持5位小数',
@@ -23,6 +24,7 @@ CREATE TABLE `kku_mex_orders` (
   PRIMARY KEY (`id`) USING BTREE,
   KEY `idx_user_id` (`user_id`) USING BTREE,
   KEY `idx_item_id` (`item_id`) USING BTREE,
+  KEY `idx_currency_type` (`currency_type`) USING BTREE COMMENT '币种类型索引',
   KEY `idx_order_type` (`order_type`) USING BTREE,
   KEY `idx_status` (`status`) USING BTREE,
   KEY `idx_created_at` (`created_at`) USING BTREE,

+ 2 - 0
app/Module/Mex/Databases/GenerateSql/mex_transactions.sql

@@ -11,6 +11,7 @@ CREATE TABLE `kku_mex_transactions` (
   `buyer_id` bigint NOT NULL COMMENT '买方用户ID',
   `seller_id` bigint NOT NULL COMMENT '卖方用户ID',
   `item_id` int NOT NULL COMMENT '商品ID,关联物品表',
+  `currency_type` int NOT NULL DEFAULT 2 COMMENT '币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石',
   `quantity` int NOT NULL COMMENT '成交数量',
   `price` decimal(15,5) NOT NULL COMMENT '成交价格',
   `total_amount` decimal(20,5) NOT NULL COMMENT '成交总金额',
@@ -24,6 +25,7 @@ CREATE TABLE `kku_mex_transactions` (
   KEY `idx_buyer_id` (`buyer_id`) USING BTREE,
   KEY `idx_seller_id` (`seller_id`) USING BTREE,
   KEY `idx_item_id` (`item_id`) USING BTREE,
+  KEY `idx_currency_type` (`currency_type`) USING BTREE COMMENT '币种类型索引',
   KEY `idx_transaction_type` (`transaction_type`) USING BTREE,
   KEY `idx_created_at` (`created_at`) USING BTREE,
   KEY `idx_is_admin_operation` (`is_admin_operation`) USING BTREE

+ 19 - 0
app/Module/Mex/Databases/Migrations/add_currency_fields.sql

@@ -0,0 +1,19 @@
+-- ******************************************************************
+-- Mex模块多币种适配 - 添加币种字段
+-- 执行时间: 2025年06月13日
+-- 说明: 为订单表和成交记录表添加币种字段,默认使用钻石币种
+-- ******************************************************************
+
+-- 1. 为订单表添加币种字段
+ALTER TABLE `kku_mex_orders` 
+ADD COLUMN `currency_type` int NOT NULL DEFAULT 2 COMMENT '币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石' AFTER `item_id`,
+ADD INDEX `idx_currency_type` (`currency_type`) USING BTREE COMMENT '币种类型索引';
+
+-- 2. 为成交记录表添加币种字段
+ALTER TABLE `kku_mex_transactions` 
+ADD COLUMN `currency_type` int NOT NULL DEFAULT 2 COMMENT '币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石' AFTER `item_id`,
+ADD INDEX `idx_currency_type` (`currency_type`) USING BTREE COMMENT '币种类型索引';
+
+-- 3. 更新现有数据为默认币种(钻石)
+UPDATE `kku_mex_orders` SET `currency_type` = 2 WHERE `currency_type` = 0;
+UPDATE `kku_mex_transactions` SET `currency_type` = 2 WHERE `currency_type` = 0;

+ 112 - 20
app/Module/Mex/Logic/FundLogic.php

@@ -4,56 +4,148 @@ namespace App\Module\Mex\Logic;
 
 use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
 use App\Module\Fund\Enums\FUND_TYPE;
-use App\Module\GameItems\Enums\FREEZE_ACTION_TYPE;
 
 /**
  * Fund 模块适配
  * 多币种适配
  *
+ * 为Mex模块提供币种与账户类型的映射关系
+ * 默认使用钻石币种进行交易
  */
 class FundLogic
 {
-
     /**
-     * 可用账户
+     * 可用账户标识
      */
     const CAN = 1;
 
     /**
-     * 冻结账户
+     * 冻结账户标识
      */
     const FREEZE = 2;
 
+    /**
+     * 默认币种:钻石
+     */
+    const DEFAULT_CURRENCY = FUND_CURRENCY_TYPE::ZUANSHI;
+
+    /**
+     * 币种与账户类型映射关系
+     *
+     * @var array
+     */
+    private static array $currencyMapping = [
+        // 金币币种映射
+        1 => [ // FUND_CURRENCY_TYPE::JINBI
+            self::CAN    => FUND_TYPE::FUND1, // 金币可用账户
+            self::FREEZE => FUND_TYPE::FUND1, // 金币暂无冻结账户,使用可用账户
+        ],
+        // 钻石币种映射(默认币种)
+        2 => [ // FUND_CURRENCY_TYPE::ZUANSHI
+            self::CAN    => FUND_TYPE::FUND2, // 钻石可用账户
+            self::FREEZE => FUND_TYPE::FUND3, // 钻石冻结账户
+        ],
+        // 人民币币种映射(预留)
+        3 => [ // FUND_CURRENCY_TYPE::CNY
+            self::CAN    => FUND_TYPE::FUND1, // 暂时映射到金币账户
+            self::FREEZE => FUND_TYPE::FUND1, // 暂时映射到金币账户
+        ],
+        // 美元币种映射(预留)
+        4 => [ // FUND_CURRENCY_TYPE::USD
+            self::CAN    => FUND_TYPE::FUND1, // 暂时映射到金币账户
+            self::FREEZE => FUND_TYPE::FUND1, // 暂时映射到金币账户
+        ],
+    ];
+
     /**
      * 获取币种适配
      *
-     * @param FUND_CURRENCY_TYPE $CURRENCY_TYPE
-     * @return array
+     * @param FUND_CURRENCY_TYPE $currencyType 币种类型
+     * @return array 账户类型映射数组
      */
-    public function get(FUND_CURRENCY_TYPE $CURRENCY_TYPE)
+    public static function get(FUND_CURRENCY_TYPE $currencyType): array
     {
-        $list = [
-            $CURRENCY_TYPE->value() => [
-                self::CAN    => FUND_TYPE::FUND1,
-                self::FREEZE => FUND_TYPE::FUND3
-            ]
-        ];
+        return self::$currencyMapping[$currencyType->value] ?? [];
+    }
 
-        return $list[$CURRENCY_TYPE->value()] ?? [];
+    /**
+     * 使用币种数字获取账户映射
+     *
+     * @param int $currencyTypeValue 币种类型值
+     * @return array 账户类型映射数组
+     */
+    public static function get4n(int $currencyTypeValue): array
+    {
+        $currencyType = FUND_CURRENCY_TYPE::tryFrom($currencyTypeValue);
+        if (!$currencyType) {
+            return [];
+        }
+
+        return self::get($currencyType);
     }
 
     /**
-     * 使用币种数字获取
+     * 获取默认币种
      *
-     * @param $ctype
-     * @return array
+     * @return FUND_CURRENCY_TYPE 默认币种(钻石)
      */
-    public function get4n($ctype)
+    public static function getDefaultCurrency(): FUND_CURRENCY_TYPE
     {
-        $type = FUND_CURRENCY_TYPE::tryFrom($ctype);
+        return self::DEFAULT_CURRENCY;
+    }
 
-        return self::get($type);
+    /**
+     * 获取默认币种的账户映射
+     *
+     * @return array 默认币种的账户类型映射数组
+     */
+    public static function getDefaultMapping(): array
+    {
+        return self::get(self::DEFAULT_CURRENCY);
+    }
 
+    /**
+     * 获取指定币种的可用账户类型
+     *
+     * @param FUND_CURRENCY_TYPE $currencyType 币种类型
+     * @return FUND_TYPE|null 可用账户类型
+     */
+    public static function getAvailableAccountType(FUND_CURRENCY_TYPE $currencyType): ?FUND_TYPE
+    {
+        $mapping = self::get($currencyType);
+        return $mapping[self::CAN] ?? null;
+    }
+
+    /**
+     * 获取指定币种的冻结账户类型
+     *
+     * @param FUND_CURRENCY_TYPE $currencyType 币种类型
+     * @return FUND_TYPE|null 冻结账户类型
+     */
+    public static function getFrozenAccountType(FUND_CURRENCY_TYPE $currencyType): ?FUND_TYPE
+    {
+        $mapping = self::get($currencyType);
+        return $mapping[self::FREEZE] ?? null;
+    }
+
+    /**
+     * 检查币种是否支持
+     *
+     * @param FUND_CURRENCY_TYPE $currencyType 币种类型
+     * @return bool 是否支持
+     */
+    public static function isCurrencySupported(FUND_CURRENCY_TYPE $currencyType): bool
+    {
+        return isset(self::$currencyMapping[$currencyType->value]);
     }
 
+    /**
+     * 获取所有支持的币种列表
+     *
+     * @return array 支持的币种ID列表
+     */
+    public static function getSupportedCurrencies(): array
+    {
+        return array_keys(self::$currencyMapping);
+    }
 }

+ 67 - 25
app/Module/Mex/Logic/MexAccountLogic.php

@@ -4,47 +4,58 @@ 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\GameItems\Services\ItemService;
 use App\Module\Mex\Logic\MexTransactionLogic;
 use App\Module\Mex\Logic\MexWarehouseLogic;
+use App\Module\Mex\Logic\FundLogic;
 use App\Module\Mex\Enums\TransactionType;
 use Illuminate\Support\Facades\DB;
 use Illuminate\Support\Facades\Log;
 
 /**
  * 农贸市场账户流转逻辑
- * 
+ *
  * 处理用户与仓库账户之间的资金和物品流转
  * 仓库账户USER_ID为15,调控账户USER_ID为16
+ * 支持多币种交易,默认使用钻石币种
  */
 class MexAccountLogic
 {
     // 仓库账户ID
     const WAREHOUSE_USER_ID = 15;
-    
-    // 调控账户ID  
+
+    // 调控账户ID
     const REGULATION_USER_ID = 16;
-    
-    // 默认资金类型(金币)
-    const DEFAULT_FUND_TYPE = FUND_TYPE::FUND1;
 
     /**
      * 处理用户卖出订单的账户流转
      * 用户卖出:资金从仓库转出到用户、物品从用户转入仓库
-     * 
+     *
      * @param int $userId 用户ID
      * @param int $itemId 商品ID
      * @param int $quantity 数量
      * @param string $price 单价
      * @param string $totalAmount 总金额
      * @param int $orderId 订单ID
+     * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
      * @return array 操作结果
      */
-    public static function processSellOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId): array
+    public static function processSellOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId, ?FUND_CURRENCY_TYPE $currencyType = null): array
     {
         try {
             DB::beginTransaction();
-            
+
+            // 获取币种类型,默认使用钻石
+            $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
+
+            // 获取对应的账户类型
+            $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
+            if (!$availableAccountType) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '不支持的币种类型'];
+            }
+
             // 1. 验证用户是否有足够的物品
             $checkResult = ItemService::checkItemQuantity($userId, $itemId, $quantity);
             if (!$checkResult->success) {
@@ -77,8 +88,9 @@ class MexAccountLogic
             }
             
             // 4. 从仓库账户转出资金给用户
-            $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, self::DEFAULT_FUND_TYPE);
-            $fundAmount = (int)bcmul($totalAmount, '100', 0); // 转换为整数(分)
+            $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, $availableAccountType->value);
+            $precision = $currencyType->getPrecision();
+            $fundAmount = (int)bcmul($totalAmount, bcpow('10', $precision), 0); // 根据币种精度转换
             
             $transferResult = $warehouseFundService->trade(
                 $userId,
@@ -106,6 +118,7 @@ class MexAccountLogic
                 'buyer_id' => self::WAREHOUSE_USER_ID,
                 'seller_id' => $userId,
                 'item_id' => $itemId,
+                'currency_type' => $currencyType->value,
                 'quantity' => $quantity,
                 'price' => $price,
                 'total_amount' => $totalAmount,
@@ -147,29 +160,41 @@ class MexAccountLogic
     /**
      * 处理用户买入订单的账户流转
      * 用户买入:资金从用户转入仓库、物品从仓库转出到用户
-     * 
+     *
      * @param int $userId 用户ID
      * @param int $itemId 商品ID
      * @param int $quantity 数量
      * @param string $price 单价
      * @param string $totalAmount 总金额
      * @param int $orderId 订单ID
+     * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
      * @return array 操作结果
      */
-    public static function processBuyOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId): array
+    public static function processBuyOrder(int $userId, int $itemId, int $quantity, string $price, string $totalAmount, int $orderId, ?FUND_CURRENCY_TYPE $currencyType = null): array
     {
         try {
             DB::beginTransaction();
-            
+
+            // 获取币种类型,默认使用钻石
+            $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
+
+            // 获取对应的账户类型
+            $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
+            if (!$availableAccountType) {
+                DB::rollBack();
+                return ['success' => false, 'message' => '不支持的币种类型'];
+            }
+
             // 1. 验证仓库是否有足够的物品
             if (!MexWarehouseLogic::checkStockSufficient($itemId, $quantity)) {
                 DB::rollBack();
                 return ['success' => false, 'message' => '仓库库存不足'];
             }
-            
+
             // 2. 验证用户是否有足够的资金
-            $userFundService = new FundService($userId, self::DEFAULT_FUND_TYPE);
-            $fundAmount = (int)bcmul($totalAmount, '100', 0); // 转换为整数(分)
+            $userFundService = new FundService($userId, $availableAccountType->value);
+            $precision = $currencyType->getPrecision();
+            $fundAmount = (int)bcmul($totalAmount, bcpow('10', $precision), 0); // 根据币种精度转换
             
             if ($userFundService->balance() < $fundAmount) {
                 DB::rollBack();
@@ -227,6 +252,7 @@ class MexAccountLogic
                 'buyer_id' => $userId,
                 'seller_id' => self::WAREHOUSE_USER_ID,
                 'item_id' => $itemId,
+                'currency_type' => $currencyType->value,
                 'quantity' => $quantity,
                 'price' => $price,
                 'total_amount' => $totalAmount,
@@ -267,23 +293,39 @@ class MexAccountLogic
 
     /**
      * 检查仓库账户资金余额
-     * 
-     * @return int 余额(分)
+     *
+     * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
+     * @return int 余额(按币种精度存储的整数)
      */
-    public static function getWarehouseFundBalance(): int
+    public static function getWarehouseFundBalance(?FUND_CURRENCY_TYPE $currencyType = null): int
     {
-        $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, self::DEFAULT_FUND_TYPE);
+        $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
+        $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
+
+        if (!$availableAccountType) {
+            return 0;
+        }
+
+        $warehouseFundService = new FundService(self::WAREHOUSE_USER_ID, $availableAccountType->value);
         return $warehouseFundService->balance();
     }
 
     /**
      * 检查调控账户资金余额
-     * 
-     * @return int 余额(分)
+     *
+     * @param FUND_CURRENCY_TYPE|null $currencyType 币种类型,默认使用钻石
+     * @return int 余额(按币种精度存储的整数)
      */
-    public static function getRegulationFundBalance(): int
+    public static function getRegulationFundBalance(?FUND_CURRENCY_TYPE $currencyType = null): int
     {
-        $regulationFundService = new FundService(self::REGULATION_USER_ID, self::DEFAULT_FUND_TYPE);
+        $currencyType = $currencyType ?? FundLogic::getDefaultCurrency();
+        $availableAccountType = FundLogic::getAvailableAccountType($currencyType);
+
+        if (!$availableAccountType) {
+            return 0;
+        }
+
+        $regulationFundService = new FundService(self::REGULATION_USER_ID, $availableAccountType->value);
         return $regulationFundService->balance();
     }
 }

+ 2 - 1
app/Module/Mex/Logic/MexTransactionLogic.php

@@ -219,7 +219,7 @@ class MexTransactionLogic
 
     /**
      * 创建成交记录
-     * 
+     *
      * @param array $data 成交数据
      * @return MexTransaction|null 成交记录
      */
@@ -232,6 +232,7 @@ class MexTransactionLogic
                 'buyer_id' => $data['buyer_id'],
                 'seller_id' => $data['seller_id'],
                 'item_id' => $data['item_id'],
+                'currency_type' => $data['currency_type'] ?? 2, // 默认使用钻石币种
                 'quantity' => $data['quantity'],
                 'price' => $data['price'],
                 'total_amount' => $data['total_amount'],

+ 6 - 2
app/Module/Mex/Models/MexOrder.php

@@ -4,14 +4,16 @@ namespace App\Module\Mex\Models;
 
 use App\Module\Mex\Enums\OrderStatus;
 use App\Module\Mex\Enums\OrderType;
+use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
 use UCore\ModelCore;
 
 /**
  * 农贸市场订单模型
- * field start 
+ * field start
  * @property  int  $id  订单ID,主键
  * @property  int  $user_id  用户ID
  * @property  int  $item_id  商品ID,关联物品表
+ * @property  \App\Module\Fund\Enums\FUND_CURRENCY_TYPE  $currency_type  币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石
  * @property  \App\Module\Mex\Enums\OrderType  $order_type  订单类型:BUY买入,SELL卖出
  * @property  int  $quantity  订单数量
  * @property  float  $price  订单价格,支持5位小数
@@ -30,11 +32,12 @@ class MexOrder extends ModelCore
 {
     protected $table = 'mex_orders';
 
-    // attrlist start 
+    // attrlist start
     protected $fillable = [
         'id',
         'user_id',
         'item_id',
+        'currency_type',
         'order_type',
         'quantity',
         'price',
@@ -51,6 +54,7 @@ class MexOrder extends ModelCore
     protected $casts = [
         'user_id' => 'integer',
         'item_id' => 'integer',
+        'currency_type' => FUND_CURRENCY_TYPE::class,
         'order_type' => OrderType::class,
         'quantity' => 'integer',
         'price' => 'decimal:5',

+ 6 - 2
app/Module/Mex/Models/MexTransaction.php

@@ -3,18 +3,20 @@
 namespace App\Module\Mex\Models;
 
 use App\Module\Mex\Enums\TransactionType;
+use App\Module\Fund\Enums\FUND_CURRENCY_TYPE;
 use UCore\ModelCore;
 
 /**
  * 农贸市场成交记录模型
  *
- * field start 
+ * field start
  * @property  int  $id  成交记录ID,主键
  * @property  int  $buy_order_id  买单ID,关联mex_orders表
  * @property  int  $sell_order_id  卖单ID,关联mex_orders表
  * @property  int  $buyer_id  买方用户ID
  * @property  int  $seller_id  卖方用户ID
  * @property  int  $item_id  商品ID,关联物品表
+ * @property  \App\Module\Fund\Enums\FUND_CURRENCY_TYPE  $currency_type  币种类型,关联FUND_CURRENCY_TYPE枚举,默认2为钻石
  * @property  int  $quantity  成交数量
  * @property  float  $price  成交价格
  * @property  float  $total_amount  成交总金额
@@ -28,7 +30,7 @@ class MexTransaction extends ModelCore
 {
     protected $table = 'mex_transactions';
 
-    // attrlist start 
+    // attrlist start
     protected $fillable = [
         'id',
         'buy_order_id',
@@ -36,6 +38,7 @@ class MexTransaction extends ModelCore
         'buyer_id',
         'seller_id',
         'item_id',
+        'currency_type',
         'quantity',
         'price',
         'total_amount',
@@ -51,6 +54,7 @@ class MexTransaction extends ModelCore
         'buyer_id' => 'integer',
         'seller_id' => 'integer',
         'item_id' => 'integer',
+        'currency_type' => FUND_CURRENCY_TYPE::class,
         'quantity' => 'integer',
         'price' => 'decimal:5',
         'total_amount' => 'decimal:5',