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

feat(fund): 完善币种服务并优化相关模型

- 重命名和更新了 FundCurrencyType 和 FundType 枚举的注释
- 调整了 FundConfigModel 和 FundCurrencyModel 的字段注释
- 重构了 FundModel 的注释,明确了账户种类和币种的关系
- 大幅扩展了 CurrencyService 类的功能,包括:
  - 添加了币种检查、获取币种信息等方法
  - 实现了币种配置、名称列表、标识列表等缓存功能
  - 新增了金额格式化和转换相关方法
Your Name 8 месяцев назад
Родитель
Сommit
84cb5d5153

+ 180 - 0
app/Module/Fund/Docs/币种与账户关系.md

@@ -0,0 +1,180 @@
+# 币种与账户关系说明文档
+
+## 1. 概述
+
+在资金模块中,币种(Currency)和账户种类(Fund Config)是两个不同但相关的概念。本文档旨在明确这两个概念的区别和关系,以及它们在系统中的应用。
+
+## 2. 核心概念
+
+### 2.1 币种(Currency)
+
+币种是指货币的种类,如美元、人民币、比特币等。在系统中,币种由 `FundCurrencyModel` 表示,存储在 `fund_currency` 表中。
+
+**特点:**
+- 每种币种有唯一的标识符(identification)
+- 币种有自己的图标(icon)和名称(name)
+- 币种可以有额外的属性(data1),如汇率、精度等
+
+**示例:**
+- 美元(USD)
+- 人民币(CNY)
+- 比特币(BTC)
+- USDT
+- BNB
+
+### 2.2 账户种类(Fund Config)
+
+账户种类是指用户资金的不同用途或状态,如可用账户、冻结账户等。在系统中,账户种类由 `FundConfigModel` 表示,存储在 `fund_config` 表中。
+
+**特点:**
+- 每种账户种类有唯一的ID和名称
+- 同一币种可以有多种账户种类
+- 账户种类决定了资金的使用限制和业务规则
+
+**示例:**
+- 可用美元账户
+- 冻结美元账户
+- 可用人民币账户
+- 冻结人民币账户
+
+### 2.3 用户账户(Fund)
+
+用户账户是用户实际持有的资金账户,由用户ID、账户种类ID和余额组成。在系统中,用户账户由 `FundModel` 表示,存储在 `fund` 表中。
+
+**特点:**
+- 每个用户可以有多个不同种类的账户
+- 账户余额以整数形式存储,需要根据币种的精度进行换算
+- 账户操作会生成日志记录
+
+## 3. 关系说明
+
+### 3.1 币种与账户种类的关系
+
+一个币种可以对应多个账户种类,例如:
+
+- 美元(币种)可以有:
+  - 可用美元账户(账户种类)
+  - 冻结美元账户(账户种类)
+
+- 比特币(币种)可以有:
+  - 可用比特币账户(账户种类)
+  - 冻结比特币账户(账户种类)
+  - 质押比特币账户(账户种类)
+
+### 3.2 账户种类与用户账户的关系
+
+一个用户可以拥有多个不同种类的账户,每个账户都有自己的余额。例如:
+
+- 用户A可以同时拥有:
+  - 可用美元账户(余额:100)
+  - 冻结美元账户(余额:50)
+  - 可用比特币账户(余额:0.01)
+
+## 4. 数据结构
+
+### 4.1 币种表(fund_currency)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| id | int | 主键 |
+| identification | varchar(10) | 币种标识 |
+| icon | varchar(20) | 币种图标 |
+| name | varchar(30) | 币种名称 |
+| data1 | text | 额外数据(JSON格式) |
+| create_time | int | 创建时间 |
+| update_time | int | 更新时间 |
+
+### 4.2 账户种类表(fund_config)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| id | int | 主键 |
+| name | varchar(30) | 账户种类名称 |
+| create_time | int | 创建时间 |
+| update_time | int | 更新时间 |
+
+### 4.3 用户账户表(fund)
+
+| 字段 | 类型 | 说明 |
+|------|------|------|
+| id | int | 主键 |
+| user_id | int | 用户ID |
+| fund_id | int | 账户种类ID |
+| balance | bigint | 余额 |
+| update_time | int | 更新时间 |
+| create_time | int | 创建时间 |
+
+## 5. 业务流程
+
+### 5.1 账户创建流程
+
+1. 系统预先配置好支持的币种(Currency)
+2. 系统预先配置好各币种的账户种类(Fund Config)
+3. 用户注册后,系统自动为用户创建默认账户
+4. 用户可以根据需要申请开通其他类型的账户
+
+### 5.2 资金操作流程
+
+1. 充值:增加用户特定账户的余额
+2. 消费:减少用户特定账户的余额
+3. 转账:减少一个账户余额,增加另一个账户余额
+4. 冻结:从可用账户转移到冻结账户
+5. 解冻:从冻结账户转移到可用账户
+
+## 6. 开发指南
+
+### 6.1 获取币种列表
+
+```php
+// 获取所有币种
+$currencies = FundCurrencyModel::all();
+
+// 获取币种名称列表
+$currencyNames = CurrencyService::getValueDesc();
+```
+
+### 6.2 获取账户种类列表
+
+```php
+// 获取所有账户种类
+$fundConfigs = FundConfigModel::all();
+
+// 获取账户种类名称列表
+$fundConfigNames = AccountService::getFundsDesc();
+```
+
+### 6.3 获取用户账户
+
+```php
+// 获取用户所有账户
+$accounts = FundModel::userAccount($userId);
+
+// 获取用户特定账户
+$account = FundModel::getAccount($userId, $fundId);
+```
+
+### 6.4 资金操作
+
+```php
+// 增加资金
+FundModel::inc($userId, $fundId, $amount);
+
+// 减少资金
+FundModel::dec($userId, $fundId, $amount);
+
+// 资金流转(同用户不同账户间转账)
+$fundService = new FundService($userId, $fromFundId);
+$fundService->circulation($toFundId, $amount, $reId, $reType, $remark);
+
+// 转账(不同用户间转账)
+$fundService = new FundService($fromUserId, $fundId);
+$fundService->transfer($toUserId, $amount, $remark);
+```
+
+## 7. 注意事项
+
+1. 币种和账户种类是一对多的关系,一个币种可以有多种账户类型
+2. 账户余额以整数形式存储,需要根据币种的精度进行换算
+3. 资金操作应在事务中进行,确保数据一致性
+4. 所有资金操作都会生成日志记录,便于追踪和审计
+5. 币种配置和账户种类配置通常由管理员在后台进行管理

+ 3 - 1
app/Module/Fund/Enums/FUND_CURRENCY_TYPE.php

@@ -5,7 +5,9 @@ namespace App\Module\Fund\Enums;
 use UCore\Enum\EnumName;
 
 /**
- * 基金货币类型枚举
+ * 币种类型枚举
+ *
+ * 定义系统支持的各种币种类型
  */
 enum FUND_CURRENCY_TYPE: int
 {

+ 6 - 2
app/Module/Fund/Enums/FUND_TYPE.php

@@ -11,12 +11,16 @@ enum FUND_TYPE: int
     use EnumToInt, EnumCore, EnumExpression;
 
     /**
-     * 代币1
+     * 可用账户
+     *
+     * 用于存储用户可以自由使用的资金
      */
     case FUND1 = 1;
 
     /**
-     * 代币1
+     * 冻结账户
+     *
+     * 用于存储用户被临时冻结的资金
      */
     case FUND2 = 2;
 

+ 8 - 12
app/Module/Fund/Models/FundConfigModel.php

@@ -5,19 +5,15 @@ namespace App\Module\Fund\Models;
 use UCore\ModelCore;
 
 /**
- * 资金配置表
- * @property int $id
- * @property string $name 配置名称
- * @property int $create_time
- * @property int $update_time
- */
-/**
- * App\Module\Fund\Models\FundConfigModel
+ * 账户种类配置表
+ *
+ * 用于存储系统支持的各种账户种类,如可用账户、冻结账户等。
+ * 同一个币种(FundCurrencyModel)可以有多个不同的账户种类。
  *
- * field start 
+ * field start
  * @property   int  $id  自增
- * @property   string  $name  资金名字
- * @property   int  $create_time  
+ * @property   string  $name  账户种类名称
+ * @property   int  $create_time  创建时间
  * @property   int  $update_time  更新时间
  * field end
  */
@@ -25,7 +21,7 @@ class FundConfigModel extends ModelCore
 {
     protected $table = 'fund_config';
 
-    // attrlist start 
+    // attrlist start
     protected $fillable = [
         'id',
         'name',

+ 11 - 15
app/Module/Fund/Models/FundCurrencyModel.php

@@ -5,22 +5,18 @@ namespace App\Module\Fund\Models;
 use UCore\ModelCore;
 
 /**
- * 货币配置表
- * @property int $id
- * @property string $name 货币名称
- * @property int $create_time
- * @property int $update_time
- */
-/**
- * App\Module\Fund\Models\FundCurrencyModel
+ * 币种配置表
+ *
+ * 用于存储系统支持的各种币种信息,如美元、人民币、比特币等。
+ * 一个币种可以对应多个账户种类(FundConfigModel)。
  *
- * field start 
+ * field start
  * @property   int  $id  自增
- * @property   string  $identification  资金标识
- * @property   string  $icon  资金标识
- * @property   string  $name  资金名字
- * @property   string  $data1  数据
- * @property   int  $create_time  
+ * @property   string  $identification  币种标识
+ * @property   string  $icon  币种图标
+ * @property   string  $name  币种名称
+ * @property   string  $data1  额外数据(JSON格式)
+ * @property   int  $create_time  创建时间
  * @property   int  $update_time  更新时间
  * field end
  */
@@ -28,7 +24,7 @@ class FundCurrencyModel extends ModelCore
 {
     protected $table = 'fund_currency';
 
-    // attrlist start 
+    // attrlist start
     protected $fillable = [
         'id',
         'identification',

+ 6 - 3
app/Module/Fund/Models/FundModel.php

@@ -10,17 +10,20 @@ use App\Module\User\Models\UserInfo;
 use UCore\ModelCore;
 
 /**
- * 资金表
+ * 用户账户表
+ *
+ * 存储用户的各种账户信息及余额。每个用户可以拥有多个不同种类的账户,
+ * 每个账户对应一种账户种类(FundConfigModel)。
+ * 同一币种可以有多个不同用途的账户,如可用账户、冻结账户等。
  *
  * field start
  * @property   int  $id  自增
  * @property   int  $user_id  用户ID
- * @property   int  $fund_id  资金ID
+ * @property   int  $fund_id  账户种类ID
  * @property   int  $balance  余额
  * @property   int  $update_time  更新时间
  * @property   int  $create_time  创建时间
  * field end
- *
  */
 class FundModel extends ModelCore
 {

+ 197 - 13
app/Module/Fund/Services/CurrencyService.php

@@ -2,41 +2,225 @@
 
 namespace App\Module\Fund\Services;
 
+
+use App\Module\Fund\Models\FundConfigModel;
 use App\Module\Fund\Models\FundCurrencyModel;
 use App\Module\System\Services\ConfigService;
+use Illuminate\Support\Facades\Cache;
+use UCore\Helper\Cache as CacheHelper;
 
-
-
+/**
+ * 币种服务类
+ *
+ * 提供币种相关的服务,包括币种信息获取、币种检查等功能
+ */
 class CurrencyService
 {
-
+    /**
+     * 缓存时间(秒)
+     */
+    const CACHE_TTL = 3600;
 
     /**
-     * @param $fund_id
-     * @param $fund_id2
-     * @return bool
+     * 检查两个账户的币种是否一致
+     *
+     * @param int $fund_id 账户种类ID1
+     * @param int $fund_id2 账户种类ID2
+     * @return bool 是否一致
      */
     static public function check($fund_id, $fund_id2): bool
     {
-        //@todo 货币种类检查
-        return true;
+        // 获取两个账户种类对应的币种
+        $currency1 = self::getCurrencyByFundId($fund_id);
+        $currency2 = self::getCurrencyByFundId($fund_id2);
+
+        // 如果任一币种信息获取失败,返回false
+        if (!$currency1 || !$currency2) {
+            return false;
+        }
+
+        // 检查两个币种ID是否一致
+        return $currency1->id === $currency2->id;
     }
 
-    public function getConfig($fund_id = null)
+    /**
+     * 获取账户种类对应的币种
+     *
+     * @param int $fund_id 账户种类ID
+     * @return FundCurrencyModel|null 币种信息
+     */
+    static public function getCurrencyByFundId($fund_id)
     {
-        //@todo 获取货币种类配置
+        // 获取账户种类信息
+        $fundConfig = FundConfigModel::find($fund_id);
+        if (!$fundConfig) {
+            return null;
+        }
 
+        // 从账户种类信息中获取币种ID
+        // 注意:这里假设FundConfigModel中有currency_id字段
+        // 如果实际结构不同,需要根据实际情况调整
+        $currencyId = $fundConfig->currency_id ?? null;
+        if (!$currencyId) {
+            return null;
+        }
+
+        // 获取币种信息
+        return FundCurrencyModel::find($currencyId);
+    }
 
+    /**
+     * 获取币种配置
+     *
+     * @param int|null $currency_id 币种ID,为null时返回所有币种配置
+     * @return array|FundCurrencyModel 币种配置
+     */
+    public function getConfig($currency_id = null)
+    {
+        if ($currency_id) {
+            // 获取指定币种的配置
+            return Cache::remember('currency_config_' . $currency_id, self::CACHE_TTL, function () use ($currency_id) {
+                return FundCurrencyModel::find($currency_id);
+            });
+        } else {
+            // 获取所有币种的配置
+            return Cache::remember('currency_config_all', self::CACHE_TTL, function () {
+                return FundCurrencyModel::all();
+            });
+        }
     }
 
+    /**
+     * 获取币种名称列表
+     *
+     * @return array 币种ID => 币种名称
+     */
     static public function getValueDesc()
     {
-        return \UCore\Helper\Cache::cacheCall([ __CLASS__, __FUNCTION__ ], function () {
-            $list = FundCurrencyModel::query()->pluck('name', 'id')->toArray();;
+        return CacheHelper::cacheCall([__CLASS__, __FUNCTION__], function () {
+            $list = FundCurrencyModel::query()->pluck('name', 'id')->toArray();
+            return $list;
+        }, [], 10, [ConfigService::CACHE_TAG]);
+    }
 
+    /**
+     * 获取币种标识列表
+     *
+     * @return array 币种ID => 币种标识
+     */
+    static public function getIdentifications()
+    {
+        return CacheHelper::cacheCall([__CLASS__, __FUNCTION__], function () {
+            $list = FundCurrencyModel::query()->pluck('identification', 'id')->toArray();
             return $list;
-        },                                    [], 10, [ ConfigService::CACHE_TAG ]);
+        }, [], 10, [ConfigService::CACHE_TAG]);
+    }
 
+    /**
+     * 根据币种标识获取币种信息
+     *
+     * @param string $identification 币种标识
+     * @return FundCurrencyModel|null 币种信息
+     */
+    static public function getCurrencyByIdentification($identification)
+    {
+        return Cache::remember('currency_by_identification_' . $identification, self::CACHE_TTL, function () use ($identification) {
+            return FundCurrencyModel::where('identification', $identification)->first();
+        });
     }
 
+    /**
+     * 获取所有币种列表
+     *
+     * @param bool $refresh 是否刷新缓存
+     * @return array 币种列表
+     */
+    static public function getAllCurrencies($refresh = false)
+    {
+        $cacheKey = 'all_currencies';
+
+        if ($refresh) {
+            Cache::forget($cacheKey);
+        }
+
+        return Cache::remember($cacheKey, self::CACHE_TTL, function () {
+            return FundCurrencyModel::all()->toArray();
+        });
+    }
+
+    /**
+     * 获取币种的精度
+     *
+     * @param int $currency_id 币种ID
+     * @return int 精度(小数位数)
+     */
+    static public function getCurrencyPrecision($currency_id)
+    {
+        $currency = FundCurrencyModel::find($currency_id);
+        if (!$currency) {
+            return 2; // 默认精度为2
+        }
+
+        // 从data1字段中获取精度信息
+        if (!empty($currency->data1)) {
+            $data = json_decode($currency->data1, true);
+            if (isset($data['precision'])) {
+                return (int)$data['precision'];
+            }
+        }
+
+        return 2; // 默认精度为2
+    }
+
+    /**
+     * 格式化金额显示
+     *
+     * @param int $amount 金额(整数形式)
+     * @param int $currency_id 币种ID
+     * @return string 格式化后的金额
+     */
+    static public function formatAmount($amount, $currency_id)
+    {
+        $precision = self::getCurrencyPrecision($currency_id);
+        $divisor = pow(10, $precision);
+
+        // 将整数形式的金额转换为带小数的形式
+        $formattedAmount = number_format($amount / $divisor, $precision, '.', ',');
+
+        // 获取币种标识
+        $currency = FundCurrencyModel::find($currency_id);
+        $symbol = $currency ? $currency->identification : '';
+
+        return $symbol . ' ' . $formattedAmount;
+    }
+
+    /**
+     * 将用户输入的金额转换为系统存储的整数形式
+     *
+     * @param float $amount 用户输入的金额
+     * @param int $currency_id 币种ID
+     * @return int 系统存储的整数形式金额
+     */
+    static public function convertToStorageAmount($amount, $currency_id)
+    {
+        $precision = self::getCurrencyPrecision($currency_id);
+        $multiplier = pow(10, $precision);
+
+        return (int)round($amount * $multiplier);
+    }
+
+    /**
+     * 将系统存储的整数形式金额转换为实际金额
+     *
+     * @param int $storageAmount 系统存储的整数形式金额
+     * @param int $currency_id 币种ID
+     * @return float 实际金额
+     */
+    static public function convertFromStorageAmount($storageAmount, $currency_id)
+    {
+        $precision = self::getCurrencyPrecision($currency_id);
+        $divisor = pow(10, $precision);
+
+        return $storageAmount / $divisor;
+    }
 }