From de8bbf1c24fd449137a522ec4c7e8f04e3dcd748 Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Mon, 02 Mar 2026 17:26:15 +0800
Subject: [PATCH] 1

---
 src/main/resources/application.properties                                |    2 
 src/main/java/com/nq/vo/pay/PayoutResponseVO.java                        |   28 +++
 src/main/java/com/nq/vo/pay/PayoutCallbackRequest.java                   |   19 ++
 src/main/java/com/nq/controller/protol/UserController.java               |   10 +
 src/main/java/com/nq/service/impl/UserWithdrawServiceImpl.java           |  128 +++++++++++++++
 src/main/java/com/nq/vo/pay/PayOutMD5Util.java                           |   31 +++
 src/main/java/com/nq/vo/pay/PayoutCallbackData.java                      |   21 ++
 src/main/java/com/nq/utils/AesEncryptUtil.java                           |   36 ++++
 src/main/java/com/nq/service/impl/SiteInfoServiceImpl.java               |    6 
 src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java |    3 
 src/main/java/com/nq/service/impl/PayServiceImpl.java                    |  154 ++++++++++++++++++
 11 files changed, 431 insertions(+), 7 deletions(-)

diff --git a/src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java b/src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java
index 8a333ba..f744833 100644
--- a/src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java
+++ b/src/main/java/com/nq/common/interceptor/ApiUserAuthorityInterceptor.java
@@ -87,6 +87,9 @@
         if ("/user/payoutCallback.do".equals(url)) {//代付回调
             return true;
         }
+        if ("/user/payoutCallbackTwo.do".equals(url)) {//代付回调
+            return true;
+        }
         User currentUser = getCurrentUser(httpServletRequest);
         GoogleTranslateUtil googleTranslateUtil = new GoogleTranslateUtil();
         String lang = httpServletRequest.getHeader("lang");
diff --git a/src/main/java/com/nq/controller/protol/UserController.java b/src/main/java/com/nq/controller/protol/UserController.java
index 6c32bb6..90e29b2 100644
--- a/src/main/java/com/nq/controller/protol/UserController.java
+++ b/src/main/java/com/nq/controller/protol/UserController.java
@@ -21,6 +21,7 @@
 import javax.servlet.http.HttpSession;
 
 import com.nq.utils.translate.GoogleTranslateUtil;
+import com.nq.vo.pay.PayoutCallbackRequest;
 import com.nq.vo.stock.UserStockSubscribeAddIn;
 import org.apache.ibatis.annotations.Property;
 import org.slf4j.Logger;
@@ -516,4 +517,13 @@
     public void payoutCallback(@RequestBody PayoutCallbackVo callbackVo, HttpServletResponse response) throws IOException {
         payService.payoutCallback(callbackVo, response);
     }
+
+
+    /**
+     * 代付回调接口
+     */
+    @PostMapping({"payoutCallbackTwo.do"})
+    public Map<String, Object> payoutCallbackTwo(@RequestBody PayoutCallbackRequest callbackVo, HttpServletResponse response) throws IOException {
+        return payService.payoutCallbackTwo(callbackVo, response);
+    }
 }
diff --git a/src/main/java/com/nq/service/impl/PayServiceImpl.java b/src/main/java/com/nq/service/impl/PayServiceImpl.java
index 2e965a2..986c2ec 100644
--- a/src/main/java/com/nq/service/impl/PayServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/PayServiceImpl.java
@@ -41,6 +41,9 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import com.nq.vo.pay.PayOutMD5Util;
+import com.nq.vo.pay.PayoutCallbackData;
+import com.nq.vo.pay.PayoutCallbackRequest;
 import net.sf.json.JSON;
 import net.sf.json.JSONObject;
 import okhttp3.*;
@@ -121,7 +124,8 @@
         }else if(type == 2){//支付2
             return getPaymentZero(tradeAmount, uipReqRul, user,request);
         } else if(type == 3){//支付2
-            return getPaymentTwo(tradeAmount, uipReqRul, user,request);
+//            return getPaymentTwo(tradeAmount, uipReqRul, user,request);
+            return ServerResponse.createByErrorMsg("未开启,请选择其他支付方式",request);
         }else if(type == 1){
 //            return getPaymentThree(tradeAmount, threeUrl, user,request);
             return getPaymentOne(tradeAmount, reqUrl,user,request);
@@ -131,7 +135,7 @@
 
     private ServerResponse getPaymentZero(String tradeAmount, String uipReqRul, User user, HttpServletRequest request) throws Exception {
         //int
-        String url = "https://gateway.kings-pays.com/gateway/payout/init";//正式地址
+        String url = "https://gateway.kings-pays.com/gateway/payment/init";//正式地址
         String merchantKey = "qqaC1DH/LeR9iPvm";//商户key 需替换
         String aesKey = "ge6vK40fHNZPFJ4p";//商户aesKey 需替换
         String aesIv = "6gJoHTEE1i2O3ovE";//商户aesIv 需替换
@@ -154,6 +158,7 @@
         Headers headers = new Headers.Builder().add("merchant_key", merchantKey).build();//merchant_key需替换
         //请求
         String resp = doPost(url, requestObj.toString(), headers);
+        log.info("代收返回:"+resp);
         Gson gson = new Gson();
         PaymentResponseZero paymentResponse = gson.fromJson(resp, PaymentResponseZero.class);
         if(paymentResponse.getCode() != 0 && !paymentResponse.getMsg().equals("success")){
@@ -1423,7 +1428,7 @@
                 transferResponseService.updateById(transferResponse);
                 
                 userWithdraw.setWithStatus(2); // 失败
-                userWithdraw.setWithMsg("代付失败:" + vo.getMsg());
+                userWithdraw.setWithMsg("Withdrawal failed:" + vo.getMsg());
                 userWithdraw.setTransTime(new Date());
                 userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
                 
@@ -1482,4 +1487,147 @@
             pw.close();
         }
     }
+
+    public Map<String, Object> payoutCallbackTwo(PayoutCallbackRequest request, HttpServletResponse response) {
+
+
+        String merchantKey = "qqaC1DH/LeR9iPvm";//商户key 需替换
+        String aesKey = "ge6vK40fHNZPFJ4p";//商户aesKey 需替换
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("code", 200);   // 固定返回 200
+
+        try {
+            PayoutCallbackData data = request.getData();
+            String signature = request.getSignature_n();
+
+            // 1. 签名验证
+            String signStr = merchantKey
+                    + nullToEmpty(data.getMessage())
+                    + nullToEmpty(data.getAmount())
+                    + nullToEmpty(data.getStatus())
+                    + nullToEmpty(data.getMerchantOrderNo())
+                    + nullToEmpty(data.getOrderNo())
+                    + aesKey;
+
+            String calculatedSign = PayOutMD5Util.md5(signStr).toLowerCase();
+
+            if (!calculatedSign.equals(signature)) {
+                log.error("代付回调签名验证失败,merchantOrderNo={},本地签名={},回调签名={}",
+                        data.getMerchantOrderNo(), calculatedSign, signature);
+                // 签名失败不处理业务,但依旧返回 200
+                return result;
+            }
+
+            // 2. 查询本地代付记录
+            TransferResponse transfer = transferResponseService.getOne(
+                    new LambdaQueryWrapper<TransferResponse>()
+                            .eq(TransferResponse::getMerTransferId, data.getMerchantOrderNo())
+                            .last("limit 1")
+            );
+
+            if (transfer == null) {
+                log.error("代付回调未找到对应记录,merchantOrderNo={}", data.getMerchantOrderNo());
+                return result;
+            }
+
+            // 3. 防止重复回调
+            if (transfer.getCallbackState() != 0) {
+                log.info("代付回调已处理过,merchantOrderNo={},状态={}", data.getMerchantOrderNo(), transfer.getCallbackState());
+                return result;
+            }
+
+            // 4. 查询提现记录
+            UserWithdraw withdraw = userWithdrawMapper.selectByPrimaryKey(transfer.getWithId());
+            if (withdraw == null) {
+                log.error("代付回调未找到提现记录,withId={}", transfer.getWithId());
+                return result;
+            }
+
+            // 5. 根据状态处理
+            String status = data.getStatus();
+            if ("SUCCESS".equals(status)) {
+                handleSuccess(transfer, withdraw, data, signature);
+            } else if ("FAILURE".equals(status)) {
+                handleFailure(transfer, withdraw, data, signature);
+            } else {
+                log.info("代付回调未知状态:{},暂不处理,merchantOrderNo={}", status, data.getMerchantOrderNo());
+            }
+
+        } catch (Exception e) {
+            log.error("代付回调处理异常", e);
+        }
+
+        return result;
+    }
+
+    /**
+     * 处理成功回调
+     */
+    private void handleSuccess(TransferResponse transfer, UserWithdraw withdraw,
+                               PayoutCallbackData data, String signature) {
+        // 更新代付记录
+        transfer.setTradeResult(1);          // 成功
+        transfer.setCallbackState(1);        // 已处理成功
+        transfer.setRespCode("SUCCESS");
+        transfer.setSignType("MD5");
+        transfer.setSign(signature);
+        transfer.setUpdatedAt(new Date());
+        transferResponseService.updateById(transfer);
+
+        // 更新提现记录
+        withdraw.setWithStatus(1);            // 成功
+        withdraw.setWithMsg("代付成功");
+        withdraw.setTransTime(new Date());
+        userWithdrawMapper.updateByPrimaryKeySelective(withdraw);
+
+        // 扣除冻结资金(提现时已冻结,此处只需将冻结减少,可用余额不变)
+        UserAssets assets = iUserAssetsServices.assetsByTypeAndUserId("IN", withdraw.getUserId());
+        if (assets != null) {
+            assets.setFreezeMoney(assets.getFreezeMoney().subtract(withdraw.getWithAmt()));
+            userAssetsMapper.updateById(assets);
+        }
+
+        log.info("代付成功处理完成,商户订单号={},平台订单号={}", data.getMerchantOrderNo(), data.getOrderNo());
+    }
+
+    /**
+     * 处理失败回调
+     */
+    private void handleFailure(TransferResponse transfer, UserWithdraw withdraw,
+                               PayoutCallbackData data, String signature) {
+        // 更新代付记录
+        transfer.setTradeResult(2);          // 失败
+        transfer.setCallbackState(2);        // 已处理失败
+        transfer.setRespCode("FAIL");
+        transfer.setErrorMsg(data.getMessage());
+        transfer.setSignType("MD5");
+        transfer.setSign(signature);
+        transfer.setUpdatedAt(new Date());
+        transferResponseService.updateById(transfer);
+
+        // 更新提现记录
+        withdraw.setWithStatus(2);            // 失败
+        withdraw.setWithMsg("Withdrawal failed:" + data.getMessage());
+        withdraw.setTransTime(new Date());
+        userWithdrawMapper.updateByPrimaryKeySelective(withdraw);
+
+        // 返还资金:解冻并增加可用余额
+        UserAssets assets = iUserAssetsServices.assetsByTypeAndUserId("IN", withdraw.getUserId());
+        if (assets != null) {
+            assets.setAvailableBalance(assets.getAvailableBalance().add(withdraw.getWithAmt()));
+            assets.setFreezeMoney(assets.getFreezeMoney().subtract(withdraw.getWithAmt()));
+            userAssetsMapper.updateById(assets);
+        }
+
+        log.info("代付失败处理完成,商户订单号={},平台订单号={},失败原因={}",
+                data.getMerchantOrderNo(), data.getOrderNo(), data.getMessage());
+    }
+
+    /**
+     * 将 null 转为空字符串,防止拼接 NPE
+     */
+    private String nullToEmpty(String str) {
+        return str == null ? "" : str;
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/com/nq/service/impl/SiteInfoServiceImpl.java b/src/main/java/com/nq/service/impl/SiteInfoServiceImpl.java
index 7b6b9e2..a2912a2 100644
--- a/src/main/java/com/nq/service/impl/SiteInfoServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/SiteInfoServiceImpl.java
@@ -125,13 +125,15 @@
                         } else if (agentUser.getId().equals(56)) {
                             siteInfo.setOnlineService("https://t.me/Greenback8");
                         } else if (agentUser.getId().equals(57)) {
-                            siteInfo.setOnlineService(""); // 代理账户138073(ID:57)客服号链接为空
+                            siteInfo.setOnlineService("https://t.me/GreenbackCapital"); // 代理账户138073(ID:57)客服号链接为空
                         } else if (agentUser.getId().equals(58)) {
                             siteInfo.setOnlineService("https://t.me/Greenback9");
                         } else if (agentUser.getId().equals(59)) {
                             siteInfo.setOnlineService("https://t.me/GC855858");
                         } else if (agentUser.getId().equals(61)) {
-                            siteInfo.setOnlineService("https://t.me/Duro_Capital2");
+                            siteInfo.setOnlineService("https://t.me/Greenback2");
+                        } else if (agentUser.getId().equals(62)) {
+                            siteInfo.setOnlineService("https://t.me/Greenback_Capital79");
                         }
                     }
 
diff --git a/src/main/java/com/nq/service/impl/UserWithdrawServiceImpl.java b/src/main/java/com/nq/service/impl/UserWithdrawServiceImpl.java
index a5503a3..5059a2d 100644
--- a/src/main/java/com/nq/service/impl/UserWithdrawServiceImpl.java
+++ b/src/main/java/com/nq/service/impl/UserWithdrawServiceImpl.java
@@ -1,6 +1,7 @@
 package com.nq.service.impl;
 
 
+import com.alibaba.fastjson2.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -33,6 +34,7 @@
 import javax.servlet.http.HttpServletResponse;
 
 import com.nq.utils.timeutil.TimeUtil;
+import okhttp3.*;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 
@@ -395,7 +397,10 @@
                     return ServerResponse.createBySuccessMsg("操作成功!");
                 }
             }else if(state == 1){//走代付
-                return getObjectServerResponseOne(withId, request, response, userWithdraw, user, userAssets);
+                return getObjectServerResponseTwo(withId, request, response, userWithdraw, user, userAssets);
+            }else if(state == 2){//走代付
+                return ServerResponse.createByErrorMsg("代付通道关闭");
+//                return getObjectServerResponseOne(withId, request, response, userWithdraw, user, userAssets);
             }else{
                 return ServerResponse.createByErrorMsg("请选择对应的操作!");
             }
@@ -406,6 +411,127 @@
         return ServerResponse.createBySuccessMsg("操作失败!");
     }
 
+    //代付二
+    private ServerResponse getObjectServerResponseTwo(Integer withId, HttpServletRequest request, HttpServletResponse response, UserWithdraw userWithdraw, User user, UserAssets userAssets) throws Exception {
+
+        String payoutUrl = "https://gateway.kings-pays.com/gateway/payout/init";//正式地址
+        String merchantKey = "qqaC1DH/LeR9iPvm";//商户key 需替换
+        String aesKey = "ge6vK40fHNZPFJ4p";//商户aesKey 需替换
+        String aesIv = "6gJoHTEE1i2O3ovE";//商户aesIv 需替换
+
+        // 1. 生成商户订单号
+        String merchantOrderNo = generatePayoutOrderId(withId);
+
+        // 2. 构建加密前的业务参数
+        JSONObject dataObj = new JSONObject();
+        dataObj.put("amount", userWithdraw.getWithAmt().intValue()); // 注意金额单位(示例中为整数)
+        dataObj.put("transferType", "BANK_TRANSFER");
+        dataObj.put("beneficiaryName", user.getNickName());
+        dataObj.put("beneficiaryEmail", "null@gmail.com");
+        dataObj.put("beneficiaryPhoneNo", user.getPhone());
+        dataObj.put("beneficiaryAccount", userWithdraw.getBankNo());
+        dataObj.put("beneficiaryIFSC", userWithdraw.getBankAddress());
+        dataObj.put("merchantOrderNo", merchantOrderNo);
+        dataObj.put("notifyUrl", "https://api.greenbackcaps.top/user/payoutCallbackTwo.do");
+
+        // 3. AES 加密
+        String encryptedData = AesEncryptUtil.encrypt(dataObj.toJSONString(), aesKey, aesIv);
+        JSONObject requestObj = new JSONObject();
+        requestObj.put("data", encryptedData);
+
+        // 4. 设置请求头
+        Headers headers = new Headers.Builder()
+                .add("merchant_key", merchantKey)
+                .build();
+
+        // 5. 发送 HTTP 请求
+        log.info("代付请求参数:{}", requestObj.toJSONString());
+        String respStr = doPost(payoutUrl, requestObj.toJSONString(), headers);
+        log.info("代付响应原始数据:{}", respStr);
+
+        // 6. 解析响应(使用 Jackson 或 fastjson,这里以 fastjson 为例)
+        JSONObject respJson = JSONObject.parseObject(respStr);
+        int code = respJson.getIntValue("code");
+        boolean success = respJson.getBooleanValue("success");
+        String msg = respJson.getString("msg");
+
+        // 6.1 接口调用失败(code != 0 或 success = false)
+        if (code != 0 || !success) {
+            handleFailure(userAssets, userWithdraw, "代付请求失败:" + msg);
+            return ServerResponse.createByErrorMsg("代付请求失败:" + msg, request);
+        }
+
+        // 6.2 获取 data 部分
+        JSONObject data = respJson.getJSONObject("data");
+        String status = data.getString("status");       // ACCEPT / FAILURE / PROCESSING
+        String failMsg = data.getString("message");     // 失败时的具体原因
+
+        // 7. 根据 status 判断业务是否成功
+        if ("ACCEPT".equals(status)) {
+            // 代付订单被接受(不一定最终成功,需等待回调)
+            String platformOrderNo = data.getString("orderNo");
+
+            // 保存代付记录
+            saveTransferRecord(merchantOrderNo, platformOrderNo, userWithdraw.getWithAmt(), user.getId(), withId);
+
+            // 更新提现记录为“已提交”
+            userWithdraw.setWithStatus(4); // 4:已提交
+            userWithdraw.setTransTime(new Date());
+            userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
+
+            log.info("代付下单成功,商户订单号:{}", merchantOrderNo);
+            return ServerResponse.createBySuccessMsg("代付申请已提交,请等待处理");
+        } else {
+            // 业务失败(如 FAILURE)
+            String errorMsg = (failMsg != null && !failMsg.isEmpty()) ? failMsg : msg;
+            handleFailure(userAssets, userWithdraw, "Withdrawal failed:" + errorMsg);
+            return ServerResponse.createByErrorMsg("Withdrawal failed:" + errorMsg, request);
+        }
+
+
+
+    }
+
+    public static String doPost(String url, String data, Headers headers) throws IOException {
+        OkHttpClient customClient = new OkHttpClient();
+        Request request = new Request.Builder()
+                .url(url)
+                .headers(headers)
+                .post(RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), data))
+                .build();
+        Response response = customClient.newCall(request).execute();
+        String resp = response.body().string();
+        return resp;
+    }
+
+    private void handleFailure(UserAssets userAssets, UserWithdraw userWithdraw, String errorMsg) {
+        userAssets.setAvailableBalance(userAssets.getAvailableBalance().add(userWithdraw.getWithAmt()));
+        userAssets.setFreezeMoney(userAssets.getFreezeMoney().subtract(userWithdraw.getWithAmt()));
+        userAssetsMapper.updateById(userAssets);
+
+        userWithdraw.setWithStatus(2); // 2:失败
+        userWithdraw.setWithMsg(errorMsg);
+        userWithdraw.setTransTime(new Date());
+        userWithdrawMapper.updateByPrimaryKeySelective(userWithdraw);
+    }
+
+    private void saveTransferRecord(String merchantOrderNo, String platformOrderNo, BigDecimal amount,
+                                    Integer userId, Integer withId) {
+        TransferResponse record = new TransferResponse();
+        record.setMerTransferId(merchantOrderNo);
+        record.setTradeNo(platformOrderNo);
+        record.setTransferAmount(amount);
+        record.setTradeResult(0);       // 0:已下单
+        record.setCallbackState(0);     // 0:未处理
+        record.setRespCode("SUCCESS");
+        record.setSignType("AES");
+        record.setApplyDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+        record.setUserId(userId);
+        record.setWithId(withId);
+        record.setCreatedAt(new Date());
+        record.setUpdatedAt(new Date());
+        transferResponseService.save(record);
+    }
 
 
     public int deleteByUserId(Integer userId) {
diff --git a/src/main/java/com/nq/utils/AesEncryptUtil.java b/src/main/java/com/nq/utils/AesEncryptUtil.java
new file mode 100644
index 0000000..092d5df
--- /dev/null
+++ b/src/main/java/com/nq/utils/AesEncryptUtil.java
@@ -0,0 +1,36 @@
+package com.nq.utils;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+/**
+ * @program: dabaogp
+ * @description:
+ * @create: 2026-03-02 15:11
+ **/
+public class AesEncryptUtil {
+
+
+    public static String encrypt(String data, String key, String iv) throws Exception {
+        // 直接使用字符串的 UTF-8 字节作为密钥和 IV(需确保长度为16)
+        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
+        byte[] ivBytes = iv.getBytes(StandardCharsets.UTF_8);
+
+        // 验证长度(可选)
+        if (keyBytes.length != 16 || ivBytes.length != 16) {
+            throw new IllegalArgumentException("Key and IV must be 16 bytes long (16 ASCII characters)");
+        }
+
+        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
+        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+
+        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+        byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
+        return Base64.getEncoder().encodeToString(encrypted);
+    }
+
+}
diff --git a/src/main/java/com/nq/vo/pay/PayOutMD5Util.java b/src/main/java/com/nq/vo/pay/PayOutMD5Util.java
new file mode 100644
index 0000000..0efe139
--- /dev/null
+++ b/src/main/java/com/nq/vo/pay/PayOutMD5Util.java
@@ -0,0 +1,31 @@
+package com.nq.vo.pay;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * @program: dabaogp
+ * @description:
+ * @create: 2026-03-02 15:18
+ **/
+public class PayOutMD5Util {
+
+    public static String md5(String source) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] bytes = md.digest(source.getBytes("UTF-8"));
+            return bytesToHex(bytes);
+        } catch (NoSuchAlgorithmException | java.io.UnsupportedEncodingException e) {
+            throw new RuntimeException("MD5加密失败", e);
+        }
+    }
+
+    private static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02x", b));
+        }
+        return sb.toString();
+    }
+
+}
diff --git a/src/main/java/com/nq/vo/pay/PayoutCallbackData.java b/src/main/java/com/nq/vo/pay/PayoutCallbackData.java
new file mode 100644
index 0000000..33c3b22
--- /dev/null
+++ b/src/main/java/com/nq/vo/pay/PayoutCallbackData.java
@@ -0,0 +1,21 @@
+package com.nq.vo.pay;
+
+import lombok.Data;
+
+/**
+ * @program: dabaogp
+ * @description:
+ * @create: 2026-03-02 15:28
+ **/
+@Data
+public class PayoutCallbackData {
+    private String amount;           // 支出金额(字符串,如 "1500.00")
+    private String orderNo;           // 平台订单号
+    private String message;           // 失败原因或成功信息
+    private String type;              // 类型,固定为 "payout"
+    private String merchantOrderNo;   // 商户订单号
+    private String processedTime;     // 成功时间(仅成功时返回)
+    private String utr;               // UTR 码
+    private String processAmount;     // 手续费
+    private String status;            // 订单状态:SUCCESS / FAILURE
+}
diff --git a/src/main/java/com/nq/vo/pay/PayoutCallbackRequest.java b/src/main/java/com/nq/vo/pay/PayoutCallbackRequest.java
new file mode 100644
index 0000000..70c7b3a
--- /dev/null
+++ b/src/main/java/com/nq/vo/pay/PayoutCallbackRequest.java
@@ -0,0 +1,19 @@
+package com.nq.vo.pay;
+
+/**
+ * @program: dabaogp
+ * @description:
+ * @create: 2026-03-02 15:17
+ **/
+
+import lombok.Data;
+
+/**
+ * 代付回调请求体
+ */
+@Data
+public class PayoutCallbackRequest {
+    private PayoutCallbackData data;
+    private String signature_n;      // 签名
+}
+
diff --git a/src/main/java/com/nq/vo/pay/PayoutResponseVO.java b/src/main/java/com/nq/vo/pay/PayoutResponseVO.java
new file mode 100644
index 0000000..382c1fb
--- /dev/null
+++ b/src/main/java/com/nq/vo/pay/PayoutResponseVO.java
@@ -0,0 +1,28 @@
+package com.nq.vo.pay;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+/**
+ * @program: dabaogp
+ * @description:
+ * @create: 2026-03-02 15:02
+ **/
+@Data
+public class PayoutResponseVO {
+    private int code;          // 0 表示接口调用成功
+    private String msg;        // 提示信息
+    private PayoutData data;   // 业务数据
+    private boolean success;   // 是否成功(与 code 对应)
+
+    @Data
+    public static class PayoutData {
+        private String orderNo;          // 平台订单号
+        private String merchantOrderNo;  // 商户订单号
+        private String status;           // 订单状态(ACCEPT/FAILURE/PROCESSING 等)
+        private BigDecimal amount;       // 金额
+        private String message;          // 失败原因(当 status=FAILURE 时存在)
+    }
+
+}
\ No newline at end of file
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 3cf593f..1d87b03 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -50,7 +50,7 @@
 JS_IN_HTTP_API = http://api-in-3-socket.js-stock.top
 JS_IN_HTTP_URL = http://api-in-pro.js-stock.top/
 JS_IN_WS_URL = ws://api-in-pro-ws.js-stock.top
-JS_IN_KEY = 5CXdBCcKHgWHZifECepM
+JS_IN_KEY = xKChgi47AP1NMwMeYI3c
 
 US_HTTP_API = http://api-us.js-stock.top/
 US_WS_URL = ws://ws-us.js-stock.top

--
Gitblit v1.9.3