4 Комити e373586967 ... 836dbfb1d3

Аутор SHA1 Порука Датум
  huangjunling 836dbfb1d3 实名认证 пре 1 недеља
  huangjunling 66c15c68f9 改renren分层接口为mp的 пре 1 недеља
  huangjunling 3ece9777e5 Merge remote-tracking branch 'origin/master' пре 2 недеља
  huangjunling c2bdf34094 转账 пре 2 недеља
100 измењених фајлова са 4261 додато и 237 уклоњено
  1. 9 0
      blockchain-transfer/.gitignore
  2. 36 0
      blockchain-transfer/README.en.md
  3. 37 0
      blockchain-transfer/README.md
  4. 211 0
      blockchain-transfer/pom.xml
  5. 12 0
      blockchain-transfer/src/main/java/com/table/transfer/TableTransferApplication.java
  6. 114 0
      blockchain-transfer/src/main/java/com/table/transfer/config/RabbitConfig.java
  7. 17 0
      blockchain-transfer/src/main/java/com/table/transfer/config/WebConfig.java
  8. 83 0
      blockchain-transfer/src/main/java/com/table/transfer/module/controller/TransferController.java
  9. 12 0
      blockchain-transfer/src/main/java/com/table/transfer/module/controller/TransferRecordController.java
  10. 24 0
      blockchain-transfer/src/main/java/com/table/transfer/module/enpty/ChainCoinDetail.java
  11. 138 0
      blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransactionInfoDTO.java
  12. 52 0
      blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransferRecord.java
  13. 49 0
      blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransferRequest.java
  14. 33 0
      blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransferResponse.java
  15. 56 0
      blockchain-transfer/src/main/java/com/table/transfer/module/enpty/Trc20TransferInfo.java
  16. 10 0
      blockchain-transfer/src/main/java/com/table/transfer/module/mapper/TransferRecordMapper.java
  17. 25 0
      blockchain-transfer/src/main/java/com/table/transfer/module/service/BlockchainService.java
  18. 523 0
      blockchain-transfer/src/main/java/com/table/transfer/module/service/EthereumService.java
  19. 12 0
      blockchain-transfer/src/main/java/com/table/transfer/module/service/Impl/TransferRecordServiceImpl.java
  20. 8 0
      blockchain-transfer/src/main/java/com/table/transfer/module/service/TransferRecordService.java
  21. 485 0
      blockchain-transfer/src/main/java/com/table/transfer/module/service/TronService.java
  22. 162 0
      blockchain-transfer/src/main/java/com/table/transfer/util/CryptoUtil.java
  23. 431 0
      blockchain-transfer/src/main/java/com/table/transfer/util/TronGridQueryUtil.java
  24. 18 0
      blockchain-transfer/src/main/java/com/table/transfer/util/aUtil.java
  25. 190 0
      blockchain-transfer/src/main/java/com/table/transfer/util/encryp/RSAEncryptionUtil.java
  26. 44 0
      blockchain-transfer/src/main/java/com/table/transfer/util/ether/ChainCoinDetailManager.java
  27. 47 0
      blockchain-transfer/src/main/java/com/table/transfer/util/ether/Web3jManager.java
  28. 90 0
      blockchain-transfer/src/main/java/com/table/transfer/util/tron/TronHexAndBase58Util.java
  29. 41 0
      blockchain-transfer/src/main/resources/application-dev.yaml
  30. 48 0
      blockchain-transfer/src/main/resources/application-local.yaml
  31. 41 0
      blockchain-transfer/src/main/resources/application-prod.yaml
  32. 4 0
      blockchain-transfer/src/main/resources/application.yaml
  33. 55 0
      blockchain-transfer/src/test/java/BlockchainServiceTest.java
  34. 6 1
      qnfhq-api/pom.xml
  35. 1 1
      qnfhq-api/src/main/java/com/qnfhq/common/ApiBaseController.java
  36. 2 1
      qnfhq-api/src/main/java/com/qnfhq/config/SaTokenConfigure.java
  37. 261 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/controller/UserAuthenticationController.java
  38. 148 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/controller/UserEkycCallbackController.java
  39. 147 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/AikycRequest.java
  40. 25 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/ExtFaceInfo.java
  41. 32 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/ExtIdInfo.java
  42. 79 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/UserAuthentication.java
  43. 20 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/mapper/UserAuthenticationMapper.java
  44. 18 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/service/UserAuthenticationService.java
  45. 22 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/service/impl/UserAuthenticationServiceImpl.java
  46. 32 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/util/AliyunEkycConfig.java
  47. 138 0
      qnfhq-api/src/main/java/com/qnfhq/modules/authentication/util/AliyunEkycUtil.java
  48. 16 14
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/controller/C2cAdController.java
  49. 1 1
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/controller/C2cMerchantController.java
  50. 27 25
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/controller/C2cOrderController.java
  51. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/AppAssetLogDao.java
  52. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cAdDao.java
  53. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cAdLogDao.java
  54. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cLegalCoinDao.java
  55. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cMerchantConfigDao.java
  56. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cMerchantDao.java
  57. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderComplainDao.java
  58. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderComplainVoucherDao.java
  59. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderDao.java
  60. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderLogDao.java
  61. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cPayWayDao.java
  62. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cPaymentVoucherDao.java
  63. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cUserReceiptDao.java
  64. 2 7
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dto/C2cAdListDTO.java
  65. 2 7
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dto/C2cOrderListDTO.java
  66. 3 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/AppAssetLogService.java
  67. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cAdLogService.java
  68. 4 4
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cAdService.java
  69. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cLegalCoinService.java
  70. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cMerchantConfigService.java
  71. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cMerchantService.java
  72. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderComplainService.java
  73. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderComplainVoucherService.java
  74. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderLogService.java
  75. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderService.java
  76. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cPayWayService.java
  77. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cPaymentVoucherService.java
  78. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cUserReceiptService.java
  79. 5 11
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/AppAssetLogServiceImpl.java
  80. 3 5
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cAdLogServiceImpl.java
  81. 26 23
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cAdServiceImpl.java
  82. 4 5
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cLegalCoinServiceImpl.java
  83. 3 4
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cMerchantConfigServiceImpl.java
  84. 6 11
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cMerchantServiceImpl.java
  85. 3 8
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderComplainServiceImpl.java
  86. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderComplainVoucherServiceImpl.java
  87. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderLogServiceImpl.java
  88. 18 18
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderServiceImpl.java
  89. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cPayWayServiceImpl.java
  90. 3 3
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cPaymentVoucherServiceImpl.java
  91. 4 4
      qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cUserReceiptServiceImpl.java
  92. 3 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppAssetDao.java
  93. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppUserDao.java
  94. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppUserDetailDao.java
  95. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppWalletRecordDao.java
  96. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppuserLoginLogDao.java
  97. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/SettingDao.java
  98. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/SmsSendDao.java
  99. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/SmsTplDao.java
  100. 2 2
      qnfhq-api/src/main/java/com/qnfhq/modules/user/service/AppAssetService.java

+ 9 - 0
blockchain-transfer/.gitignore

@@ -0,0 +1,9 @@
+.idea
+target
+*.iml
+/*.iml
+/.idea/misc.xml
+/.idea/workspace.xml
+./table-admin/src/main/resources/application-dev.yml
+./table-api/src/main/resources/application-dev.yml
+*.log

+ 36 - 0
blockchain-transfer/README.en.md

@@ -0,0 +1,36 @@
+# blockchain-transfer
+
+#### Description
+区块链转账
+
+#### Software Architecture
+Software architecture description
+
+#### Installation
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Instructions
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### Contribution
+
+1.  Fork the repository
+2.  Create Feat_xxx branch
+3.  Commit your code
+4.  Create Pull Request
+
+
+#### Gitee Feature
+
+1.  You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
+2.  Gitee blog [blog.gitee.com](https://blog.gitee.com)
+3.  Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
+4.  The most valuable open source project [GVP](https://gitee.com/gvp)
+5.  The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
+6.  The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 37 - 0
blockchain-transfer/README.md

@@ -0,0 +1,37 @@
+# blockchain-transfer
+
+#### 介绍
+区块链转账
+
+#### 软件架构
+软件架构说明
+
+
+#### 安装教程
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 使用说明
+
+1.  xxxx
+2.  xxxx
+3.  xxxx
+
+#### 参与贡献
+
+1.  Fork 本仓库
+2.  新建 Feat_xxx 分支
+3.  提交代码
+4.  新建 Pull Request
+
+
+#### 特技
+
+1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
+2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
+3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
+4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
+5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
+6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

+ 211 - 0
blockchain-transfer/pom.xml

@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+         http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>3.1.5</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>blockchain-transfer</artifactId>
+    <groupId>com.table</groupId>
+
+    <packaging>jar</packaging>
+
+    <name>Blockchain Transfer Service</name>
+    <description>ETH/BNB/TRON transfer service</description>
+
+    <properties>
+        <java.version>20</java.version>
+        <maven.compiler.source>20</maven.compiler.source>
+        <maven.compiler.target>20</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <!-- Spring Boot Starter Web -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- Spring Boot Starter Validation -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!-- HTTP Client -->
+        <dependency>
+            <groupId>org.apache.httpcomponents.client5</groupId>
+            <artifactId>httpclient5</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.5.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>8.0.33</version>
+        </dependency>
+        <!-- JSON Processing -->
+
+        <!-- Ethereum cryptography -->
+        <dependency>
+            <groupId>org.web3j</groupId>
+            <artifactId>core</artifactId>
+            <version>4.9.8</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </exclusion>
+                <!-- 排除旧版本的 OkHttp -->
+                <exclusion>
+                    <groupId>com.squareup.okhttp3</groupId>
+                    <artifactId>okhttp</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.squareup.okio</groupId>
+                    <artifactId>okio</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 统一引入较新版本的 OkHttp(无 Kotlin 依赖的版本) -->
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.12.0</version>
+        </dependency>
+        <dependency>
+            <groupId>io.github.tronprotocol</groupId>
+            <artifactId>trident</artifactId>
+            <version>0.10.0</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-http</artifactId>
+            <version>5.8.39</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-json -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-json</artifactId>
+            <version>5.8.39</version>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-crypto</artifactId>
+            <version>5.8.39</version>
+        </dependency>
+
+        <!-- Lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+        </dependency>
+    </dependencies>
+    <!--打包配置-->
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+                <includes>
+                    <include>application.yaml</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>false</filtering>
+                <includes>
+                    <!-- 只包含当前激活环境的配置文件 -->
+                    <include>application-${profile.active}.yaml</include>
+                    <include>application-${profile.active}.properties</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>false</filtering>
+                <excludes>
+                    <!-- 排除所有其他环境的配置文件 -->
+                    <exclude>application-*.yaml</exclude>
+                    <exclude>application-*.properties</exclude>
+                    <exclude>bootstrap-*.yaml</exclude>
+                    <exclude>bootstrap-*.properties</exclude>
+                </excludes>
+            </resource>
+        </resources>
+
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+
+            <!-- 资源过滤插件 -->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>3.3.1</version>
+                <configuration>
+                    <propertiesEncoding>UTF-8</propertiesEncoding>
+                    <useDefaultDelimiters>true</useDefaultDelimiters>
+                    <delimiters>
+                        <delimiter>@</delimiter>
+                    </delimiters>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>dev</id>
+            <properties>
+                <profile.active>dev</profile.active>
+            </properties>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+        </profile>
+
+        <profile>
+            <id>local</id>
+            <properties>
+                <profile.active>local</profile.active>
+            </properties>
+        </profile>
+
+        <profile>
+            <id>prod</id>
+            <properties>
+                <profile.active>prod</profile.active>
+            </properties>
+        </profile>
+    </profiles>
+    
+</project>

+ 12 - 0
blockchain-transfer/src/main/java/com/table/transfer/TableTransferApplication.java

@@ -0,0 +1,12 @@
+package com.table.transfer;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+
+@SpringBootApplication
+public class TableTransferApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(TableTransferApplication.class, args);
+    }
+}

+ 114 - 0
blockchain-transfer/src/main/java/com/table/transfer/config/RabbitConfig.java

@@ -0,0 +1,114 @@
+package com.table.transfer.config;
+
+import org.springframework.amqp.core.*;
+import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
+import org.springframework.amqp.support.converter.MessageConverter;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Component;
+
+// RabbitConfig.java
+@Component
+public class RabbitConfig {
+    public static final String TRANSFER_EXCHANGE = "transfer";
+
+    // 请求队列和路由键
+    public static final String TRANSFER_REQUEST_QUEUE = "transfer.request";
+    public static final String TRANSFER_ETH = "ETH";
+    public static final String TRANSFER_BSC = "BSC";
+    public static final String TRANSFER_TRON = "TRON";
+
+    // 结果队列和路由键
+    public static final String TRANSFER_RESULT_QUEUE = "transfer.result";
+    public static final String TRANSFER_RESULT = "result";
+
+    // 请求队列
+    @Bean
+    public Queue transferRequestQueue() {
+        return QueueBuilder.durable(TRANSFER_REQUEST_QUEUE)
+                .singleActiveConsumer()
+                .build();
+    }
+
+    // 结果队列
+    @Bean
+    public Queue transferResultQueue() {
+        return QueueBuilder.durable(TRANSFER_RESULT_QUEUE)
+                .singleActiveConsumer()
+                .build();
+    }
+
+    // 只需要一个交换机
+    @Bean
+    public DirectExchange transferExchange() {
+        return new DirectExchange(TRANSFER_EXCHANGE);
+    }
+
+    // 请求队列的绑定(修正路由键)
+    @Bean
+    public Binding transferETHBinding() {
+        return BindingBuilder.bind(transferRequestQueue())
+                .to(transferExchange())
+                .with(TRANSFER_ETH);
+    }
+
+    @Bean
+    public Binding transferBSCBinding() {
+        return BindingBuilder.bind(transferRequestQueue())
+                .to(transferExchange())
+                .with(TRANSFER_BSC);
+    }
+
+    @Bean
+    public Binding transferTRONBinding() {
+        return BindingBuilder.bind(transferRequestQueue())
+                .to(transferExchange())
+                .with(TRANSFER_TRON);
+    }
+
+    // 结果队列的绑定
+    @Bean
+    public Binding transferResultBinding() {
+        return BindingBuilder.bind(transferResultQueue())
+                .to(transferExchange())
+                .with(TRANSFER_RESULT);
+    }
+
+    @Bean
+    public MessageConverter jsonMessageConverter() {
+        return new Jackson2JsonMessageConverter();
+    }
+
+    /**
+     * 配置RabbitTemplate使用JSON转换器
+     */
+    @Bean
+    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
+        RabbitTemplate template = new RabbitTemplate(connectionFactory);
+        template.setMessageConverter(jsonMessageConverter());
+        return template;
+    }
+
+    /**
+     * 配置监听容器工厂使用JSON转换器
+     */
+    @Bean
+    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(
+            ConnectionFactory connectionFactory) {
+        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
+        factory.setConnectionFactory(connectionFactory);
+        factory.setMessageConverter(jsonMessageConverter());
+
+        // 可选:配置并发等参数
+        factory.setConcurrentConsumers(1);
+        factory.setMaxConcurrentConsumers(1);
+        factory.setPrefetchCount(1); // 串行处理,每次只处理一个消息
+
+        return factory;
+    }
+
+}

+ 17 - 0
blockchain-transfer/src/main/java/com/table/transfer/config/WebConfig.java

@@ -0,0 +1,17 @@
+package com.table.transfer.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class WebConfig implements WebMvcConfigurer {
+    
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        registry.addMapping("/**")
+                .allowedOrigins("http://localhost", "http://127.0.0.1")
+                .allowedMethods("POST")
+                .allowedHeaders("*");
+    }
+}

+ 83 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/controller/TransferController.java

@@ -0,0 +1,83 @@
+package com.table.transfer.module.controller;
+
+
+import com.rabbitmq.client.Channel;
+import com.table.transfer.config.RabbitConfig;
+import com.table.transfer.module.enpty.TransferRecord;
+import com.table.transfer.module.enpty.TransferRequest;
+import com.table.transfer.module.enpty.TransferResponse;
+import com.table.transfer.module.service.BlockchainService;
+import com.table.transfer.module.service.EthereumService;
+import com.table.transfer.module.service.TransferRecordService;
+import com.table.transfer.module.service.TronService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.amqp.support.AmqpHeaders;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import java.io.IOException;
+
+
+@Slf4j
+@Validated
+@Component
+public class TransferController {
+
+    @Resource
+    TronService tronService;
+    @Resource
+    EthereumService ethereumService;
+    @Resource
+    RabbitTemplate rabbitTemplate;
+
+    @Resource
+    TransferRecordService transferRecordService;
+
+    @RabbitListener(queues = RabbitConfig.TRANSFER_REQUEST_QUEUE, ackMode = "MANUAL")
+    public void transfer (@RequestBody TransferRequest request, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag) throws IOException {
+        TransferResponse response = new TransferResponse();
+        try {
+            log.info("收到转账请求: chain={}, to={}, amount={}", request.getChain(), request.getToAddress(), request.getAmount());
+            String chain = request.getChain().toUpperCase();
+            if (chain.equals("TRON")){
+                response= tronService.transfer(request);
+            }
+            if (chain.equals("ETH")||chain.equals("BSC")){
+                if(chain.equals("ETH")){}
+                Thread.sleep(5000);
+                response= ethereumService.transfer(request);
+
+            }
+
+            if (response.isSuccess()) {
+                log.info("转账成功: txHash={}", response.getTransactionHash());
+            } else {
+                log.error("转账失败: error={}", response.getMessage());
+            }
+        } catch (Exception e) {
+            response = TransferResponse.error(e.getMessage());
+            log.error("转账处理异常: {}", e.getMessage(), e);
+        } finally {
+            response.setRequestId(request.getRequestId());
+            try {
+                TransferRecord record = TransferRecord.create(request, response);
+                transferRecordService.save(record);
+            }catch (Exception e){
+                log.error("什么?写入转账记录失败了?{}", e.getMessage(), e);
+            }
+
+            //回调发送结果
+            rabbitTemplate.convertAndSend(
+                    RabbitConfig.TRANSFER_EXCHANGE,
+                    RabbitConfig.TRANSFER_RESULT,
+                    response
+            );
+            channel.basicAck(deliveryTag, false); // 总是 ACK,绝不 requeue,避免重复转账
+        }
+    }
+}

+ 12 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/controller/TransferRecordController.java

@@ -0,0 +1,12 @@
+package com.table.transfer.module.controller;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("transfer")
+public class TransferRecordController {
+
+
+
+}

+ 24 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/enpty/ChainCoinDetail.java

@@ -0,0 +1,24 @@
+package com.table.transfer.module.enpty;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+@Data
+@AllArgsConstructor
+public class ChainCoinDetail {
+    private Integer chainId;
+    private String chain;             // 链标识:eth, bsc, polygon 等
+    private String coin;//币-链
+    private String contractAddress;   // 代币合约地址,主币为 null
+    private Integer decimal;          // 代币精度,主币默认 18
+    private BigInteger minGasPrice;   // 最小 gas price(Gwei)
+    private BigInteger maxGasPrice;   // 最大 gas price(Gwei)
+    private String nodeUrl;// 节点 RPC 地址
+
+    public String getAssetCode(){
+        return coin+"-"+chain;
+    }
+}

+ 138 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransactionInfoDTO.java

@@ -0,0 +1,138 @@
+package com.table.transfer.module.enpty;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * 用于封装不同区块链(如 TRON、Ethereum、BNB Chain 等)的交易信息,
+ * 将各异的原始 API 返回结构标准化,便于业务层统一处理。
+ * 支持主币(TRX/ETH/BNB)和代币(USDT、USDC 等)转账的统一表示。
+ */
+@Data
+public final class TransactionInfoDTO {
+
+    /**
+     * 交易哈希(Hash)
+     * 区块链上交易的唯一标识符
+     */
+    private String hash;
+
+    /**
+     * 发送方地址
+     * 资产转出的源地址
+     */
+    private String fromAddress;
+
+    /**
+     * 接收方地址
+     * 资产转入的目标地址
+     */
+    private String toAddress;
+
+    /**
+     * 转账金额(主单位)
+     * 已根据代币精度转换为人类可读单位,例如:
+     * - 13.611877 USDT(非 13611877 Sun)
+     * - 0.5 TRX / ETH / BNB
+     */
+    private BigDecimal amount;
+
+    /**
+     * 代币符号
+     * 例如:TRX, ETH, BNB, USDT, USDC, BTC
+     */
+    private String symbol;
+
+    /**
+     * 代币类型
+     * 取值包括:
+     * - NATIVE:主币(如 TRX、ETH、BNB)
+     * - ERC20:Ethereum 上的代币
+     * - BEP20:BNB Chain 上的代币
+     * - TRC20:TRON 上的代币
+     * - SPL:Solana 代币(可扩展)
+     */
+    private String tokenType;
+
+    /**
+     * 代币合约地址
+     * - 对于代币转账:填写代币的智能合约地址(如 USDT 合约)
+     * - 对于主币转账:填写 null 或空字符串
+     */
+    private String contractAddress;
+
+    /**
+     * 交易时间戳(毫秒)
+     * Unix 时间戳,单位为毫秒(例如:1758089232000)
+     */
+    private Long timestamp;
+
+    /**
+     * 区块链名称
+     * 标识该交易所属的链,例如:
+     * - tron
+     * - ethereum
+     * - bnb
+     * - polygon
+     * - arbitrum
+     * - optimism
+     */
+    private String chain;
+
+    /**
+     * 交易状态
+     * 取值:
+     * - success:成功
+     * - failed:失败
+     * - pending:待确认
+     * - reverted:已回滚
+     */
+    private String status;
+
+
+    /**
+     * 所在区块高度
+     * 交易被打包的区块编号
+     */
+    private Long blockNumber;
+
+    /**
+     * 交易手续费(主单位)
+     * 已转换为链的主币单位,例如:
+     * - 0.0021 ETH
+     * - 0.1 TRX
+     * - 0.0003 BNB
+     */
+    private BigDecimal gasFee;
+
+
+    /**
+     * 代币精度(小数位数)
+     * 例如:
+     * - USDT/TRC20: 6
+     * - TRX: 6
+     * - BNB: 18
+     * 用于金额转换和展示
+     */
+    private Integer decimals;
+
+    /**
+     * 调用的方法名(Function Name)
+     * 例如:transfer, approve, swapExactTokensForTokens
+     * 主要用于合约交互类交易
+     */
+    private String methodName;
+
+    /**
+     * 交易类型
+     * 用于分类交易行为,例如:
+     * - transfer:转账
+     * - approve:授权
+     * - swap:兑换
+     * - mint:铸币
+     * - burn:销毁
+     */
+    private String type;
+
+}

+ 52 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransferRecord.java

@@ -0,0 +1,52 @@
+package com.table.transfer.module.enpty;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Data
+@TableName("t_transfer_records")
+public class TransferRecord {
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    
+    private String requestId;
+    
+    private String fromAddress;
+    
+    private String toAddress;
+    
+    private BigDecimal amount;
+
+    private String transactionHash;
+
+    private String status; // SUCCESS, FAILED, PENDING
+    
+    private String Message;
+    
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+    
+    @TableField(fill = FieldFill.INSERT_UPDATE)
+    private LocalDateTime updateTime;
+
+    private boolean deleted;
+    public static TransferRecord create(TransferRequest request,TransferResponse response){
+        TransferRecord record =new TransferRecord();
+        record.setRequestId(request.getRequestId());
+        record.setAmount(new BigDecimal(request.getAmount()));
+        record.setFromAddress(request.getFromAddress());
+        record.setToAddress(request.getToAddress());
+
+        LocalDateTime now = LocalDateTime.now();
+        record.setCreateTime(now);
+        record.setUpdateTime(now);
+
+        record.setStatus(response.isSuccess()?"SUCCESS":"FAILED");
+        record.setTransactionHash(response.getTransactionHash());
+        record.setMessage(response.getMessage());
+        return record;
+    };
+}

+ 49 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransferRequest.java

@@ -0,0 +1,49 @@
+package com.table.transfer.module.enpty;
+
+import cn.hutool.core.util.StrUtil;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
+import lombok.Data;
+
+import java.math.BigInteger;
+
+
+@Data
+public class TransferRequest {
+    /**
+     * 请求方自己携带的用于区分的id
+     */
+    private String requestId;
+    @NotBlank(message = "链类型不能为空")
+    private String chain; // ETH, BSC, TRON
+    @NotBlank(message = "链类型不能为空")
+    private String coin; // ETH, BSC, TRON
+
+    private String privateKey;
+    @NotBlank(message = "加密私钥不能为空")
+    private String encryptionPrivateKey;
+    @NotBlank(message = "发送地址不能为空")
+    private String fromAddress;
+    @NotBlank(message = "接收地址不能为空")
+    private String toAddress;
+
+    @NotBlank(message = "转账金额不能为空")
+    @Pattern(regexp = "^[0-9]+(\\.[0-9]+)?$", message = "金额格式不正确")
+    private String amount;
+    private BigInteger amountWei;
+    private String contractAddress; // 代币合约地址,为空表示主币转账
+
+    @Pattern(regexp = "^[0-9]*$", message = "Gas Limit必须为数字")
+    private String gasLimit;
+
+    @Pattern(regexp = "^[0-9]+(\\.[0-9]+)?$", message = "Gas Price格式不正确")
+    private String gasPrice;
+
+    public String getAssetCode() {
+        return coin + "-" + chain;
+    }
+
+    public boolean isTokenTransfer() {
+       return !StrUtil.equalsAnyIgnoreCase(getAssetCode(), "ETH-ETH", "BNB-BSC", "TRX-TRON");
+    }
+}

+ 33 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/enpty/TransferResponse.java

@@ -0,0 +1,33 @@
+package com.table.transfer.module.enpty;
+
+import lombok.Data;
+
+@Data
+public class TransferResponse {
+    private boolean success;
+    private String message;
+    /**
+     * 请求方自己携带的用于区分的id
+     */
+    private String requestId;
+    /**
+     * 转账服务用来查询的id
+     */
+    private String responseId;
+    private String transactionHash;
+    
+    public static TransferResponse success(String transactionHash) {
+        TransferResponse response = new TransferResponse();
+        response.setSuccess(true);
+        response.setMessage("转账成功");
+        response.setTransactionHash(transactionHash);
+        return response;
+    }
+    
+    public static TransferResponse error(String error) {
+        TransferResponse response = new TransferResponse();
+        response.setSuccess(false);
+        response.setMessage(error);
+        return response;
+    }
+}

+ 56 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/enpty/Trc20TransferInfo.java

@@ -0,0 +1,56 @@
+package com.table.transfer.module.enpty;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+@Data
+public class Trc20TransferInfo {
+    private String icon_url;
+    private String symbol;
+    private String level;
+    private String to_address;
+    private String tokenType2;
+    private String contract_address;
+    private String type;
+    private int decimals;
+    private String name;
+    private boolean vip;
+    private String tokenType;
+    private String from_address;
+    private String amount_str;
+    private int status;
+
+    /**
+     * 【注意】此字段单位为 SUN
+     * 请优先使用 {@link #getDecimalsAmount()} 获取 代币 单位余额
+     * @deprecated 此方法返回的是未转换的余额,请确认需要的是sun单位
+     */
+    @Deprecated
+    public String getAmount_str() {
+        return amount_str;
+    }
+    public BigDecimal getDecimalsAmount() {
+        return new BigDecimal(amount_str).divide(
+                BigDecimal.valueOf(Math.pow(10, decimals)),
+                decimals,
+                RoundingMode.DOWN
+        );
+    }
+
+    public TransactionInfoDTO Trc20TransferInfo2TransactionInfoDTO(){
+        TransactionInfoDTO transactionInfoDTO = new TransactionInfoDTO();
+        transactionInfoDTO.setSymbol(symbol);
+        transactionInfoDTO.setAmount(getDecimalsAmount());
+        transactionInfoDTO.setTokenType(getTokenType());
+        transactionInfoDTO.setFromAddress(from_address);
+        transactionInfoDTO.setTokenType(tokenType2);
+        transactionInfoDTO.setContractAddress(contract_address);
+        transactionInfoDTO.setType(type);
+        transactionInfoDTO.setDecimals(decimals);
+        transactionInfoDTO.setToAddress(to_address);
+        return transactionInfoDTO;
+    }
+
+}

+ 10 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/mapper/TransferRecordMapper.java

@@ -0,0 +1,10 @@
+package com.table.transfer.module.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.table.transfer.module.enpty.TransferRecord;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface TransferRecordMapper extends BaseMapper<TransferRecord> {
+
+}

+ 25 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/service/BlockchainService.java

@@ -0,0 +1,25 @@
+package com.table.transfer.module.service;
+
+
+import com.table.transfer.module.enpty.TransactionInfoDTO;
+import com.table.transfer.module.enpty.TransferRequest;
+import com.table.transfer.module.enpty.TransferResponse;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public interface BlockchainService {
+    TransferResponse transfer(TransferRequest request) throws Exception;
+
+    boolean validateAddress(String address);
+
+    void validateTransferRequest(TransferRequest transferRequest) throws Exception;
+
+    BigInteger getNonce(String assetCode, String address) throws Exception;
+
+    BigDecimal getTokenBalance(String chain, String contractAddress, String targetAddress) throws Exception;
+
+    BigDecimal getBalance(String chain, String targetAddress) throws Exception;
+
+    TransactionInfoDTO getTransactionInfoByHash(String assetCode, String transactionHash) throws Exception;
+}

+ 523 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/service/EthereumService.java

@@ -0,0 +1,523 @@
+package com.table.transfer.module.service;
+
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.table.transfer.module.enpty.ChainCoinDetail;
+import com.table.transfer.module.enpty.TransactionInfoDTO;
+import com.table.transfer.module.enpty.TransferRequest;
+import com.table.transfer.module.enpty.TransferResponse;
+import com.table.transfer.util.CryptoUtil;
+import com.table.transfer.util.aUtil;
+import com.table.transfer.util.ether.ChainCoinDetailManager;
+import com.table.transfer.util.ether.Web3jManager;
+import com.table.transfer.util.encryp.RSAEncryptionUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.web3j.abi.FunctionEncoder;
+import org.web3j.abi.FunctionReturnDecoder;
+import org.web3j.abi.TypeReference;
+import org.web3j.abi.datatypes.Address;
+import org.web3j.abi.datatypes.Bool;
+import org.web3j.abi.datatypes.Function;
+import org.web3j.abi.datatypes.Type;
+import org.web3j.abi.datatypes.generated.Uint256;
+import org.web3j.crypto.Credentials;
+import org.web3j.crypto.RawTransaction;
+import org.web3j.crypto.TransactionEncoder;
+import org.web3j.protocol.Web3j;
+import org.web3j.protocol.core.DefaultBlockParameterName;
+import org.web3j.protocol.core.methods.request.Transaction;
+import org.web3j.protocol.core.methods.response.*;
+import org.web3j.utils.Convert;
+import org.web3j.utils.Numeric;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.rmi.ServerException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+@Service
+public class EthereumService implements BlockchainService {
+
+    //EVM 链上的 ERC20 固定的事件签名keccak256 哈希
+    String TRANSFER_EVENT_SIGNATURE = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef";
+
+    // 默认 Gas Limit(保险值)
+    public static final BigInteger DEFAULT_GAS_LIMIT_NATIVE = BigInteger.valueOf(21_000);
+    public static final BigInteger DEFAULT_GAS_LIMIT_TOKEN = BigInteger.valueOf(120_000);
+    // BSC:官方显示平均手续费,后续应该在数据库中配置,2021年时出现过手续费暴涨的情况,手动配置可以提高最低值,提高成功率
+
+    // 全局 nonce 锁,到期自动释放
+    private final Cache<String, Object> nonceLocks = CacheBuilder.newBuilder()
+            .expireAfterAccess(1, TimeUnit.HOURS) // 1小时无访问自动移除
+            .build();
+    private final Map<String, Object> pendingTransfers = new ConcurrentHashMap<>();
+
+
+    /**
+     * 获取当前网络 gas price,并设置“最低安全值”
+     */
+    public BigInteger getSafeGasPrice(TransferRequest transferRequest) throws IOException {
+        BigInteger networkGasPrice = Web3jManager.getWeb3j(transferRequest.getChain()).ethGasPrice().send().getGasPrice();
+        ChainCoinDetail chainCoinDetail = ChainCoinDetailManager.getChainCoinDetail(transferRequest.getAssetCode());
+        //设置的最低值
+        BigInteger minGasPrice = chainCoinDetail.getMinGasPrice();
+        //低于最低手续费,就取最低值
+        if (networkGasPrice.compareTo(minGasPrice) <= 0) {
+            networkGasPrice = minGasPrice;
+        } else {
+            //设定的最低值就直接加价20%防止拥堵被抛弃
+            networkGasPrice = networkGasPrice.multiply(BigInteger.valueOf(12)).divide(BigInteger.TEN);
+        }
+
+        BigInteger maxGasPrice = chainCoinDetail.getMaxGasPrice();
+        if (networkGasPrice.compareTo(maxGasPrice) > 0) {
+            throw new ServerException("手续费超过设定最大值,当前估算Price"+networkGasPrice);
+        }
+        return networkGasPrice;
+    }
+
+
+
+    public void validateTransferRequest(TransferRequest transferRequest) throws Exception {
+        String pk = RSAEncryptionUtil.decrypt(transferRequest.getEncryptionPrivateKey());
+        Credentials credentials = Credentials.create(pk);
+        String fromAddress = credentials.getAddress();
+        if (!transferRequest.getFromAddress().equalsIgnoreCase(fromAddress)) {
+            throw new Exception("私钥和from地址不一致");
+        }
+        transferRequest.setPrivateKey(pk);
+        // 验证私钥
+        if (!CryptoUtil.validatePrivateKey(transferRequest.getPrivateKey())) {
+            throw new Exception("无效的私钥格式");
+        }
+
+        // 验证地址
+        if (!CryptoUtil.validateEthAddress(transferRequest.getToAddress())) {
+            throw new Exception("无效的接收地址");
+        }
+        if (ChainCoinDetailManager.getChainCoinDetail(transferRequest.getAssetCode()) == null) {
+            throw new Exception("不支持" + transferRequest.getAssetCode());
+        }
+        //todo 支持的类型校验 合约
+    }
+
+
+    @Override
+    public TransferResponse transfer(TransferRequest transferRequest) throws Exception {
+        validateTransferRequest(transferRequest);
+        //交易对
+        String assetCode = transferRequest.getAssetCode();
+        //接受地址
+        String toAddress = transferRequest.getToAddress();
+        //金额
+        String amount = transferRequest.getAmount();
+        //使用对应链的web3j
+        Web3j web3j = Web3jManager.getWeb3j(transferRequest.getChain());
+        //私钥
+        String privateKey = transferRequest.getPrivateKey();
+        //是否代币转账
+        boolean isTokenTransfer = transferRequest.isTokenTransfer();
+        //发送地址
+        String fromAddress = transferRequest.getFromAddress();
+        //合约地址
+        String contractAddress = transferRequest.getContractAddress();
+        //代币配置
+        ChainCoinDetail chainCoinDetail = ChainCoinDetailManager.getChainCoinDetail(assetCode);
+
+        Credentials credentials = Credentials.create(privateKey);
+        //重试次数
+        int retryCount = 0;
+        //hash
+        String sentTxHash = null;
+
+        try {
+            //todo chainId和链检查 必须相同,避免跨链丢币风险。
+
+            //4. 转换金额为wei
+            BigInteger decimalsAmount = toWei(transferRequest.getAmount(), chainCoinDetail.getDecimal());
+            if (decimalsAmount.compareTo(BigInteger.ONE) < 0) {
+                return TransferResponse.error("转账金额过低");
+            }
+            //2.上锁获取nonce
+            BigInteger nonce = null;
+            if (pendingTransfers.containsKey(fromAddress)) {
+                throw new Exception("该发送地址已有未完成转账");
+            }
+            pendingTransfers.put(fromAddress, true);
+
+            Object lock = nonceLocks.get(fromAddress, Object::new);
+            nonce = getNonce(assetCode, fromAddress);
+            while (retryCount < 3) {
+                try {
+
+                    synchronized (lock) {
+                        log.info("【转账开始】账户={},目标={}, 金额={}, nonce={}", fromAddress, toAddress, amount, nonce);
+                        //5. 构建交易
+                        RawTransaction rawTransaction;
+                        //3.估算gas和gaslimit 估算个屁,limit和price估算完全不靠谱
+//                        BigInteger gasLimit = estimateGasSafely(transferRequest);
+                        BigInteger gasLimit= isTokenTransfer ? DEFAULT_GAS_LIMIT_TOKEN : DEFAULT_GAS_LIMIT_NATIVE;
+                        BigInteger currentGasPrice = getSafeGasPrice(transferRequest);
+                        log.info("gasLimit: {},currentGasPrice {}", gasLimit, currentGasPrice);
+                        //代币转账
+                        if (isTokenTransfer) {
+                            // 构造代币转账的 function 调用
+                            Function function = new Function(
+                                    "transfer",
+                                    Arrays.asList(new Address(toAddress), new Uint256(decimalsAmount)),
+                                    Arrays.asList(new TypeReference<Bool>() {
+                                    })
+                            );
+                            String data = FunctionEncoder.encode(function);
+
+                            log.info("【代币转账开始】发送者={}, 接收者={}, 代币合约={}, 金额={}, nonce={}", fromAddress, toAddress, contractAddress, decimalsAmount, nonce);
+                            // 构造 RawTransaction:目标是代币合约地址
+                            rawTransaction = RawTransaction.createTransaction(
+                                    nonce,
+                                    currentGasPrice,
+                                    gasLimit,
+                                    transferRequest.getContractAddress(),
+                                    BigInteger.ZERO,
+                                    data
+                            );
+                        } else {
+                            //主币转账
+                            log.info("【转账开始】账户={},目标={}, 金额={}, nonce={}", fromAddress, toAddress, amount, nonce);
+                            rawTransaction = RawTransaction.createEtherTransaction(
+                                    nonce,
+                                    currentGasPrice,
+                                    gasLimit,
+                                    toAddress,
+                                    decimalsAmount
+                            );
+                        }
+
+                        //6.签名交易
+                        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, chainCoinDetail.getChainId(), credentials);
+                        String hexValue = Numeric.toHexString(signedMessage);
+                        //7.发送交易
+                        EthSendTransaction response = web3j.ethSendRawTransaction(hexValue).send();
+
+                        if (response.hasError()) {
+                            String errorMsg = response.getError().getMessage();
+                            // 仅对 underpriced 错误重试(同一 nonce)
+                            if (errorMsg.contains("underpriced") || errorMsg.contains("replacement transaction underpriced")) {
+                                retryCount++;
+                                log.warn(" 交易因手续费太低被拒,nonce={},第 {}/3 次重试,gasPrice={}",
+                                        nonce, retryCount, currentGasPrice);
+
+                                // 根据重试次数动态提高 gasPrice
+                                currentGasPrice = currentGasPrice.multiply(BigInteger.valueOf(12)).divide(BigInteger.valueOf(10)); // +20%
+
+                                // 不超过链上限
+                                if (currentGasPrice.compareTo(chainCoinDetail.getMaxGasPrice()) > 0) {
+                                    //todo 超过了链的上限,直接抛弃,然后修改数据库错误提示,告知是因为手续费太高导致的,避免大额手续费浪费
+                                    // 更新数据库
+                                    break;
+                                }
+
+                                continue; // 重试(同一 nonce)
+                            } else {
+                                // 其他错误直接抛出,如 nonce too low, insufficient funds, already known
+                                log.error("节点拒绝交易(不可重试): {}", errorMsg);
+                                throw new Exception("交易失败: " + errorMsg);
+                            }
+                        }
+
+                        // 8.成功发送,拿到哈希
+                        sentTxHash = response.getTransactionHash();
+                    }
+                    log.info("交易已广播,TxHash={}", sentTxHash);
+                    // 不再重试发送,直接等待确认
+                    break;
+
+                } catch (IOException e) {
+                    // 网络层异常:可能是超时,但交易可能已在链上
+                    if (sentTxHash != null) {
+                        TransactionInfoDTO transactionInfoByHash = getTransactionInfoByHash(assetCode, sentTxHash);
+                        if (transactionInfoByHash != null) {
+                            log.warn("网络异常,但交易已发送,尝试查询链上状态: {}", sentTxHash);
+                        }
+                        break; // 跳出重试,进入等待
+                    } else {
+                        // 连广播都没完成,且不是 underpriced 错误,不重试
+                        log.error("网络异常且无交易哈希,放弃重试", e);
+                        throw new Exception("网络异常,无法发送交易" + e);
+                    }
+                } catch (Exception e) {
+                    log.error("交易过程发生未预期异常", e);
+                    throw e;
+
+                }
+            }
+
+            if (sentTxHash == null) {
+                // 说明 3 次都失败了,且没拿到哈希
+                log.error("交易发送失败:尝试 3 次均被拒绝(gasPrice 过低),nonce={}", nonce);
+                // 注意:这里不能抛“可重试”异常,否则外部可能再调用
+                throw new Exception("交易因手续费太低被拒,已尝试3次,请稍后重试");
+            }
+            log.info("交易已发送,TxHash: {}", sentTxHash);
+
+//            // 11. 立即验证是否进入 mempool?
+//            if (!isTransactionInMempool(web3j, sentTxHash)) {
+//                log.error("交易未立即进入 mempool,可能广播失败: {}", sentTxHash);
+//            }
+            return TransferResponse.success(sentTxHash);
+
+        } catch (Exception e) {
+            log.error("ETH转账失败: {}", e.getMessage());
+            return TransferResponse.error("ETH转账失败: " + e.getMessage());
+        } finally {
+            pendingTransfers.remove(fromAddress);
+        }
+    }
+
+    /**
+     * 获取gasLimit
+     *
+     * @param request
+     * @return
+     */
+    public BigInteger estimateGasSafely(TransferRequest request) {
+        String chain = request.getChain();
+        boolean isTokenTransfer = request.isTokenTransfer();
+        String fromAddress = request.getFromAddress();
+        String toAddress = request.getToAddress();
+        String contractAddress = request.getContractAddress();
+        BigInteger amount = request.getAmountWei();
+        Web3j web3j = Web3jManager.getWeb3j(chain);
+        Transaction transaction;
+
+        try {
+            if (isTokenTransfer) {
+                // 代币转账:调用合约的 transfer(to, amount)
+                Function function = new Function(
+                        "transfer",
+                        Arrays.asList(
+                                new Address(toAddress),
+                                new Uint256(amount != null ? amount : BigInteger.ONE)
+                        ),
+                        List.of()
+                );
+                String data = FunctionEncoder.encode(function);
+                transaction = Transaction.createEthCallTransaction(fromAddress, contractAddress, data);
+            } else {
+                // 主币转账:data 为空
+                transaction = Transaction.createEthCallTransaction(fromAddress, toAddress, "", BigInteger.ONE);
+            }
+
+            EthEstimateGas estimate;
+
+            try {
+                estimate = web3j.ethEstimateGas(transaction).send();
+                BigInteger gasUsed = estimate.getAmountUsed();
+
+                return gasUsed;
+            } catch (Exception e) {
+                //删掉重试机制,减少响应时间,失败直接返回默认值
+                log.error("Gas 估算失败{}", e.getMessage());
+            }
+
+            // 兜底:返回默认值
+            BigInteger defaultValue = (transaction.getData() == null || transaction.getData().isEmpty()) ?
+                    DEFAULT_GAS_LIMIT_NATIVE : // 主币
+                    DEFAULT_GAS_LIMIT_TOKEN;   // 代币
+
+            log.error("使用保险默认 Gas Limit: {}", defaultValue);
+            return defaultValue;
+
+        } catch (Exception e) {
+            log.error("Gas 估算准备阶段异常: {}", e.getMessage());
+            e.printStackTrace();
+            // 返回基于链类型的默认值
+            return isTokenTransfer ? DEFAULT_GAS_LIMIT_TOKEN : DEFAULT_GAS_LIMIT_NATIVE;
+        }
+    }
+
+
+    /**
+     * 获取nonce/交易总数
+     *
+     * @return
+     * @throws Exception
+     */
+    public BigInteger getNonce(String assetCode, String address) throws Exception {
+        Web3j web3j = Web3jManager.getWeb3j(aUtil.assetCode2Chain(assetCode));
+        EthGetTransactionCount ethGetTransactionCount = web3j
+                .ethGetTransactionCount(address, DefaultBlockParameterName.PENDING)
+                .send();
+        return ethGetTransactionCount.getTransactionCount();
+
+    }
+
+
+    private BigInteger toWei(String amount, Integer decimal) throws Exception {
+        // 简化的转换,实际需要处理小数
+        BigDecimal pow = BigDecimal.TEN.pow(decimal);
+        return new BigDecimal(amount).multiply(pow).toBigInteger();
+
+    }
+
+
+    /**
+     * 目标地址代币余额
+     */
+    public BigDecimal getTokenBalance(String assetCode, String contractAddress, String targetAddress) throws Exception {
+
+        Function function = new Function("balanceOf",
+                List.of(new Address(targetAddress)),
+                List.of(new TypeReference<Uint256>() {
+                })
+        );
+
+        String data = FunctionEncoder.encode(function);
+        Transaction transaction = Transaction.createEthCallTransaction(null, contractAddress, data);
+
+        EthCall response = Web3jManager.getWeb3j(aUtil.assetCode2Chain(assetCode)).ethCall(transaction, DefaultBlockParameterName.LATEST).send();
+        log.info("EthCall response: {}", JSONUtil.toJsonStr(response));
+        List<Type> result = FunctionReturnDecoder.decode(response.getValue(), function.getOutputParameters());
+
+        if (result.isEmpty()) {
+            throw new Exception("获取代币余额失败");
+        }
+
+        BigInteger balanceWei = (BigInteger) result.get(0).getValue();
+        log.info("Raw balance: {}", balanceWei);
+
+        int decimals = ChainCoinDetailManager.getChainCoinDetail(assetCode).getDecimal(); // 如果需要精确,应该调用合约的 decimals() 方法
+        BigDecimal balance = new BigDecimal(balanceWei)
+                .divide(new BigDecimal(BigInteger.TEN.pow(decimals)), decimals, RoundingMode.DOWN);
+
+        return balance;
+    }
+
+
+    /**
+     * 获取目标地址代主币余额
+     *
+     * @param targetAddress
+     * @return
+     * @throws Exception
+     */
+    public BigDecimal getBalance(String chain, String targetAddress) throws Exception {
+
+        EthGetBalance balanceResponse = Web3jManager.getWeb3j(chain).ethGetBalance(targetAddress, DefaultBlockParameterName.LATEST).send();
+        Convert.Unit unit;
+        if (chain.equalsIgnoreCase("ETH") || chain.equalsIgnoreCase("BSC")) {
+            unit = Convert.Unit.ETHER;
+        } else {
+            throw new Exception("暂不支持的链");
+        }
+        return Convert.fromWei(balanceResponse.getBalance().toString(), unit);
+    }
+
+    public Long getLastBlock(String chain) throws IOException {
+        EthBlockNumber blockNumber = Web3jManager.getWeb3j(chain).ethBlockNumber().send();
+        return blockNumber.getBlockNumber().longValue();
+    }
+
+
+    /**
+     * 校验地址有效性
+     *
+     * @param address
+     * @return
+     */
+    @Override
+    public boolean validateAddress(String address) {
+        return CryptoUtil.validateEthAddress(address);
+    }
+
+    /**
+     * 通过hash获取交易信息
+     */
+    @Override
+    public TransactionInfoDTO getTransactionInfoByHash(String assetCode, String transactionHash) throws Exception {
+        String chain = aUtil.assetCode2Chain(assetCode);
+        // 查询交易回执
+        EthGetTransactionReceipt receiptResponse = Web3jManager.getWeb3j(chain).ethGetTransactionReceipt(transactionHash).send();
+        Optional<TransactionReceipt> receiptOpt = receiptResponse.getTransactionReceipt();
+        if (!receiptOpt.isPresent()) {
+            log.warn("交易尚未上链: {}", transactionHash);
+            throw new ServerException("交易尚未上链: " + transactionHash);
+        }
+
+        TransactionReceipt receipt = receiptOpt.get();
+        // 必须有区块号(已上链)
+        if (receipt.getBlockNumber() == null) {
+            log.warn("交易回执无区块号: {}", transactionHash);
+            throw new ServerException("交易回执无区块号: " + transactionHash);
+        }
+
+        //判断交易是否执行成功
+        boolean isSuccess = "0x1".equals(receipt.getStatus()) || "1".equals(receipt.getStatus());
+
+        if (!isSuccess) {
+            log.warn("交易执行失败 (reverted): {}, status={}", transactionHash, receipt.getStatus());
+            throw new ServerException(StrUtil.format("交易执行失败 (reverted): {}, status={}", transactionHash, receipt.getStatus()));
+        }
+        TransactionReceipt transactionReceipt = receiptOpt.orElseThrow(RuntimeException::new);
+
+
+        // 解析 logs 获取真正的 to 地址和 amount
+        List<Log> logs = transactionReceipt.getLogs();
+        if (!logs.isEmpty()) {
+
+            for (Log log : logs) {
+                //确保有3个主题并且符合keccak256
+                if (log.getTopics().size() >= 3 && TRANSFER_EVENT_SIGNATURE.equals(log.getTopics().get(0))) {
+
+                    // 主题解析:主题0是事件签名,主题1是from,主题2是to
+                    List<String> topics = log.getTopics();
+                    String transferFrom = Numeric.toBigInt(topics.get(1)).toString(16);
+                    transferFrom = "0x" + padZeroes(transferFrom, 40); // 补齐40位(20字节)
+
+                    String transferTo = Numeric.toBigInt(topics.get(2)).toString(16);
+                    transferTo = "0x" + padZeroes(transferTo, 40); // 补齐40位
+
+
+                    String data = log.getData();
+                    BigInteger amountValue = Numeric.toBigInt(data);
+
+                    //计算gas费
+                    BigInteger gasUsed = Numeric.toBigInt(transactionReceipt.getGasUsed().toByteArray());
+                    BigInteger effectiveGasPrice = Numeric.toBigInt(transactionReceipt.getEffectiveGasPrice());
+                    BigInteger totalGasFeeWei = gasUsed.multiply(effectiveGasPrice);
+                    // todo eth和bsc位数一样,后续增加其他EVM币种若是位数不一样这里需要改适配
+                    BigDecimal totalGasFeeEth = Convert.fromWei(totalGasFeeWei.toString(), Convert.Unit.ETHER);
+
+                    TransactionInfoDTO transactionInfoDTO = new TransactionInfoDTO();
+                    transactionInfoDTO.setStatus("success");
+
+                    Integer decimal = ChainCoinDetailManager.getChainCoinDetail(assetCode).getDecimal();
+                    // USDT 是 6 位小数,所以除以 10^6
+
+                    BigDecimal amount = new BigDecimal(amountValue).divide(new BigDecimal(BigInteger.TEN.pow(decimal)), decimal, RoundingMode.DOWN);
+                    transactionInfoDTO.setAmount(amount);
+                    transactionInfoDTO.setGasFee(totalGasFeeEth);
+                    transactionInfoDTO.setHash(transactionReceipt.getTransactionHash());
+                    transactionInfoDTO.setFromAddress(transferFrom);
+                    transactionInfoDTO.setToAddress(transferTo);
+                    return transactionInfoDTO;
+                }
+            }
+        }
+        throw new Exception("ethscan解析Hash失败");
+    }
+
+    private static String padZeroes(String hex, int length) {
+        if (hex.length() >= length) return hex;
+        return "0".repeat(length - hex.length()) + hex;
+    }
+
+}

+ 12 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/service/Impl/TransferRecordServiceImpl.java

@@ -0,0 +1,12 @@
+package com.table.transfer.module.service.Impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.table.transfer.module.enpty.TransferRecord;
+import com.table.transfer.module.mapper.TransferRecordMapper;
+import com.table.transfer.module.service.TransferRecordService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TransferRecordServiceImpl extends ServiceImpl<TransferRecordMapper, TransferRecord> implements TransferRecordService {
+
+}

+ 8 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/service/TransferRecordService.java

@@ -0,0 +1,8 @@
+package com.table.transfer.module.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.table.transfer.module.enpty.TransferRecord;
+
+public interface TransferRecordService extends IService<TransferRecord> {
+
+}

+ 485 - 0
blockchain-transfer/src/main/java/com/table/transfer/module/service/TronService.java

@@ -0,0 +1,485 @@
+package com.table.transfer.module.service;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.util.concurrent.RateLimiter;
+import com.table.transfer.module.enpty.TransactionInfoDTO;
+import com.table.transfer.module.enpty.TransferRequest;
+import com.table.transfer.module.enpty.TransferResponse;
+import com.table.transfer.util.encryp.RSAEncryptionUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.util.encoders.Hex;
+import org.springframework.stereotype.Service;
+import org.tron.trident.core.ApiWrapper;
+import org.tron.trident.core.contract.Contract;
+import org.tron.trident.core.contract.Trc20Contract;
+import org.tron.trident.crypto.Hash;
+import org.tron.trident.proto.Chain;
+import org.tron.trident.proto.Response;
+import org.tron.trident.utils.Base58Check;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.nio.charset.StandardCharsets;
+import java.rmi.ServerException;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+
+@Slf4j
+@Service
+public class TronService {
+
+
+    // tronGrid API配置
+    private static final String API_KEY = "0ab62ce0-04bd-45e8-9570-db636c19b6df";
+    /**
+     * 租赁一次能量需要的trx
+     */
+    public static final long DEFAULT_LEASE_AMOUNT_SUN = 2_500_000L; // 2.5 TRX
+    /**
+     * 能量租赁地址
+     */
+    public static final String DEFAULT_ENERGY_LEASE_ADDRESS = "TDCaC2PcAWenMv6ErDUq847ENHMtufud2H";
+
+    /**
+     * 能量租赁等待时间上限
+     */
+    private static final long ENERGY_WAIT_TIMEOUT_MS = 120_000L;
+    /**
+     * 地址+合约,余额(健康检查的时候顺便加载)
+     */
+    private final Cache<String, BigDecimal> addressBalance = CacheBuilder.newBuilder()
+            .expireAfterAccess(1, TimeUnit.HOURS)
+            .build();
+
+    /**
+     * trx 精度
+     */
+    private static final BigDecimal SUN_TO_TRX = BigDecimal.valueOf(1_000_000);
+    /**
+     * 单词转账的能量阈值
+     */
+    private static final long ENERGY_PER_TRANSFER = 65_000L;
+    /**
+     * 转账地址锁,todo mq保证串行后可删
+     */
+    private final Map<String, Object> transferLocks = new ConcurrentHashMap<>();
+
+    /**
+     * 频率限制器
+     */
+    private final RateLimiter ApiWrapperLimiter = RateLimiter.create(2);
+    /**
+     * ApiWrapper 连接异常的重试次数
+     */
+    private int heathApiWrapperCount = 0;
+    /**
+     * ApiWrapper 连接异常的最大重试次数
+     */
+    private final int MaxHeathApiWrapperCount = 20;
+
+    /**
+     * 配合限制器限制请求频率
+     */
+    private ApiWrapper limitApiWrapper(ApiWrapper apiWrapper) {
+        ApiWrapperLimiter.acquire();
+        return apiWrapper;
+    }
+
+    /**
+     * 获取一个健康可用的ApiWrapper
+     */
+    public ApiWrapper heathApiWrapper(String privateKey, String fromAddress, String trc20Contract) {
+        ApiWrapper apiWrapper = null;
+        while (heathApiWrapperCount < MaxHeathApiWrapperCount) {
+            try {
+                apiWrapper = ApiWrapper.ofMainnet(privateKey, API_KEY);
+                //健康检查,顺便更新余额
+                long trxBalance = limitApiWrapper(apiWrapper).getAccountBalance(fromAddress);
+                BigDecimal trxInTrx = new BigDecimal(trxBalance).divide(new BigDecimal(1_000_000), 6, RoundingMode.HALF_UP);
+                addressBalance.put(fromAddress, trxInTrx);
+
+                Contract contract = limitApiWrapper(apiWrapper).getContract(trc20Contract);
+                Trc20Contract token = new Trc20Contract(contract, fromAddress, limitApiWrapper(apiWrapper));
+                BigInteger balanceOf = token.balanceOf(fromAddress);
+                // todo 管理代币精度
+                BigDecimal divisor = new BigDecimal(1000000);
+                BigDecimal divide = new BigDecimal(balanceOf).divide(divisor, 8, RoundingMode.HALF_UP);
+                addressBalance.put(fromAddress + trc20Contract, divide);
+                heathApiWrapperCount = 0;
+                return apiWrapper;
+            } catch (Exception e) {
+                apiWrapper.close();
+                log.warn("ApiWrapper连接异常{},尝试第{}次重新连接", e.getMessage(), MaxHeathApiWrapperCount);
+                heathApiWrapperCount++;
+            }
+        }
+        throw new RuntimeException("ApiWrapper连接异常,全部重试都已失败 heathApiWrapperCount:" + heathApiWrapperCount);
+
+    }
+
+    /**
+     * 转账服务
+     */
+    public TransferResponse transfer(TransferRequest request) throws Exception {
+        validateTransferRequest(request);
+        //私钥
+        String privateKey = request.getPrivateKey();
+        //目标地址
+        String toAddress = request.getToAddress();
+        //金额
+        String amount = request.getAmount();
+        //发送地址
+        String fromAddress = request.getFromAddress();
+        //是否代币转账
+        boolean isTokenTransfer = request.isTokenTransfer();
+        //合约地址
+        String contractAddress = request.getContractAddress();
+        //mq串行,无并发
+        ApiWrapper apiWrapper = null;
+        try {
+            //获取检查过后的apiWrapper
+            apiWrapper = heathApiWrapper(privateKey, fromAddress, contractAddress);
+
+            // 验证私钥和地址匹配
+            String derivedAddress = limitApiWrapper(apiWrapper).keyPair.toBase58CheckAddress();
+            if (!fromAddress.equalsIgnoreCase(derivedAddress)) {
+                throw new RuntimeException("私钥和发送地址不匹配");
+            }
+
+            String txId;
+            if (isTokenTransfer) {
+                //代币转账
+                txId = transferToken(apiWrapper, fromAddress, toAddress, contractAddress, amount);
+            } else {
+                //主币转账
+                txId = transferTrx(apiWrapper, fromAddress, toAddress, amount);
+            }
+
+            log.info("TRON交易已发送,交易ID: {}", txId);
+            return TransferResponse.success(txId);
+
+        } catch (Exception e) {
+            log.error("TRON转账失败: {}", e.getMessage(), e);
+            return TransferResponse.error("TRON转账失败: " + e.getMessage());
+        } finally {
+            apiWrapper.close();
+            transferLocks.remove(fromAddress);
+        }
+
+    }
+
+    /**
+     * TRX 主币转账
+     */
+    private String transferTrx(ApiWrapper apiWrapper, String fromAddress, String toAddress, String amount) throws Exception {
+        try {
+            long amountInSun = new BigDecimal(amount).multiply(SUN_TO_TRX).longValue();
+
+            if (amountInSun <= 0) {
+                throw new RuntimeException("转账金额必须大于0");
+            }
+
+            // 检查主币余额
+            BigDecimal balance = addressBalance.getIfPresent(fromAddress);
+            if (balance == null) {
+                balance = getBalance(apiWrapper, fromAddress);
+            }
+
+            BigDecimal requiredBalance = new BigDecimal(amount);
+            if (balance.compareTo(requiredBalance) < 0) {
+                throw new RuntimeException("TRX余额不足,当前余额: " + balance + " TRX,需要: " + requiredBalance + " TRX");
+            }
+
+            log.info("开始TRX转账: {} -> {}, 金额: {} TRX ({} SUN)", fromAddress, toAddress, amount, amountInSun);
+
+            Response.TransactionExtention transactionExtention = limitApiWrapper(apiWrapper).transfer(fromAddress, toAddress, amountInSun);
+
+            if (!transactionExtention.getResult().getResult()) {
+                throw new RuntimeException("交易构建失败: " + transactionExtention.getResult().getCode());
+            }
+
+            Chain.Transaction transaction = transactionExtention.getTransaction();
+            Chain.Transaction signedTx = limitApiWrapper(apiWrapper).signTransaction(transaction);
+            return limitApiWrapper(apiWrapper).broadcastTransaction(signedTx);
+//            return "测试503hash";
+        } catch (Exception e) {
+            log.error("TRX转账失败: {}", e.getMessage(), e);
+            throw new RuntimeException("TRX转账失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * TRC20 代币转账
+     */
+    private String transferToken(ApiWrapper apiWrapper, String fromAddress, String toAddress,
+                                 String contractAddress, String amount) throws Exception {
+        String txHash = null;
+        try {
+
+            // 1. 检查代币余额
+            BigDecimal tokenBalance = addressBalance.getIfPresent(fromAddress + contractAddress);
+            if (tokenBalance == null) {
+                tokenBalance = getTokenBalance(apiWrapper, contractAddress, fromAddress);
+            }
+            BigDecimal transferAmount = new BigDecimal(amount);
+            if (tokenBalance.compareTo(transferAmount) < 0) {
+                throw new RuntimeException("代币余额不足,当前余额: " + tokenBalance + ",需要: " + transferAmount);
+            }
+
+
+            // 2. 计算需要的能量笔数
+            //todo 没有U需要2笔能量,有的需要1笔 ,但是转账其他代币不知道是不是也是以USDT为基数的
+            int energyCount = calculateRequiredEnergyCount(apiWrapper, contractAddress, toAddress);
+            long requiredEnergy = ENERGY_PER_TRANSFER * energyCount;
+            log.info("代币转账需要 {} 笔能量,总计 {} 能量", energyCount, requiredEnergy);
+
+            // 3. 检查当前能量是否足够
+            long currentEnergy = getAvailableEnergy(apiWrapper, fromAddress);
+            if (currentEnergy < requiredEnergy) {
+                log.info("能量不足: {} < {},需要租赁 {} 笔能量", currentEnergy, requiredEnergy, energyCount);
+                // 租赁精确数量的能量
+                leaseEnergy(apiWrapper, fromAddress, energyCount);
+                // 等待能量到账
+                waitForEnergyReplenishment(apiWrapper, fromAddress, requiredEnergy);
+            } else {
+                log.info("能量充足: {} >= {},直接进行转账", currentEnergy, requiredEnergy);
+            }
+
+            // 4. 执行代币转账
+            BigInteger amountInSmallestUnit = new BigDecimal(amount)
+                    .multiply(BigDecimal.TEN.pow(6)) // 默认6位小数
+                    .toBigInteger();
+
+            if (amountInSmallestUnit.compareTo(BigInteger.ZERO) <= 0) {
+                throw new RuntimeException("转账金额必须大于0");
+            }
+
+            log.info("开始TRC20转账: {} -> {}, 合约: {}, 金额: {}, 能量笔数: {}", fromAddress, toAddress, contractAddress, amount, energyCount);
+
+            // 使用Trc20Contract进行转账
+            Contract contract = limitApiWrapper(apiWrapper).getContract(contractAddress);
+            Trc20Contract token = new Trc20Contract(contract, fromAddress, limitApiWrapper(apiWrapper));
+            txHash = token.transfer(toAddress, amountInSmallestUnit.longValue(), 0, "", 1000000000L);
+
+            log.info("代币转账广播成功: txId={}", txHash);
+
+            return txHash;
+
+        } catch (Exception e) {
+            log.error("TRC20代币转账失败: {}", e.getMessage(), e);
+
+            // 如果交易已广播但后续出错,检查是否已确认
+            if (txHash != null && isTransactionConfirmed(apiWrapper, txHash)) {
+                log.info("检测到交易已上链,尽管本地异常: {}", txHash);
+                return txHash;
+            }
+
+            throw new RuntimeException("TRC20代币转账失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 循环等待能量补充
+     */
+    public void waitForEnergyReplenishment(ApiWrapper apiWrapper, String address, long requiredEnergy) throws Exception {
+        long startTime = System.currentTimeMillis();
+
+        while (System.currentTimeMillis() - startTime < ENERGY_WAIT_TIMEOUT_MS) {
+            try {
+                long availableEnergy = getAvailableEnergy(apiWrapper, address);
+                if (availableEnergy >= requiredEnergy) {
+                    log.info("能量已补充至 {}", availableEnergy);
+                    return;
+                }
+                log.info("当前能量 {},需要 {},继续等待...", availableEnergy, requiredEnergy);
+                Thread.sleep(3000);
+            } catch (Exception e) {
+                log.warn("查询能量失败: {}", e.getMessage());
+                Thread.sleep(3000);
+            }
+        }
+        throw new RuntimeException("能量租赁未到账,超时");
+    }
+
+    /**
+     * 计算需要的能量笔数
+     * 目标地址有代币:1笔能量
+     * 目标地址无代币:2笔能量
+     */
+    private int calculateRequiredEnergyCount(ApiWrapper apiWrapper, String contractAddress, String toAddress) throws Exception {
+        try {
+            BigDecimal targetBalance = getTokenBalance(apiWrapper, contractAddress, toAddress);
+            return targetBalance.compareTo(BigDecimal.ZERO) > 0 ? 1 : 2;
+        } catch (Exception e) {
+            log.warn("计算能量笔数失败,使用保守值2: {}", e.getMessage());
+            return 2; // 保守起见,使用2笔能量
+        }
+    }
+
+    /**
+     * 查询余额
+     */
+    public BigDecimal getBalance(ApiWrapper apiWrapper, String address) throws Exception {
+        try {
+            long balanceInSun = limitApiWrapper(apiWrapper).getAccountBalance(address);
+            return BigDecimal.valueOf(balanceInSun).divide(SUN_TO_TRX);
+        } catch (Exception e) {
+            log.error("获取主币余额失败: {}", address, e);
+            throw new ServerException("获取TRX余额失败: " + address);
+        }
+    }
+
+    /**
+     * 查询代币余额
+     */
+    public BigDecimal getTokenBalance(ApiWrapper apiWrapper, String contractAddress, String targetAddress) {
+        Contract contract = limitApiWrapper(apiWrapper).getContract(contractAddress);
+        Trc20Contract token = new Trc20Contract(contract, targetAddress, limitApiWrapper(apiWrapper));
+        BigInteger balanceOf = token.balanceOf(targetAddress);
+        //配置代币精度和小数点保留位数
+        BigDecimal divisor = new BigDecimal(1000000);
+        BigDecimal divide = new BigDecimal(balanceOf).divide(divisor, 8, RoundingMode.HALF_UP);
+        return divide;
+
+    }
+
+
+    /**
+     * 检查交易是否确认
+     */
+    private boolean isTransactionConfirmed(ApiWrapper apiWrapper, String txHash) {
+        try {
+            Response.TransactionInfo transactionInfo = limitApiWrapper(apiWrapper).getTransactionInfoById(txHash);
+            return transactionInfo != null;
+        } catch (Exception e) {
+            log.warn("检查交易确认状态失败: {}", txHash, e);
+            return false;
+        }
+    }
+
+
+    public TransactionInfoDTO getTransactionInfoByHash(ApiWrapper apiWrapper, String assetCode, String transactionHash) throws Exception {
+        try {
+            // 先尝试用ApiWrapper获取
+
+            Response.TransactionInfo transactionInfo = limitApiWrapper(apiWrapper).getTransactionInfoById(transactionHash);
+
+            if (transactionInfo != null) {
+                return buildTransactionInfoDTO(transactionInfo, assetCode);
+            }
+        } catch (Exception e) {
+            log.warn("ApiWrapper获取交易信息失败,降级到TronScan API: {}", transactionHash);
+        }
+        throw new Exception();
+        // 降级到TronScan API
+//        return getTransactionInfoFromTronScan(assetCode, transactionHash);
+    }
+
+    /**
+     * 构建交易信息DTO
+     */
+    private TransactionInfoDTO buildTransactionInfoDTO(Response.TransactionInfo transactionInfo, String assetCode) {
+        TransactionInfoDTO dto = new TransactionInfoDTO();
+        dto.setHash(transactionInfo.getId().toString());
+        dto.setStatus(transactionInfo.getResult().toString().toLowerCase());
+        dto.setBlockNumber(transactionInfo.getBlockNumber());
+        dto.setTimestamp(transactionInfo.getBlockTimeStamp());
+
+        // 设置手续费
+        BigDecimal feeInSun = new BigDecimal(transactionInfo.getFee());
+        BigDecimal feeInTrx = feeInSun.divide(SUN_TO_TRX);
+        dto.setGasFee(feeInTrx);
+
+        // 这里可以根据transactionInfo解析from/to/amount等详细信息
+        // 需要根据实际交易类型进行解析
+
+        return dto;
+    }
+
+    /**
+     * 验证地址格式
+     */
+    public boolean validateAddress(String address) {
+        if (address == null || address.length() < 20) return false;
+        try {
+            byte[] decoded = Base58Check.base58ToBytes(address);
+            return decoded.length == 21;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
+     * 转账前参数检查
+     */
+    public void validateTransferRequest(TransferRequest transferRequest) throws Exception {
+        String pk = RSAEncryptionUtil.decrypt(transferRequest.getEncryptionPrivateKey());
+
+        transferRequest.setPrivateKey(pk);
+
+        if (!validateAddress(transferRequest.getToAddress())) {
+            throw new Exception("无效的接收地址");
+        }
+        if (!validateAddress(transferRequest.getFromAddress())) {
+            throw new Exception("无效的发送地址");
+        }
+
+        try {
+            BigDecimal amount = new BigDecimal(transferRequest.getAmount());
+            if (amount.compareTo(BigDecimal.ZERO) <= 0) {
+                throw new Exception("转账金额必须大于0");
+            }
+        } catch (NumberFormatException e) {
+            throw new Exception("无效的金额格式");
+        }
+
+        if (transferRequest.isTokenTransfer() &&
+                (transferRequest.getContractAddress() == null || transferRequest.getContractAddress().isEmpty())) {
+            throw new Exception("代币转账需要合约地址");
+        }
+    }
+
+    /**
+     * 检查账户能量值
+     *
+     * @param address
+     * @return
+     * @throws Exception
+     */
+    public long getAvailableEnergy(ApiWrapper apiWrapper, String address) throws Exception {
+        try {
+            Response.AccountResourceMessage resource = limitApiWrapper(apiWrapper).getAccountResource(address);
+            return resource.getEnergyLimit() - resource.getEnergyUsed();
+        } catch (Exception e) {
+            log.error("获取账户能量失败: {}", address, e);
+            throw new RuntimeException("获取账户能量失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 租赁能量(精确笔数,无法叠加)
+     */
+    public void leaseEnergy(ApiWrapper apiWrapper, String fromAddress, int energyCount) throws Exception {
+        if (energyCount <= 0) {
+            throw new IllegalArgumentException("能量笔数必须大于0");
+        }
+
+        long leaseAmount = DEFAULT_LEASE_AMOUNT_SUN * energyCount;
+        log.info("租赁 {} 笔能量,金额: {} TRX from {} to {}", energyCount, BigDecimal.valueOf(leaseAmount).divide(BigDecimal.valueOf(1_000_000)), fromAddress, DEFAULT_ENERGY_LEASE_ADDRESS);
+
+        Response.TransactionExtention transfer = limitApiWrapper(apiWrapper).transfer(fromAddress, DEFAULT_ENERGY_LEASE_ADDRESS, leaseAmount);
+        Chain.Transaction signedTx = limitApiWrapper(apiWrapper).signTransaction(transfer);
+        String txId = limitApiWrapper(apiWrapper).broadcastTransaction(signedTx);
+
+        if (txId == null || txId.isEmpty()) {
+            throw new RuntimeException("能量租赁交易广播失败");
+        }
+
+        log.info("能量租赁交易广播成功: {}", txId);
+    }
+}

+ 162 - 0
blockchain-transfer/src/main/java/com/table/transfer/util/CryptoUtil.java

@@ -0,0 +1,162 @@
+package com.table.transfer.util;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.encoders.Hex;
+import org.web3j.abi.FunctionEncoder;
+import org.web3j.abi.TypeReference;
+import org.web3j.abi.datatypes.Address;
+import org.web3j.abi.datatypes.Function;
+import org.web3j.abi.datatypes.generated.Uint256;
+import org.web3j.crypto.*;
+import org.web3j.utils.Numeric;
+
+import java.math.BigInteger;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Collections;
+
+public class CryptoUtil {
+    
+    // secp256k1曲线的阶n
+    private static final BigInteger SECP256K1_N = new BigInteger("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16);
+    
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+    
+    public static ECKeyPair createKeyPairFromPrivateKey(String privateKeyHex) {
+        try {
+            // 处理0x前缀
+            if (privateKeyHex.startsWith("0x")) {
+                privateKeyHex = privateKeyHex.substring(2);
+            }
+            
+            BigInteger privateKey = new BigInteger(privateKeyHex, 16);
+            return ECKeyPair.create(privateKey);
+        } catch (Exception e) {
+            throw new RuntimeException("无效的私钥: " + e.getMessage());
+        }
+    }
+    
+    public static String getAddressFromPrivateKey(String privateKeyHex) {
+        ECKeyPair keyPair = createKeyPairFromPrivateKey(privateKeyHex);
+        return Keys.getAddress(keyPair);
+    }
+    
+    public static String getChecksumAddress(String address) {
+        return Keys.toChecksumAddress(address);
+    }
+    
+    public static RawTransaction createEthTransaction(
+            BigInteger nonce, 
+            BigInteger gasPrice, 
+            BigInteger gasLimit, 
+            String toAddress,
+            BigInteger value, 
+            String data) {
+        
+        return RawTransaction.createTransaction(
+            nonce,
+            gasPrice,
+            gasLimit,
+            toAddress,
+            value,
+            data
+        );
+    }
+    
+    public static String signTransaction(RawTransaction rawTransaction, byte chainId, ECKeyPair keyPair) {
+        Credentials credentials = Credentials.create(keyPair);
+        byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, chainId, credentials);
+        return Numeric.toHexString(signedMessage);
+    }
+    
+    public static String buildTokenTransferData(String toAddress, BigInteger value) {
+        try {
+            // 确保地址格式正确
+            String normalizedToAddress = toAddress;
+            if (normalizedToAddress.startsWith("0x")) {
+                normalizedToAddress = normalizedToAddress.substring(2);
+            }
+            
+            Function function = new Function(
+                "transfer",
+                Arrays.asList(
+                    new Address(normalizedToAddress),
+                    new Uint256(value)
+                ),
+                Collections.singletonList(new TypeReference<org.web3j.abi.datatypes.Bool>() {})
+            );
+            
+            return FunctionEncoder.encode(function);
+        } catch (Exception e) {
+            throw new RuntimeException("构建代币转账数据失败: " + e.getMessage());
+        }
+    }
+    
+    public static boolean validatePrivateKey(String privateKey) {
+        try {
+            if (privateKey.startsWith("0x")) {
+                privateKey = privateKey.substring(2);
+            }
+            
+            if (privateKey.length() != 64) {
+                return false;
+            }
+            
+            BigInteger pk = new BigInteger(privateKey, 16);
+            
+            // 检查私钥范围: 1 <= privateKey < n
+            return pk.compareTo(BigInteger.ONE) >= 0 && 
+                   pk.compareTo(SECP256K1_N) < 0;
+            
+        } catch (Exception e) {
+            return false;
+        }
+    }
+    
+    public static boolean validateEthAddress(String address) {
+        if (address == null || !address.matches("^0x[a-fA-F0-9]{40}$")) {
+            return false;
+        }
+        
+        // 简单的校验和验证
+        try {
+            String checksumAddress = Keys.toChecksumAddress(address);
+            return address.equals(checksumAddress) || 
+                   address.equalsIgnoreCase(checksumAddress);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+    
+    public static BigInteger weiToEther(BigInteger wei) {
+        return wei.divide(BigInteger.TEN.pow(18));
+    }
+    
+    public static BigInteger etherToWei(BigInteger ether) {
+        return ether.multiply(BigInteger.TEN.pow(18));
+    }
+    
+    public static BigInteger etherToWei(String etherAmount) {
+        try {
+            // 处理小数
+            String[] parts = etherAmount.split("\\.");
+            BigInteger integerPart = new BigInteger(parts[0]).multiply(BigInteger.TEN.pow(18));
+            
+            if (parts.length > 1) {
+                String decimalPart = parts[1];
+                if (decimalPart.length() > 18) {
+                    decimalPart = decimalPart.substring(0, 18);
+                }
+                BigInteger decimalValue = new BigInteger(decimalPart)
+                    .multiply(BigInteger.TEN.pow(18 - decimalPart.length()));
+                integerPart = integerPart.add(decimalValue);
+            }
+            
+            return integerPart;
+        } catch (Exception e) {
+            throw new RuntimeException("ETH金额格式错误: " + etherAmount);
+        }
+    }
+}

+ 431 - 0
blockchain-transfer/src/main/java/com/table/transfer/util/TronGridQueryUtil.java

@@ -0,0 +1,431 @@
+package com.table.transfer.util;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.table.transfer.module.enpty.TransactionInfoDTO;
+import com.table.transfer.util.tron.TronHexAndBase58Util;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+
+/**
+ * TRONGrid 查询工具类
+ * 封装独立查询功能,避免使用有问题的一次性接口
+ */
+public class TronGridQueryUtil {
+
+    private static final String TRONGRID_BASE_URL = "https://api.trongrid.io";
+    private static String apiKey = "8c5536e3-a852-43f6-add4-55421317f61c"; // 可选:设置你的 TRONGrid API Key
+    private static final String QUICKNODE_URL = "https://quaint-wild-layer.tron-mainnet.quiknode.pro/7d1ea336b14b5f53d8c897fe012aceec97a55fd7/";
+
+    /**
+     * 设置 TRONGrid API Key(可选)
+     */
+    public static void setApiKey(String key) {
+        apiKey = key;
+    }
+
+    public static void main(String[] args) {
+        String usdtContract = "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t";
+        String address = "TDTAYsJDnUNCHJgPWLbyE1GutRJ5KBh1Bd";
+//        String address = "TDFtN7nyfweR8WeUraZM7WuCrtUTruD4Er";
+        System.out.println(getTRXBalance(address));
+        System.out.println(getTokenBalance(address, usdtContract,6));
+//
+//        System.out.println(JSONUtil.toJsonStr(getTransactionStatus("a8cd72046d1f6f60a86366cc006c7106037f7188a9bad5aca813389bf0cfec75")));
+
+    }
+
+    /**
+     * 1. 通过地址查询主币余额(TRX)
+     *
+     * @param address TRON地址
+     * @return TRX余额(单位:TRX)
+     */
+    public static BigDecimal getTRXBalance(String address) {
+        String url = TRONGRID_BASE_URL + "/wallet/getaccount";
+
+        JSONObject params = new JSONObject();
+        params.put("address", address);
+        params.put("visible", true);
+
+        try {
+            String response = HttpRequest.post(url)
+                    .header("Content-Type", "application/json")
+                    .timeout(10000)
+                    .body(params.toString())
+                    .execute()
+                    .body();
+
+            JSONObject jsonResponse = JSONUtil.parseObj(response);
+
+            if (jsonResponse.containsKey("balance")) {
+                long balanceSun = jsonResponse.getLong("balance");
+                // 转换为 TRX: 1 TRX = 1,000,000 SUN
+                return BigDecimal.valueOf(balanceSun)
+                        .divide(BigDecimal.valueOf(1_000_000L), 6, BigDecimal.ROUND_DOWN);
+            } else {
+                // 账户不存在或没有余额
+                return BigDecimal.ZERO;
+            }
+
+        } catch (Exception e) {
+            throw new RuntimeException("查询TRX余额失败: " + e.getMessage(), e);
+        }
+    }
+
+
+
+    /**
+     * 查询可读代币余额
+     * @param targetAddress 目标地址
+     * @param contractAddress 合约地址
+     * @param decimals 代币精度
+     * @return 转换后的金额
+     */
+    public static BigDecimal getTokenBalance(String targetAddress, String contractAddress, int decimals) {
+        BigInteger balanceWei = getTokenBalanceWei(targetAddress, contractAddress);
+        BigDecimal divisor = BigDecimal.TEN.pow(decimals);
+        return new BigDecimal(balanceWei).divide(divisor, decimals, RoundingMode.DOWN);
+    }
+
+    /**
+     * 通过地址和合约查询代币余额
+     * @param ownerAddress    持有者地址
+     * @param contractAddress 代币合约地址
+     * @return 未转换的代币余额(wei)
+     */
+    public static BigInteger getTokenBalanceWei(String ownerAddress, String contractAddress) {
+        String url = TRONGRID_BASE_URL + "/wallet/triggerconstantcontract";
+
+        // 编码地址参数
+        String parameter = TronHexAndBase58Util.base58ToHex(ownerAddress);
+
+        JSONObject params = new JSONObject();
+        params.set("owner_address", ownerAddress);
+        params.set("contract_address", contractAddress);
+        params.set("function_selector", "balanceOf(address)");
+        params.set("parameter", parameter);
+        params.set("visible", true);
+
+        try {
+            String response = HttpRequest.post(url)
+                    .header("Content-Type", "application/json")
+                    .timeout(10000)
+                    .body(params.toString())
+                    .execute()
+                    .body();
+
+            JSONObject jsonResponse = JSONUtil.parseObj(response);
+
+            if (jsonResponse.containsKey("constant_result")) {
+                String hexBalance = jsonResponse.getJSONArray("constant_result").getStr(0);
+                if (hexBalance != null && !hexBalance.isEmpty()) {
+                    try {
+                        return new BigInteger(hexBalance,16);//解析16进制
+                    } catch (NumberFormatException e) {
+                        throw new RuntimeException("解析代币余额失败: " + hexBalance, e);
+                    }
+                }
+            }
+            return BigInteger.ZERO;
+
+        } catch (Exception e) {
+            throw new RuntimeException("查询代币余额失败: " + e.getMessage(), e);
+        }
+    }
+
+
+
+
+    /**
+     * 通过交易哈希查询交易状态(基于实际的事件日志数据)
+     */
+    public static TransactionInfoDTO getTransactionStatus(String txHash) {
+        // 获取交易收据(包含事件日志)
+        JSONObject txReceipt = getTransactionReceipt(txHash);
+
+        TransactionInfoDTO dto = new TransactionInfoDTO();
+
+        // 基础信息
+        dto.setHash(txHash);
+        dto.setBlockNumber(txReceipt.getLong("blockNumber"));
+        dto.setTimestamp(txReceipt.getLong("blockTimeStamp"));
+
+        // 交易状态
+        String result = txReceipt.getJSONObject("receipt").getStr("result");
+        dto.setStatus("SUCCESS".equals(result) ? "success" : "failed");
+
+        // 手续费信息
+        long feeSun = txReceipt.getLong("fee", 0L);
+        dto.setGasFee(BigDecimal.valueOf(feeSun).divide(BigDecimal.valueOf(1_000_000L), 6, RoundingMode.DOWN));
+
+        // 解析事件日志
+        JSONArray logs = txReceipt.getJSONArray("log");
+        if (!logs.isEmpty()) {
+            JSONObject log = logs.getJSONObject(0);
+            JSONArray topics = log.getJSONArray("topics");
+            String data = log.getStr("data");
+
+            // 解析 Transfer 事件
+            if (topics.size() >= 3) {
+                // 解析 from 地址(topics[1])
+                String fromHex = topics.getStr(1).substring(24); // 取后40个字符
+                dto.setFromAddress(TronHexAndBase58Util.hexToBase58(fromHex));
+
+                // 解析 to 地址(topics[2])
+                String toHex = topics.getStr(2).substring(24); // 取后40个字符
+                dto.setToAddress(TronHexAndBase58Util.hexToBase58(toHex));
+
+                // 解析金额(data 字段)
+                if (data != null && !data.isEmpty()) {
+                    BigInteger valueWei = new BigInteger(data.substring(24), 16); // 取后64个字符
+
+                    // 代币信息
+                    String contractAddress = txReceipt.getStr("contract_address");
+                    dto.setContractAddress(contractAddress);
+
+
+                    // todo 根据合约地址确定代币符号和精度
+                    dto.setDecimals(6);
+                    // 金额处理
+                    BigDecimal amount = new BigDecimal(valueWei).divide(BigDecimal.TEN.pow(dto.getDecimals()), dto.getDecimals(), RoundingMode.DOWN);
+                    dto.setAmount(amount);
+                }
+            }
+        }
+
+        return dto;
+    }
+
+    /**
+     * 查询交易事件
+     */
+    private static JSONObject getTransactionEvents(String txHash) {
+        String url = TRONGRID_BASE_URL + "/v1/transactions/" + txHash + "/events";
+
+        try {
+            String response = HttpRequest.get(url)
+                    .header("accept", "application/json")
+                    .timeout(10000)
+                    .execute()
+                    .body();
+
+            return JSONUtil.parseObj(response);
+
+        } catch (Exception e) {
+            throw new RuntimeException("查询交易事件失败: " + e.getMessage(), e);
+        }
+    }
+    /**
+     * 3.1 查询交易基本信息
+     */
+    private static JSONObject getTransactionInfo(String txHash) {
+        String url = TRONGRID_BASE_URL + "/wallet/gettransactionbyid";
+
+        JSONObject params = new JSONObject();
+        params.put("value", txHash);
+        params.put("visible", true);
+
+        try {
+            String response = HttpRequest.post(url)
+                    .header("Content-Type", "application/json")
+                    .timeout(10000)
+                    .body(params.toString())
+                    .execute()
+                    .body();
+
+            return JSONUtil.parseObj(response);
+
+        } catch (Exception e) {
+            throw new RuntimeException("查询交易信息失败: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 3.2 查询交易收据(包含执行结果)
+     */
+    private static JSONObject getTransactionReceipt(String txHash) {
+        String url = TRONGRID_BASE_URL + "/wallet/gettransactioninfobyid";
+
+        JSONObject params = new JSONObject();
+        params.set("value", txHash);
+        params.set("visible", true);
+
+        try {
+            String response = HttpRequest.post(url)
+                    .header("Content-Type", "application/json")
+                    .timeout(10000)
+                    .body(params.toString())
+                    .execute()
+                    .body();
+
+            return JSONUtil.parseObj(response);
+
+        } catch (Exception e) {
+            // 交易收据可能不存在,返回空对象
+            return new JSONObject();
+        }
+    }
+
+//    /**
+//     * 3.3 分析交易状态
+//     */
+//    private static JSONObject analyzeTransactionStatus(JSONObject txInfo, JSONObject txReceipt) {
+//        JSONObject status = new JSONObject();
+//        status.set("tx_hash", txInfo.getStr("txID"));
+//
+//        // 判断交易是否确认
+//        if (txInfo.containsKey("ret")) {
+//            JSONArray retArray = txInfo.getJSONArray("ret");
+//            if (retArray.size() > 0) {
+//                JSONObject ret = retArray.getJSONObject(0);
+//                String retCode = ret.getStr("ret");
+//                status.set("confirmed", !"FAILED".equals(retCode));
+//                status.set("ret_code", retCode);
+//            }
+//        }
+//
+//        // 检查交易收据(更详细的状态)
+//        if (!txReceipt.isEmpty() && txReceipt.containsKey("result")) {
+//            String result = txReceipt.getStr("result");
+//            status.set("execution_result", result);
+//            status.set("success", "SUCCESS".equals(result));
+//
+//            // 能量消耗
+//            if (txReceipt.containsKey("energy_usage")) {
+//                status.set("energy_used", txReceipt.getLong("energy_usage"));
+//            }
+//            if (txReceipt.containsKey("energy_penalty")) {
+//                status.set("energy_penalty", txReceipt.getLong("energy_penalty"));
+//            }
+//
+//            // 合约结果(代币交易)
+//            if (txReceipt.containsKey("contract_result")) {
+//                status.set("contract_result", txReceipt.getJSONArray("contract_result"));
+//            }
+//        }
+//
+//        // 交易基本信息
+//        if (txInfo.containsKey("raw_data")) {
+//            JSONObject rawData = txInfo.getJSONObject("raw_data");
+//            status.set("timestamp", rawData.getLong("timestamp"));
+//            status.set("expiration", rawData.getLong("expiration"));
+//
+//            // 交易类型
+//            if (rawData.containsKey("contract")) {
+//                JSONArray contracts = rawData.getJSONArray("contract");
+//                if (contracts.size() > 0) {
+//                    JSONObject contract = contracts.getJSONObject(0);
+//                    status.set("contract_type", contract.getStr("type"));
+//                }
+//            }
+//        }
+//
+//        return status;
+//    }
+
+    /**
+     * 4. 通过地址查询账户能量余额
+     *
+     * @param address TRON地址
+     * @return 能量信息
+     */
+    public static JSONObject getAccountEnergy(String address) {
+        String url = TRONGRID_BASE_URL + "/wallet/getaccountresource";
+
+        JSONObject params = new JSONObject();
+        params.put("address", address);
+        params.put("visible", true);
+
+        try {
+            String response = HttpRequest.post(url)
+                    .header("Content-Type", "application/json")
+                    .timeout(10000)
+                    .body(params.toString())
+                    .execute()
+                    .body();
+
+            JSONObject resourceData = JSONUtil.parseObj(response);
+            return parseEnergyInfo(address, resourceData);
+
+        } catch (Exception e) {
+            throw new RuntimeException("查询账户能量失败: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 4.1 解析能量信息
+     */
+    private static JSONObject parseEnergyInfo(String address, JSONObject resourceData) {
+        JSONObject energyInfo = new JSONObject();
+        energyInfo.set("address", address);
+
+        // 能量信息
+        if (resourceData.containsKey("EnergyUsed")) {
+            energyInfo.set("energy_used", resourceData.getLong("EnergyUsed"));
+        }
+        if (resourceData.containsKey("EnergyLimit")) {
+            energyInfo.set("energy_limit", resourceData.getLong("EnergyLimit"));
+        }
+
+        // 计算剩余能量
+        long energyUsed = resourceData.getLong("EnergyUsed", 0L);
+        long energyLimit = resourceData.getLong("EnergyLimit", 0L);
+        long energyRemaining = Math.max(0, energyLimit - energyUsed);
+        energyInfo.set("energy_remaining", energyRemaining);
+
+        // 带宽信息
+        if (resourceData.containsKey("free_net_used")) {
+            energyInfo.set("free_bandwidth_used", resourceData.getLong("free_net_used"));
+        }
+        if (resourceData.containsKey("free_net_limit")) {
+            energyInfo.set("free_bandwidth_limit", resourceData.getLong("free_net_limit"));
+        }
+
+        // 计算剩余带宽
+        long bandwidthUsed = resourceData.getLong("free_net_used", 0L);
+        long bandwidthLimit = resourceData.getLong("free_net_limit", 0L);
+        long bandwidthRemaining = Math.max(0, bandwidthLimit - bandwidthUsed);
+        energyInfo.set("free_bandwidth_remaining", bandwidthRemaining);
+
+        return energyInfo;
+    }
+
+    // ========== 工具方法 ==========
+
+
+//
+//    /**
+//     * 解析代币余额
+//     */
+//    private static BigDecimal parseTokenBalance(JSONObject response, int decimals) {
+//        if (response.containsKey("constant_result")) {
+//            String hexBalance = response.getJSONArray("constant_result").getStr(0);
+//            if (hexBalance != null && !hexBalance.isEmpty()) {
+//                try {
+//                    BigInteger balanceWei = new BigInteger(hexBalance, 16);
+//                    BigDecimal divisor = BigDecimal.TEN.pow(decimals);
+//                    return new BigDecimal(balanceWei).divide(divisor, decimals, BigDecimal.ROUND_DOWN);
+//                } catch (NumberFormatException e) {
+//                    throw new RuntimeException("解析代币余额失败: " + hexBalance, e);
+//                }
+//            }
+//        }
+//        return BigDecimal.ZERO;
+//    }
+//
+//    /**
+//     * 添加请求头(包含API Key)
+//     */
+//    private static HttpRequest addHeaders(HttpRequest request) {
+//        request.header("Content-Type", "application/json");
+//        if (apiKey != null && !apiKey.isEmpty()) {
+//            request.header("TRON-PRO-API-KEY", apiKey);
+//        }
+//        return request;
+//    }
+}

+ 18 - 0
blockchain-transfer/src/main/java/com/table/transfer/util/aUtil.java

@@ -0,0 +1,18 @@
+package com.table.transfer.util;
+
+public class aUtil {
+    public static String assetCode2Chain(String assetCode) throws Exception {
+        if(assetCode.contains("-")){
+            return assetCode.substring(assetCode.indexOf("-")+1);
+        }
+        throw new Exception("不正确的assetCode");
+    }
+    public static String assetCode2Coin(String assetCode) throws Exception {
+        if(assetCode.contains("-")){
+            return assetCode.substring(0,assetCode.indexOf("-")-1);
+        }
+        throw new Exception("不正确的assetCode");
+    }
+
+
+}

+ 190 - 0
blockchain-transfer/src/main/java/com/table/transfer/util/encryp/RSAEncryptionUtil.java

@@ -0,0 +1,190 @@
+package com.table.transfer.util.encryp;
+
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import jakarta.annotation.PostConstruct;
+import lombok.extern.slf4j.Slf4j;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Cipher;
+import java.security.*;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+@Slf4j
+
+public class RSAEncryptionUtil {
+
+    public static void a() {
+        try {
+            System.out.println("开始初始化 Bouncy Castle...");
+            System.out.println("Java 版本: " + System.getProperty("java.version"));
+            System.out.println("Java Home: " + System.getProperty("java.home"));
+
+            // 列出所有已注册的安全提供者
+            Provider[] providers = Security.getProviders();
+            System.out.println("当前安全提供者:");
+            for (Provider provider : providers) {
+                System.out.println(" - " + provider.getName() + " v" + provider.getVersion());
+            }
+
+            // 检查BC是否已存在 - 这里修改:不移除,直接使用现有的
+            Provider existingBC = Security.getProvider("BC");
+            if (existingBC != null) {
+                System.out.println("发现已存在的 BC 提供者: " + existingBC.getInfo());
+                // 不移除,直接使用现有的BC提供者
+                System.out.println("使用现有的 BC 提供者");
+            } else {
+                // 添加新的BC提供者
+                BouncyCastleProvider newProvider = new BouncyCastleProvider();
+                Security.addProvider(newProvider);
+                System.out.println("成功添加 Bouncy Castle 提供者: " + newProvider.getInfo());
+            }
+
+            // 验证BC提供者
+            Provider verifiedBC = Security.getProvider("BC");
+            if (verifiedBC != null) {
+                System.out.println("BC 提供者验证成功: " + verifiedBC.getName());
+            } else {
+                System.err.println("BC 提供者验证失败!");
+            }
+
+            System.out.println("=== 开始加密测试 ===");
+
+            // 测试加密 - 添加更详细的错误处理
+            try {
+                String testText = "尝试进行加密";
+                System.out.println("加密原文: " + testText);
+
+                String encrypted = encrypt(testText);
+                System.out.println("加密成功,结果: " + encrypted);
+                log.info("加密后: " + encrypted);
+
+                System.out.println("=== 开始解密测试 ===");
+                String decrypted = decrypt(encrypted);
+                System.out.println("解密成功,结果: " + decrypted);
+
+                boolean match = testText.equals(decrypted);
+                System.out.println("加解密验证: " + (match ? "成功" : "失败"));
+
+            } catch (Exception cryptoException) {
+                System.err.println("加解密操作失败:");
+                cryptoException.printStackTrace();
+                log.error("加解密操作失败", cryptoException);
+
+                // 输出更详细的错误信息
+                System.err.println("错误类型: " + cryptoException.getClass().getName());
+                System.err.println("错误信息: " + cryptoException.getMessage());
+
+                // 检查公钥
+                try {
+                    byte[] publicKeyBytes = Base64.getDecoder().decode(pubk);
+                    System.out.println("公钥长度: " + publicKeyBytes.length + " bytes");
+
+                    // 尝试解析公钥
+                    PublicKey publicKey = getPublicKey(publicKeyBytes);
+                    System.out.println("公钥算法: " + publicKey.getAlgorithm());
+                    System.out.println("公钥格式: " + publicKey.getFormat());
+                } catch (Exception keyException) {
+                    System.err.println("公钥解析失败:");
+                    keyException.printStackTrace();
+                }
+            }
+            System.out.println("没有异常");
+        } catch (Exception e) {
+            System.err.println("RSA初始化失败:");
+            e.printStackTrace();
+            log.error("RSA初始化失败", e);
+        }
+
+    }
+
+
+    //todo -d解密
+    private static String PK =
+            "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDAf2lhRMQC8xK529AiMnTXbFHXvDRT5AIhCSHRFqczqhfxIRanuZ0G3+kz0Leqrqom50XuIsi0jcUMoHbB9hgbg1GnuWtHgxTWtP9uxZiGF6++KhWP/XYgpsZYPcRtNc1W/P71wyfX8VHsBDQqbEoi3hTXJyVG4lClnk4mtAUAO+6+PeUsScUC0Pg2kdYKaPtVvlszLEQhFrIkK0YI021DIZEoyAOw87ncbkS77ekxu9dSwvcGo3dW/ggulhQv8LLgshEWBL1oH1VgC6vDjG/skkkIg416GIsRZ5BtQlVzlmxY3hLQGs8CoXhdTa5zTT+rpDy135pBF6k99KJ28/JjAgMBAAECggEABoKf5U2fQOe85qpEkpOBuzNoXHYdp01mtWVQq4/lYzIyel1/er32B9qsC5UHC1h0XC4aXuZqcUu0shRa230CkJ9Hhci6wrvwFMHEU5gaSUU8WnDpvlIbs0eK17snDT3D8UDuduHlx7R+ST5U+JfIb4tyskMDHdKwtY2VJiSr7M7cgFslAhvDhzyeJxMKZ0LGcPiEpLUTi39szgbST8wYxwY65UkAEVLPSNsZjiREhioMFqK3ikMIx1W2QI7la5JO6HVMApMx77CEK12otI/8u3x/myl2L7ABtn5Z1aPkKAUNJYNV7vy20Fcxve8qFv0tPmU6bWZCPoVcG9fjs+jFcQKBgQDr0k8nojol4dLWQfYfkauRH7nt0DzNuO+6pMfcGOs1yg1w6mf8+OCDFkfYnW9XZnzVjFoYd6ln+1QGQBC+DbpVeGFgaB4fWc+/HdXm5a8fASxG5eIPy5yrirsnwzku7q7y4edp0YNgO8/o+wbiuvbf18R9bwOP8MfO9IufpGbQ6QKBgQDQ+BcnnMROIcjKLgKkMsdnPMNRyZg1xrKPgZLQSv/uyeK2N+XsWQMMGUapjC/pKAgNZ1V0oxzHW+wkYeizRFZQPGmAAXT9lmlu5bbryRbNCZ9LyjPiKN7PafArWGi5SaOq2rsrDUz6tstwh9XVj9RGEW7yA4HFaCPeeUpRy4j5awKBgAXau8JVIbJtD8nn609PU34P1pLT156X18O/cYLCT5yPPpQuDZTXLOO0OuZiyi/WSIUYrefrmJYPRD+/eWrudlDG40v8absHhMPO3s+TpixT4CCGdn1D5cjQceMD0riajldTSmZzIBrUgU3cZYhdceGOvr8KcYEyThOSOKEm+LJ5AoGAfnLxR/YTz5ef8b+/t25GvVDGfDI52aifmjj1BverQOqHNm5Cwi7mqiaNXMFIqJShssKpskeVfYlBLo7Uic27URgNWvkGuwCOUh3M/4aSNoYxD2KO3LaQhP/85a28yQoncJalFZsZzshX+IMpwO4krDWWZfn7R+IJenD4qOA5xXsCgYBUTdfq7iZJGwU0YD/MeO/Y8PhIOe2CYo4dp9GyzGncXNxxNULCGBCUC13XWUFxs34thz2OLJQBjiIYNVRsb2ojsqrlQZWgip2PUxSgMaWeDNVu/g2ixNdFcKvROhsKbuZtkoJ6Z/Y8l7JrmAM7f2IMk8fObgKpUaTOrVh2NtnvRw==";
+    private static String pubk =
+            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwH9pYUTEAvMSudvQIjJ012xR17w0U+QCIQkh0RanM6oX8SEWp7mdBt/pM9C3qq6qJudF7iLItI3FDKB2wfYYG4NRp7lrR4MU1rT/bsWYhhevvioVj/12IKbGWD3EbTXNVvz+9cMn1/FR7AQ0KmxKIt4U1yclRuJQpZ5OJrQFADvuvj3lLEnFAtD4NpHWCmj7Vb5bMyxEIRayJCtGCNNtQyGRKMgDsPO53G5Eu+3pMbvXUsL3BqN3Vv4ILpYUL/Cy4LIRFgS9aB9VYAurw4xv7JJJCIONehiLEWeQbUJVc5ZsWN4S0BrPAqF4XU2uc00/q6Q8td+aQRepPfSidvPyYwIDAQAB";
+    private static final String ALGORITHM = "RSA";
+    // 必须显式指定 SHA-256,且强制使用 Bouncy Castle
+
+    // 使用系统默认提供者,不指定BC
+    private static final String TRANSFORMATION = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
+
+    /**
+     * 使用公钥加密数据 - 使用系统默认提供者
+     */
+    public static String encrypt(String plainText) throws Exception {
+        try {
+            System.out.println("开始加密,使用系统默认提供者");
+
+            byte[] publicKeyBytes = Base64.getDecoder().decode(pubk);
+            PublicKey publicKey = getPublicKey(publicKeyBytes);
+
+            // 关键修改:不使用"BC",让系统选择默认提供者
+            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
+
+            byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(java.nio.charset.StandardCharsets.UTF_8));
+            return Base64.getEncoder().encodeToString(encryptedBytes);
+
+        } catch (Exception e) {
+            throw new Exception("加密失败: " + e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 使用私钥解密数据 - 使用系统默认提供者
+     */
+    public static String decrypt(String encryptedData) throws Exception {
+        try {
+            byte[] privateKeyBytes = Base64.getDecoder().decode(PK);
+            PrivateKey privateKey = getPrivateKey(privateKeyBytes);
+
+            // 关键修改:不使用"BC"
+            Cipher cipher = Cipher.getInstance(TRANSFORMATION);
+            cipher.init(Cipher.DECRYPT_MODE, privateKey);
+
+            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
+            byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
+            return new String(decryptedBytes, java.nio.charset.StandardCharsets.UTF_8);
+
+        } catch (Exception e) {
+            throw new Exception("解密失败: " + e.getMessage(), e);
+        }
+    }
+
+    private static PublicKey getPublicKey(byte[] keyBytes) throws Exception {
+        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
+        // 关键修改:不使用"BC"
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        return keyFactory.generatePublic(spec);
+    }
+
+    private static PrivateKey getPrivateKey(byte[] keyBytes) throws Exception {
+        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
+        // 关键修改:不使用"BC"
+        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+        return keyFactory.generatePrivate(spec);
+    }
+
+    /**
+     * 生成 RSA 密钥对(2048 位)
+     */
+    public static KeyPair generateKeyPair() throws Exception {
+        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM, "BC");
+        keyPairGenerator.initialize(2048, new SecureRandom());
+        return keyPairGenerator.generateKeyPair();
+    }
+
+    public static String getPublicKeyBase64(KeyPair keyPair) {
+        return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
+    }
+
+    public static String getPrivateKeyBase64(KeyPair keyPair) {
+        return Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
+    }
+
+}

+ 44 - 0
blockchain-transfer/src/main/java/com/table/transfer/util/ether/ChainCoinDetailManager.java

@@ -0,0 +1,44 @@
+package com.table.transfer.util.ether;
+
+import com.table.transfer.module.enpty.ChainCoinDetail;
+import com.table.transfer.module.enpty.TransferRequest;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class ChainCoinDetailManager {
+    public static final Map<String, ChainCoinDetail> chainCoinDetailMap = new HashMap<>();
+    private static final String ethNode = "https://billowing-greatest-feather.quiknode.pro/591e36c78f14e843e629d72c07a3fb39c5955541";
+    private static final String bscNode = "https://empty-quiet-sunset.bsc.quiknode.pro/69b72a1ee6e3efe4ad03d31b04a9a1b0c8a6e6d3";
+
+    static {
+        List<ChainCoinDetail> ChainCoinDetailList = new ArrayList<>();
+        ChainCoinDetailList.add(new ChainCoinDetail(1, "ETH", "USDT", "0xdAC17F958D2ee523a2206206994597C13D831ec7", 6, BigInteger.valueOf(800000000L), BigInteger.valueOf(20000000000L), ethNode));
+        ChainCoinDetailList.add(new ChainCoinDetail(1, "ETH", "ETH", null, 18, BigInteger.valueOf(800000000L), BigInteger.valueOf(20000000000L), ethNode));
+        ChainCoinDetailList.add(new ChainCoinDetail(56, "BSC", "USDT", "0x55d398326f99059fF775485246999027B3197955", 18, BigInteger.valueOf(100000000L), BigInteger.valueOf(1000000000L), bscNode));
+        ChainCoinDetailList.add(new ChainCoinDetail(56, "BSC", "BNB", null, 18,  BigInteger.valueOf(100000000L), BigInteger.valueOf(1000000000L), bscNode));
+        ChainCoinDetailList.add(new ChainCoinDetail(56, "BSC", "TRX", "0xCE7de646e7208a4Ef112cb6ed5038FA6cC6b12e3", 6, BigInteger.valueOf(100000000L), BigInteger.valueOf(1000000000L), bscNode));
+        ChainCoinDetailList.add(new ChainCoinDetail(56, "BSC", "ETH", "0x2170Ed0880ac9A755fd29B2688956BD959F933F8", 18, BigInteger.valueOf(100000000L), BigInteger.valueOf(1000000000L), bscNode));
+        ChainCoinDetailList.add(new ChainCoinDetail(56, "BSC", "WBNB", "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c", 18, BigInteger.valueOf(100000000L), BigInteger.valueOf(1000000000L), bscNode));
+        ChainCoinDetailList.add(new ChainCoinDetail(56, "BSC", "WBTC", "0x0555E30da8f98308EdB960aa94C0Db47230d2B9c", 8, BigInteger.valueOf(100000000L), BigInteger.valueOf(1000000000L), bscNode));
+
+        for (ChainCoinDetail one : ChainCoinDetailList) {
+            chainCoinDetailMap.put(one.getAssetCode(), one);
+        }
+
+    }
+    public static ChainCoinDetail getChainCoinDetail(TransferRequest transferRequest) {
+        return chainCoinDetailMap.get(transferRequest.getAssetCode());
+    }
+
+    public static ChainCoinDetail getChainCoinDetail(String assetCode) {
+        return chainCoinDetailMap.get(assetCode);
+    }
+    public static int getDecimal(TransferRequest transferRequest) {
+       return chainCoinDetailMap.get(transferRequest.getAssetCode()).getDecimal();
+    }
+
+}

+ 47 - 0
blockchain-transfer/src/main/java/com/table/transfer/util/ether/Web3jManager.java

@@ -0,0 +1,47 @@
+package com.table.transfer.util.ether;
+
+import jakarta.annotation.PostConstruct;
+import okhttp3.ConnectionPool;
+import okhttp3.OkHttpClient;
+import org.web3j.protocol.Web3j;
+import org.web3j.protocol.http.HttpService;
+
+import java.time.Duration;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+public class Web3jManager {
+    private static final String ethNode = "https://billowing-greatest-feather.quiknode.pro/591e36c78f14e843e629d72c07a3fb39c5955541";
+    private static final String bscNode = "https://empty-quiet-sunset.bsc.quiknode.pro/69b72a1ee6e3efe4ad03d31b04a9a1b0c8a6e6d3";
+
+    public static final Map<String, Web3j> web3jClients = new ConcurrentHashMap<>();
+
+     static {
+        // 假设你有多个链的节点配置
+        registerWeb3j("ETH", ethNode);
+        registerWeb3j("BSC", bscNode);
+    }
+    public static void registerWeb3j(String chain, String nodeUrl) {
+        OkHttpClient httpClient = new OkHttpClient.Builder()
+                .connectTimeout(10, TimeUnit.SECONDS)
+                .readTimeout(30, TimeUnit.SECONDS)
+                .writeTimeout(30, TimeUnit.SECONDS)
+                .connectionPool(new ConnectionPool(10, 60, TimeUnit.SECONDS))
+                .retryOnConnectionFailure(true) // 对 GET 请求自动重试
+                .build();
+
+        HttpService httpService = new HttpService(nodeUrl, httpClient, false);
+        Web3j web3j = Web3j.build(httpService);
+        web3jClients.put(chain, web3j);
+    }
+
+    public static Web3j getWeb3j(String chain) {
+        Web3j web3j = web3jClients.get(chain);
+        if (web3j == null) {
+            throw new IllegalArgumentException("不支持的链: " + chain);
+        }
+        return web3j;
+    }
+
+}

+ 90 - 0
blockchain-transfer/src/main/java/com/table/transfer/util/tron/TronHexAndBase58Util.java

@@ -0,0 +1,90 @@
+package com.table.transfer.util.tron;
+
+import cn.hutool.core.codec.Base58;
+import cn.hutool.core.util.HexUtil;
+import cn.hutool.crypto.digest.DigestUtil;
+
+import java.util.Arrays;
+
+/**
+ * TRON 地址转换工具(纯 Hutool 版本)
+ */
+public class TronHexAndBase58Util {
+    
+    /**
+     * Hex 地址转 Base58 地址
+     */
+    public static String hexToBase58(String hexAddress) {
+        try {
+            // 移除可能存在的 0x 前缀
+            if (hexAddress.startsWith("0x")) {
+                hexAddress = hexAddress.substring(2);
+            }
+            
+            if (hexAddress.length() != 40) {
+                throw new IllegalArgumentException("无效的地址长度: " + hexAddress.length());
+            }
+            
+            // 添加 TRON 地址前缀 0x41
+            String fullHex = "41" + hexAddress;
+            
+            // 使用 Hutool 将 Hex 转换为字节数组
+            byte[] addressBytes = HexUtil.decodeHex(fullHex);
+            
+            // 计算校验和
+            byte[] checksum = calculateChecksum(addressBytes);
+            
+            // 组合地址字节和校验和
+            byte[] fullBytes = new byte[addressBytes.length + checksum.length];
+            System.arraycopy(addressBytes, 0, fullBytes, 0, addressBytes.length);
+            System.arraycopy(checksum, 0, fullBytes, addressBytes.length, checksum.length);
+            
+            // 使用 Hutool 的 Base58 编码
+            return Base58.encode(fullBytes);
+            
+        } catch (Exception e) {
+            throw new RuntimeException("Hex 转 Base58 失败: " + e.getMessage(), e);
+        }
+    }
+    
+    /**
+     * Base58 地址转 Hex 地址
+     */
+    public static String base58ToHex(String base58Address) {
+        try {
+            // 使用 Hutool 的 Base58 解码
+            byte[] decoded = Base58.decode(base58Address);
+            
+            // 提取地址部分(前21字节)
+            byte[] addressBytes = Arrays.copyOfRange(decoded, 0, 21);
+            
+            // 使用 Hutool 将字节数组转换为 Hex
+            String hexAddress = HexUtil.encodeHexStr(addressBytes);
+            
+            if (hexAddress.startsWith("41") && hexAddress.length() == 42) {
+                return "000000000000000000000000" + hexAddress.substring(2);
+            } else {
+                throw new IllegalArgumentException("无效的 TRON 地址格式: " + hexAddress);
+            }
+            
+        } catch (Exception e) {
+            throw new RuntimeException("Base58 转 Hex 失败: " + e.getMessage(), e);
+        }
+    }
+    
+    /**
+     * 计算校验和
+     */
+    private static byte[] calculateChecksum(byte[] data) {
+        byte[] hash1 = DigestUtil.sha256(data);
+        byte[] hash2 = DigestUtil.sha256(hash1);
+        return Arrays.copyOfRange(hash2, 0, 4);
+    }
+    
+    /**
+     * 验证 TRON 地址格式
+     */
+    public static boolean isValidTronAddress(String address) {
+        return address != null && address.length() == 34 && address.startsWith("T");
+    }
+}

+ 41 - 0
blockchain-transfer/src/main/resources/application-dev.yaml

@@ -0,0 +1,41 @@
+server:
+  port: 8080
+spring:
+  application:
+    name: blockchain-transfer-service
+  jackson:
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+  rabbitmq:
+    host: localhost
+    port: 5672
+    username: guest
+    password: guest
+    virtual-host: /adae
+    connection-timeout: 10000  # 增加超时时间
+  #mysql
+  datasource:
+    url: jdbc:mysql://156.233.229.79:3306/echo2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+    username: echo2
+    password: 6YdejnWXdFdTRwsB
+    driver-class-name: com.mysql.cj.jdbc.Driver
+mybatis-plus:
+  configuration:
+    map-underscore-to-camel-case: true
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 开发时开启SQL日志
+  global-config:
+    db-config:
+      id-type: auto
+      logic-delete-field: deleted  # 逻辑删除字段名
+      logic-delete-value: 1
+      logic-not-delete-value: 0
+  mapper-locations: classpath*:/mapper/**/*.xml
+logging:
+  level:
+    org.springframework.amqp: DEBUG  # 添加 RabbitMQ 调试日志
+    com.table.transfer: INFO
+    com.example.blockchain: INFO
+  file:
+    name: logs/transfer.log
+  pattern:
+    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

+ 48 - 0
blockchain-transfer/src/main/resources/application-local.yaml

@@ -0,0 +1,48 @@
+# application.yml
+server:
+  port: 8080
+
+
+
+spring:
+  application:
+    name: blockchain-transfer-service
+  jackson:
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+  rabbitmq:
+    host: localhost
+    port: 5672
+    username: guest
+    password: guest
+    virtual-host: /adae
+    connection-timeout: 10000  # 增加超时时间
+  #mysql
+  datasource:
+    url: jdbc:mysql://156.233.229.79:3306/echo2?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+    username: echo2
+    password: 6YdejnWXdFdTRwsB
+    driver-class-name: com.mysql.cj.jdbc.Driver
+
+mybatis-plus:
+  configuration:
+    map-underscore-to-camel-case: true
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 开发时开启SQL日志
+  global-config:
+    db-config:
+      id-type: auto
+      logic-delete-field: del_flag  # 逻辑删除字段名
+      logic-delete-value: 1
+      logic-not-delete-value: 0
+  mapper-locations: classpath*:/mapper/**/*.xml
+
+logging:
+  level:
+    org.springframework.amqp: DEBUG  # 添加 RabbitMQ 调试日志
+    com.table.transfer: INFO
+    com.example.blockchain: INFO
+  file:
+    name: logs/transfer.log
+  pattern:
+    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
+

+ 41 - 0
blockchain-transfer/src/main/resources/application-prod.yaml

@@ -0,0 +1,41 @@
+server:
+  port: 8888
+spring:
+  application:
+    name: blockchain-transfer-service
+  jackson:
+    time-zone: GMT+8
+    date-format: yyyy-MM-dd HH:mm:ss
+  rabbitmq:
+    host: 127.0.0.1
+    port: 5672
+    username: blockchain
+    password: bl@nkchaine69139fa
+    virtual-host: /adae
+    connection-timeout: 10000  # 增加超时时间
+  #mysql
+  datasource:
+    url: jdbc:mysql://t6w2dyvggz5fk.aliyun-ap-southeast-1.oceanbase.cloud:3306/adae?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+    username: adae
+    password: q8s:%~[(m7lStxC;@_bX31~7l7xj)z
+    driver-class-name: com.mysql.cj.jdbc.Driver
+mybatis-plus:
+  configuration:
+    map-underscore-to-camel-case: true
+    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl  # 开发时开启SQL日志
+  global-config:
+    db-config:
+      id-type: auto
+      logic-delete-field: deleted  # 逻辑删除字段名
+      logic-delete-value: 1
+      logic-not-delete-value: 0
+  mapper-locations: classpath*:/mapper/**/*.xml
+logging:
+  level:
+    org.springframework.amqp: DEBUG  # 添加 RabbitMQ 调试日志
+    com.table.transfer: INFO
+    com.example.blockchain: INFO
+  file:
+    name: logs/transfer.log
+  pattern:
+    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

+ 4 - 0
blockchain-transfer/src/main/resources/application.yaml

@@ -0,0 +1,4 @@
+spring:
+  profiles:
+    active: @profile.active@
+

+ 55 - 0
blockchain-transfer/src/test/java/BlockchainServiceTest.java

@@ -0,0 +1,55 @@
+import cn.hutool.json.JSONUtil;
+import com.table.transfer.module.enpty.TransactionInfoDTO;
+import com.table.transfer.module.enpty.TransferRequest;
+import com.table.transfer.module.service.EthereumService;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class BlockchainServiceTest {
+    private static final EthereumService ethereumService= new EthereumService();
+
+    //   SENDADDRESSMAP.put("ETH","0x6F18844e79BeefF5f2D1eE30508aB695A829C12e");
+//        SENDADDRESSMAP.put("tron","TDFtN7nyfweR8WeUraZM7WuCrtUTruD4Er");
+//        SENDADDRESSMAP.put("BSC","0xcBea8F7907078B07B0f491D1B65Ea92905E57827");
+
+
+    public static void main(String[] args) throws Exception {
+//        Web3jManager.init();
+        TransferRequest bscTransferRequest = new TransferRequest();
+        bscTransferRequest.setToAddress("0x4472E7346a38AfB457562895c4Aa974C2A516a84");
+        bscTransferRequest.setFromAddress("0xe78d1f011c52f15012a7f964072750e7b8d7b80a");
+        bscTransferRequest.setPrivateKey("7f79238fc14b539fc6d7d3697db7fc4c2578f03307547b8625ff30f6d48da433");
+        bscTransferRequest.setAmount("0.0000097311403");
+        bscTransferRequest.setContractAddress("0x55d398326f99059ff775485246999027b3197955");
+        bscTransferRequest.setChain("BSC");
+        bscTransferRequest.setCoin("BNB");
+        //獲取nonce
+        BigInteger bscNonce = ethereumService.getNonce(bscTransferRequest.getAssetCode(), bscTransferRequest.getFromAddress());
+        System.out.println("bsc链获取nonce" + bscNonce);
+        //获取gasLimit和SafeGasPrice
+        BigInteger bscSafeGasPrice = ethereumService.getSafeGasPrice(bscTransferRequest);
+        System.out.println("bsc链获取GasPrice" + bscSafeGasPrice);
+        BigInteger bscGasLimit = ethereumService.estimateGasSafely(bscTransferRequest);
+        System.out.println("bsc链获取bscGasLimit" + bscGasLimit);
+        //获取代币和主币余额
+        BigDecimal tokenBalance=ethereumService.getTokenBalance(bscTransferRequest.getAssetCode(),bscTransferRequest.getContractAddress(),bscTransferRequest.getFromAddress());
+        BigDecimal balance = ethereumService.getBalance(bscTransferRequest.getChain(), bscTransferRequest.getFromAddress());
+        System.out.println("代币余额:"+tokenBalance);
+        System.out.println("主币余额:"+balance);
+
+        Long lastBlock = ethereumService.getLastBlock(bscTransferRequest.getChain());
+        System.out.println("获取最"+bscTransferRequest.getChain()+"新区块:"+lastBlock);
+
+
+        TransactionInfoDTO transactionInfoByHash = ethereumService.getTransactionInfoByHash(bscTransferRequest.getAssetCode(), "0xda1fbf2fe5f5afbe2c7fde92bce9eb2d1baa6e6b3a5ca430845b78ce879422a3");
+        System.out.println(bscTransferRequest.getChain()+"链根据hash查询交易结果:"+JSONUtil.toJsonStr(transactionInfoByHash));
+
+
+        ethereumService.transfer(bscTransferRequest);
+        BigInteger ethNonce = ethereumService.getNonce("USDT-ETH", "0x6F18844e79BeefF5f2D1eE30508aB695A829C12e");
+        System.out.println("eth链获取nonce" + ethNonce);
+
+    }
+
+}

+ 6 - 1
qnfhq-api/pom.xml

@@ -59,7 +59,12 @@
             <artifactId>easy-captcha</artifactId>
             <version>${captcha.version}</version>
         </dependency>
-
+<!--        阿里云实名认证-->
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>cloudauth_intl20220809</artifactId>
+            <version>2.0.2</version>
+        </dependency>
         <dependency>
             <groupId>org.redisson</groupId>
             <artifactId>redisson-spring-boot-starter</artifactId>

+ 1 - 1
qnfhq-api/src/main/java/com/qnfhq/common/ApiBaseController.java

@@ -26,7 +26,7 @@ public class ApiBaseController {
     public AppUserEntity getAppUser(){
         long loginIdAsLong = StpUtil.getLoginIdAsLong();
         AppUserService appUserService = SpringContextUtils.getBean(AppUserService.class);
-        return appUserService.selectById(loginIdAsLong);
+        return appUserService.getById(loginIdAsLong);
     }
     /**
      * 返回成功

+ 2 - 1
qnfhq-api/src/main/java/com/qnfhq/config/SaTokenConfigure.java

@@ -28,8 +28,9 @@ public class SaTokenConfigure {
     public SaServletFilter getSaServletFilter() {
         return new SaServletFilter()
 
-                // 指定 拦截路由 与 放行路由
+                // 指定 拦截路由 与 放行路由 todo 测试过鉴权
                 .addInclude("/**")
+//                .addExclude("/**")
                 .addExclude(
                         "/user/register",
                         "/user/login",

+ 261 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/controller/UserAuthenticationController.java

@@ -0,0 +1,261 @@
+//package com.qnfhq.modules.authentication.controller;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import cn.hutool.core.convert.Convert;
+//import cn.hutool.core.util.StrUtil;
+//import cn.hutool.json.JSONUtil;
+//import com.aliyun.cloudauth_intl20220809.models.InitializeResponse;
+//import com.aliyun.cloudauth_intl20220809.models.InitializeResponseBody;
+//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+//import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+//import com.qnfhq.common.ApiBaseController;
+//import com.qnfhq.common.service.FileService;
+//import com.qnfhq.common.utils.MessageUtils;
+//import com.qnfhq.common.utils.Result;
+//import com.qnfhq.modules.user.entity.AppUserDetailEntity;
+//import com.qnfhq.modules.user.enums.UserCodeTypeEnum;
+//import com.qnfhq.common.utils.cache.RedisCache;
+//import com.qnfhq.modules.authentication.entity.AikycRequest;
+//import com.qnfhq.modules.authentication.entity.UserAuthentication;
+//import com.qnfhq.modules.authentication.service.UserAuthenticationService;
+//import com.qnfhq.modules.authentication.util.AliyunEkycUtil;
+//import com.qnfhq.modules.user.entity.AppUserEntity;
+//import com.qnfhq.modules.user.service.AppUserDetailService;
+//import com.qnfhq.modules.user.service.AppUserService;
+//import io.swagger.v3.oas.annotations.Operation;
+//import io.swagger.v3.oas.annotations.tags.Tag;
+//import jakarta.annotation.Resource;
+//import org.apache.commons.codec.binary.Base64;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.transaction.annotation.Transactional;
+//import org.springframework.web.bind.annotation.PostMapping;
+//import org.springframework.web.bind.annotation.RequestBody;
+//import org.springframework.web.bind.annotation.RequestMapping;
+//import org.springframework.web.bind.annotation.RestController;
+//import org.springframework.web.multipart.MultipartFile;
+//
+//import java.util.HashMap;
+//import java.util.List;
+//import java.util.Map;
+//import java.util.concurrent.TimeUnit;
+//
+//
+///**
+// * <p>
+// * 认证请求响应记录表 前端控制器
+// * </p>
+// *
+// * @author huang
+// * @since 2025-07-18
+// */
+//@Tag(name = "认证请求响应记录表模块")
+//@RestController
+//@RequestMapping("/api/appuser")
+//public class UserAuthenticationController extends ApiBaseController {
+//    @Resource
+//    private AliyunEkycUtil aliyunEkycUtil;
+//    @Resource
+//    UserAuthenticationService userAuthenticationService;
+//    @Resource
+//    private AppUserDetailService appUserDetailService;
+//    @Resource
+//    AppUserService appUserService;
+//
+//    @Autowired
+//    private FileService fileService;
+//
+//    @Resource
+//    private RedisCache redisCache;
+//
+//    @Operation(summary = "实名认证初始化")
+//    @PostMapping("/initialize")
+//    public Result initialize(@RequestBody Map<String, Object> params) {
+//        //参数错误
+//        if (params.get("docType") == null || params.get("authorize") == null || params.get("metaInfo") == null) {
+//            return new Result().error(MessageUtils.message("login.param.null"));
+//        }
+//        Long userId = getStpUserId();
+//        try {
+//            AikycRequest aikycRequest = new AikycRequest();
+//            aikycRequest.setDocType(params.get("docType").toString());
+//            aikycRequest.setAuthorize(params.get("authorize").toString());
+//            aikycRequest.setMetaInfo(params.get("metaInfo").toString());
+//            aikycRequest.setMerchantUserId(String.valueOf(getStpUserId()));
+//            aikycRequest.setReturnUrl(params.containsKey("url") ? params.get("url").toString() : "");
+//            InitializeResponse initialize = aliyunEkycUtil.initialize(aikycRequest);
+//            if (initialize.getStatusCode() == 200) {
+//                InitializeResponseBody.InitializeResponseBodyResult authResult = initialize.getBody().getResult();
+//                String transactionId = authResult.getTransactionId();
+//                Map<String, Object> result = new HashMap<>();
+//                result.put("transactionId", transactionId);
+//                result.put("transactionUrl", authResult.getTransactionUrl());
+//
+//                String keyCache = StrUtil.format("api-userauther-callback:{}", userId);
+//                redisCache.setCacheObject(keyCache, "1", 60 * 20, TimeUnit.MINUTES);
+//
+//                return success(result);
+//            }
+//            return error(initialize.getBody().message);
+//        } catch (Exception e) {
+//            return error(e.getMessage());
+//        }
+//    }
+//
+//    @Operation(summary = "验证实名认证")
+//    @PostMapping("/checkID")
+//    @Transactional(rollbackFor = Exception.class)
+//    public Result checkID(@RequestBody Map<String, Object> params) throws Exception {
+//        if (params.get("transactionId") == null) {
+//            return error(MessageUtils.message("login.param.null"));
+//        }
+//        String transactionId = params.get("transactionId").toString();
+//        Long userId = getStpUserId();
+//
+//        String keyCache = StrUtil.format("api-userauther-check:{}", userId);
+//        if (StrUtil.isNotBlank(redisCache.getCacheObject(keyCache))) {
+//            return error(MessageUtils.message("login.repeat.operation"));
+//        }
+////        userAuthenticationService;
+//                appUserService.selectById()
+//        redisCache.setCacheObject(keyCache, "1", 30, TimeUnit.MINUTES);
+//        UserAuthentication one = userAuthenticationService.getOne(
+//                new LambdaQueryWrapper<UserAuthentication>()
+//                        .eq(UserAuthentication::getTransactionId, transactionId));
+//        if (one != null) {
+//            redisCache.deleteObject(keyCache);
+//            return error(MessageUtils.message("user.kyc.completed"));
+//        }
+//
+//        //是否重新实名认证
+//        boolean reKyc = false;
+//
+//        AppUserEntity userInfo = appUserService.selectById(userId);
+//        String checkEmailKey = String.format("%s%s", UserCodeTypeEnum.CHANGE_KYC.name(), userInfo.getEmail());
+//        int checkEmail = 0;
+//        if (StrUtil.isNotBlank(redisCache.getCacheObject(checkEmailKey))) {
+//            checkEmail = Convert.toInt(redisCache.getCacheObject(checkEmailKey));
+//        }
+//        String checkPhoneKey = String.format("%s%s", UserCodeTypeEnum.CHANGE_KYC.name(), userInfo.getPhone());
+//        int checkPhone = 0;
+//        if (StrUtil.isNotBlank(redisCache.getCacheObject(checkPhoneKey))) {
+//            checkPhone = Convert.toInt(redisCache.getCacheObject(checkPhoneKey));
+//        }
+//        if (checkEmail == 1 && checkPhone == 1) {
+//            reKyc = true;
+//        }
+//
+//        AppUserDetailEntity detail = appUserDetailService.se(
+//                new LambdaQueryWrapper<TAppUserDetail>()
+//                        .eq(TAppUserDetail::getUserId, userId));
+//        //实名认证校验,重新实名认证不校验
+//        if (!reKyc) {
+//            //如果账户已认证且已经有了身份证和头部照片,则认定为已认证
+//            if (detail != null &&
+//                    "1".equals(detail.getAuditStatusPrimary()) &&
+//                    StringUtils.isNotBlank(detail.getFrontUrl()) &&
+//                    StringUtils.isNotBlank(detail.getHandelUrl())) {
+//
+//                redisCache.deleteObject(keyCache);
+//                return error(MessageUtils.message("user.kyc.already_completed"));
+//
+//            }
+//        }
+//        try {
+//            CheckResultResponse checkResultResponse = aliyunEkycUtil.checkResult(transactionId);
+//            UserAuthentication userAuthentication = new UserAuthentication();
+//            userAuthentication.setHttpStatusCode(checkResultResponse.getStatusCode());
+//            if (200 == checkResultResponse.getStatusCode()) {
+//                CheckResultResponseBody body = checkResultResponse.getBody();
+//
+//
+//                String extFaceInfoString = checkResultResponse.getBody().getResult().getExtFaceInfo();
+//                String extIdInfoString = checkResultResponse.getBody().getResult().getExtIdInfo();
+//                ExtFaceInfo extFaceInfo = JSONUtil.toBean(extFaceInfoString, ExtFaceInfo.class);
+//                ExtIdInfo extIdInfo = JSONUtil.toBean(extIdInfoString, ExtIdInfo.class);
+//                String cardName = extIdInfo.getOcrIdInfo().getName();
+//                String idNumber = extIdInfo.getOcrIdInfo().getIdNumber();
+//                List<TAppUserDetail> details = appUserDetailService.list(new LambdaQueryWrapper<TAppUserDetail>()
+//                        .select(TAppUserDetail::getUserId)
+//                        .eq(TAppUserDetail::getIdCard, idNumber)
+//                );
+//                if (CollUtil.isNotEmpty(details)) {
+//
+//                    return error(MessageUtils.message("user.already.bind.account"));
+//                }
+//                userAuthentication.setRequestId(body.getRequestId());
+//                userAuthentication.setCode(body.getCode());
+//                userAuthentication.setMessage(body.getMessage());
+//                userAuthentication.setResultPassed(body.getResult().getPassed());
+//                userAuthentication.setResultSubCode(body.getResult().getSubCode());
+//                userAuthentication.setUserId(userId);
+//                userAuthentication.setTransactionId(transactionId);
+//
+//
+//                userAuthentication.setExtFaceInfo(JSONUtil.toJsonPrettyStr(extFaceInfo));
+//                userAuthentication.setExtIdInfo(JSONUtil.toJsonPrettyStr(extIdInfo));
+//
+//
+//                userAuthenticationService.save(userAuthentication);
+//
+//                Object idImage = JSONUtil.parseObj(body.getResult().getExtIdInfo()).get("idImage");
+//                Object faceImg = JSONUtil.parseObj(body.getResult().getExtFaceInfo()).get("faceImg");
+//
+//                byte[] idImageBytes = Base64.decodeBase64(String.valueOf(idImage));
+//                byte[] faceImgBytes = Base64.decodeBase64(String.valueOf(faceImg));
+//
+//                String idImageFileName = IdUtils.simpleUUID() + ".png";
+//                MultipartFile multipartFile = new ByteArrayMultipartFile(idImageBytes, idImageFileName, "image");
+//                String frontUrlOssUrl = fileService.uploadFileOSS(multipartFile, idImageFileName);
+//
+//                String faceImgFileName = IdUtils.simpleUUID() + ".png";
+//                MultipartFile faceImgMultipartFile = new ByteArrayMultipartFile(faceImgBytes, faceImgFileName, "image");
+//                String faceImgOssUrl = fileService.uploadFileOSS(faceImgMultipartFile, faceImgFileName);
+//
+//                //如果是重新实名认证,旧的实名认证信息存档
+//                if (reKyc) {
+//                    if (appUserDetailService.backupTAppUserDetailByUserId(detail) == 0) {
+//                        throw new Exception(MessageUtils.message("re.kyc.backup.fail"));
+//                    }
+//                }
+//
+//                //更新实名认证
+//                if (body.result.getPassed().equals("Y")) {
+//                    LambdaUpdateWrapper<TAppUserDetail> updateWrapper = new LambdaUpdateWrapper<>();
+//                    updateWrapper.eq(TAppUserDetail::getUserId, userId)
+//                            .set(TAppUserDetail::getAuditStatusPrimary, 1)
+//                            .set(TAppUserDetail::getAuditStatusAdvanced, 1)
+//                            .set(TAppUserDetail::getFrontUrl, frontUrlOssUrl)
+//                            .set(TAppUserDetail::getHandelUrl, faceImgOssUrl)
+//                            .set(TAppUserDetail::getRealName, cardName)
+//                            .set(TAppUserDetail::getIdCard, idNumber);
+//                    //重新实名认证次数+1
+//                    if (reKyc) {
+//                        updateWrapper.setSql("re_kyc=re_kyc+1");
+//                    }
+//                    appUserDetailService.update(updateWrapper);
+//                    redisCache.deleteObject(keyCache);
+//                    redisCache.deleteObject(checkEmailKey);
+//                    redisCache.deleteObject(checkPhoneKey);
+//                    return success(MessageUtils.message("user.kyc.success"));
+//                } else {
+//                    LambdaUpdateWrapper<TAppUserDetail> updateWrapper = new LambdaUpdateWrapper<>();
+//                    updateWrapper.eq(TAppUserDetail::getUserId, userId)
+//                            .set(TAppUserDetail::getAuditStatusPrimary, -1)
+//                            .set(TAppUserDetail::getFrontUrl, frontUrlOssUrl)
+//                            .set(TAppUserDetail::getHandelUrl, faceImgOssUrl)
+//                            .set(TAppUserDetail::getRealName, body.result.getSubCode());
+//                    appUserDetailService.update(updateWrapper);
+//                    redisCache.deleteObject(keyCache);
+//                    return error(userAuthentication.getMessage());
+//                }
+//            }
+//            redisCache.deleteObject(keyCache);
+//            return error(checkResultResponse.getBody().message);
+//        } catch (Exception e) {
+//            redisCache.deleteObject(keyCache);
+//            throw new Exception(e.getMessage());
+//        }
+//    }
+//
+//
+//}

+ 148 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/controller/UserEkycCallbackController.java

@@ -0,0 +1,148 @@
+//package com.qnfhq.modules.authentication.controller;
+//
+//import cn.hutool.json.JSONUtil;
+//import com.aliyun.cloudauth_intl20220809.models.CheckResultResponse;
+//import com.aliyun.cloudauth_intl20220809.models.CheckResultResponseBody;
+//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+//import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+//import com.table.authentication.entity.UserAuthentication;
+//import com.table.authentication.service.UserAuthenticationService;
+//import com.table.authentication.util.AliyunEkycUtil;
+//import com.table.bussiness.domain.TAppUserDetail;
+//import com.table.bussiness.service.FileService;
+//import com.table.bussiness.service.ITAppUserDetailService;
+//import com.table.common.core.domain.Result;
+//import com.table.common.core.redis.RedisCache;
+//import com.table.common.utils.MessageUtils;
+//import com.table.common.utils.StringUtils;
+//import com.table.common.utils.uuid.IdUtils;
+//import com.table.util.ByteArrayMultipartFile;
+//import com.table.web.controller.common.ApiBaseController;
+//import io.swagger.annotations.Api;
+//import io.swagger.annotations.ApiOperation;
+//import org.apache.commons.codec.binary.Base64;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.web.bind.annotation.GetMapping;
+//import org.springframework.web.bind.annotation.RequestMapping;
+//import org.springframework.web.bind.annotation.RestController;
+//import org.springframework.web.multipart.MultipartFile;
+//
+//import javax.annotation.Resource;
+//
+//
+//@Api(tags = "认证请求响应记录表模块")
+//@RestController
+//@RequestMapping("/api/ekyc")
+//public class UserEkycCallbackController extends ApiBaseController {
+//    // redis缓存
+//    @Resource
+//    private RedisCache redisCache;
+//
+//    // 阿里云 人脸识别
+//    @Resource
+//    private AliyunEkycUtil aliyunEkycUtil;
+//
+//    @Autowired
+//    private FileService fileService;
+//
+//    @Resource
+//    UserAuthenticationService userAuthenticationService;
+//    @Resource
+//    private ITAppUserDetailService tAppUserDetailService;
+//
+//
+//
+//    /**
+//     * 实名认证回调函数
+//     * https://www.aliyun.com?callbackToken=100000****&transactionId=shaxxxx&passed=Y&subCode=200
+//     * @param callbackToken
+//     * @param transactionId
+//     * @return
+//     */
+//    @ApiOperation(value = "验证实名认证")
+//    @GetMapping("/callback")
+//    public Result checkID(String callbackToken, String transactionId){
+//        String keyCache = StringUtils.format("api-userauther-callback:{}", callbackToken);
+//        String userId = redisCache.getCacheObject(keyCache);
+//        if(StringUtils.isNull(userId)) {
+//            return error(MessageUtils.message("login.param.null"));
+//        }
+//        UserAuthentication one = userAuthenticationService.getOne(
+//                new LambdaQueryWrapper<UserAuthentication>()
+//                        .eq(UserAuthentication::getTransactionId, transactionId));
+//        if (one != null) {
+//            redisCache.deleteObject(keyCache);
+//            return error(MessageUtils.message("user.kyc.completed"));
+//        }
+//        //获取会员情况
+//        TAppUserDetail detail = tAppUserDetailService.getOne(
+//                new LambdaQueryWrapper<TAppUserDetail>()
+//                        .eq(TAppUserDetail::getUserId, userId));
+//        //如果账户已认证且已经有了身份证和头部照片,则认定为已认证
+//        if (detail != null &&
+//                "1".equals(detail.getAuditStatusPrimary()) &&
+//                StringUtils.isNotBlank(detail.getFrontUrl()) &&
+//                StringUtils.isNotBlank(detail.getHandelUrl())) {
+//            redisCache.deleteObject(keyCache);
+//            return error(MessageUtils.message("user.kyc.already_completed"));
+//        }
+//        try {
+//            CheckResultResponse checkResultResponse = aliyunEkycUtil.checkResult(transactionId);
+//            UserAuthentication userAuthentication = new UserAuthentication();
+//            userAuthentication.setHttpStatusCode(checkResultResponse.getStatusCode());
+//            if (200 == checkResultResponse.getStatusCode()) {
+//                CheckResultResponseBody body = checkResultResponse.getBody();
+//                userAuthentication.setRequestId(body.getRequestId());
+//                userAuthentication.setCode(body.getCode());
+//                userAuthentication.setMessage(body.getMessage());
+//                userAuthentication.setResultPassed(body.getResult().getPassed());
+//                userAuthentication.setResultSubCode(body.getResult().getSubCode());
+//                userAuthentication.setUserId(Long.valueOf(userId));
+//                userAuthenticationService.save(userAuthentication);
+//
+//                Object idImage = JSONUtil.parseObj(body.getResult().getExtIdInfo()).get("idImage");
+//                Object faceImg = JSONUtil.parseObj(body.getResult().getExtFaceInfo()).get("faceImg");
+//
+//                byte[] idImageBytes = Base64.decodeBase64(String.valueOf(idImage));
+//                byte[] faceImgBytes = Base64.decodeBase64(String.valueOf(faceImg));
+//
+//                String idImageFileName = IdUtils.simpleUUID() + ".png";
+//                MultipartFile multipartFile = new ByteArrayMultipartFile(idImageBytes, idImageFileName, "image");
+//                String frontUrlOssUrl = fileService.uploadFileOSS(multipartFile, idImageFileName);
+//
+//                String faceImgFileName = IdUtils.simpleUUID() + ".png";
+//                MultipartFile faceImgMultipartFile = new ByteArrayMultipartFile(faceImgBytes, faceImgFileName, "image");
+//                String faceImgOssUrl = fileService.uploadFileOSS(faceImgMultipartFile, faceImgFileName);
+//
+//
+//                //更新实名认证
+//                if(body.result.getPassed().equals("Y")) {
+//                    LambdaUpdateWrapper<TAppUserDetail> updateWrapper = new LambdaUpdateWrapper<>();
+//                    updateWrapper.eq(TAppUserDetail::getUserId, userId)
+//                            .set(TAppUserDetail::getAuditStatusPrimary, 1)
+//                            .set(TAppUserDetail::getAuditStatusAdvanced, 1)
+//                            .set(TAppUserDetail::getFrontUrl, frontUrlOssUrl)
+//                            .set(TAppUserDetail::getHandelUrl, faceImgOssUrl);
+//                    tAppUserDetailService.update(updateWrapper);
+//                    redisCache.deleteObject(keyCache);
+//                    return success(userAuthentication.getResultPassed());
+//                } else {
+//                    LambdaUpdateWrapper<TAppUserDetail> updateWrapper = new LambdaUpdateWrapper<>();
+//                    updateWrapper.eq(TAppUserDetail::getUserId, userId)
+//                            .set(TAppUserDetail::getAuditStatusPrimary, -1)
+//                            .set(TAppUserDetail::getFrontUrl, frontUrlOssUrl)
+//                            .set(TAppUserDetail::getHandelUrl, faceImgOssUrl)
+//                            .set(TAppUserDetail::getRealName, body.result.getSubCode());
+//                    tAppUserDetailService.update(updateWrapper);
+//                    redisCache.deleteObject(keyCache);
+//                    return error(userAuthentication.getMessage());
+//                }
+//            }
+//            redisCache.deleteObject(keyCache);
+//            return error(checkResultResponse.getBody().message);
+//        } catch (Exception e) {
+//            redisCache.deleteObject(keyCache);
+//            return error(e.getMessage());
+//        }
+//    }
+//}

+ 147 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/AikycRequest.java

@@ -0,0 +1,147 @@
+package com.qnfhq.modules.authentication.entity;
+
+import lombok.Data;
+
+/**
+ * 用于eKYC认证流程的Java实体类,封装所有请求参数。
+ */
+@Data
+public class AikycRequest {
+
+    /**
+     * 产品方案标识,必填。
+     * 取值说明:
+     * eKYC:使用eKYC产品方案,用户需完成证件识别和活体认证整个流程。
+     * 示例:eKYC
+     */
+    private String productCode;
+
+    /**
+     * 自定义认证场景ID,非必填。
+     * 支持长度为10位的字母、数字或下划线的组合。
+     * 用于后续控制台查询相关记录。
+     * 示例:1234567890
+     */
+    private String sceneCode;
+
+    /**
+     * 业务唯一标识,必填。
+     * 支持长度为32位的字母和数字的组合,需确保唯一性。
+     * 阿里云服务器不会校验唯一性,建议自行保证唯一。
+     * 示例:e0c34a77f5ac40a5aa5e6ed20c35****
+     */
+    private String merchantBizId;
+    /**
+     * MetaInfo环境参数,必填。
+     * 需通过客户端SDK获取,原样透传,无需修改。
+     * 示例为JSON格式,包含设备信息、SDK版本等。
+     * 示例:
+     * {
+     * "zimVer": "3.0.0",
+     * "appVersion": "1",
+     * "bioMetaInfo": "4.1.0:1150****,0",
+     * "appName": "com.aliyun.antcloudauth",
+     * "deviceType": "h5",
+     * "osVersion": "iOS 10.3.2",
+     * "apdidToken": "",
+     * "deviceModel": "iPhone9,1"
+     * }
+     */
+    private String metaInfo;
+
+    /**
+     * 用户唯一标识,必填。
+     * 可为用户ID、手机号码、邮箱等,建议脱敏处理(如哈希)。
+     * 示例:123456789
+     */
+    private String merchantUserId;
+
+    /**
+     * 是否开启证件防伪检测,非必填。
+     * Y:开启;N:关闭(默认)。
+     * 示例:Y
+     */
+    private String idSpoof;
+
+    /**
+     * 证件类型,必填。* 8位数字组合作为唯一标识,示例如下:
+     * 01000000:全球护照
+     * 00000001:中国内地第二代居民身份证* 示例:01000000
+     */
+    private String docType;
+
+    /**
+     * 是否开启官方数据库身份核验,非必填。* T:开启;F:关闭(默认)。仅适用于中国内地第二代居民身份证。* 示例:F
+     */
+    private String authorize;
+
+    /**
+     * 认证流程安全水位模式,非必填。* 可选值:
+     * 01:普通模式(低风险场景)
+     * 02:安全模式(默认,通过设备信息增强安全性)* 示例:02
+     */
+    private String securityLevel;
+
+    /**
+     * OCR质量检测阈值模式,非必填。* 0:标准模式;1:严格模式;2:宽松模式;3:关闭质量检测(默认)。* 示例:0
+     */
+    private String idThreshold;
+
+    /**
+     * 活体检测类型,非必填。* 可选值:
+     * LIVENESS:眨眼动作活体检测(默认)
+     * PHOTINUS_LIVENESS:眨眼+炫彩双重检测
+     * PHOTINUS_FAR_NEAR_LIVENESS:眨眼+远近+炫彩检测(仅APP SDK支持)* 示例:PHOTINUS_LIVENESS
+     */
+    private String model;
+
+    /**
+     * 是否需要存证视频,非必填。* Y:需要;N:不需要(默认)。PC端不支持。* 示例:N
+     */
+    private String docVideo;
+
+    /**
+     * 认证结果回调地址,非必填。* 必须以HTTPS开头,回调时携带transactionId、passed等参数。
+     * 示例:https://www.aliyun.com?callbackToken=100000****&transactionId=shaxxxx&passed=Y&subCode=200
+     */
+    private String callbackUrl;
+
+
+    /**
+     *
+     * H5 认证成功后跳转地址,非必填。* 必须以HTTPS开头。
+     *
+     */
+    private String returnUrl;
+
+    /**
+     * 安全Token,非必填。* 用于防重复、防篡改校验。若设置,回调时会携带该字段。
+     * 示例:NMjvQanQgplBSaEI0sL86WnQplB
+     */
+    private String callbackToken;
+
+    /**
+     * 是否开启人脸严格质量检测,非必填。* Y:开启(默认);N:关闭。需客户端SDK版本1.2.5及以上支持。* 示例:N
+     */
+    private String appQualityCheck;
+
+    /**
+     * 证件扫描模式,非必填。* 可选值:
+     * shoot(默认):拍照
+     * scan:扫描
+     * auto:自动切换* 示例:shoot
+     */
+    private String docScanMode;
+
+    /**
+     * 是否展示引导页面,非必填。* 1:展示(默认);0:不展示。* 示例:1
+     */
+    private String showGuidePage;
+
+    /**
+     * 证件反面采集配置,非必填。* JSON数组格式,仅支持中国内地身份证类型。
+     * 示例:["OCR_ID_BACK"]
+     */
+    private String docPageConfig;
+
+}

+ 25 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/ExtFaceInfo.java

@@ -0,0 +1,25 @@
+
+package com.qnfhq.modules.authentication.entity;
+
+import lombok.Data;
+
+/**
+ * @author huang
+ */
+@Data
+public class ExtFaceInfo {
+
+    private int faceAge;
+    private String faceAttack;
+    private double faceAttackScore;
+    private double faceComparisonScore;
+    private String faceGender;
+    /**
+     * 照片信息过大,不存
+     */
+//    private String faceImg;
+    private String faceOcclusion;
+    private String facePassed;
+    private double faceQuality;
+    private int guardRiskScore;
+}

+ 32 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/ExtIdInfo.java

@@ -0,0 +1,32 @@
+
+package com.qnfhq.modules.authentication.entity;
+
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class ExtIdInfo {
+//    private String idImage;
+    private OcrIdEditInfo ocrIdEditInfo;
+    private OcrIdEditInfo ocrIdInfo;
+    private String ocrIdPassed;
+    private SpoofInfo spoofInfo;
+
+    @Data
+    public static class OcrIdEditInfo {
+
+        private String address;
+        private String ethnicity;
+        private String sex;
+        private String name;
+        private String idNumber;
+        private Date birthDate;
+    }
+
+    @Data
+    public static class SpoofInfo {
+        private String spoofResult;
+    }
+}
+

+ 79 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/entity/UserAuthentication.java

@@ -0,0 +1,79 @@
+package com.qnfhq.modules.authentication.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 认证请求响应记录表
+ * </p>
+ *
+ * @author huang
+ * @since 2025-07-18
+ */
+@Getter
+@Setter
+@TableName("t_user_authentication")
+@Tag(name = "TUserAuthentication对象", description = "认证请求响应记录表")
+public class UserAuthentication implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+
+    @Schema(title = "id")
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @Schema(title ="HTTP状态码")
+    @TableField("http_status_code")
+    private Integer httpStatusCode;
+
+    @Schema(title ="请求ID")
+    @TableField("request_id")
+    private String requestId;
+
+    @Schema(title ="返回Code")
+    @TableField("code")
+    private String code;
+
+    @Schema(title ="请求消息的响应信息")
+    @TableField("message")
+    private String message;
+
+    @Schema(title ="认证最终结果:Y(通过)、N(不通过)")
+    @TableField("result_passed")
+    private String resultPassed;
+
+    @Schema(title ="认证结果描述(SubCode)")
+    @TableField("result_sub_code")
+    private String resultSubCode;
+
+    @Schema(title ="活体人脸验证相关结果信息(JSON格式)")
+    @TableField("ext_face_info")
+    private String extFaceInfo;
+
+    @Schema(title ="证件识别相关结果信息(JSON格式)")
+    @TableField("ext_id_info")
+    private String extIdInfo;
+
+    @Schema(title ="记录创建时间")
+    @TableField("created_time")
+    private LocalDateTime createdTime;
+
+    @Schema(title ="用户id")
+    @TableField("user_id")
+    private Long userId;
+
+    @Schema(title ="整个认证流程的唯一标识")
+    @TableField("transaction_id")
+    private String transactionId;
+}

+ 20 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/mapper/UserAuthenticationMapper.java

@@ -0,0 +1,20 @@
+package com.qnfhq.modules.authentication.mapper;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qnfhq.modules.authentication.entity.UserAuthentication;
+import org.apache.ibatis.annotations.Mapper;
+
+
+/**
+ * <p>
+ * 认证请求响应记录表 Mapper 接口
+ * </p>
+ *
+ * @author huang
+ * @since 2025-07-18
+ */
+@Mapper
+public interface UserAuthenticationMapper extends BaseMapper<UserAuthentication> {
+
+}

+ 18 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/service/UserAuthenticationService.java

@@ -0,0 +1,18 @@
+package com.qnfhq.modules.authentication.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.qnfhq.modules.authentication.entity.UserAuthentication;
+
+
+/**
+ * <p>
+ * 认证请求响应记录表 服务类
+ * </p>
+ *
+ * @author huang
+ * @since 2025-07-18
+ */
+public interface UserAuthenticationService extends IService<UserAuthentication> {
+
+}

+ 22 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/service/impl/UserAuthenticationServiceImpl.java

@@ -0,0 +1,22 @@
+package com.qnfhq.modules.authentication.service.impl;
+
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.qnfhq.modules.authentication.entity.UserAuthentication;
+import com.qnfhq.modules.authentication.mapper.UserAuthenticationMapper;
+import com.qnfhq.modules.authentication.service.UserAuthenticationService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 认证请求响应记录表 服务实现类
+ * </p>
+ *
+ * @author huang
+ * @since 2025-07-18
+ */
+@Service
+public class UserAuthenticationServiceImpl extends ServiceImpl<UserAuthenticationMapper, UserAuthentication> implements UserAuthenticationService {
+
+}

+ 32 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/util/AliyunEkycConfig.java

@@ -0,0 +1,32 @@
+package com.qnfhq.modules.authentication.util;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration("AliyunEkycConfig")
+public class AliyunEkycConfig {
+
+    @Value("${aliyun.ekyc.access-key-id}")
+    private String accessKeyId;
+
+    @Value("${aliyun.ekyc.access-key-secret}")
+    private String accessKeySecret;
+
+    @Value("${aliyun.ekyc.region-id}")
+    private String regionId;
+
+    @Value("${aliyun.ekyc.endpoint}")
+    private String endpoint;
+
+    @Bean
+    public AliyunEkycUtil aliyunEkycUtil() throws Exception {
+        AliyunEkycUtil aliyunEkycService = new AliyunEkycUtil(
+                accessKeyId,
+                accessKeySecret,
+                regionId,
+                endpoint
+        );
+        return aliyunEkycService;
+    }
+}

+ 138 - 0
qnfhq-api/src/main/java/com/qnfhq/modules/authentication/util/AliyunEkycUtil.java

@@ -0,0 +1,138 @@
+package com.qnfhq.modules.authentication.util;
+
+import cn.hutool.json.JSONUtil;
+import com.aliyun.cloudauth_intl20220809.Client;
+import com.aliyun.cloudauth_intl20220809.models.CheckResultRequest;
+import com.aliyun.cloudauth_intl20220809.models.CheckResultResponse;
+import com.aliyun.cloudauth_intl20220809.models.InitializeRequest;
+import com.aliyun.cloudauth_intl20220809.models.InitializeResponse;
+import com.aliyun.teaopenapi.models.Config;
+
+import com.qnfhq.modules.authentication.entity.AikycRequest;
+import com.qnfhq.modules.authentication.entity.ExtFaceInfo;
+import com.qnfhq.modules.authentication.entity.ExtIdInfo;
+import org.springframework.beans.factory.annotation.Value;
+
+/**
+ * 阿里云 eKYC 国际化版实名认证服务接口封装
+ */
+public class AliyunEkycUtil {
+
+    /**
+     * 代表认证流程不同安全水位的模式,可选值:
+     * 01:普通模式,仅适用低风险且对设备信息采集限制的场景
+     * 02:安全模式,相对严格的模式(默认)。
+     */
+    @Value("${aliyun.initialize.securityLevel}")
+    private String securityLevel;
+    /**
+     * 自定义OCR质量检测阀值模式:
+     * 0:标准模式
+     * 1:严格模式
+     * 2:宽松模式
+     * 3(默认):关闭质量检测
+     */
+    @Value("${aliyun.initialize.idThreshold}")
+    private String idThreshold;
+    /**
+     * 要接入的产品方案。取值:
+     * eKYC:使用eKYC产品方案,您的用户需要完成证件识别和活体认证整个流程。
+     */
+    @Value("${aliyun.initialize.productCode}")
+    private String productCode;
+
+    /**
+     * merchantBizId
+     */
+    @Value("${aliyun.initialize.merchantBizId}")
+    private String merchantBizId;
+
+    /**
+     * 回调地址
+     */
+    @Value("${aliyun.initialize.callbackUrl}")
+    private String callbackUrl;
+
+
+    //是否返回图片("N"/"Y")
+    private final String isReturnImage="Y";
+
+    private final Client client;
+
+    /**
+     * 构造认证服务客户端
+     *
+     * @param accessKeyId     阿里云 AccessKey ID
+     * @param accessKeySecret 阿里云 AccessKey Secret
+     * @param regionId        区域ID(如 cn-hongkong)
+     * @param endpoint        服务端点(如 cloudauth-intl.cn-hongkong.aliyuncs.com)
+     * @throws Exception 初始化客户端异常
+     */
+    public AliyunEkycUtil(String accessKeyId, String accessKeySecret, String regionId, String endpoint) throws Exception {
+        Config config = new Config()
+                .setAccessKeyId(accessKeyId)
+                .setAccessKeySecret(accessKeySecret)
+                .setRegionId(regionId)
+                .setEndpoint(endpoint);
+        this.client = new Client(config);
+    }
+
+    /**
+     * 初始化实名认证流程
+     *
+     * @param aikycRequest 官方请求需要的所有参数
+     * @return 初始化响应结果
+     * @throws Exception API调用异常
+     */
+    public InitializeResponse initialize(AikycRequest aikycRequest) throws Exception {
+        InitializeRequest request = new InitializeRequest()
+                .setProductCode(productCode)
+                .setMerchantBizId(merchantBizId)
+                .setMerchantUserId(aikycRequest.getMerchantUserId())
+                .setDocType(aikycRequest.getDocType())
+                .setMetaInfo(aikycRequest.getMetaInfo())
+                .setSecurityLevel(securityLevel)
+                .setIdThreshold(idThreshold)
+                .setReturnUrl(aikycRequest.getReturnUrl())
+                .setCallbackUrl(callbackUrl)
+                .setAuthorize(aikycRequest.getAuthorize());
+
+        return client.initialize(request);
+    }
+
+    /**
+     * 检查认证结果
+     * @param transactionId 事务ID(初始化返回的 transactionId)
+     * @return 认证结果
+     * @throws Exception API调用异常
+     */
+    public CheckResultResponse checkResult(String transactionId) throws Exception {
+        CheckResultRequest request = new CheckResultRequest()
+                .setMerchantBizId(merchantBizId)
+                .setTransactionId(transactionId)
+                .setIsReturnImage(isReturnImage);
+
+        return client.checkResult(request);
+    }
+
+    public static void main(String[] args) throws Exception {
+        Config config = new Config()
+                .setAccessKeyId("LTAI5tLViGeNkcYAwiw3pccS")
+                .setAccessKeySecret("I5XkvAUpoRgqpm77QPBXgkQbjg47K0")
+                .setRegionId("cn-hongkong")
+                .setEndpoint("cloudauth-intl.cn-hongkong.aliyuncs.com");
+        Client client = new Client(config);
+        CheckResultRequest request = new CheckResultRequest()
+                .setMerchantBizId("qiniufuhuaqi")
+                .setTransactionId("hksd93c76aabbe6ec2d029e6c4725e51")
+                .setIsReturnImage("Y");
+        CheckResultResponse checkResultResponse = client.checkResult(request);
+        String extFaceInfo = checkResultResponse.getBody().getResult().getExtFaceInfo();
+        String extIdInfo = checkResultResponse.getBody().getResult().getExtIdInfo();
+        ExtFaceInfo bean = JSONUtil.toBean(extFaceInfo, ExtFaceInfo.class);
+        ExtIdInfo bean2 = JSONUtil.toBean(extIdInfo, ExtIdInfo.class);
+        ExtIdInfo.OcrIdEditInfo ocrIdInfo = bean2.getOcrIdInfo();
+        System.out.println(bean);
+        System.out.println(bean2);
+    }
+}

+ 16 - 14
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/controller/C2cAdController.java

@@ -4,6 +4,7 @@ package com.qnfhq.modules.c2c.controller;
 import cn.dev33.satoken.stp.StpUtil;
 import cn.hutool.core.convert.Convert;
 import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qnfhq.annotation.RepeatSubmit;
 import com.qnfhq.common.ApiBaseController;
 import com.qnfhq.common.constant.Constant;
@@ -148,7 +149,7 @@ public class C2cAdController extends ApiBaseController {
         }
 
         Long adId = c2cAd.getId();
-        C2cAdEntity ad = c2cAdService.selectById(adId);
+        C2cAdEntity ad = c2cAdService.getById(adId);
         if(ad==null) {
             return error(MessageUtils.message("c2c.ad.id.invalid"));//广告编号无效
         }
@@ -178,17 +179,18 @@ public class C2cAdController extends ApiBaseController {
         if(c2cAdVo.getMerchantId()==null) {
             return error(MessageUtils.message("c2c.ad.merchant.id.blank"));//商家编号不能空
         }
-        //分页
-        String pageNum = Convert.toStr(c2cAdVo.getPageNum(),"1");
-        String pageSize = Convert.toStr(c2cAdVo.getPageSize(),"10");
-        Map<String,Object> params = new HashMap<>();
-        params.put(Constant.PAGE,pageNum);
-        params.put(Constant.LIMIT,pageSize);
-        params.put("merchantId",c2cAdVo.getMerchantId());
-        params.put("direction",c2cAdVo.getDirection());
-        params.put("status", AdStatusEnum.PASS.getCode());
-        PageData<C2cAdEntity> page = c2cAdService.page(params);
-        return new Result<PageData<C2cAdEntity>>().ok(page);
+        Page<C2cAdEntity> page = c2cAdService.page(c2cAdVo.getPage(),c2cAdVo.timeQuery());
+//        //分页
+//        String pageNum = Convert.toStr(c2cAdVo.getPageNum(),"1");
+//        String pageSize = Convert.toStr(c2cAdVo.getPageSize(),"10");
+//        Map<String,Object> params = new HashMap<>();
+//        params.put(Constant.PAGE,pageNum);
+//        params.put(Constant.LIMIT,pageSize);
+//        params.put("merchantId",c2cAdVo.getMerchantId());
+//        params.put("direction",c2cAdVo.getDirection());
+//        params.put("status", AdStatusEnum.PASS.getCode());
+//        PageData<C2cAdEntity> page = c2cAdService.page(params);
+        return new Result<>().ok(page);
     }
 
 
@@ -220,12 +222,12 @@ public class C2cAdController extends ApiBaseController {
             if(Objects.isNull(myReceipt)) {
                 inReceipt.setCreateTime(new Date());
                 inReceipt.setUpdateTime(new Date());
-                return toAjax(c2cUserReceiptService.insert(inReceipt));
+                return toAjax(c2cUserReceiptService.save(inReceipt));
             } else {
                 return error(MessageUtils.message("c2c.userReceipt.add.repeat"));//添加成功,请勿重复提交
             }
         } else {
-            C2cUserReceiptEntity oldReceipt =c2cUserReceiptService.selectById(dto.getId());
+            C2cUserReceiptEntity oldReceipt =c2cUserReceiptService.getById(dto.getId());
             if(Objects.isNull(oldReceipt)) {
                 return error(MessageUtils.message("c2c.userReceipt.id.invalid"));//编号无效
             }

+ 1 - 1
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/controller/C2cMerchantController.java

@@ -72,7 +72,7 @@ public class C2cMerchantController {
     @GetMapping(value = "/info/{id}")
     public Result getInfo(@PathVariable("id") Long id)
     {
-        C2cMerchantEntity merchant = c2cMerchantService.selectById(id);
+        C2cMerchantEntity merchant = c2cMerchantService.getById(id);
         return new Result().ok(merchant);
     }
 

+ 27 - 25
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/controller/C2cOrderController.java

@@ -6,6 +6,7 @@ import cn.hutool.core.convert.Convert;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qnfhq.annotation.RepeatSubmit;
 import com.qnfhq.common.ApiBaseController;
 import com.qnfhq.common.constant.Constant;
@@ -150,7 +151,7 @@ public class C2cOrderController extends ApiBaseController {
             }
         }
 
-        C2cAdEntity c2cAd = c2cAdService.selectById(c2cOrder.getC2cAdId());
+        C2cAdEntity c2cAd = c2cAdService.getById(c2cOrder.getC2cAdId());
         if(c2cAd==null) {
             //清除缓存
             Integer adDirection = direction.intValue() == DirectionEnum.SELL.getCode().intValue() ? DirectionEnum.BUY.getCode() : DirectionEnum.SELL.getCode();
@@ -429,7 +430,7 @@ public class C2cOrderController extends ApiBaseController {
             entity.setStatus(1);
             entity.setCreateTime(new Date());
             entity.setUpdateTime(new Date());
-            if(c2cPaymentVoucherService.insert(entity)) {
+            if(c2cPaymentVoucherService.save(entity)) {
                 Map data = MapUtil.of("id", entity.getId());
                 return success(data);
             } else {
@@ -437,7 +438,7 @@ public class C2cOrderController extends ApiBaseController {
             }
 
         } else {
-            C2cPaymentVoucherEntity voucher = c2cPaymentVoucherService.selectById(c2cPaymentVoucher.getId());
+            C2cPaymentVoucherEntity voucher = c2cPaymentVoucherService.getById(c2cPaymentVoucher.getId());
             if(voucher==null) {
                 return error(MessageUtils.message("c2c.order.pay.cert.id.invalid"));//凭证编号无效
             }
@@ -470,7 +471,7 @@ public class C2cOrderController extends ApiBaseController {
     public Result deletePayment(@RequestBody C2cPaymentVoucherIdDTO c2cPaymentVoucher) {
         ValidatorUtils.validateEntity(c2cPaymentVoucher);
 
-        C2cPaymentVoucherEntity voucher = c2cPaymentVoucherService.selectById(c2cPaymentVoucher.getId());
+        C2cPaymentVoucherEntity voucher = c2cPaymentVoucherService.getById(c2cPaymentVoucher.getId());
         if(voucher==null) {
             return error(MessageUtils.message("c2c.order.pay.cert.id.invalid"));//凭证编号无效
         }
@@ -496,28 +497,29 @@ public class C2cOrderController extends ApiBaseController {
     @PostMapping("/mylist")
     public Result mylist(@RequestBody C2cOrderListDTO orderVo)
     {
+
         ValidatorUtils.validateEntity(orderVo);
         //分页
-        String pageNum = Convert.toStr(orderVo.getPageNum(),"1");
-        String pageSize = Convert.toStr(orderVo.getPageSize(),"10");
-
-        Map<String,Object> params = new HashMap<>();
-        params.put(Constant.PAGE,pageNum);
-        params.put(Constant.LIMIT,pageSize);
-        params.put("direction",orderVo.getDirection());
-        params.put("flow",orderVo.getFlow());
-        params.put("status",orderVo.getStatus());
-        params.put("orderNo",orderVo.getOrderNo());
-        params.put("isMt",orderVo.getIsMt());
-        PageData<C2cOrderEntity> page = c2cOrderService.page(params);
-
-        List<C2cOrderEntity> orderList = page.getList();
+        Page<C2cOrderEntity> page = c2cOrderService.page(orderVo.getPage());
+//        String pageNum = Convert.toStr(orderVo.getPageNum(),"1");
+//        String pageSize = Convert.toStr(orderVo.getPageSize(),"10");
+//
+//        Map<String,Object> params = new HashMap<>();
+//        params.put(Constant.PAGE,pageNum);
+//        params.put(Constant.LIMIT,pageSize);
+//        params.put("direction",orderVo.getDirection());
+//        params.put("flow",orderVo.getFlow());
+//        params.put("status",orderVo.getStatus());
+//        params.put("orderNo",orderVo.getOrderNo());
+//        params.put("isMt",orderVo.getIsMt());
+//        PageData<C2cOrderEntity> page = c2cOrderService.page(params);
+
+        List<C2cOrderEntity> orderList = page.getRecords();
         // 查询付款凭证
         orderList = c2cOrderService.selectPaymentVoucherByOrderList(orderList);
-        page.setList(orderList);
-
+        page.setRecords(orderList);
 
-        return new Result<PageData<C2cOrderEntity>>().ok(page);
+        return new Result<>().ok(page);
 
     }
 
@@ -640,7 +642,7 @@ log.info("商户待处理数Count:"+unpayCounts+":"+releaseCounts);
     {
         ValidatorUtils.validateEntity(dto);
 
-        C2cOrderComplainEntity orderComplain = orderComplainService.selectById(dto.getComplainId());
+        C2cOrderComplainEntity orderComplain = orderComplainService.getById(dto.getComplainId());
         if(orderComplain == null) {
             return error(MessageUtils.message("c2c.order.complain.not.exist"));//申诉编号无效
         }
@@ -670,7 +672,7 @@ log.info("商户待处理数Count:"+unpayCounts+":"+releaseCounts);
             voucherEntity.setStatus(1);
             voucherEntity.setCreateTime(new Date());
             voucherEntity.setUpdateTime(new Date());
-            if(orderComplainVoucherService.insert(voucherEntity)) {
+            if(orderComplainVoucherService.save(voucherEntity)) {
                 Map data = MapUtil.of("id", voucherEntity.getId());
                 return success(data);
             } else {
@@ -678,7 +680,7 @@ log.info("商户待处理数Count:"+unpayCounts+":"+releaseCounts);
             }
 
         } else {
-            C2cOrderComplainVoucherEntity voucherEntity = orderComplainVoucherService.selectById(dto.getId());
+            C2cOrderComplainVoucherEntity voucherEntity = orderComplainVoucherService.getById(dto.getId());
             if(voucherEntity==null) {
                 return error(MessageUtils.message("c2c.order.complain.voucher.id.invalid"));//申诉凭证编号无效
             }
@@ -745,7 +747,7 @@ log.info("商户待处理数Count:"+unpayCounts+":"+releaseCounts);
 
         C2cOrderComplainEntity orderComplain = null;
         if (dto.getComplainId() != null) {
-            orderComplain = orderComplainService.selectById(dto.getComplainId());
+            orderComplain = orderComplainService.getById(dto.getComplainId());
         } else {
             List<C2cOrderComplainEntity> orderComplainList = orderComplainService.selectC2cOrderComplainList(dto.getOrderId());
             orderComplain = orderComplainList.get(0);

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/AppAssetLogDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.AppAssetLogEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-19
  */
 @Mapper
-public interface AppAssetLogDao extends BaseDao<AppAssetLogEntity> {
+public interface AppAssetLogDao extends BaseMapper<AppAssetLogEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cAdDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cAdEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -13,7 +13,7 @@ import java.util.Map;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cAdDao extends BaseDao<C2cAdEntity> {
+public interface C2cAdDao extends BaseMapper<C2cAdEntity> {
 
     /**
      * 减少商家广告可用数量

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cAdLogDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cAdLogEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cAdLogDao extends BaseDao<C2cAdLogEntity> {
+public interface C2cAdLogDao extends BaseMapper<C2cAdLogEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cLegalCoinDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cLegalCoinEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-18
  */
 @Mapper
-public interface C2cLegalCoinDao extends BaseDao<C2cLegalCoinEntity> {
+public interface C2cLegalCoinDao extends BaseMapper<C2cLegalCoinEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cMerchantConfigDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cMerchantConfigEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cMerchantConfigDao extends BaseDao<C2cMerchantConfigEntity> {
+public interface C2cMerchantConfigDao extends BaseMapper<C2cMerchantConfigEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cMerchantDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cMerchantEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cMerchantDao extends BaseDao<C2cMerchantEntity> {
+public interface C2cMerchantDao extends BaseMapper<C2cMerchantEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderComplainDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cOrderComplainEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cOrderComplainDao extends BaseDao<C2cOrderComplainEntity> {
+public interface C2cOrderComplainDao extends BaseMapper<C2cOrderComplainEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderComplainVoucherDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cOrderComplainVoucherEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cOrderComplainVoucherDao extends BaseDao<C2cOrderComplainVoucherEntity> {
+public interface C2cOrderComplainVoucherDao extends BaseMapper<C2cOrderComplainVoucherEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cOrderEntity;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
@@ -16,7 +16,7 @@ import java.util.Map;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cOrderDao extends BaseDao<C2cOrderEntity> {
+public interface C2cOrderDao extends BaseMapper<C2cOrderEntity> {
 
     @Select("select count(1) NUM from c2c_order where tran_user_id=#{tranUserId} and status=0 and direction=2")
     public List<Map> selectMtUnPayCount(@Param("tranUserId") Long tranUserId);

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cOrderLogDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cOrderLogEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cOrderLogDao extends BaseDao<C2cOrderLogEntity> {
+public interface C2cOrderLogDao extends BaseMapper<C2cOrderLogEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cPayWayDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cPayWayEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-18
  */
 @Mapper
-public interface C2cPayWayDao extends BaseDao<C2cPayWayEntity> {
+public interface C2cPayWayDao extends BaseMapper<C2cPayWayEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cPaymentVoucherDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cPaymentVoucherEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -13,7 +13,7 @@ import java.util.List;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cPaymentVoucherDao extends BaseDao<C2cPaymentVoucherEntity> {
+public interface C2cPaymentVoucherDao extends BaseMapper<C2cPaymentVoucherEntity> {
     /**
      * 查询c2c付款证明列表
      * @param ids

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dao/C2cUserReceiptDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.c2c.entity.C2cUserReceiptEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-17
  */
 @Mapper
-public interface C2cUserReceiptDao extends BaseDao<C2cUserReceiptEntity> {
+public interface C2cUserReceiptDao extends BaseMapper<C2cUserReceiptEntity> {
 	
 }

+ 2 - 7
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dto/C2cAdListDTO.java

@@ -1,5 +1,6 @@
 package com.qnfhq.modules.c2c.dto;
 
+import com.qnfhq.common.entity.BaseQueryDTO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.SchemaProperty;
 import jakarta.validation.constraints.NotNull;
@@ -17,7 +18,7 @@ import java.util.Date;
  */
 @Data
 @Schema(name = "c2c商家广告列表")
-public class C2cAdListDTO implements Serializable {
+public class C2cAdListDTO extends BaseQueryDTO implements Serializable {
     private static final long serialVersionUID = 1L;
 
 
@@ -32,10 +33,4 @@ public class C2cAdListDTO implements Serializable {
 	@SchemaProperty(name = "1可用 -1不可用")
 //    @NotNull(message="{NotNull.status}")//状态不能空
 	private Integer status;
-
-	@SchemaProperty(name = "页码")
-	private Integer pageNum;
-
-    @SchemaProperty(name = "每页大小")
-    private Integer pageSize;
 }

+ 2 - 7
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/dto/C2cOrderListDTO.java

@@ -1,5 +1,6 @@
 package com.qnfhq.modules.c2c.dto;
 
+import com.qnfhq.common.entity.BaseQueryDTO;
 import io.swagger.v3.oas.annotations.media.Schema;
 import io.swagger.v3.oas.annotations.media.SchemaProperty;
 import jakarta.validation.constraints.NotBlank;
@@ -18,7 +19,7 @@ import java.util.Date;
  */
 @Data
 @Schema(name = "c2c订单历史查询")
-public class C2cOrderListDTO implements Serializable {
+public class C2cOrderListDTO extends BaseQueryDTO implements Serializable {
     private static final long serialVersionUID = 1L;
 
 	@SchemaProperty(name = "订单编号")
@@ -40,10 +41,4 @@ public class C2cOrderListDTO implements Serializable {
 	@SchemaProperty(name = "是否商家")
 	private Integer isMt;
 
-    @SchemaProperty(name = "页码")
-    private Integer pageNum;
-
-    @SchemaProperty(name = "每页条数")
-    private Integer pageSize;
-
 }

+ 3 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/AppAssetLogService.java

@@ -1,6 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.AppAssetLogDTO;
 import com.qnfhq.modules.c2c.entity.AppAssetLogEntity;
 
@@ -12,7 +13,7 @@ import java.math.BigDecimal;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-19
  */
-public interface AppAssetLogService extends CrudService<AppAssetLogEntity, AppAssetLogDTO> {
+public interface AppAssetLogService extends IService<AppAssetLogEntity> {
 
     /**
      * 插入资产日志

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cAdLogService.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.entity.C2cAdLogEntity;
 
 import java.math.BigDecimal;
@@ -11,7 +11,7 @@ import java.math.BigDecimal;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cAdLogService extends BaseService<C2cAdLogEntity> {
+public interface C2cAdLogService extends IService<C2cAdLogEntity> {
 
     boolean insertC2cAdLog(Long adId, Long orderId, BigDecimal symbolNum,
                        BigDecimal availableNum, BigDecimal afterAvailNum,

+ 4 - 4
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cAdService.java

@@ -1,8 +1,8 @@
 package com.qnfhq.modules.c2c.service;
 
 import com.qnfhq.common.page.PageData;
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.common.utils.Result;
 import com.qnfhq.modules.c2c.dto.*;
 import com.qnfhq.modules.c2c.entity.C2cAdEntity;
@@ -16,13 +16,13 @@ import java.util.Map;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cAdService extends BaseService<C2cAdEntity> {
+public interface C2cAdService extends IService<C2cAdEntity> {
 
     public Result createAd(C2cAdCreateDTO c2cAdDTO, long loginId) throws Exception;
 
     public Result cancelAd(C2cAdEntity ad) throws Exception;
 
-    PageData<C2cAdEntity> page(Map<String, Object> params);
+//    PageData<C2cAdEntity> page(Map<String, Object> params);
 
     /**
      *  设置广告缓存

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cLegalCoinService.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cLegalCoinDTO;
 import com.qnfhq.modules.c2c.entity.C2cLegalCoinEntity;
 
@@ -13,7 +13,7 @@ import java.util.List;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-18
  */
-public interface C2cLegalCoinService extends BaseService<C2cLegalCoinEntity> {
+public interface C2cLegalCoinService extends IService<C2cLegalCoinEntity> {
     C2cLegalCoinEntity selectC2cLegalCoinByLegalCoin(String legalCoin);
     List<C2cLegalCoinEntity> selectAllList();
 }

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cMerchantConfigService.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cMerchantConfigDTO;
 import com.qnfhq.modules.c2c.entity.C2cMerchantConfigEntity;
 
@@ -15,7 +15,7 @@ import java.util.Map;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cMerchantConfigService extends BaseService<C2cMerchantConfigEntity> {
+public interface C2cMerchantConfigService extends IService<C2cMerchantConfigEntity> {
 
     C2cMerchantConfigEntity getMerchantConfig(String legalCoin);
 

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cMerchantService.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cMerchantApplyDTO;
 import com.qnfhq.modules.c2c.dto.C2cMerchantDTO;
 import com.qnfhq.modules.c2c.entity.C2cMerchantEntity;
@@ -16,7 +16,7 @@ import java.util.Map;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cMerchantService extends BaseService<C2cMerchantEntity> {
+public interface C2cMerchantService extends IService<C2cMerchantEntity> {
 
     C2cMerchantEntity getMerchantEntity(long userId);
 

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderComplainService.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cOrderComplainDTO;
 import com.qnfhq.modules.c2c.entity.C2cOrderComplainEntity;
 
@@ -13,7 +13,7 @@ import java.util.List;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cOrderComplainService extends BaseService<C2cOrderComplainEntity> {
+public interface C2cOrderComplainService extends IService<C2cOrderComplainEntity> {
 
     /**
      *  查询申诉列表

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderComplainVoucherService.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cOrderComplainVoucherDTO;
 import com.qnfhq.modules.c2c.entity.C2cOrderComplainVoucherEntity;
 
@@ -13,6 +13,6 @@ import java.util.List;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cOrderComplainVoucherService extends BaseService<C2cOrderComplainVoucherEntity> {
+public interface C2cOrderComplainVoucherService extends IService<C2cOrderComplainVoucherEntity> {
     List<C2cOrderComplainVoucherEntity> selectList(Long complainId);
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderLogService.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cOrderLogDTO;
 import com.qnfhq.modules.c2c.entity.C2cOrderLogEntity;
 
@@ -10,6 +10,6 @@ import com.qnfhq.modules.c2c.entity.C2cOrderLogEntity;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cOrderLogService extends BaseService<C2cOrderLogEntity> {
+public interface C2cOrderLogService extends IService<C2cOrderLogEntity> {
 
 }

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cOrderService.java

@@ -2,7 +2,7 @@ package com.qnfhq.modules.c2c.service;
 
 
 import com.qnfhq.common.page.PageData;
-import com.qnfhq.common.service.BaseService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.common.utils.Result;
 import com.qnfhq.modules.c2c.dto.C2cOrderCreateDTO;
 import com.qnfhq.modules.c2c.dto.C2cOrderDTO;
@@ -20,9 +20,9 @@ import java.util.Map;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cOrderService extends BaseService<C2cOrderEntity> {
+public interface C2cOrderService extends IService<C2cOrderEntity> {
 
-    PageData<C2cOrderEntity> page(Map<String, Object> params);
+//    PageData<C2cOrderEntity> page(Map<String, Object> params);
 
     /**
      * c2c订单编号缓存Key

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cPayWayService.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.entity.C2cPayWayEntity;
 
 import java.util.List;
@@ -12,7 +12,7 @@ import java.util.List;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-18
  */
-public interface C2cPayWayService extends BaseService<C2cPayWayEntity> {
+public interface C2cPayWayService extends IService<C2cPayWayEntity> {
     /**
      * 查询法币
      * @param legalCoin

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cPaymentVoucherService.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
-import com.qnfhq.common.service.CrudService;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cPaymentVoucherDTO;
 import com.qnfhq.modules.c2c.entity.C2cPaymentVoucherEntity;
 
@@ -13,7 +13,7 @@ import java.util.List;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cPaymentVoucherService extends BaseService<C2cPaymentVoucherEntity> {
+public interface C2cPaymentVoucherService extends IService<C2cPaymentVoucherEntity> {
     List<C2cPaymentVoucherEntity> selectList(Long orderId);
 
     public List<C2cPaymentVoucherEntity> selectC2cPaymentVoucherByIds(Long[] ids);

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/C2cUserReceiptService.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.c2c.service;
 
-import com.qnfhq.common.service.BaseService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.c2c.dto.C2cMyReceiptDTO;
 import com.qnfhq.modules.c2c.dto.C2cUserReceiptDTO;
 import com.qnfhq.modules.c2c.entity.C2cUserReceiptEntity;
@@ -13,7 +13,7 @@ import java.util.List;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-17
  */
-public interface C2cUserReceiptService extends BaseService<C2cUserReceiptEntity> {
+public interface C2cUserReceiptService extends IService<C2cUserReceiptEntity> {
 
     List<C2cUserReceiptEntity> selectListMyReceipt(C2cMyReceiptDTO dto);
 

+ 5 - 11
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/AppAssetLogServiceImpl.java

@@ -1,12 +1,14 @@
 package com.qnfhq.modules.c2c.service.impl;
 
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.AppAssetLogDao;
 import com.qnfhq.modules.c2c.dto.AppAssetLogDTO;
 import com.qnfhq.modules.c2c.entity.AppAssetLogEntity;
 import com.qnfhq.modules.c2c.service.AppAssetLogService;
-import cn.hutool.core.util.StrUtil;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -20,17 +22,9 @@ import java.util.Map;
  * @since 1.0.0 2025-11-19
  */
 @Service
-public class AppAssetLogServiceImpl extends CrudServiceImpl<AppAssetLogDao, AppAssetLogEntity, AppAssetLogDTO> implements AppAssetLogService {
+public class AppAssetLogServiceImpl extends ServiceImpl<AppAssetLogDao, AppAssetLogEntity> implements AppAssetLogService {
 
-    @Override
-    public QueryWrapper<AppAssetLogEntity> getWrapper(Map<String, Object> params){
-        String id = (String)params.get("id");
 
-        QueryWrapper<AppAssetLogEntity> wrapper = new QueryWrapper<>();
-        wrapper.eq(StrUtil.isNotBlank(id), "id", id);
-
-        return wrapper;
-    }
 
 
     @Override
@@ -52,6 +46,6 @@ public class AppAssetLogServiceImpl extends CrudServiceImpl<AppAssetLogDao, AppA
         appAssetLogEntity.setAfterFrozen(afterFrozen);
         appAssetLogEntity.setRemark(remark);
         appAssetLogEntity.setCreateTime(new Date());
-        return insert(appAssetLogEntity);
+        return save(appAssetLogEntity);
     }
 }

+ 3 - 5
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cAdLogServiceImpl.java

@@ -1,9 +1,7 @@
 package com.qnfhq.modules.c2c.service.impl;
 
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cAdLogDao;
-import com.qnfhq.modules.c2c.dto.C2cAdLogDTO;
 import com.qnfhq.modules.c2c.entity.C2cAdLogEntity;
 import com.qnfhq.modules.c2c.service.C2cAdLogService;
 import org.springframework.stereotype.Service;
@@ -19,7 +17,7 @@ import java.util.Date;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cAdLogServiceImpl extends BaseServiceImpl<C2cAdLogDao, C2cAdLogEntity> implements C2cAdLogService {
+public class C2cAdLogServiceImpl extends ServiceImpl<C2cAdLogDao, C2cAdLogEntity> implements C2cAdLogService {
 
 //    @Override
 //    public QueryWrapper<C2cAdLogEntity> getWrapper(Map<String, Object> params){
@@ -46,7 +44,7 @@ public class C2cAdLogServiceImpl extends BaseServiceImpl<C2cAdLogDao, C2cAdLogEn
         c2cAdLogEntity.setAfterMaxAmount(afterMaxAmount);
         c2cAdLogEntity.setRemark(remark);
         c2cAdLogEntity.setCreateTime(new Date());
-        return insert(c2cAdLogEntity);
+        return save(c2cAdLogEntity);
     }
 
 

+ 26 - 23
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cAdServiceImpl.java

@@ -9,11 +9,12 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.Query;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.qnfhq.common.constant.Constant;
 import com.qnfhq.common.exception.ErrorCode;
 import com.qnfhq.common.page.PageData;
 import com.qnfhq.common.redis.RedisUtils;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.common.utils.MessageUtils;
 import com.qnfhq.common.utils.Result;
@@ -49,7 +50,7 @@ import java.util.concurrent.TimeUnit;
  */
 @Slf4j
 @Service
-public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> implements C2cAdService {
+public class C2cAdServiceImpl extends ServiceImpl<C2cAdDao, C2cAdEntity> implements C2cAdService {
 
     @Resource
     private C2cMerchantService c2cMerchantService;
@@ -140,7 +141,7 @@ public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> imp
 //        c2cAd.setFinishNum(merchant.getFinishNum());
         //成单率
 //        c2cAd.setFinishRate(merchant.getFinishRate());
-        if(!insert(c2cAd)) {
+        if(!save(c2cAd)) {
             throw new Exception(MessageUtils.message("c2c.order.save.fail"));//保存广告失败
         }
         if (direction.intValue() == DirectionEnum.SELL.getCode().intValue()) {
@@ -245,15 +246,15 @@ public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> imp
     }
 
 
-    @Override
-    public PageData<C2cAdEntity> page(Map<String, Object> params) {
-        IPage<C2cAdEntity> page = baseDao.selectPage(
-                getPage(params, "id", false),
-                getWrapper(params)
-        );
-
-        return getPageData(page, C2cAdEntity.class);
-    }
+//    @Override
+//    public PageData<C2cAdEntity> page(Map<String, Object> params) {
+//        IPage<C2cAdEntity> page = baseDao.selectPage(
+//                getPage(params, "id", false),
+//                getWrapper(params)
+//        );
+//
+//        return getPageData(page, C2cAdEntity.class);
+//    }
 
     private QueryWrapper<C2cAdEntity> getWrapper(Map<String, Object> params){
 
@@ -316,7 +317,7 @@ public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> imp
                     Long adIdLong = Long.valueOf((String)adId);
                     C2cAdEntity ad = selectAdFromRedis(adIdLong);
                     if(ad == null) {
-                        ad = selectById(adIdLong);
+                        ad = getById(adIdLong);
                         if(ad==null) {
                             redisUtils.removeZset(zQuickKey, adIdLong.toString());
                         }
@@ -379,7 +380,7 @@ public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> imp
      */
     private List<C2cAdEntity> selectC2cAdTranList(String symbol,Integer direction,
                                                   String legalCoin,BigDecimal tranAmount) {
-        return baseDao.selectList(new LambdaQueryWrapper<C2cAdEntity>()
+        return list(new LambdaQueryWrapper<C2cAdEntity>()
                     .eq(C2cAdEntity::getDirection,direction)
                     .eq(C2cAdEntity::getLegalCoin,legalCoin)
                     .eq(C2cAdEntity::getSymbol,symbol)
@@ -404,7 +405,7 @@ public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> imp
         if(viewDTO.getId()!=null) {
             C2cAdEntity ad = selectAdFromRedis(viewDTO.getId());
             if(ad == null) {
-                ad = selectById(viewDTO.getId());
+                ad = getById(viewDTO.getId());
             }
             if(ad!=null) {
                 resList.add(ad);
@@ -448,7 +449,7 @@ public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> imp
                     Long adIdLong = Long.valueOf((String)adId);
                     C2cAdEntity ad = selectAdFromRedis(adIdLong);
                     if(ad == null) {
-                        ad = selectById(adIdLong);
+                        ad = getById(adIdLong);
                         delSetAdCache(ad);
                     }
                     if(ad!=null && ad.getUserId().longValue()!=StpUtil.getLoginIdAsLong()) {
@@ -478,13 +479,15 @@ public class C2cAdServiceImpl extends BaseServiceImpl<C2cAdDao, C2cAdEntity> imp
             wrapper.and(qw -> createQw(qw, finalPaywayList));
         }
 
-
-        IPage<C2cAdEntity> page = baseDao.selectPage(
-                getPage(params, "price", "asc".equals(type) ? true : false),
-                wrapper
-        );
-        PageData<C2cAdEntity> data = getPageData(page, C2cAdEntity.class);
-        return result.ok(data);
+        //todo 分页
+        return null;
+//        IPage<C2cAdEntity> page2 =new Page<>();
+//        IPage<C2cAdEntity> page = baseDao.selectPage(
+//                getPage(params, "price", "asc".equals(type) ? true : false),
+//                wrapper
+//        );
+//        PageData<C2cAdEntity> data = getPageData(page, C2cAdEntity.class);
+//        return result.ok(data);
     }
 
     private void createQw(LambdaQueryWrapper<C2cAdEntity> qw, List<String> paywayList) {

+ 4 - 5
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cLegalCoinServiceImpl.java

@@ -2,7 +2,7 @@ package com.qnfhq.modules.c2c.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cLegalCoinDao;
 import com.qnfhq.modules.c2c.dto.C2cLegalCoinDTO;
@@ -21,21 +21,20 @@ import java.util.Map;
  * @since 1.0.0 2025-11-18
  */
 @Service
-public class C2cLegalCoinServiceImpl extends BaseServiceImpl<C2cLegalCoinDao, C2cLegalCoinEntity> implements C2cLegalCoinService {
+public class C2cLegalCoinServiceImpl extends ServiceImpl<C2cLegalCoinDao, C2cLegalCoinEntity> implements C2cLegalCoinService {
 
 
     @Override
     public C2cLegalCoinEntity selectC2cLegalCoinByLegalCoin(String legalCoin) {
-        return baseDao.selectOne(new LambdaQueryWrapper<C2cLegalCoinEntity>()
+        return getOne(new LambdaQueryWrapper<C2cLegalCoinEntity>()
                 .eq(StrUtil.isNotBlank(legalCoin), C2cLegalCoinEntity::getCurrencyCode, legalCoin)
                 .eq(C2cLegalCoinEntity::getStatus,1)
-                .last(" limit 1")
         );
     }
 
     @Override
     public List<C2cLegalCoinEntity> selectAllList() {
-        return baseDao.selectList(new LambdaQueryWrapper<C2cLegalCoinEntity>()
+        return list(new LambdaQueryWrapper<C2cLegalCoinEntity>()
                 .eq(C2cLegalCoinEntity::getStatus,1)
         );
     }

+ 3 - 4
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cMerchantConfigServiceImpl.java

@@ -2,7 +2,7 @@ package com.qnfhq.modules.c2c.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cMerchantConfigDao;
 import com.qnfhq.modules.c2c.dto.C2cMerchantConfigDTO;
@@ -23,7 +23,7 @@ import java.util.Map;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cMerchantConfigServiceImpl extends BaseServiceImpl<C2cMerchantConfigDao, C2cMerchantConfigEntity> implements C2cMerchantConfigService {
+public class C2cMerchantConfigServiceImpl extends ServiceImpl<C2cMerchantConfigDao, C2cMerchantConfigEntity> implements C2cMerchantConfigService {
 
 //    @Override
 //    public QueryWrapper<C2cMerchantConfigEntity> getWrapper(Map<String, Object> params){
@@ -37,9 +37,8 @@ public class C2cMerchantConfigServiceImpl extends BaseServiceImpl<C2cMerchantCon
 
     @Override
     public C2cMerchantConfigEntity getMerchantConfig(String legalCoin) {
-        return baseDao.selectOne(new LambdaQueryWrapper<C2cMerchantConfigEntity>()
+        return getOne(new LambdaQueryWrapper<C2cMerchantConfigEntity>()
                 .eq(C2cMerchantConfigEntity::getLegalCoin, legalCoin)
-                .last(" limit 1")
         );
     }
 

+ 6 - 11
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cMerchantServiceImpl.java

@@ -2,21 +2,17 @@ package com.qnfhq.modules.c2c.service.impl;
 
 import cn.hutool.core.map.MapUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.exception.RenException;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
-import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.common.utils.MessageUtils;
 import com.qnfhq.common.utils.Result;
 import com.qnfhq.modules.c2c.dao.C2cMerchantDao;
 import com.qnfhq.modules.c2c.dto.C2cMerchantApplyDTO;
-import com.qnfhq.modules.c2c.dto.C2cMerchantDTO;
 import com.qnfhq.modules.c2c.entity.C2cMerchantConfigEntity;
 import com.qnfhq.modules.c2c.entity.C2cMerchantEntity;
 import com.qnfhq.modules.c2c.enums.MerchantStatusEnum;
 import com.qnfhq.modules.c2c.service.C2cMerchantConfigService;
 import com.qnfhq.modules.c2c.service.C2cMerchantService;
-import cn.hutool.core.util.StrUtil;
 import com.qnfhq.modules.user.entity.AppAssetEntity;
 import com.qnfhq.modules.user.entity.AppUserDetailEntity;
 import com.qnfhq.modules.user.entity.AppUserEntity;
@@ -26,7 +22,6 @@ import com.qnfhq.modules.user.service.AppUserDetailService;
 import com.qnfhq.modules.user.service.AppUserService;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
-import org.springframework.util.StringUtils;
 
 import java.math.BigDecimal;
 import java.util.*;
@@ -39,7 +34,7 @@ import java.util.stream.Collectors;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cMerchantServiceImpl extends BaseServiceImpl<C2cMerchantDao, C2cMerchantEntity> implements C2cMerchantService {
+public class C2cMerchantServiceImpl extends ServiceImpl<C2cMerchantDao, C2cMerchantEntity> implements C2cMerchantService {
 
 //    @Override
 //    public QueryWrapper<C2cMerchantEntity> getWrapper(Map<String, Object> params){
@@ -65,7 +60,7 @@ public class C2cMerchantServiceImpl extends BaseServiceImpl<C2cMerchantDao, C2cM
 
     @Override
     public C2cMerchantEntity getMerchantEntity(long userId) {
-        return baseDao.selectOne(new LambdaQueryWrapper<C2cMerchantEntity>()
+        return getOne(new LambdaQueryWrapper<C2cMerchantEntity>()
                 .eq(C2cMerchantEntity::getUserId, userId)
                 .last(" limit 1")
         );
@@ -96,7 +91,7 @@ public class C2cMerchantServiceImpl extends BaseServiceImpl<C2cMerchantDao, C2cM
             ret.put("margin",new Result().set(1, MapUtil.of("availableAmount",avaAmount),"ok"));
         }
 
-        AppUserEntity appUser = appUserService.selectById(loginId);
+        AppUserEntity appUser = appUserService.getById(loginId);
         if(Objects.isNull(appUser) || appUser.getPhone().isEmpty()) {
             ret.put("phone",new Result().error(0,MessageUtils.message("complete.mobile.bind")));
         } else {
@@ -149,7 +144,7 @@ public class C2cMerchantServiceImpl extends BaseServiceImpl<C2cMerchantDao, C2cM
             throw new RenException(MessageUtils.message("your.account.available.balance.insufficient",margin));
         }
 
-        AppUserEntity appUser = appUserService.selectById(loginId);
+        AppUserEntity appUser = appUserService.getById(loginId);
         if(Objects.isNull(appUser) || appUser.getPhone().isEmpty()) {
             throw new RenException(MessageUtils.message("complete.mobile.bind"));//完成手机号绑定
         }
@@ -174,7 +169,7 @@ public class C2cMerchantServiceImpl extends BaseServiceImpl<C2cMerchantDao, C2cM
             merchant.setStatus(MerchantStatusEnum.PENDING.getCode());//0 审批中
             merchant.setCreateTime(new Date());
             merchant.setUpdateTime(new Date());
-            insert(merchant);
+            save(merchant);
         }
     }
 

+ 3 - 8
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderComplainServiceImpl.java

@@ -1,18 +1,13 @@
 package com.qnfhq.modules.c2c.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
-import com.qnfhq.common.service.impl.CrudServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cOrderComplainDao;
-import com.qnfhq.modules.c2c.dto.C2cOrderComplainDTO;
 import com.qnfhq.modules.c2c.entity.C2cOrderComplainEntity;
 import com.qnfhq.modules.c2c.service.C2cOrderComplainService;
-import cn.hutool.core.util.StrUtil;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -22,7 +17,7 @@ import java.util.Objects;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cOrderComplainServiceImpl extends BaseServiceImpl<C2cOrderComplainDao, C2cOrderComplainEntity> implements C2cOrderComplainService {
+public class C2cOrderComplainServiceImpl extends ServiceImpl<C2cOrderComplainDao, C2cOrderComplainEntity> implements C2cOrderComplainService {
 
 //    @Override
 //    public QueryWrapper<C2cOrderComplainEntity> getWrapper(Map<String, Object> params){
@@ -35,7 +30,7 @@ public class C2cOrderComplainServiceImpl extends BaseServiceImpl<C2cOrderComplai
 //    }
     @Override
     public List<C2cOrderComplainEntity> selectC2cOrderComplainList(Long orderId) {
-        return baseDao.selectList(new LambdaQueryWrapper<C2cOrderComplainEntity>()
+        return list(new LambdaQueryWrapper<C2cOrderComplainEntity>()
                 .eq(Objects.nonNull(orderId),C2cOrderComplainEntity::getOrderId, orderId)
                 .orderByDesc(C2cOrderComplainEntity::getId)
             );

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderComplainVoucherServiceImpl.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cOrderComplainVoucherDao;
 import com.qnfhq.modules.c2c.dto.C2cOrderComplainVoucherDTO;
@@ -21,7 +21,7 @@ import java.util.Objects;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cOrderComplainVoucherServiceImpl extends BaseServiceImpl<C2cOrderComplainVoucherDao, C2cOrderComplainVoucherEntity> implements C2cOrderComplainVoucherService {
+public class C2cOrderComplainVoucherServiceImpl extends ServiceImpl<C2cOrderComplainVoucherDao, C2cOrderComplainVoucherEntity> implements C2cOrderComplainVoucherService {
 
 //    @Override
 //    public QueryWrapper<C2cOrderComplainVoucherEntity> getWrapper(Map<String, Object> params){
@@ -35,7 +35,7 @@ public class C2cOrderComplainVoucherServiceImpl extends BaseServiceImpl<C2cOrder
 
     @Override
     public List<C2cOrderComplainVoucherEntity> selectList(Long complainId) {
-        return baseDao.selectList(new QueryWrapper<C2cOrderComplainVoucherEntity>()
+        return list(new QueryWrapper<C2cOrderComplainVoucherEntity>()
                 .eq(Objects.nonNull(complainId),"complain_id", complainId)
                 .eq("status", 1)
                 .orderByDesc("id")

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderLogServiceImpl.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cOrderLogDao;
 import com.qnfhq.modules.c2c.dto.C2cOrderLogDTO;
@@ -19,7 +19,7 @@ import java.util.Map;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cOrderLogServiceImpl extends BaseServiceImpl<C2cOrderLogDao, C2cOrderLogEntity> implements C2cOrderLogService {
+public class C2cOrderLogServiceImpl extends ServiceImpl<C2cOrderLogDao, C2cOrderLogEntity> implements C2cOrderLogService {
 
 //    @Override
 //    public QueryWrapper<C2cOrderLogEntity> getWrapper(Map<String, Object> params){

+ 18 - 18
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cOrderServiceImpl.java

@@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qnfhq.common.constant.Constant;
 import com.qnfhq.common.page.PageData;
 import com.qnfhq.common.redis.RedisUtils;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.common.utils.DateUtils;
 import com.qnfhq.common.utils.MessageUtils;
@@ -50,7 +50,7 @@ import java.util.stream.Collectors;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEntity> implements C2cOrderService {
+public class C2cOrderServiceImpl extends ServiceImpl<C2cOrderDao, C2cOrderEntity> implements C2cOrderService {
     @Resource
     private RedisUtils redisUtils;
 
@@ -85,15 +85,15 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
     private C2cOrderDao c2cOrderDao;
 
 
-    @Override
-    public PageData<C2cOrderEntity> page(Map<String, Object> params) {
-        IPage<C2cOrderEntity> page = baseDao.selectPage(
-                getPage(params, "id", false),
-                getWrapper(params)
-        );
-
-        return getPageData(page, C2cOrderEntity.class);
-    }
+//    @Override
+//    public PageData<C2cOrderEntity> page(Map<String, Object> params) {
+//        IPage<C2cOrderEntity> page = baseDao.selectPage(
+//                getPage(params, "id", false),
+//                getWrapper(params)
+//        );
+//
+//        return getPageData(page, C2cOrderEntity.class);
+//    }
 
 
     public QueryWrapper<C2cOrderEntity> getWrapper(Map<String, Object> params){
@@ -146,7 +146,7 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
 
     @Override
     public C2cOrderEntity getTradingByAdId(long adId) {
-        return baseDao.selectOne(new LambdaQueryWrapper<C2cOrderEntity>()
+        return getOne(new LambdaQueryWrapper<C2cOrderEntity>()
                 .eq(C2cOrderEntity::getC2cAdId, adId)
                 .eq(C2cOrderEntity::getFlow, 0)
                 .last(" limit 1")
@@ -159,7 +159,7 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
     public C2cOrderEntity selectOrder(Long id) {
         C2cOrderEntity order = selectOrderFromRedis(id);
         if(order == null) {
-            order = selectById(id);
+            order = getById(id);
             if(order == null) {
                 return null;
             }
@@ -384,7 +384,7 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
         c2cOrderLog.setOpUserId(loginId);
         c2cOrderLog.setOpType(opType);
         c2cOrderLog.setCreateTime(new Date());
-        if(!c2cOrderLogService.insert(c2cOrderLog)) {
+        if(!c2cOrderLogService.save(c2cOrderLog)) {
             throw new Exception(MessageUtils.message("c2c.order.log.fail"));//插入订单日志失败
         }
     }
@@ -393,7 +393,7 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
     @Override
     public int cancelC2cOrderRedis(int oldStatus,C2cOrderEntity order) {
         //redis广告可用数量恢复
-        C2cAdEntity c2cAd = c2cAdService.selectById(order.getC2cAdId());
+        C2cAdEntity c2cAd = c2cAdService.getById(order.getC2cAdId());
         c2cAdService.deleteAdCache(c2cAd.getId(),c2cAd.getPayway().replaceAll("^,|,$", ""),c2cAd.getLegalCoin(),c2cAd.getSymbol(),c2cAd.getDirection());
         c2cAdService.setAdCache(c2cAd);
         deleteOrderCache(order);
@@ -475,7 +475,7 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
                     info.getFrozen(),info.getFrozen().subtract(order.getSymbolNum()),"用户卖出订单取消解冻资产");
         }
         //广告可用数量恢复
-        C2cAdEntity c2cAd = c2cAdService.selectById(order.getC2cAdId());
+        C2cAdEntity c2cAd = c2cAdService.getById(order.getC2cAdId());
         BigDecimal maxAmount = null;
         if(order.getTranAmount().compareTo(c2cAd.getMaxAmount())==1) {
             maxAmount = order.getTranAmount();
@@ -630,7 +630,7 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
 
         //判断是否需要创建买家资产账户
         if (Objects.isNull(buyerAsset)) {
-            AppUserEntity buyUser = appUserService.selectById(buyUserId);
+            AppUserEntity buyUser = appUserService.getById(buyUserId);
             appAssetService.createAsset(buyUser, order.getSymbol(), AssetEnum.PLATFORM_ASSETS.getCode());
 
             buyerAsset = new AppAssetEntity();
@@ -748,7 +748,7 @@ public class C2cOrderServiceImpl extends BaseServiceImpl<C2cOrderDao, C2cOrderEn
         }
         c2cOrderComplain.setStatus(C2cOrderComplainEnum.COMPLAINT.getCode());
         c2cOrderComplain.setCreateTime(new Date());
-        if(!complainService.insert(c2cOrderComplain)) {
+        if(!complainService.save(c2cOrderComplain)) {
             throw new Exception(MessageUtils.message("c2c.order.complain.submit.fail"));//提交申诉失败
         }
 

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cPayWayServiceImpl.java

@@ -2,7 +2,7 @@ package com.qnfhq.modules.c2c.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cPayWayDao;
 import com.qnfhq.modules.c2c.dto.C2cPayWayDTO;
@@ -22,7 +22,7 @@ import java.util.Map;
  * @since 1.0.0 2025-11-18
  */
 @Service
-public class C2cPayWayServiceImpl extends BaseServiceImpl<C2cPayWayDao, C2cPayWayEntity> implements C2cPayWayService {
+public class C2cPayWayServiceImpl extends ServiceImpl<C2cPayWayDao, C2cPayWayEntity> implements C2cPayWayService {
 
 //    @Override
 //    public QueryWrapper<C2cPayWayEntity> getWrapper(Map<String, Object> params){
@@ -36,7 +36,7 @@ public class C2cPayWayServiceImpl extends BaseServiceImpl<C2cPayWayDao, C2cPayWa
 
     @Override
     public List<C2cPayWayEntity> selectListByLegalCoin(String legalCoin) {
-        return baseDao.selectList(new LambdaQueryWrapper<C2cPayWayEntity>()
+        return list(new LambdaQueryWrapper<C2cPayWayEntity>()
                 .eq(StrUtil.isNotBlank(legalCoin), C2cPayWayEntity::getCurrencyCode, legalCoin)
                 .eq(C2cPayWayEntity::getStatus,1)
         );

+ 3 - 3
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cPaymentVoucherServiceImpl.java

@@ -1,7 +1,7 @@
 package com.qnfhq.modules.c2c.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cPaymentVoucherDao;
 import com.qnfhq.modules.c2c.dto.C2cPaymentVoucherDTO;
@@ -20,7 +20,7 @@ import java.util.Map;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cPaymentVoucherServiceImpl extends BaseServiceImpl<C2cPaymentVoucherDao, C2cPaymentVoucherEntity> implements C2cPaymentVoucherService {
+public class C2cPaymentVoucherServiceImpl extends ServiceImpl<C2cPaymentVoucherDao, C2cPaymentVoucherEntity> implements C2cPaymentVoucherService {
     private final C2cPaymentVoucherDao c2cPaymentVoucherDao;
 
     public C2cPaymentVoucherServiceImpl(C2cPaymentVoucherDao c2cPaymentVoucherDao) {
@@ -40,7 +40,7 @@ public class C2cPaymentVoucherServiceImpl extends BaseServiceImpl<C2cPaymentVouc
 
     @Override
     public List<C2cPaymentVoucherEntity> selectList(Long orderId) {
-        return baseDao.selectList(new QueryWrapper<C2cPaymentVoucherEntity>().eq("order_id", orderId)
+        return list(new QueryWrapper<C2cPaymentVoucherEntity>().eq("order_id", orderId)
                 .eq("status", 1).orderByDesc("id"));
 
     }

+ 4 - 4
qnfhq-api/src/main/java/com/qnfhq/modules/c2c/service/impl/C2cUserReceiptServiceImpl.java

@@ -3,7 +3,7 @@ package com.qnfhq.modules.c2c.service.impl;
 import cn.dev33.satoken.stp.StpUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.qnfhq.common.service.impl.BaseServiceImpl;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.qnfhq.common.service.impl.CrudServiceImpl;
 import com.qnfhq.modules.c2c.dao.C2cUserReceiptDao;
 import com.qnfhq.modules.c2c.dto.C2cMyReceiptDTO;
@@ -24,7 +24,7 @@ import java.util.Objects;
  * @since 1.0.0 2025-11-17
  */
 @Service
-public class C2cUserReceiptServiceImpl extends BaseServiceImpl<C2cUserReceiptDao, C2cUserReceiptEntity> implements C2cUserReceiptService {
+public class C2cUserReceiptServiceImpl extends ServiceImpl<C2cUserReceiptDao, C2cUserReceiptEntity> implements C2cUserReceiptService {
 
 
     private QueryWrapper<C2cUserReceiptEntity> getWrapper(Map<String, Object> params){
@@ -41,12 +41,12 @@ public class C2cUserReceiptServiceImpl extends BaseServiceImpl<C2cUserReceiptDao
         QueryWrapper<C2cUserReceiptEntity> wrapper = new QueryWrapper<>();
         wrapper.eq(Objects.nonNull(dto.getUserId()), "user_id", dto.getUserId());
         wrapper.eq(Objects.nonNull(dto.getType()), "type", dto.getType());
-        return baseDao.selectList(wrapper);
+        return list(wrapper);
     }
 
     @Override
     public C2cUserReceiptEntity selectOneMyReceipt(Long userId,Integer type) {
-        return baseDao.selectOne(new LambdaQueryWrapper<C2cUserReceiptEntity>()
+        return getOne(new LambdaQueryWrapper<C2cUserReceiptEntity>()
                 .eq(Objects.nonNull(userId), C2cUserReceiptEntity::getUserId, userId)
                 .eq(Objects.nonNull(type), C2cUserReceiptEntity::getType, type)
                 .last(" limit 1"));

+ 3 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppAssetDao.java

@@ -1,6 +1,7 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.AppAssetEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -13,7 +14,7 @@ import java.util.Map;
  * @since 1.0.0 2025-11-13
  */
 @Mapper
-public interface AppAssetDao extends BaseDao<AppAssetEntity> {
+public interface AppAssetDao extends BaseMapper<AppAssetEntity> {
 
     /**
      * 冻结资产

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppUserDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.AppUserEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,7 +11,7 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-11
  */
 @Mapper
-public interface AppUserDao extends BaseDao<AppUserEntity> {
+public interface AppUserDao extends BaseMapper<AppUserEntity> {
 
     AppUserEntity getUserByMobile(String mobile);
 

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppUserDetailDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.AppUserDetailEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-13
  */
 @Mapper
-public interface AppUserDetailDao extends BaseDao<AppUserDetailEntity> {
+public interface AppUserDetailDao extends BaseMapper<AppUserDetailEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppWalletRecordDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.AppWalletRecordEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-20
  */
 @Mapper
-public interface AppWalletRecordDao extends BaseDao<AppWalletRecordEntity> {
+public interface AppWalletRecordDao extends BaseMapper<AppWalletRecordEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/AppuserLoginLogDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.AppuserLoginLogEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -12,6 +12,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-11
  */
 @Mapper
-public interface AppuserLoginLogDao extends BaseDao<AppuserLoginLogEntity> {
+public interface AppuserLoginLogDao extends BaseMapper<AppuserLoginLogEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/SettingDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.SettingEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-13
  */
 @Mapper
-public interface SettingDao extends BaseDao<SettingEntity> {
+public interface SettingDao extends BaseMapper<SettingEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/SmsSendDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.SmsSendEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-13
  */
 @Mapper
-public interface SmsSendDao extends BaseDao<SmsSendEntity> {
+public interface SmsSendDao extends BaseMapper<SmsSendEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/dao/SmsTplDao.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.dao;
 
-import com.qnfhq.common.dao.BaseDao;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.qnfhq.modules.user.entity.SmsTplEntity;
 import org.apache.ibatis.annotations.Mapper;
 
@@ -11,6 +11,6 @@ import org.apache.ibatis.annotations.Mapper;
  * @since 1.0.0 2025-11-13
  */
 @Mapper
-public interface SmsTplDao extends BaseDao<SmsTplEntity> {
+public interface SmsTplDao extends BaseMapper<SmsTplEntity> {
 	
 }

+ 2 - 2
qnfhq-api/src/main/java/com/qnfhq/modules/user/service/AppAssetService.java

@@ -1,6 +1,6 @@
 package com.qnfhq.modules.user.service;
 
-import com.qnfhq.common.service.BaseService;
+import com.baomidou.mybatisplus.extension.service.IService;
 import com.qnfhq.modules.user.entity.AppAssetEntity;
 import com.qnfhq.modules.user.entity.AppUserEntity;
 import com.qnfhq.modules.user.enums.AssetEnum;
@@ -14,7 +14,7 @@ import java.util.List;
  * @author yelz 30262728@qq.com
  * @since 1.0.0 2025-11-13
  */
-public interface AppAssetService extends BaseService<AppAssetEntity> {
+public interface AppAssetService extends IService<AppAssetEntity> {
 
     /**
      * 获取用户资产

Неке датотеке нису приказане због велике количине промена