Procházet zdrojové kódy

Merge branch 'master' of http://124.220.229.80:9093/root/cif

linxk před 1 měsícem
rodič
revize
c8555b897c
23 změnil soubory, kde provedl 693 přidání a 242 odebrání
  1. 18 0
      cif-api/src/main/java/com/txz/cif/dto/jpush/JPushSmsDTO.java
  2. 22 0
      cif-api/src/main/java/com/txz/cif/dto/jpush/JPushTemplateDTO.java
  3. 12 14
      cif-api/src/main/java/com/txz/cif/param/CancelParam.java
  4. 27 0
      cif-service/src/main/java/com/txz/cif/configurer/TecrmConf.java
  5. 28 0
      cif-service/src/main/java/com/txz/cif/configurer/jpush/JPushConf.java
  6. 4 2
      cif-service/src/main/java/com/txz/cif/dubbo/impl/AccountDubboServiceImpl.java
  7. 13 9
      cif-service/src/main/java/com/txz/cif/model/BizLog.java
  8. 12 0
      cif-service/src/main/java/com/txz/cif/service/JPushService.java
  9. 13 0
      cif-service/src/main/java/com/txz/cif/service/TecrmService.java
  10. 3 0
      cif-service/src/main/java/com/txz/cif/service/impl/CSHuaGuServiceImpl.java
  11. 69 0
      cif-service/src/main/java/com/txz/cif/service/impl/JPushServiceImpl.java
  12. 8 3
      cif-service/src/main/java/com/txz/cif/service/impl/RechargeRecordServiceImpl.java
  13. 10 5
      cif-service/src/main/java/com/txz/cif/service/impl/RedEnvelopeServiceImpl.java
  14. 153 0
      cif-service/src/main/java/com/txz/cif/service/impl/TecrmServiceImpl.java
  15. 29 8
      cif-service/src/main/java/com/txz/cif/service/impl/UserServiceImpl.java
  16. 54 29
      cif-service/src/main/java/com/txz/cif/service/impl/WithdrawRecordServiceImpl.java
  17. 97 103
      cif-service/src/main/java/com/txz/cif/web/RedEnvelopeApiController.java
  18. 37 28
      cif-service/src/main/java/com/txz/cif/web/WithdrawRecordApiController.java
  19. 25 19
      cif-service/src/main/java/com/txz/cif/web/bo/UserBo2.java
  20. 7 1
      cif-service/src/main/java/com/txz/cif/web/bo/UserDetailBo.java
  21. 24 20
      cif-service/src/main/java/com/txz/cif/web/mng/UserController.java
  22. 0 1
      cif-service/src/main/resources/mapper/RedEnvelopeMapper.xml
  23. 28 0
      cif-service/src/test/java/com/txz/cif/CifLocalTest.java

+ 18 - 0
cif-api/src/main/java/com/txz/cif/dto/jpush/JPushSmsDTO.java

@@ -0,0 +1,18 @@
+package com.txz.cif.dto.jpush;
+
+import lombok.Data;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/13
+ */
+@Data
+public class JPushSmsDTO {
+    
+    private String to;
+    
+    private String code;
+    
+    private JPushTemplateDTO template;
+}

+ 22 - 0
cif-api/src/main/java/com/txz/cif/dto/jpush/JPushTemplateDTO.java

@@ -0,0 +1,22 @@
+package com.txz.cif.dto.jpush;
+
+import cn.hutool.json.JSONObject;
+import lombok.Data;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/13
+ */
+@Data
+public class JPushTemplateDTO {
+    
+    // 缺省模板
+    private String id = "UNIFIED_TEMPLATE";
+    
+    // 确认默认语言
+    private String language = "default";
+    
+    private JSONObject params;
+    
+}

+ 12 - 14
cif-api/src/main/java/com/txz/cif/param/CancelParam.java

@@ -1,9 +1,9 @@
 /*
-*
-* FreezdParam.java
-* Copyright(C) 2017-2020 fendo公司
-* @date 2022-11-02
-*/
+ *
+ * FreezdParam.java
+ * Copyright(C) 2017-2020 fendo公司
+ * @date 2022-11-02
+ */
 package com.txz.cif.param;
 
 import lombok.AllArgsConstructor;
@@ -41,22 +41,20 @@ public class CancelParam implements Serializable {
      * 开团人
      */
     private Long openGroupUserId;
-
-
+    
+    
     /**
      * 开团金额
      */
     private BigDecimal amount;
-
-
+    
+    
     /**
      * 交易时间
      */
     private Date transTime;
-
+    
     private static final long serialVersionUID = 1L;
-
-
-
-
+    
+    
 }

+ 27 - 0
cif-service/src/main/java/com/txz/cif/configurer/TecrmConf.java

@@ -0,0 +1,27 @@
+package com.txz.cif.configurer;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/17
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "tecrm")
+public class TecrmConf {
+    
+    private String appId;
+    
+    private String appKey;
+    
+    private String cid;
+    
+    private String templateCode;
+    
+    private String domain;
+    
+}

+ 28 - 0
cif-service/src/main/java/com/txz/cif/configurer/jpush/JPushConf.java

@@ -0,0 +1,28 @@
+package com.txz.cif.configurer.jpush;
+
+import cn.hutool.core.codec.Base64;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/13
+ */
+
+@Data
+@Component
+@ConfigurationProperties(prefix = "jpush")
+public class JPushConf {
+    
+    private String appKey;
+    
+    private String masterSecret;
+    
+    private String reqUrl;
+    
+    public String getAuth() {
+        return "Basic " + Base64.encode((this.appKey + ":" + this.masterSecret));
+    }
+}

+ 4 - 2
cif-service/src/main/java/com/txz/cif/dubbo/impl/AccountDubboServiceImpl.java

@@ -148,7 +148,8 @@ public class AccountDubboServiceImpl implements AccountDubboService {
         for (Long userId : param.getUserIds()) {
             Result result = flowService.refund(RefundParam.builder()
                     .transTime(param.getTransTime())
-                    .bizType(BizTypeEnum.FAIL_GROUP_REFUND.getKey()).bizNo(param.getBizNo())
+                    .bizType(BizTypeEnum.FAIL_GROUP_REFUND.getKey())
+                    .bizNo(param.getBizNo())
                     .bizId(param.getBizId())
                     .amount(param.getAmount())
                     .userId(userId)
@@ -167,7 +168,8 @@ public class AccountDubboServiceImpl implements AccountDubboService {
         for (OrderParam orderParam : param.getUserIds()) {
             Result result = flowService.refund(RefundParam.builder()
                     .transTime(param.getTransTime())
-                    .bizType(BizTypeEnum.SUCCESS_GROUP_REFUND.getKey()).bizNo(param.getBizNo())
+                    .bizType(BizTypeEnum.SUCCESS_GROUP_REFUND.getKey())
+                    .bizNo(orderParam.getOrderNo())
                     .bizId(param.getBizId())
                     .amount(param.getAmount())
                     .userId(orderParam.getUserId())

+ 13 - 9
cif-service/src/main/java/com/txz/cif/model/BizLog.java

@@ -19,50 +19,54 @@ public class BizLog {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     @ApiModelProperty(value = "id")
     private Long id;
-    
+
     /**
      * 订单号
      */
     @Column(name = "biz_no")
     @ApiModelProperty(value = "bizNo订单号")
     private String bizNo;
+
+    @Column(name = "third_order_No")
+    @ApiModelProperty(value = "提现流水号")
+    private String thirdOrderNo;
     @ApiModelProperty(value = "备注")
     private String memo;
     @Column(name = "biz_type")
     @ApiModelProperty(value = "类型1充值 2提现")
     private Integer bizType;
-    
+
     /**
      * type类型1提交充值订单 2充值调用第三方 3充值回调通知成功 4提交提现申请 5提现审核通过 6提现审核失败 7提现调用第三方 8提现回调通知成功
      */
     @ApiModelProperty(value = "type类型1提交充值订单 2充值调用第三方 3充值回调通知成功 4提交提现申请 5提现审核通过 6提现审核失败 7提现调用第三方 8提现回调通知成功 9提现回调通知失败")
     private Integer type;
-    
+
     /**
      * 三方接口请求消息
      */
     @Column(name = "send_message")
     private String sendMessage;
-    
+
     /**
      * 三方接口接收消息
      */
     @Column(name = "receive_message")
     private String receiveMessage;
-    
+
     /**
      * 创建人
      */
     @Column(name = "create_user")
     @ApiModelProperty(value = "createUser创建人")
     private String createUser;
-    
+
     /**
      * 创建时间
      */
     @Column(name = "create_time")
     @ApiModelProperty(value = "createTime创建时间")
     private Date createTime;
-    
-    
-}
+
+
+}

+ 12 - 0
cif-service/src/main/java/com/txz/cif/service/JPushService.java

@@ -0,0 +1,12 @@
+package com.txz.cif.service;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/13
+ */
+
+public interface JPushService {
+    
+    boolean sendSms(String mobile, String code);
+}

+ 13 - 0
cif-service/src/main/java/com/txz/cif/service/TecrmService.java

@@ -0,0 +1,13 @@
+package com.txz.cif.service;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/17
+ */
+
+public interface TecrmService {
+    
+    boolean sendSms(String mobile, String code);
+    
+}

+ 3 - 0
cif-service/src/main/java/com/txz/cif/service/impl/CSHuaGuServiceImpl.java

@@ -29,6 +29,9 @@ public class CSHuaGuServiceImpl implements CSHuaGuService {
         body.put("context", message);
         body.put("secret", csHuaGuConf.getSmsApisecret());
         String result = "";
+        
+        log.info("csHuaGu-sms-req:{}", body.toJSONString());
+        
         try {
             result = HttpUtil.createPost(csHuaGuConf.getSmsApiurl())
                     .body(body.toJSONString())

+ 69 - 0
cif-service/src/main/java/com/txz/cif/service/impl/JPushServiceImpl.java

@@ -0,0 +1,69 @@
+package com.txz.cif.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.txz.cif.configurer.jpush.JPushConf;
+import com.txz.cif.dto.jpush.JPushSmsDTO;
+import com.txz.cif.dto.jpush.JPushTemplateDTO;
+import com.txz.cif.service.JPushService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/13
+ */
+@Service
+@Slf4j
+@AllArgsConstructor
+public class JPushServiceImpl implements JPushService {
+    
+    private final JPushConf jPushConf;
+    
+    @Override
+    public boolean sendSms(String mobile, String code) {
+        // {
+        //     "to": "+8618701235678",
+        //     "code": "398210",
+        //     "template": {
+        //         "id": "test-template-1",
+        //         "language": "default",
+        //         "params": {
+        //             "key1": "value1",
+        //             "key2": "value2"
+        //         }
+        //     }
+        // }
+        
+        log.info("开始发送短信--->" + mobile + ",--->" + code);
+        
+        JPushTemplateDTO templateDTO = new JPushTemplateDTO();
+        
+        JPushSmsDTO pushSmsDTO = new JPushSmsDTO();
+        pushSmsDTO.setTo("+" + mobile);
+        pushSmsDTO.setCode(code);
+        pushSmsDTO.setTemplate(templateDTO);
+        
+        log.info("jpush-sms-req:{}", JSONUtil.toJsonStr(pushSmsDTO));
+        
+        String body = HttpUtil.createPost(jPushConf.getReqUrl())
+                .contentType("application/json")
+                .auth(jPushConf.getAuth())
+                .body(JSONUtil.toJsonStr(pushSmsDTO))
+                .execute()
+                .body();
+        
+        log.info("jpush-sms-result:{}", body);
+        // "{"send_channel":"sms","message_id":"1988900596811325440"}"
+        JSONObject resultJson = JSONUtil.parseObj(body);
+        
+        if (ObjectUtil.isNotEmpty(resultJson.get("message_id"))) {
+            return true;
+        }
+        return false;
+    }
+}

+ 8 - 3
cif-service/src/main/java/com/txz/cif/service/impl/RechargeRecordServiceImpl.java

@@ -4,14 +4,16 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateUtil;
 import com.txz.cif.core.AbstractService;
 import com.txz.cif.dao.RechargeRecordMapper;
+import com.txz.cif.dubbo.client.OperatingConfigDubboServiceClient;
 import com.txz.cif.model.RechargeRecord;
 import com.txz.cif.param.RechargeParam;
-import com.txz.cif.service.AccountService;
 import com.txz.cif.service.FlowService;
 import com.txz.cif.service.RechargeRecordService;
 import com.txz.cif.web.bo.RechargeRecordBO;
 import com.txz.cif.web.para.RecordParam;
 import com.txz.cif.web.vo.ListVO;
+import com.txz.operating.dto.ConfigDTO;
+import com.txz.operating.result.Result;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import tk.mybatis.mapper.entity.Condition;
@@ -37,12 +39,13 @@ public class RechargeRecordServiceImpl extends AbstractService<RechargeRecord> i
     private FlowService flowService;
     
     @Resource
-    private AccountService accountService;
+    private OperatingConfigDubboServiceClient operatingConfigDubboServiceClient;
     
     @Override
     public void success(RechargeRecord record) {
         update(RechargeRecord.builder()
                 .id(record.getId())
+                .realAmount(record.getRealAmount())
                 .successTime(DateUtil.date())
                 .status(2)
                 .build());
@@ -65,7 +68,9 @@ public class RechargeRecordServiceImpl extends AbstractService<RechargeRecord> i
     
     @Override
     public void closeRecharge() {
-        Date thirtyMinutesAgo = DateUtil.offsetMinute(new Date(), -30);
+        Result<ConfigDTO> rechargeOrderClosingTimeR = operatingConfigDubboServiceClient.getConfigByCode("recharge_order_closing_time");
+        int rechargeOrderClosingTime = Integer.parseInt(rechargeOrderClosingTimeR.getData().getValueInfo());
+        Date thirtyMinutesAgo = DateUtil.offsetMinute(new Date(), -rechargeOrderClosingTime);
         Condition condition = new Condition(RechargeRecord.class);
         Example.Criteria criteria = condition.createCriteria();
         criteria.andEqualTo("status", 1);

+ 10 - 5
cif-service/src/main/java/com/txz/cif/service/impl/RedEnvelopeServiceImpl.java

@@ -4,7 +4,6 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONObject;
-import com.github.pagehelper.PageHelper;
 import com.txz.cif.constants.MyConstants;
 import com.txz.cif.core.AbstractService;
 import com.txz.cif.dao.RedEnvelopeMapper;
@@ -110,12 +109,18 @@ public class RedEnvelopeServiceImpl extends AbstractService<RedEnvelope> impleme
     
     @Override
     public List<UserTopBo> top(Integer type, Integer page, Integer size) {
-        PageHelper.startPage(page, size);
         HashMap<String, Object> map = new HashMap<>();
-        map.put("page", page);
-        map.put("size", size);
+        // map.put("page", page);
+        // map.put("size", size);
         map.put("startTime", DateUtil.offsetDay(DateUtil.date(), -8));
-        return cRedEnvelopeMapper.top(map);
+        List<UserTopBo> allResults = cRedEnvelopeMapper.top(map);
+        // 手动分页
+        int fromIndex = (page - 1) * size;
+        int toIndex = Math.min(fromIndex + size, allResults.size());
+        if (fromIndex > allResults.size()) {
+            return new ArrayList<>(); // 返回空列表而不是null
+        }
+        return allResults.subList(fromIndex, toIndex);
     }
     
     @Override

+ 153 - 0
cif-service/src/main/java/com/txz/cif/service/impl/TecrmServiceImpl.java

@@ -0,0 +1,153 @@
+package com.txz.cif.service.impl;
+
+import cn.hutool.http.HttpUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.txz.cif.configurer.TecrmConf;
+import com.txz.cif.service.TecrmService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.security.MessageDigest;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/17
+ */
+@Service
+@Slf4j
+@AllArgsConstructor
+public class TecrmServiceImpl implements TecrmService {
+    
+    private static final String smsUrl = "/backend/msg-channel/v1/external/send-otp";
+    
+    private final TecrmConf tecrmConf;
+    
+    @Override
+    public boolean sendSms(String mobile, String code) {
+        log.info("开始发送短信--->" + mobile + ",--->" + code);
+        
+        try {
+            // 生成签名参数
+            Map<String, String> signParams = generateSignature(tecrmConf.getAppId(), tecrmConf.getAppKey());
+            
+            // 构建请求URL
+            String url = tecrmConf.getDomain() + smsUrl;
+            
+            // 构建请求体
+            JSONObject requestBody = new JSONObject();
+            requestBody.put("cid", tecrmConf.getCid());
+            requestBody.put("phone_number", mobile);
+            requestBody.put("otp", code);
+            requestBody.put("template_code", tecrmConf.getTemplateCode());
+            
+            log.info("tecrm-sms-body:{}", JSONUtil.toJsonStr(requestBody));
+            
+            // 构建完整URL(包含查询参数)
+            String fullUrl = String.format("%s?timestamp=%s&nonce=%s&appid=%s&signature=%s",
+                    url,
+                    signParams.get("timestamp"),
+                    signParams.get("nonce"),
+                    signParams.get("appid"),
+                    signParams.get("signature"));
+            
+            // 发送HTTP请求
+            String result = HttpUtil.createPost(fullUrl)
+                    .body(JSONUtil.toJsonStr(requestBody))
+                    .contentType("application/json")
+                    .execute()
+                    .body();
+            
+            log.info("tecrm-sms-result:{}", result);
+            
+            // 解析响应结果
+            JSONObject resultJson = JSONUtil.parseObj(result);
+            
+            // 根据API响应格式判断成功条件
+            // 成功条件:code为0且data.ok为true
+            if (resultJson.getInt("code", -1) == 0) {
+                JSONObject data = resultJson.getJSONObject("data");
+                if (data != null && data.getBool("ok", false)) {
+                    log.info("发送短信成功");
+                    return true;
+                }
+            }
+            
+            // 记录失败原因
+            String message = resultJson.getStr("message", "未知错误");
+            log.error("发送短信失败,code: {}, message: {}", resultJson.getInt("code"), message);
+            return false;
+        } catch (Exception e) {
+            log.error("发送短信异常", e);
+            return false;
+        }
+    }
+    
+    /**
+     * 生成签名
+     *
+     * @param appid  应用ID
+     * @param appkey 应用密钥
+     *
+     * @return 包含签名信息的Map
+     */
+    private Map<String, String> generateSignature(String appid, String appkey) {
+        long timestamp = System.currentTimeMillis() / 1000;
+        String nonce = generateNonce(6);
+        
+        // 构建签名字符串: timestamp:nonce:appkey
+        String signString = timestamp + ":" + nonce + ":" + appkey;
+        
+        // SHA1加密
+        String signature = sha1(signString);
+        
+        Map<String, String> signMap = new HashMap<>();
+        signMap.put("timestamp", String.valueOf(timestamp));
+        signMap.put("nonce", nonce);
+        signMap.put("appid", appid);
+        signMap.put("signature", signature);
+        
+        return signMap;
+    }
+    
+    /**
+     * SHA1加密
+     */
+    private String sha1(String input) {
+        try {
+            MessageDigest md = MessageDigest.getInstance("SHA-1");
+            byte[] digest = md.digest(input.getBytes("UTF-8"));
+            StringBuilder sb = new StringBuilder();
+            for (byte b : digest) {
+                sb.append(String.format("%02x", b));
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            throw new RuntimeException("SHA-1算法不可用", e);
+        }
+    }
+    
+    /**
+     * 生成指定长度的随机字符串(大小写字母)
+     */
+    private String generateNonce(int length) {
+        Random random = new Random(System.currentTimeMillis());
+        StringBuilder sb = new StringBuilder();
+        
+        for (int i = 0; i < length; i++) {
+            int num = random.nextInt(57) + 65; // 65-122范围
+            // 跳过91-96之间的字符(大写字母Z和小写字母a之间的符号)
+            while (num > 90 && num < 97) {
+                num = random.nextInt(57) + 65;
+            }
+            sb.append((char) num);
+        }
+        
+        return sb.toString();
+    }
+}

+ 29 - 8
cif-service/src/main/java/com/txz/cif/service/impl/UserServiceImpl.java

@@ -14,9 +14,7 @@ import com.txz.cif.dto.UserDTO;
 import com.txz.cif.dubbo.client.OperatingConfigDubboServiceClient;
 import com.txz.cif.model.Account;
 import com.txz.cif.model.User;
-import com.txz.cif.service.AccountService;
-import com.txz.cif.service.CSHuaGuService;
-import com.txz.cif.service.UserService;
+import com.txz.cif.service.*;
 import com.txz.cif.web.para.UserAddParam;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -53,13 +51,19 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
     //    private OperatorService operatorService;
     
     @Resource
-    private OperatingConfigDubboServiceClient messageDubboServiceClient;
+    private OperatingConfigDubboServiceClient operatingConfigDubboServiceClient;
     
     private static final String SMS_MESSAGE = "Your verification code is %s .It will expire in 5 minutes.Do not share it with anyone";
     
     @Resource
     private CSHuaGuService csHuaGuService;
     
+    @Resource
+    private JPushService jPushService;
+    
+    @Resource
+    private TecrmService tecrmService;
+    
     @Override
     public Boolean checkMail(String email) {
         User user = findBy("email", email);
@@ -85,11 +89,28 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
             return Result.success();
         }
         String code = RandomUtil.randomNumbers(6);
-        if (csHuaGuService.sendSmsValidCode(phoneNo, String.format(SMS_MESSAGE, code))) {
-            redisClient.set(key, code, 60 * 5);
-            return Result.fail();
+        String smsType = operatingConfigDubboServiceClient.getConfigByCode("sms_type").getData().getValueInfo();
+        switch (smsType) {
+            case "jpush":
+                if (jPushService.sendSms(phoneNo, code)) {
+                    redisClient.set(key, code, 60 * 5);
+                    return Result.success();
+                }
+                return Result.fail();
+            case "tecrm":
+                if (tecrmService.sendSms(phoneNo, code)) {
+                    redisClient.set(key, code, 60 * 5);
+                    return Result.success();
+                }
+                return Result.fail();
+            default:
+            case "cshuagu":
+                if (csHuaGuService.sendSmsValidCode(phoneNo, String.format(SMS_MESSAGE, code))) {
+                    redisClient.set(key, code, 60 * 5);
+                    return Result.success();
+                }
+                return Result.fail();
         }
-        return Result.success();
     }
     
     @Override

+ 54 - 29
cif-service/src/main/java/com/txz/cif/service/impl/WithdrawRecordServiceImpl.java

@@ -32,8 +32,10 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.math.BigDecimal;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.List;
 
 
 /**
@@ -43,33 +45,33 @@ import java.util.HashMap;
 @Slf4j
 @Transactional
 public class WithdrawRecordServiceImpl extends AbstractService<WithdrawRecord> implements WithdrawRecordService {
-    
+
     @Resource
     private WithdrawRecordMapper withdrawRecordMapper;
     @Resource
     private AccountService accountService;
-    
+
     @Resource
     private FlowService flowService;
-    
+
     @Resource
     private PaymentChannelService paymentChannelService;
-    
+
     @Resource
     private SequenceService sequenceService;
-    
+
     @Resource
     private UserService userService;
-    
+
     @Resource
     private TFPayService tfPayService;
-    
+
     @Resource
     private BizLogService bizLogService;
-    
+
     @Resource
     private LockTemplate lockTemplate;
-    
+
     @Override
     public void add(WithdrawRecord withdrawRecord) {
         saveUseGeneratedKeys(withdrawRecord);
@@ -87,7 +89,7 @@ public class WithdrawRecordServiceImpl extends AbstractService<WithdrawRecord> i
                 .build());
         update(WithdrawRecord.builder().id(withdrawRecord.getId()).freezeId(Long.valueOf(freeze.getData().toString())).build());
     }
-    
+
     @Override
     public void review(WithdrawRecord w, Integer status, String review, Long channelId, String userName) {
         // 同意提现
@@ -100,11 +102,12 @@ public class WithdrawRecordServiceImpl extends AbstractService<WithdrawRecord> i
                 User user = userService.findById(w.getUserId());
                 DateTime now = DateUtil.date();
                 String thirdOrderNo = sequenceService.genSerialNumber("withdraw_rule", null);
-                
+
                 PaymentChannel paymentChannel = paymentChannelService.findById(channelId);
                 if (ObjectUtil.isEmpty(paymentChannel)) {
                     throw new ServiceException(LocalUtil.get("withdrawal.channel.does.not.exist"));
                 }
+                List<BizLog> bizLogList = new ArrayList<>();
                 switch (paymentChannel.getChannelName()) {
                     case "TFPAY":
 //                        Map<String, Object> payMentChannelMap = TFPayUtil.convertObjectToMap(paymentChannel);
@@ -125,20 +128,6 @@ public class WithdrawRecordServiceImpl extends AbstractService<WithdrawRecord> i
                                         .payBankcode(w.getBank().toLowerCase())
                                         .build()
                                 , paymentChannel.getSecretKey());
-                        try {
-                            // 新增日志
-                            bizLogService.save(BizLog.builder()
-                                    .bizType(2)
-                                    .bizNo(thirdOrderNo)
-                                    .type(4)
-                                    .receiveMessage(bizLog.getReceiveMessage())
-                                    .sendMessage(bizLog.getSendMessage())
-                                    .createTime(now)
-                                    .createUser(userName)
-                                    .memo("提交提现申请").build());
-                        } catch (Exception e) {
-                            log.error("新增提现提交订单日志失败", e);
-                        }
                         JSONObject resultJson;
                         try {
                             resultJson = JSONUtil.parseObj(bizLog.getReceiveMessage());
@@ -146,19 +135,55 @@ public class WithdrawRecordServiceImpl extends AbstractService<WithdrawRecord> i
                             log.error("提现失败三方返回-->" + bizLog);
                             throw new ServiceException(LocalUtil.get("withdrawal.failed"));
                         }
+                      bizLogList.add(BizLog.builder()
+                        .bizType(2)
+                        .bizNo(w.getOrderNo())
+                        .thirdOrderNo(thirdOrderNo)
+                        .type(7)
+                        .receiveMessage(bizLog.getReceiveMessage())
+                        .sendMessage(bizLog.getSendMessage())
+                        .createTime(now)
+                        .createUser(userName)
+                        .memo(resultJson.getStr("msg")).build());
                         if (!resultJson.getStr("status").equals("200")) {
                             log.error("提现失败--->" + resultJson.getStr("msg"));
-                            throw new RuntimeException("提现失败--->" + resultJson.getStr("msg"));
                         }
                         break;
                     default:
                         throw new ServiceException(LocalUtil.get("this.channel.is.not.supported.temporarily"));
                 }
+                try {
+                  // 新增日志
+                  bizLogList.add(BizLog.builder()
+                    .bizType(2)
+                    .bizNo(w.getOrderNo())
+                    .thirdOrderNo(thirdOrderNo)
+                    .type(5)
+                    .createTime(now)
+                    .createUser(userName)
+                    .memo(review).build());
+                  bizLogService.save(bizLogList);
+                } catch (Exception e) {
+                  log.error("新增提现提交订单日志失败", e);
+                }
                 this.update(WithdrawRecord.builder().id(w.getId()).channel(paymentChannel.getChannelName()).review(review).status(status).updateUser(userName).thirdOrderNo(thirdOrderNo).build());
             } finally {
                 lockTemplate.releaseLock(lockInfo);
             }
             return;
+        } else {
+          try {
+            // 新增日志
+            bizLogService.save(BizLog.builder()
+              .bizType(2)
+              .bizNo(w.getOrderNo())
+              .type(6)
+              .createTime(DateUtil.date())
+              .createUser(userName)
+              .memo(review).build());
+          } catch (Exception e) {
+            log.error("新增提现提交订单日志失败", e);
+          }
         }
         // 解冻
         if (w.getFreezeId() != null) {
@@ -198,7 +223,7 @@ public class WithdrawRecordServiceImpl extends AbstractService<WithdrawRecord> i
                 .build());
         update(WithdrawRecord.builder().id(record.getId()).successTime(successTime).status(4).build());
     }
-    
+
     @Override
     public void fail(WithdrawRecord record) {
         if (record.getFreezeId() != null) {
@@ -206,12 +231,12 @@ public class WithdrawRecordServiceImpl extends AbstractService<WithdrawRecord> i
         }
         update(WithdrawRecord.builder().id(record.getId()).status(5).build());
     }
-    
+
     @Override
     public Integer countByUserId(HashMap map) {
         return withdrawRecordMapper.countByUserId(map);
     }
-    
+
     @Override
     public BigDecimal sumByStatus(HashMap map) {
         return withdrawRecordMapper.sumByStatus(map);

+ 97 - 103
cif-service/src/main/java/com/txz/cif/web/RedEnvelopeApiController.java

@@ -1,28 +1,24 @@
 package com.txz.cif.web;
+
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.json.JSONUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
 import com.txz.cif.core.*;
 import com.txz.cif.core.cache.CacheKey;
 import com.txz.cif.core.cache.CacheType;
 import com.txz.cif.model.RedEnvelope;
 import com.txz.cif.model.User;
 import com.txz.cif.service.RedEnvelopeService;
-
-import com.github.pagehelper.PageHelper;
-import com.github.pagehelper.PageInfo;
 import com.txz.cif.service.UserService;
 import com.txz.cif.web.bo.TopBO;
-import com.txz.cif.web.bo.UserDetailBo;
 import com.txz.cif.web.bo.UserTopBo;
 import com.txz.cif.web.para.RedEnvelopeListParam;
-import com.txz.cif.web.para.RedEnvelopeParam;
-import org.springframework.web.bind.annotation.*;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.txz.core.ServiceException;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.annotation.*;
 import tk.mybatis.mapper.entity.Condition;
 import tk.mybatis.mapper.entity.Example.Criteria;
 
@@ -33,110 +29,108 @@ import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
-import org.apache.commons.lang.StringUtils;
-
 /**
-* Created by CodeGenerator on 2025/07/15.
-*/
+ * Created by CodeGenerator on 2025/07/15.
+ */
 @Api(tags = "[api]redEnvelope管理")
 @RestController
 @RequestMapping("/api/red/envelope")
 public class RedEnvelopeApiController {
-
-	private static Logger log = LoggerFactory.getLogger(RedEnvelopeApiController.class);
-
+    
+    private static Logger log = LoggerFactory.getLogger(RedEnvelopeApiController.class);
+    
     @Resource
     private RedEnvelopeService redEnvelopeService;
-
-	@Resource
-	private AuthService authService;
-
-	@Resource
-	private RedisUtil redisUtil;
-
-	@Resource
-	private UserService userService;
-
+    
+    @Resource
+    private AuthService authService;
+    
+    @Resource
+    private RedisUtil redisUtil;
+    
+    @Resource
+    private UserService userService;
+    
     @PostMapping("/list")
-	@ApiOperation(value = "redEnvelope获取列表",httpMethod = "POST")
+    @ApiOperation(value = "redEnvelope获取列表", httpMethod = "POST")
     public Result<List<RedEnvelope>> list(@RequestBody RedEnvelopeListParam param, HttpServletRequest request) {
-		Long userId = authService.getTokenUserId(request);
-		if (userId == null ){
-			return ResultGenerator.genFailResult(ResultCode.OAUTH_INVALID_ACCESS_TOKEN);
-		}
-
-		PageHelper.startPage(param.getPage(), param.getSize());
-
+        Long userId = authService.getTokenUserId(request);
+        if (userId == null) {
+            return ResultGenerator.genFailResult(ResultCode.OAUTH_INVALID_ACCESS_TOKEN);
+        }
+        
+        PageHelper.startPage(param.getPage(), param.getSize());
+        
         Condition condition = new Condition(RedEnvelope.class);
         Criteria criteria = condition.createCriteria();
-		criteria.andEqualTo("userId",userId);
-		if (param.getType() == 1 ){
-			Date todayStart = DateUtil.beginOfDay(DateUtil.date());
-			criteria.andGreaterThanOrEqualTo("createTime", todayStart);
-		} else if (param.getType() == 2){
-			Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday());
-			Date todayStart = DateUtil.beginOfDay(DateUtil.date());
-			criteria.andBetween("createTime", yesterdayStart,todayStart);
-		} else if (param.getType() == 3){
-			Date start = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.date(),-7));
-			criteria.andGreaterThanOrEqualTo("createTime",start);
-		} else if (param.getType() == 4){
-			Date start = DateUtil.beginOfMonth(DateUtil.date());
-			criteria.andGreaterThanOrEqualTo("createTime",start);
-		} else if (param.getType() == 5){
-			Date start = DateUtil.beginOfYear(DateUtil.date());
-			criteria.andGreaterThanOrEqualTo("createTime",start);
-		}
-		PageInfo pageInfo = null;
-		try {
-			condition.setOrderByClause("create_time desc");
-    		 List<RedEnvelope> list = redEnvelopeService.findByCondition(condition);
-    		 pageInfo = new PageInfo(list);
-		} catch (Exception e) {
-			log.error("查询对象操作异常e:{}",e);
-			return ResultGenerator.genFailResult(ResultCode.INTERNAL_SERVER_ERROR);
-		}
+        criteria.andEqualTo("userId", userId);
+        if (param.getType() == 1) {
+            Date todayStart = DateUtil.beginOfDay(DateUtil.date());
+            criteria.andGreaterThanOrEqualTo("createTime", todayStart);
+        } else if (param.getType() == 2) {
+            Date yesterdayStart = DateUtil.beginOfDay(DateUtil.yesterday());
+            Date todayStart = DateUtil.beginOfDay(DateUtil.date());
+            criteria.andBetween("createTime", yesterdayStart, todayStart);
+        } else if (param.getType() == 3) {
+            Date start = DateUtil.beginOfDay(DateUtil.offsetDay(DateUtil.date(), -7));
+            criteria.andGreaterThanOrEqualTo("createTime", start);
+        } else if (param.getType() == 4) {
+            Date start = DateUtil.beginOfMonth(DateUtil.date());
+            criteria.andGreaterThanOrEqualTo("createTime", start);
+        } else if (param.getType() == 5) {
+            Date start = DateUtil.beginOfYear(DateUtil.date());
+            criteria.andGreaterThanOrEqualTo("createTime", start);
+        }
+        PageInfo pageInfo = null;
+        try {
+            condition.setOrderByClause("create_time desc");
+            List<RedEnvelope> list = redEnvelopeService.findByCondition(condition);
+            pageInfo = new PageInfo(list);
+        } catch (Exception e) {
+            log.error("查询对象操作异常e:{}", e);
+            return ResultGenerator.genFailResult(ResultCode.INTERNAL_SERVER_ERROR);
+        }
         return ResultGenerator.genSuccessResult(pageInfo);
     }
-
-
-	@GetMapping("/top")
-	@ApiOperation(value = "排行榜type 1 7天收益排行",httpMethod = "GET")
-	public Result<TopBO> top(@RequestParam(defaultValue = "1") Integer type, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) {
-		String key = CacheKey.generateKey(CacheType.Top4,type+":"+page+":"+size).toString();
-		Object o = redisUtil.get(key);
-		if (o != null){
-			return ResultGenerator.genSuccessResult(JSONUtil.toBean(o.toString(),TopBO.class));
-		}
-		List<UserTopBo> tops= redEnvelopeService.top(type,page,size);
-		PageInfo pageInfo = new PageInfo(tops);
-		TopBO bo = new TopBO();
-		pageInfo.setList(tops.stream().map(e->{
-			User user = userService.findById(e.getUserId());
-			if (user != null){
-				e.setHeadPic(user.getHeadPic());
-				e.setNickname(user.getNickname());
-				e.setName(user.getName());
-				e.setVipLevel(user.getVipLevel());
-				e.setUserNo(user.getUserNo());
-			}
-			Condition c = new Condition(User.class);
-			c.createCriteria().andEqualTo("pid",e.getUserId());
-			Integer invited = userService.countByCondition(c);
-			if (invited != null){
-				e.setInviteNum(invited);
-			}
-			c = new Condition(User.class);
-			c.createCriteria().andEqualTo("ppid",e.getUserId());
-			Integer invited2 = userService.countByCondition(c);
-			if (invited != null && invited2 != null){
-				e.setTeamNum(invited+invited2);
-			}
-			return e;
-		}).collect(Collectors.toList()));
-		bo.setUsers(pageInfo);
-		bo.setUpdateTime(DateUtil.date());
-		redisUtil.set(key,JSONUtil.toJsonStr(bo),5, TimeUnit.MINUTES);
-		return ResultGenerator.genSuccessResult(bo);
-	}
+    
+    
+    @GetMapping("/top")
+    @ApiOperation(value = "排行榜type 1 7天收益排行", httpMethod = "GET")
+    public Result<TopBO> top(@RequestParam(defaultValue = "1") Integer type, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) {
+        String key = CacheKey.generateKey(CacheType.Top4, type + ":" + page + ":" + size).toString();
+        Object o = redisUtil.get(key);
+        if (o != null) {
+            return ResultGenerator.genSuccessResult(JSONUtil.toBean(o.toString(), TopBO.class));
+        }
+        List<UserTopBo> tops = redEnvelopeService.top(type, page, size);
+        PageInfo pageInfo = new PageInfo(tops);
+        TopBO bo = new TopBO();
+        pageInfo.setList(tops.stream().map(e -> {
+            User user = userService.findById(e.getUserId());
+            if (user != null) {
+                e.setHeadPic(user.getHeadPic());
+                e.setNickname(user.getNickname());
+                e.setName(user.getName());
+                e.setVipLevel(user.getVipLevel());
+                e.setUserNo(user.getUserNo());
+            }
+            Condition c = new Condition(User.class);
+            c.createCriteria().andEqualTo("pid", e.getUserId());
+            Integer invited = userService.countByCondition(c);
+            if (invited != null) {
+                e.setInviteNum(invited);
+            }
+            c = new Condition(User.class);
+            c.createCriteria().andEqualTo("ppid", e.getUserId());
+            Integer invited2 = userService.countByCondition(c);
+            if (invited != null && invited2 != null) {
+                e.setTeamNum(invited + invited2);
+            }
+            return e;
+        }).collect(Collectors.toList()));
+        bo.setUsers(pageInfo);
+        bo.setUpdateTime(DateUtil.date());
+        redisUtil.set(key, JSONUtil.toJsonStr(bo), 5, TimeUnit.MINUTES);
+        return ResultGenerator.genSuccessResult(bo);
+    }
 }

+ 37 - 28
cif-service/src/main/java/com/txz/cif/web/WithdrawRecordApiController.java

@@ -53,40 +53,40 @@ import static com.txz.cif.core.AbstractApiController.X_CLIENT_TOKEN;
 @RestController
 @RequestMapping("/api/withdraw/record")
 public class WithdrawRecordApiController {
-    
+
     private static Logger log = LoggerFactory.getLogger(WithdrawRecordApiController.class);
-    
+
     @Resource
     private WithdrawRecordService withdrawRecordService;
-    
+
     @Resource
     private SequenceService sequenceService;
-    
+
     @Resource
     private AuthService authService;
-    
+
     @Resource
     private AccountService accountService;
-    
+
     @Resource
     private BizLogService bizLogService;
-    
+
     @Resource
     private PaymentChannelService paymentChannelService;
-    
+
     @Resource
     private UserService userService;
-    
+
     @Resource
     private LockTemplate lockTemplate;
-    
+
     @Resource
     private OperatingConfigDubboServiceClient operatingConfigDubboServiceClient;
-    
-    
+
+
     @Resource
     private NoticeDubboServiceClient noticeDubboServiceClient;
-    
+
     @PostMapping("/add")
     @ApiOperation(value = "新增提现订单", httpMethod = "POST")
     public Result add(@RequestBody WithdrawParam param, @RequestHeader(value = X_CLIENT_TOKEN, required = false) String token) {
@@ -95,7 +95,7 @@ public class WithdrawRecordApiController {
         }
         try {
             Triple<Boolean, String, Claims> result = authService.verifyToken(token);
-            
+
             if (!result.getLeft()) {
                 // token无效
                 String errorMsg = result.getMiddle();
@@ -104,7 +104,7 @@ public class WithdrawRecordApiController {
             }
             Claims claims = result.getRight();
             Long userId = Long.valueOf(claims.get("userId").toString());
-            
+
             User user = userService.findById(userId);
             if (user == null) {
                 return ResultGenerator.genFailResult(ResultCode.USER_IS_NULL);
@@ -149,7 +149,7 @@ public class WithdrawRecordApiController {
             com.txz.operating.result.Result<ConfigDTO> openRedEnvelopeRate = operatingConfigDubboServiceClient.getConfigByCode(key);
             String rate = openRedEnvelopeRate.getData().getValueInfo();
             BigDecimal fee = param.getAmount().multiply(new BigDecimal(rate)).divide(BigDecimal.valueOf(100), 2, RoundingMode.DOWN);
-            
+
             Account account = accountService.getAccount(userId, param.getAccountType());
             if (account == null) {
                 return ResultGenerator.genFailResult(ResultCode.ACCOUNT_IS_NULL);
@@ -157,9 +157,9 @@ public class WithdrawRecordApiController {
             if (account.getEffectiveBalance().compareTo(param.getAmount().add(fee)) < 0) {
                 return ResultGenerator.genFailResult(ResultCode.EFFECTIVE_BALANCE_IS_INSUFFICIENT);
             }
-            
+
             String orderNo = sequenceService.genSerialNumber("withdraw_rule", null);
-            
+
             WithdrawRecord withdrawRecord = new WithdrawRecord();
             withdrawRecord.setOrderNo(orderNo);
             withdrawRecord.setStatus(1);
@@ -177,15 +177,23 @@ public class WithdrawRecordApiController {
             withdrawRecord.setAmount(param.getAmount());
             withdrawRecord.setCreateTime(DateUtil.date());
             withdrawRecordService.add(withdrawRecord);
+            // 新增日志
+            bizLogService.save(BizLog.builder()
+              .bizType(2)
+              .bizNo(orderNo)
+              .type(4)
+              .createTime(DateUtil.date())
+              .createUser(user.getName())
+              .memo("提交提现申请").build());
             return ResultGenerator.genSuccessResult(withdrawRecord);
         } catch (Exception e) {
             log.error("新增对象操作异常e:{}", e);
             return ResultGenerator.genFailResult(ResultCode.INTERNAL_SERVER_ERROR);
         }
-        
+
     }
-    
-    
+
+
     @PostMapping("/list")
     @ApiOperation(value = "withdrawRecord获取列表", httpMethod = "POST")
     public Result<List<WithdrawRecord>> list(@RequestBody RecordParam param, HttpServletRequest request) {
@@ -194,7 +202,7 @@ public class WithdrawRecordApiController {
             ResultGenerator.genFailResult(ResultCode.OAUTH_INVALID_ACCESS_TOKEN);
         }
         PageHelper.startPage(param.getPage(), param.getSize());
-        
+
         Condition condition = new Condition(WithdrawRecord.class);
         Criteria criteria = condition.createCriteria();
         criteria.andEqualTo("userId", userId);
@@ -238,7 +246,7 @@ public class WithdrawRecordApiController {
         }
         return ResultGenerator.genSuccessResult(pageInfo);
     }
-    
+
     /**
      * tfpay提现通知
      */
@@ -265,7 +273,7 @@ public class WithdrawRecordApiController {
                 log.error("签名校验失败");
                 return "FAIL";
             }
-            
+
             Condition condition = new Condition(WithdrawRecord.class);
             Example.Criteria criteria = condition.createCriteria();
             criteria.andEqualTo("thirdOrderNo", dto.getOrderid());
@@ -275,7 +283,7 @@ public class WithdrawRecordApiController {
                 log.error("提现订单不存在");
                 return "FAIL";
             }
-            
+
             // //TODO 回调成功
             // JSONObject json = JSONUtil.parseObj(data);
             // String orderNo = json.getStr("orderNo");
@@ -318,7 +326,8 @@ public class WithdrawRecordApiController {
                 // 新增充值回调日志
                 bizLogService.save(BizLog.builder()
                         .bizType(2)
-                        .bizNo(dto.getOrderid())
+                        .bizNo(record.getOrderNo())
+                        .thirdOrderNo(dto.getOrderid())
                         .type(type)
                         .receiveMessage(dto.toString())
                         .createTime(DateUtil.date())
@@ -327,7 +336,7 @@ public class WithdrawRecordApiController {
             } catch (Exception e) {
                 log.error("新增充值回调日志失败", e);
                 // }
-                
+
             }
             try {
                 noticeDubboServiceClient.addMoneyNotice(ne, record.getUserId());
@@ -339,5 +348,5 @@ public class WithdrawRecordApiController {
             lockTemplate.releaseLock(lockInfo);
         }
     }
-    
+
 }

+ 25 - 19
cif-service/src/main/java/com/txz/cif/web/bo/UserBo2.java

@@ -21,61 +21,67 @@ public class UserBo2 {
      */
     @ApiModelProperty(value = "用户id")
     private Long id;
-    
+
     /**
      * 用户号
      */
     private String userNo;
-    
+
     @ApiModelProperty("名称")
     private String nickname;
-    
+
     @ApiModelProperty("名称")
     private String name;
-    
+
     @ApiModelProperty("头像")
     private String headPic;
-    
+
     @ApiModelProperty(value = "状态  1正常 2禁止提现 3禁止登录 4禁止下单")
     private Byte status;
-    
+
     private String phoneNo;
-    
+
     /**
      * token
      */
     @ApiModelProperty(value = "vip")
     private Integer vipLevel;
-    
+
     @ApiModelProperty(value = "备注")
     private String memo;
-    
+
     @ApiModelProperty(value = "邀请好友数")
     private Integer inviteNum;
-    
+
     @ApiModelProperty(value = "团队人数")
     private Integer teamNum;
-    
-    
+
+
     @ApiModelProperty(value = "成团数")
     private Integer successGroupNum;
-    
+
     @ApiModelProperty(value = "钱包余额")
     private BigDecimal walletBalance;
-    
+
+    @ApiModelProperty(value="freezeAmount冻结金额")
+    private BigDecimal freezeAmount;
+
+    @ApiModelProperty(value="可用金额")
+    private BigDecimal availableAmount;
+
     @ApiModelProperty(value = "收益余额")
     private BigDecimal earningsBalance;
-    
+
     @ApiModelProperty(value = "createTime创建时间")
     private Date createTime;
-    
+
     @ApiModelProperty(value = "是否有提现权限 1是 2否")
     private Integer hasWithdraw;
-    
+
     @ApiModelProperty(value = "是否有登录权限 1是 2否")
     private Integer hasLogin;
-    
+
     @ApiModelProperty(value = "是否有下单权限 1是 2否")
     private Integer hasOrder;
-    
+
 }

+ 7 - 1
cif-service/src/main/java/com/txz/cif/web/bo/UserDetailBo.java

@@ -75,6 +75,12 @@ public class UserDetailBo {
     @ApiModelProperty(value="钱包余额")
     private BigDecimal walletBalance;
 
+    @ApiModelProperty(value="freezeAmount冻结金额")
+    private BigDecimal freezeAmount;
+
+    @ApiModelProperty(value="可用金额")
+    private BigDecimal availableAmount;
+
     @ApiModelProperty(value="收益余额")
     private BigDecimal earningsBalance;
 
@@ -102,7 +108,7 @@ public class UserDetailBo {
 
     @ApiModelProperty(value="是否有下单权限 1是 2否")
     private Integer hasOrder;
-    
+
     /**
      * 邀请码
      */

+ 24 - 20
cif-service/src/main/java/com/txz/cif/web/mng/UserController.java

@@ -40,26 +40,26 @@ import java.util.stream.Collectors;
 @Api(tags = "[后台]用户管理")
 @Slf4j
 public class UserController extends AbstractApiController {
-    
+
     @Resource
     private RedisUtil redisUtil;
-    
+
     @Resource
     private UserService userService;
-    
+
     @Resource
     private FlowService flowService;
-    
+
     @Resource
     private AccountService accountService;
-    
+
     @Resource
     private RedEnvelopeService redEnvelopeService;
-    
+
     @Resource
     private ConfigMemberService configMemberService;
-    
-    
+
+
     @PostMapping("/update")
     @ApiOperation(value = "更新用户资料", httpMethod = "POST")
     public Result update(@RequestBody UserUpdateParam param) {
@@ -81,7 +81,7 @@ public class UserController extends AbstractApiController {
         userService.update(temp);
         return ResultGenerator.genSuccessResult();
     }
-    
+
     @PostMapping("/list")
     @ApiOperation(value = "获取用户", httpMethod = "POST")
     public Result<List<UserBo2>> list(@RequestBody MyUserParam param) {
@@ -120,7 +120,7 @@ public class UserController extends AbstractApiController {
         if (StrUtil.isNotBlank(param.getEndTime())) {
             criteria.andLessThanOrEqualTo("createTime", param.getEndTime());
         }
-        
+
         PageInfo pageInfo = null;
         try {
             condition.setOrderByClause("create_time desc");
@@ -160,9 +160,11 @@ public class UserController extends AbstractApiController {
                 // 钱包余额
                 Account wallet = accountService.getAccount(u.getId(), 1);
                 bo.setWalletBalance(wallet.getBalance());
+                bo.setFreezeAmount(wallet.getFreezeAmount());
+                bo.setAvailableAmount(wallet.getBalance().subtract(wallet.getFreezeAmount()));
                 Account earnings = accountService.getAccount(u.getId(), 2);
                 bo.setEarningsBalance(earnings.getBalance());
-                
+
                 return bo;
             }).collect(Collectors.toList()));
         } catch (Exception e) {
@@ -171,7 +173,7 @@ public class UserController extends AbstractApiController {
         }
         return ResultGenerator.genSuccessResult(pageInfo);
     }
-    
+
     @GetMapping("/detail")
     @ApiOperation(value = "获取用户详情", httpMethod = "GET")
     public Result<UserDetailBo> list(@RequestParam Long userId) {
@@ -206,15 +208,17 @@ public class UserController extends AbstractApiController {
         // 钱包余额
         Account wallet = accountService.getAccount(u.getId(), 1);
         bo.setWalletBalance(wallet.getBalance());
+        bo.setFreezeAmount(wallet.getFreezeAmount());
+        bo.setAvailableAmount(wallet.getBalance().subtract(wallet.getFreezeAmount()));
         Account earnings = accountService.getAccount(u.getId(), 2);
         bo.setEarningsBalance(earnings.getBalance());
-        
+
         //  可参团数
         ConfigMember member = configMemberService.findBy("level", u.getVipLevel());
         bo.setGroupNum(member.getJoinedGroupsNo());
         BigDecimal totalEarnings = redEnvelopeService.sumWithDay(null, u.getId(), 3);
         bo.setTotalEarnings(totalEarnings);
-        
+
         c = new Condition(Flow.class);
         c.createCriteria().andGreaterThanOrEqualTo("createTime", DateUtil.today())
                 .andIn("bizType", CollUtil.newArrayList(BizTypeEnum.OPEN_GROUP_PAY.getKey(), BizTypeEnum.JOIN_GROUP_PAY.getKey()));
@@ -243,8 +247,8 @@ public class UserController extends AbstractApiController {
         bo.setVipLevel(u.getVipLevel());
         return ResultGenerator.genSuccessResult(bo);
     }
-    
-    
+
+
     @PostMapping("/myUsers")
     @ApiOperation(value = "获取我的下级用户和下下级", httpMethod = "POST")
     public Result<List<User>> myUsers(@RequestBody MyUserParam param) {
@@ -271,7 +275,7 @@ public class UserController extends AbstractApiController {
         if (StrUtil.isNotBlank(param.getEndTime())) {
             criteria.andLessThanOrEqualTo("createTime", param.getEndTime());
         }
-        
+
         PageInfo pageInfo = null;
         try {
             List<User> list = userService.findByCondition(condition);
@@ -286,7 +290,7 @@ public class UserController extends AbstractApiController {
         }
         return ResultGenerator.genSuccessResult(pageInfo);
     }
-    
+
     @GetMapping("/report")
     @ApiOperation(value = "导出", httpMethod = "GET")
     public void report(
@@ -383,6 +387,6 @@ public class UserController extends AbstractApiController {
             log.info("导出结束");
         }
     }
-    
-    
+
+
 }

+ 0 - 1
cif-service/src/main/resources/mapper/RedEnvelopeMapper.xml

@@ -52,7 +52,6 @@
       c_red_envelope
     WHERE
     create_time >= #{startTime}
-    AND user_id = #{userId} <!-- 添加分片键确保查询正确路由 -->
     GROUP BY
     user_id
     ORDER BY

+ 28 - 0
cif-service/src/test/java/com/txz/cif/CifLocalTest.java

@@ -0,0 +1,28 @@
+package com.txz.cif;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import org.junit.jupiter.api.Test;
+
+/**
+ *
+ * @author: MTD®️
+ * @date: 2025/11/13
+ */
+
+public class CifLocalTest {
+    
+    @Test
+    public void test() {
+        
+        // String body = "{\"send_channel\":\"sms\",\"message_id\":\"1988900596811325440\"}";
+        String body = "{\"code\": 3005,\"message\": \"balance not enough\"}";
+        JSONObject resultJson = JSONUtil.parseObj(body);
+        
+        if (ObjectUtil.isNotEmpty(resultJson.get("message_id"))) {
+            System.out.println("success");
+            
+        }
+    }
+}