From c72910d2b90f74d23e770717d80921b4fd064d48 Mon Sep 17 00:00:00 2001
From: 无关风月 <443237572@qq.com>
Date: 星期二, 16 九月 2025 16:24:08 +0800
Subject: [PATCH] 新增用户提现

---
 ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/AppUserBank.java                |   12 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/UserWithdrawServiceImpl.java |   20 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/HttpUtilWithdraw.java       |  492 ++++++++++++++++
 ruoyi-service/ruoyi-account/pom.xml                                                                   |    5 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRequester.java                   |  204 ++++++
 ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserPoint.java                  |    2 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/IUserWithdrawService.java         |   17 
 ruoyi-service/ruoyi-account/src/main/resources/mapper/account/UserWithdrawMapper.xml                  |   31 +
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/WithdrawCallBackDTO.java    |   36 +
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserController.java         |   88 ++
 ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserWithdraw.java               |  110 +++
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/UUIDUtil.java                        |  103 +++
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserBankController.java     |   19 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/dto/SaveWithdrawalAccount.java            |   25 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRespons.java                     |  184 ++++++
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/UserWithdrawController.java    |  169 +++++
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/mapper/UserWithdrawMapper.java            |   24 
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/BankCode.java                        |  217 +++++++
 18 files changed, 1,751 insertions(+), 7 deletions(-)

diff --git a/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/AppUserBank.java b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/AppUserBank.java
index 663845b..2400952 100644
--- a/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/AppUserBank.java
+++ b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/AppUserBank.java
@@ -40,4 +40,16 @@
 	@TableField("bank_number")
 	@ApiModelProperty(value = "银行卡号", required = true)
 	private String bankNumber;
+	/**
+	 * 持卡人名称
+	 */
+	@TableField("user_name")
+	@ApiModelProperty(value = "持卡人名称", required = true)
+	private String userName;
+	@ApiModelProperty("账户类型(对私账户201,对公账户204)")
+	@TableField("receiverAccountType")
+	private Integer receiverAccountType;
+	@ApiModelProperty("收款方开户行编号")
+	@TableField("receiverBankChannelNo")
+	private String receiverBankChannelNo;
 }
diff --git a/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserPoint.java b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserPoint.java
index 6785dc6..754bdac 100644
--- a/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserPoint.java
+++ b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserPoint.java
@@ -39,7 +39,7 @@
     private Long id;
 
     @ApiModelProperty(value = "变动类型(4=兑换商品,12=他人赠送,13=赠与他人,16=取消订单,17=充值 )")
-    @Excel(name = "变动类型", readConverterExp = "4=兑换商品,12=他人赠送,13=赠与他人,16=取消订单,17=充值 ")
+    @Excel(name = "变动类型", readConverterExp = "4=兑换商品,12=他人赠送,13=赠与他人,16=取消订单,17=充值 18=提现 19=提现失败回退积分 ")
     @TableField("type")
     private Integer type;
 
diff --git a/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserWithdraw.java b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserWithdraw.java
new file mode 100644
index 0000000..88fa78f
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/UserWithdraw.java
@@ -0,0 +1,110 @@
+package com.ruoyi.account.api.model;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 用户提现记录
+ * </p>
+ *
+ * @author lingma
+ * @since 2025-04-05
+ */
+@Data
+@TableName("t_user_withdraw")
+@ApiModel(value = "UserWithdraw对象", description = "用户提现记录")
+public class UserWithdraw implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(value = "主键")
+    @TableId("id")
+    private Long id;
+
+
+    @ApiModelProperty(value = "uid")
+    @TableField(exist = false)
+
+    private String uid;
+    @ApiModelProperty(value = "用户id")
+    @TableField("app_user_id")
+    private Long appUserId;
+
+    @ApiModelProperty(value = "提现金额")
+    @TableField("money")
+    private BigDecimal money;
+
+    @ApiModelProperty(value = "消耗积分")
+    @TableField("integral")
+    private Integer integral;
+
+    @ApiModelProperty(value = "审核状态(0=待审核,1=审核通过,2=审核失败)")
+    @TableField("audit_status")
+    private Integer auditStatus;
+
+    @ApiModelProperty(value = "审核人id")
+    @TableField("audit_user_id")
+    private Long auditUserId;
+
+    @ApiModelProperty(value = "审核时间")
+    @TableField("audit_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime auditTime;
+
+    @ApiModelProperty(value = "审核结果")
+    @TableField("audit_msg")
+    private String auditMsg;
+
+    @ApiModelProperty(value = "状态(1=申请中,2=已到账)")
+    @TableField("status")
+    private Integer status;
+
+    @ApiModelProperty(value = "到账时间")
+    @TableField("arrival_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime arrivalTime;
+
+    @ApiModelProperty(value = "删除(0=否,1=是)")
+    @TableField("del_flag")
+    private Integer delFlag;
+
+    @ApiModelProperty(value = "添加时间")
+    @TableField("create_time")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+    @TableField(exist = false)
+    @ApiModelProperty(value = "联系电话")
+    private String phone;
+    @TableField(exist = false)
+    @ApiModelProperty(value = "用户名称")
+    private String name;
+    @ApiModelProperty("收款银行卡号")
+    @TableField("receiverAccountNoEnc")
+    private String receiverAccountNoEnc;
+
+    @ApiModelProperty("收款银行卡持卡人名称")
+    @TableField("receiverNameEnc")
+    private String receiverNameEnc;
+
+    @ApiModelProperty("账户类型(对私账户201,对公账户204)")
+    @TableField("receiverAccountType")
+    private Integer receiverAccountType;
+    @ApiModelProperty(value = "提现单号")
+    @TableField("code")
+    private String code;
+    @ApiModelProperty(value = "提现流水号")
+    @TableField("order_number")
+    private String orderNumber;
+    @ApiModelProperty("收款方开户行编号")
+    @TableField("receiverBankChannelNo")
+    private String receiverBankChannelNo;
+}
diff --git a/ruoyi-service/ruoyi-account/pom.xml b/ruoyi-service/ruoyi-account/pom.xml
index 256bf58..9a57a28 100644
--- a/ruoyi-service/ruoyi-account/pom.xml
+++ b/ruoyi-service/ruoyi-account/pom.xml
@@ -16,6 +16,11 @@
 
     <dependencies>
         <dependency>
+            <groupId>commons-httpclient</groupId>
+            <artifactId>commons-httpclient</artifactId>
+            <version>3.1</version>
+        </dependency>
+        <dependency>
             <groupId>com.ruoyi</groupId>
             <artifactId>ruoyi-api-order</artifactId>
         </dependency>
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserBankController.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserBankController.java
index e242c63..6727744 100644
--- a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserBankController.java
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserBankController.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.ruoyi.account.api.model.AppUserBank;
+import com.ruoyi.account.dto.SaveWithdrawalAccount;
 import com.ruoyi.account.service.AppUserBankService;
 import com.ruoyi.common.core.utils.bean.BeanUtils;
 import com.ruoyi.common.core.web.domain.AjaxResult;
@@ -33,18 +34,24 @@
 	@ResponseBody
 	@PostMapping("/saveAppUserBank")
 	@ApiOperation(value = "保存银行卡")
-	public AjaxResult saveAppUserBank(@RequestBody AppUserBank appUserBank){
+	public AjaxResult saveAppUserBank(@RequestBody SaveWithdrawalAccount appUserBank){
 		LoginUser loginUserApplet = tokenService.getLoginUserApplet();
 
 		AppUserBank bank = appUserBankService.getOne(new LambdaQueryWrapper<AppUserBank>()
 				.eq(AppUserBank::getAppUserId, loginUserApplet.getUserid()));
 		if (bank == null){
-			appUserBank.setAppUserId(loginUserApplet.getUserid());
-			appUserBankService.saveOrUpdate(appUserBank);
+			AppUserBank bank1 = new AppUserBank();
+			bank1.setAppUserId(loginUserApplet.getUserid());
+			bank1.setBankNumber(appUserBank.getReceiverAccountNoEnc());
+			bank1.setUserName(appUserBank.getReceiverNameEnc());
+			bank1.setReceiverAccountType(appUserBank.getReceiverAccountType());
+			appUserBankService.saveOrUpdate(bank1);
 		}else {
-			appUserBank.setId(bank.getId());
-			appUserBank.setAppUserId(bank.getAppUserId());
-			appUserBankService.updateById(appUserBank);
+			bank.setAppUserId(loginUserApplet.getUserid());
+			bank.setBankNumber(appUserBank.getReceiverAccountNoEnc());
+			bank.setUserName(appUserBank.getReceiverNameEnc());
+			bank.setReceiverAccountType(appUserBank.getReceiverAccountType());
+			appUserBankService.updateById(bank);
 		}
 		return AjaxResult.success();
 	}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserController.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserController.java
index 24dab3c..b4ceb83 100644
--- a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserController.java
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/AppUserController.java
@@ -14,11 +14,13 @@
 import com.ruoyi.account.mapper.AppUserMapper;
 import com.ruoyi.account.service.*;
 import com.ruoyi.account.util.ObsUploadUtil;
+import com.ruoyi.account.util.UUIDUtil;
 import com.ruoyi.account.util.weChat.EnvVersion;
 import com.ruoyi.account.util.weChat.WeChatUtil;
 import com.ruoyi.account.vo.*;
 import com.ruoyi.common.core.constant.CacheConstants;
 import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.exception.ServiceException;
 import com.ruoyi.common.core.utils.StringUtils;
 import com.ruoyi.common.core.utils.poi.ExcelUtil;
 import com.ruoyi.common.core.web.controller.BaseController;
@@ -29,6 +31,8 @@
 import com.ruoyi.order.feignClient.RemoteOrderGoodsClient;
 import com.ruoyi.order.model.Order;
 import com.ruoyi.other.api.domain.Shop;
+import com.ruoyi.other.api.domain.ShopBalanceStatement;
+import com.ruoyi.other.api.domain.ShopWithdraw;
 import com.ruoyi.other.api.feignClient.ShopClient;
 import com.ruoyi.system.api.domain.SysConfig;
 import com.ruoyi.system.api.domain.SysUser;
@@ -53,8 +57,10 @@
 import java.io.File;
 import java.io.IOException;
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.temporal.ChronoUnit;
@@ -81,6 +87,12 @@
     @Resource
     private AppUserService appUserService;
     @Resource
+    private IUserWithdrawService userWithdrawService;
+    @Resource
+    private UserPointService userPointService;
+    @Resource
+    private AppUserBankService appUserBankService;
+    @Resource
     private AppUserMapper appUserMapper;
     @Resource
     private ShopClient shopClient;
@@ -106,6 +118,82 @@
     @Value("${file.upload.location}")
     private String filePath;
 
+    @PostMapping("/verifyBankInfo")
+    @ApiOperation(value = "用户提现前校验银行卡信息")
+    public R<Boolean> mobileLogin() {
+        LoginUser loginUserApplet = tokenService.getLoginUserApplet();
+        AppUser appUser = appUserService.getById(loginUserApplet.getUserid());
+        AppUserBank bank = appUserBankService.lambdaQuery().eq(AppUserBank::getAppUserId, appUser.getId()).last("limit 1")
+                .one();
+        if (bank == null){
+            return R.ok(false);
+        }else{
+            return R.ok(true);
+        }
+    }
+    @ApiOperation(value = "提现申请")
+    @GetMapping("/withdrawalApplication")
+    @ResponseBody
+    public R withdrawalApplication(@ApiParam("提现金额") @RequestParam BigDecimal money) {
+        LoginUser loginUser = tokenService.getLoginUserApplet();
+        SysConfig data = sysConfigClient.getInfo(8L).getData();
+        AppUser appUser = appUserService.getById(loginUser.getUserid());
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
+        String code = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5);
+        money=money.setScale(2, BigDecimal.ROUND_HALF_DOWN);
+        if (money.compareTo(BigDecimal.ZERO)==0){
+            throw new ServiceException("提现金额必须大于零");
+        }
+        Integer rate = Integer.valueOf(data.getConfigValue());
+        BigDecimal availablePoint = new BigDecimal(appUser.getAvailablePoint());
+        BigDecimal unMoney = availablePoint.divide(BigDecimal.valueOf(rate), 2, RoundingMode.HALF_DOWN);
+        if (unMoney.compareTo( money)<0){
+            throw new ServiceException("提现金额不能大于可提现金额,当前可提现金额为:"+unMoney);
+        }
+        AppUserBank bank = appUserBankService.lambdaQuery().eq(AppUserBank::getAppUserId, appUser.getId()).last("limit 1")
+                .one();
+        if(bank==null){
+            throw new ServiceException("请完善账户信息后再申请提现!");
+        }
+        if(!org.springframework.util.StringUtils.hasLength(bank.getBankNumber())){
+            throw new ServiceException("请完善银行卡后再申请提现!");
+        }
+        // 增加用户提现积分变动记录
+        UserPoint one = userPointService.lambdaQuery().eq(UserPoint::getAppUserId, appUser.getId())
+                .orderByDesc(UserPoint::getCreateTime).last("limit 1").one();
+        UserWithdraw userWithdraw = new UserWithdraw();
+        userWithdraw.setAppUserId(appUser.getId());
+        userWithdraw.setMoney(money);
+        BigDecimal multiply = money.multiply(BigDecimal.valueOf(rate));
+        appUser.setAvailablePoint(appUser.getAvailablePoint()-multiply.setScale(0, RoundingMode.HALF_UP).intValue());
+        if (multiply.compareTo(new BigDecimal(appUser.getAvailablePoint()))>0){
+            throw new ServiceException("积分不足!");
+        }
+        userWithdraw.setIntegral(Integer.valueOf(multiply.setScale(0, RoundingMode.HALF_UP).toString()));
+        userWithdraw.setAuditStatus(0);
+        userWithdraw.setStatus(1);
+        userWithdraw.setCode(code);
+        userWithdraw.setCreateTime(LocalDateTime.now());
+        if (one.getBalance() - Integer.valueOf(multiply.setScale(0, RoundingMode.HALF_UP).toString())<0){
+            throw new ServiceException("积分不足!");
+        }
+        userWithdraw.setReceiverAccountNoEnc(bank.getBankNumber());
+        userWithdraw.setReceiverNameEnc(bank.getUserName());
+        userWithdraw.setReceiverBankChannelNo(bank.getReceiverBankChannelNo());
+        userWithdraw.setReceiverAccountType(201);
+        userWithdrawService.save(userWithdraw);
+        UserPoint userPoint = new UserPoint();
+        userPoint.setType(18);
+        userPoint.setVariablePoint(Integer.valueOf(multiply.setScale(0, RoundingMode.HALF_UP).toString()));
+        userPoint.setHistoricalPoint(one.getBalance());
+        userPoint.setBalance(one.getBalance() - Integer.valueOf(multiply.setScale(0, RoundingMode.HALF_UP).toString()));
+        userPoint.setCreateTime(LocalDateTime.now());
+        userPoint.setAppUserId(appUser.getId());
+        userPoint.setObjectId(userWithdraw.getId());
+        userPointService.save(userPoint);
+        appUserService.updateById(appUser);
+        return R.ok();
+    }
 
     @ResponseBody
     @PostMapping("/mobileLogin")
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/UserWithdrawController.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/UserWithdrawController.java
new file mode 100644
index 0000000..5b9499f
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/UserWithdrawController.java
@@ -0,0 +1,169 @@
+package com.ruoyi.account.controller;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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.ruoyi.account.api.model.AppUser;
+import com.ruoyi.account.api.model.UserPoint;
+import com.ruoyi.account.api.model.UserWithdraw;
+import com.ruoyi.account.mapper.UserPointMapper;
+import com.ruoyi.account.mapper.UserWithdrawMapper;
+import com.ruoyi.account.service.AppUserService;
+import com.ruoyi.account.service.IUserWithdrawService;
+import com.ruoyi.account.service.UserPointService;
+import com.ruoyi.account.util.BankCode;
+import com.ruoyi.account.util.HttpRequester;
+import com.ruoyi.account.util.HttpRespons;
+import com.ruoyi.account.util.withdraw.HttpUtilWithdraw;
+import com.ruoyi.account.vo.*;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.core.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.web.controller.BaseController;
+import com.ruoyi.common.core.web.page.PageInfo;
+import com.ruoyi.common.security.service.TokenService;
+import com.ruoyi.common.security.utils.SecurityUtils;
+import com.ruoyi.order.feignClient.OrderClient;
+import com.ruoyi.order.model.Order;
+import com.ruoyi.other.api.domain.Shop;
+import com.ruoyi.other.api.domain.ShopBalanceStatement;
+import com.ruoyi.other.api.domain.ShopWithdraw;
+import com.ruoyi.system.api.model.LoginUser;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.YearMonth;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 前端控制器
+ * </p>
+ *
+ * @author luodangjia
+ * @since 2024-11-21
+ */
+@RestController
+@RequestMapping("/user-point")
+@Api(tags = "用户提现列表")
+public class UserWithdrawController extends BaseController {
+    @Resource
+    private IUserWithdrawService userWithdrawService;
+    @Resource
+    private UserPointService userPointService;
+    @Resource
+    private UserWithdrawMapper userWithdrawMapper;
+    @Resource
+    private AppUserService appUserService;
+    @Resource
+    private TokenService tokenService;
+    @GetMapping("/shop/list")
+    @ApiOperation(value = "用户提现申请列表")
+    public R<IPage<UserWithdraw>> shoplist(@ApiParam("页码") @RequestParam Integer pageNum,
+                                           @ApiParam("每一页数据大小") Integer pageSize,
+                                           @ApiParam("用户手机号") String phone,
+                                           @ApiParam("审核状态(0=待审核,1=审核通过,2=审核失败)")Integer auditStatus) {
+        //模糊查询手机号
+        List<Long> appUserIds=new ArrayList<>();
+        if (StringUtils.isNotEmpty(phone)) {
+            QueryWrapper<AppUser> queryWrapper=new QueryWrapper<>();
+            queryWrapper.like(StringUtils.isNotEmpty(phone),"phone", phone);
+            appUserIds=appUserService.list(queryWrapper).stream().map(AppUser::getId).collect(Collectors.toList());
+            if (CollectionUtils.isEmpty(appUserIds)) {
+                return R.ok(new PageInfo<>());
+            }
+        }
+        PageInfo<UserWithdraw> page=new PageInfo<>(pageNum,pageSize);
+        List<UserWithdraw> list =userWithdrawMapper.page(page,appUserIds,auditStatus);
+        for (UserWithdraw userWithdraw : list) {
+            userWithdraw.setUid(userWithdraw.getId().toString());
+        }
+        page.setRecords(list);
+        return R.ok(page);
+    }
+    /**
+     * 审核
+     */
+    @GetMapping("/audit")
+    @ApiOperation("提现审核")
+    public R<Void> audit(@ApiParam("审核状态 1=通过 2=失败") @RequestParam Integer auditstatus,
+                         @ApiParam("提现id") Long id,
+                         @ApiParam("审核失败备注") String auditMsg
+    ) throws IOException {
+        LoginUser loginUser = tokenService.getLoginUser();
+
+        UserWithdraw userWithdraw = userWithdrawService.getById(id);
+        if(0 != userWithdraw.getAuditStatus()){
+            return R.fail("不能重复审核");
+        }
+        AppUser appUser = appUserService.getById(userWithdraw.getAppUserId());
+        if(1 == auditstatus){
+            // 打款
+            String url = "https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?_input_charset=utf-8&" +
+                    "cardNo="+userWithdraw.getReceiverAccountNoEnc()+"&cardBinCheck=true";
+            HashMap<String, String> hashMap = new HashMap<>();
+            HttpRequester hr = new HttpRequester();
+            HttpRespons HP = hr.sendPost(url, hashMap);
+            System.out.println("接收返回参数:" + HP.getContent());
+            com.alibaba.fastjson.JSONObject resPay = com.alibaba.fastjson.JSONObject.parseObject(HP.getContent());
+            System.err.println(resPay);
+            if (resPay.getString("validated")==null){
+                System.err.println("不合法的银行卡号");
+            }
+            String bankCode = resPay.getString("bank");
+            String bankName = BankCode.getBankNameByCode(bankCode); // 返回ABC枚举实例
+            System.err.println(bankName);
+            String withdraw = HttpUtilWithdraw.userWithdraw(userWithdraw, bankName);
+            if (!withdraw.equals("success")){
+                return R.fail("打款失败,原因:"+withdraw);
+            }
+
+            userWithdraw.setStatus(2);
+            userWithdraw.setArrivalTime(LocalDateTime.now());
+            userWithdrawService.updateById(userWithdraw);
+        }
+        if(2 == auditstatus){
+            //审核不通过
+            //回退积分和添加变动明细
+            UserPoint userPoint = new UserPoint();
+            userPoint.setType(19);
+            UserPoint one = userPointService.lambdaQuery().eq(UserPoint::getAppUserId, appUser.getId())
+                    .orderByDesc(UserPoint::getCreateTime).last("limit 1").one();
+            userPoint.setVariablePoint(userWithdraw.getIntegral());
+            userPoint.setHistoricalPoint(one.getBalance());
+            userPoint.setBalance(one.getBalance() + userWithdraw.getIntegral());
+            userPoint.setCreateTime(LocalDateTime.now());
+            userPoint.setAppUserId(appUser.getId());
+            userPoint.setObjectId(userWithdraw.getId());
+            userPointService.save(userPoint);
+            // 回退积分
+            appUser.setAvailablePoint(appUser.getAvailablePoint()+userWithdraw.getIntegral());
+            appUserService.updateById(appUser);
+        }
+        userWithdraw.setAuditStatus(auditstatus);
+        userWithdraw.setAuditUserId(loginUser.getUserid());
+        userWithdraw.setAuditTime(LocalDateTime.now());
+        userWithdraw.setAuditMsg(auditMsg);
+        userWithdrawService.updateById(userWithdraw);
+        return R.ok();
+    }
+}
+
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/dto/SaveWithdrawalAccount.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/dto/SaveWithdrawalAccount.java
new file mode 100644
index 0000000..a42c1ef
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/dto/SaveWithdrawalAccount.java
@@ -0,0 +1,25 @@
+package com.ruoyi.account.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author zhibing.pu
+ * @Date 2025/1/1 11:54
+ */
+@Data
+public class SaveWithdrawalAccount {
+
+	
+	@ApiModelProperty("收款银行卡号")
+	private String receiverAccountNoEnc;
+	
+	@ApiModelProperty("收款银行卡持卡人名称")
+	private String receiverNameEnc;
+	
+	@ApiModelProperty("账户类型(对私账户201,对公账户204)")
+	private Integer receiverAccountType;
+	
+	@ApiModelProperty("收款账户联行号")
+	private String receiverBankChannelNo;
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/mapper/UserWithdrawMapper.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/mapper/UserWithdrawMapper.java
new file mode 100644
index 0000000..561fc14
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/mapper/UserWithdrawMapper.java
@@ -0,0 +1,24 @@
+package com.ruoyi.account.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.account.api.model.UserWithdraw;
+import com.ruoyi.common.core.web.page.PageInfo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 用户提现记录 Mapper 接口
+ * </p>
+ *
+ * @author lingma
+ * @since 2025-04-05
+ */
+@Mapper
+public interface UserWithdrawMapper extends BaseMapper<UserWithdraw> {
+
+    List<UserWithdraw> page(PageInfo<UserWithdraw> page, @Param("appUserIds")List<Long> appUserIds, @Param("auditStatus")Integer auditStatus);
+
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/IUserWithdrawService.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/IUserWithdrawService.java
new file mode 100644
index 0000000..3c34d57
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/IUserWithdrawService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.account.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.account.api.model.UserWithdraw;
+
+/**
+ * <p>
+ * 用户提现记录 服务类
+ * </p>
+ *
+ * @author lingma
+ * @since 2025-04-05
+ */
+public interface IUserWithdrawService extends IService<UserWithdraw> {
+
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/UserWithdrawServiceImpl.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/UserWithdrawServiceImpl.java
new file mode 100644
index 0000000..b673808
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/service/impl/UserWithdrawServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.account.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.account.api.model.UserWithdraw;
+import com.ruoyi.account.mapper.UserWithdrawMapper;
+import com.ruoyi.account.service.IUserWithdrawService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 用户提现记录 服务实现类
+ * </p>
+ *
+ * @author lingma
+ * @since 2025-04-05
+ */
+@Service
+public class UserWithdrawServiceImpl extends ServiceImpl<UserWithdrawMapper, UserWithdraw> implements IUserWithdrawService {
+
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/BankCode.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/BankCode.java
new file mode 100644
index 0000000..d2279d9
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/BankCode.java
@@ -0,0 +1,217 @@
+package com.ruoyi.account.util;
+
+/**
+ * 银行代码枚举类
+ * 用于通过银行简称获取对应的银行名称
+ */
+public enum BankCode {
+    SRCB("SRCB", "深圳农村商业银行"),
+    BGB("BGB", "广西北部湾银行"),
+    SHRCB("SHRCB", "上海农村商业银行"),
+    BJBANK("BJBANK", "北京银行"),
+    WHCCB("WHCCB", "威海市商业银行"),
+    BOZK("BOZK", "周口银行"),
+    KORLABANK("KORLABANK", "库尔勒市商业银行"),
+    SPABANK("SPABANK", "平安银行"),
+    SDEB("SDEB", "顺德农商银行"),
+    HURCB("HURCB", "湖北省农村信用社"),
+    WRCB("WRCB", "无锡农村商业银行"),
+    BOCY("BOCY", "朝阳银行"),
+    CZBANK("CZBANK", "浙商银行"),
+    HDBANK("HDBANK", "邯郸银行"),
+    BOC("BOC", "中国银行"),
+    BOD("BOD", "东莞银行"),
+    CCB("CCB", "中国建设银行"),
+    ZYCBANK("ZYCBANK", "遵义市商业银行"),
+    SXCB("SXCB", "绍兴银行"),
+    GZRCU("GZRCU", "贵州省农村信用社"),
+    ZJKCCB("ZJKCCB", "张家口市商业银行"),
+    BOJZ("BOJZ", "锦州银行"),
+    BOP("BOP", "平顶山银行"),
+    HKB("HKB", "汉口银行"),
+    SPDB("SPDB", "上海浦东发展银行"),
+    NXRCU("NXRCU", "宁夏黄河农村商业银行"),
+    NYNB("NYNB", "广东南粤银行"),
+    GRCB("GRCB", "广州农商银行"),
+    BOSZ("BOSZ", "苏州银行"),
+    HZCB("HZCB", "杭州银行"),
+    HSBK("HSBK", "衡水银行"),
+    HBC("HBC", "湖北银行"),
+    JXBANK("JXBANK", "嘉兴银行"),
+    HRXJB("HRXJB", "华融湘江银行"),
+    BODD("BODD", "丹东银行"),
+    AYCB("AYCB", "安阳银行"),
+    EGBANK("EGBANK", "恒丰银行"),
+    CDB("CDB", "国家开发银行"),
+    TCRCB("TCRCB", "江苏太仓农村商业银行"),
+    NJCB("NJCB", "南京银行"),
+    ZZBANK("ZZBANK", "郑州银行"),
+    DYCB("DYCB", "德阳商业银行"),
+    YBCCB("YBCCB", "宜宾市商业银行"),
+    SCRCU("SCRCU", "四川省农村信用"),
+    KLB("KLB", "昆仑银行"),
+    LSBANK("LSBANK", "莱商银行"),
+    YDRCB("YDRCB", "尧都农商行"),
+    CCQTGB("CCQTGB", "重庆三峡银行"),
+    FDB("FDB", "富滇银行"),
+    JSRCU("JSRCU", "江苏省农村信用联合社"),
+    JNBANK("JNBANK", "济宁银行"),
+    CMB("CMB", "招商银行"),
+    JINCHB("JINCHB", "晋城银行JCBANK"),
+    FXCB("FXCB", "阜新银行"),
+    WHRCB("WHRCB", "武汉农村商业银行"),
+    HBYCBANK("HBYCBANK", "湖北银行宜昌分行"),
+    TZCB("TZCB", "台州银行"),
+    TACCB("TACCB", "泰安市商业银行"),
+    XCYH("XCYH", "许昌银行"),
+    CEB("CEB", "中国光大银行"),
+    NXBANK("NXBANK", "宁夏银行"),
+    HSBANK("HSBANK", "徽商银行"),
+    JJBANK("JJBANK", "九江银行"),
+    NHQS("NHQS", "农信银清算中心"),
+    MTBANK("MTBANK", "浙江民泰商业银行"),
+    LANGFB("LANGFB", "廊坊银行"),
+    ASCB("ASCB", "鞍山银行"),
+    KSRB("KSRB", "昆山农村商业银行"),
+    YXCCB("YXCCB", "玉溪市商业银行"),
+    DLB("DLB", "大连银行"),
+    DRCBCL("DRCBCL", "东莞农村商业银行"),
+    GCB("GCB", "广州银行"),
+    NBBANK("NBBANK", "宁波银行"),
+    BOYK("BOYK", "营口银行"),
+    SXRCCU("SXRCCU", "陕西信合"),
+    GLBANK("GLBANK", "桂林银行"),
+    BOQH("BOQH", "青海银行"),
+    CDRCB("CDRCB", "成都农商银行"),
+    QDCCB("QDCCB", "青岛银行"),
+    HKBEA("HKBEA", "东亚银行"),
+    HBHSBANK("HBHSBANK", "湖北银行黄石分行"),
+    WZCB("WZCB", "温州银行"),
+    TRCB("TRCB", "天津农商银行"),
+    QLBANK("QLBANK", "齐鲁银行"),
+    GDRCC("GDRCC", "广东省农村信用社联合社"),
+    ZJTLCB("ZJTLCB", "浙江泰隆商业银行"),
+    GZB("GZB", "赣州银行"),
+    GYCB("GYCB", "贵阳市商业银行"),
+    CQBANK("CQBANK", "重庆银行"),
+    DAQINGB("DAQINGB", "龙江银行"),
+    CGNB("CGNB", "南充市商业银行"),
+    SCCB("SCCB", "三门峡银行"),
+    CSRCB("CSRCB", "常熟农村商业银行"),
+    SHBANK("SHBANK", "上海银行"),
+    JLBANK("JLBANK", "吉林银行"),
+    CZRCB("CZRCB", "常州农村信用联社"),
+    BANKWF("BANKWF", "潍坊银行"),
+    ZRCBANK("ZRCBANK", "张家港农村商业银行"),
+    FJHXBC("FJHXBC", "福建海峡银行"),
+    ZJNX("ZJNX", "浙江省农村信用社联合社"),
+    LZYH("LZYH", "兰州银行"),
+    JSB("JSB", "晋商银行"),
+    BOHAIB("BOHAIB", "渤海银行"),
+    CZCB("CZCB", "浙江稠州商业银行"),
+    YQCCB("YQCCB", "阳泉银行"),
+    SJBANK("SJBANK", "盛京银行"),
+    XABANK("XABANK", "西安银行"),
+    BSB("BSB", "包商银行"),
+    JSBANK("JSBANK", "江苏银行"),
+    FSCB("FSCB", "抚顺银行"),
+    HNRCU("HNRCU", "河南省农村信用"),
+    COMM("COMM", "交通银行"),
+    XTB("XTB", "邢台银行"),
+    CITIC("CITIC", "中信银行"),
+    HXBANK("HXBANK", "华夏银行"),
+    HNRCC("HNRCC", "湖南省农村信用社"),
+    DYCCB("DYCCB", "东营市商业银行"),
+    ORBANK("ORBANK", "鄂尔多斯银行"),
+    BJRCB("BJRCB", "北京农村商业银行"),
+    XYBANK("XYBANK", "信阳银行"),
+    ZGCCB("ZGCCB", "自贡市商业银行"),
+    CDCB("CDCB", "成都银行"),
+    HANABANK("HANABANK", "韩亚银行"),
+    CMBC("CMBC", "中国民生银行"),
+    LYBANK("LYBANK", "洛阳银行"),
+    GDB("GDB", "广东发展银行"),
+    ZBCB("ZBCB", "齐商银行"),
+    CBKF("CBKF", "开封市商业银行"),
+    H3CB("H3CB", "内蒙古银行"),
+    CIB("CIB", "兴业银行"),
+    CRCBANK("CRCBANK", "重庆农村商业银行"),
+    SZSBK("SZSBK", "石嘴山银行"),
+    DZBANK("DZBANK", "德州银行"),
+    SRBANK("SRBANK", "上饶银行"),
+    LSCCB("LSCCB", "乐山市商业银行"),
+    JXRCU("JXRCU", "江西省农村信用"),
+    ICBC("ICBC", "中国工商银行"),
+    JZBANK("JZBANK", "晋中市商业银行"),
+    HZCCB("HZCCB", "湖州市商业银行"),
+    NHB("NHB", "南海农村信用联社"),
+    XXBANK("XXBANK", "新乡银行"),
+    JRCB("JRCB", "江苏江阴农村商业银行"),
+    YNRCC("YNRCC", "云南省农村信用社"),
+    ABC("ABC", "中国农业银行"),
+    GXRCU("GXRCU", "广西省农村信用"),
+    PSBC("PSBC", "中国邮政储蓄银行"),
+    BZMD("BZMD", "驻马店银行"),
+    ARCU("ARCU", "安徽省农村信用社"),
+    GSRCU("GSRCU", "甘肃省农村信用"),
+    LYCB("LYCB", "辽阳市商业银行"),
+    JLRCU("JLRCU", "吉林农信"),
+    URMQCCB("URMQCCB", "乌鲁木齐市商业银行"),
+    XLBANK("XLBANK", "中山小榄村镇银行"),
+    CSCB("CSCB", "长沙银行"),
+    JHBANK("JHBANK", "金华银行"),
+    BHB("BHB", "河北银行"),
+    NBYZ("NBYZ", "鄞州银行"),
+    LSBC("LSBC", "临商银行"),
+    BOCD("BOCD", "承德银行"),
+    SDRCU("SDRCU", "山东农信"),
+    NCB("NCB", "南昌银行"),
+    TCCB("TCCB", "天津银行"),
+    WJRCB("WJRCB", "吴江农商银行"),
+    CBBQS("CBBQS", "城市商业银行资金清算中心"),
+    HBRCU("HBRCU", "河北省农村信用社");
+
+    private final String code;
+    private final String name;
+
+    BankCode(String code, String name) {
+        this.code = code;
+        this.name = name;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * 根据银行简称获取银行名称
+     * @param code 银行简称
+     * @return 银行名称,如果未找到返回null
+     */
+    public static String getBankNameByCode(String code) {
+        for (BankCode bankCode : values()) {
+            if (bankCode.getCode().equals(code)) {
+                return bankCode.getName();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 根据银行简称获取枚举实例
+     * @param code 银行简称
+     * @return BankCode枚举实例,如果未找到返回null
+     */
+    public static BankCode getBankByCode(String code) {
+        for (BankCode bankCode : values()) {
+            if (bankCode.getCode().equals(code)) {
+                return bankCode;
+            }
+        }
+        return null;
+    }
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRequester.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRequester.java
new file mode 100644
index 0000000..5737349
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRequester.java
@@ -0,0 +1,204 @@
+package com.ruoyi.account.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.Vector;
+
+public class HttpRequester {
+	private String defaultContentEncoding;  
+	   
+    public HttpRequester() {  
+        this.defaultContentEncoding = Charset.defaultCharset().name();  
+    }  
+	
+    /** 
+     * 发送POST请求 
+     *  
+     * @param urlString 
+     *            URL地址 
+     * @return 响应对象 
+     * @throws IOException 
+     */  
+    public HttpRespons sendPost(String urlString) throws IOException {
+        return this.send(urlString, "POST", null, null);  
+    }  
+   
+    /** 
+     * 发送POST请求 
+     *  
+     * @param urlString 
+     *            URL地址 
+     * @param params 
+     *            参数集合 
+     * @return 响应对象 
+     * @throws IOException 
+     */  
+    public HttpRespons sendPost(String urlString, Map<String, String> params)  
+            throws IOException {  
+    	
+    	for(String key : params.keySet()) {
+			if(params.get(key)!=null&&!"".equals(params.get(key))) {
+				params.put(key, (String)URLEncoder.encode(params.get(key),"utf-8")) ;//(String) 强制类型转换
+			}
+    	}
+    	
+
+    	
+        return this.send(urlString, "POST", params, null);  
+    }  
+   
+    /** 
+     * 发送POST请求 
+     *  
+     * @param urlString 
+     *            URL地址 
+     * @param params 
+     *            参数集合 
+     * @param propertys 
+     *            请求属性 
+     * @return 响应对象 
+     * @throws IOException 
+     */  
+    public HttpRespons sendPost(String urlString, Map<String, String> params,  
+            Map<String, String> propertys) throws IOException {  
+        return this.send(urlString, "POST", params, propertys);  
+    }  
+   
+    /** 
+     * 发送HTTP请求 
+     *  
+     * @param urlString 
+     * @return 响映对象 
+     * @throws IOException 
+     */  
+    private HttpRespons send(String urlString, String method,  
+            Map<String, String> parameters, Map<String, String> propertys)  
+            throws IOException {  
+        HttpURLConnection urlConnection = null;  
+   
+        if (method.equalsIgnoreCase("GET") && parameters != null) {  
+            StringBuffer param = new StringBuffer();  
+            int i = 0;  
+            for (String key : parameters.keySet()) {  
+                if (i == 0)  
+                    param.append("?");  
+                else  
+                    param.append("&");  
+                param.append(key).append("=").append(parameters.get(key));  
+                i++;  
+            }  
+            urlString += param;  
+        }  
+        URL url = new URL(urlString);  
+        urlConnection = (HttpURLConnection) url.openConnection();  
+   
+        urlConnection.setRequestMethod(method);  
+        urlConnection.setDoOutput(true);  
+        urlConnection.setDoInput(true);  
+        urlConnection.setUseCaches(false);  
+   
+        if (propertys != null)  
+            for (String key : propertys.keySet()) {  
+                urlConnection.addRequestProperty(key, propertys.get(key));  
+            }  
+   
+        if (method.equalsIgnoreCase("POST") && parameters != null) {  
+            StringBuffer param = new StringBuffer();  
+            for (String key : parameters.keySet()) {  
+                param.append("&");  
+                param.append(key).append("=").append(parameters.get(key));  
+            }  
+            urlConnection.getOutputStream().write(param.toString().getBytes());  
+            urlConnection.getOutputStream().flush();  
+            urlConnection.getOutputStream().close();  
+        }  
+   
+        return this.makeContent(urlString, urlConnection);  
+    }  
+   
+    /** 
+     * 得到响应对象 
+     *  
+     * @param urlConnection 
+     * @return 响应对象 
+     * @throws IOException 
+     */  
+    private HttpRespons makeContent(String urlString,  
+            HttpURLConnection urlConnection) throws IOException {  
+        HttpRespons httpResponser = new HttpRespons();  
+        try {  
+            InputStream in = urlConnection.getInputStream();  
+            BufferedReader bufferedReader = new BufferedReader(  
+                    new InputStreamReader(in));  
+            httpResponser.contentCollection = new Vector<String>();  
+            StringBuffer temp = new StringBuffer();  
+            String line = bufferedReader.readLine();  
+            while (line != null) {  
+                httpResponser.contentCollection.add(line);  
+                temp.append(line).append("\r\n");  
+                line = bufferedReader.readLine();  
+            }  
+            bufferedReader.close();  
+   
+            String ecod = urlConnection.getContentEncoding();  
+            if (ecod == null)  
+                ecod = this.defaultContentEncoding;  
+   
+            httpResponser.urlString = urlString;  
+   
+            httpResponser.defaultPort = urlConnection.getURL().getDefaultPort();  
+            httpResponser.file = urlConnection.getURL().getFile();  
+            httpResponser.host = urlConnection.getURL().getHost();  
+            httpResponser.path = urlConnection.getURL().getPath();  
+            httpResponser.port = urlConnection.getURL().getPort();  
+            httpResponser.protocol = urlConnection.getURL().getProtocol();  
+            httpResponser.query = urlConnection.getURL().getQuery();  
+            httpResponser.ref = urlConnection.getURL().getRef();  
+            httpResponser.userInfo = urlConnection.getURL().getUserInfo();  
+   
+            httpResponser.content = new String(temp.toString().getBytes(), ecod);  
+            httpResponser.contentEncoding = ecod;  
+            httpResponser.code = urlConnection.getResponseCode();  
+            httpResponser.message = urlConnection.getResponseMessage();  
+            httpResponser.contentType = urlConnection.getContentType();  
+            httpResponser.method = urlConnection.getRequestMethod();  
+            httpResponser.connectTimeout = urlConnection.getConnectTimeout();  
+            httpResponser.readTimeout = urlConnection.getReadTimeout();  
+   
+            return httpResponser;  
+        } catch (IOException e) {  
+            throw e;  
+        } finally {  
+            if (urlConnection != null)  
+                urlConnection.disconnect();  
+        }  
+    }  
+   
+    /** 
+     * 默认的响应字符集 
+     */  
+    public String getDefaultContentEncoding() {  
+        return this.defaultContentEncoding;  
+    }  
+   
+    /** 
+     * 设置默认的响应字符集 
+     */  
+    public void setDefaultContentEncoding(String defaultContentEncoding) {  
+        this.defaultContentEncoding = defaultContentEncoding;  
+    }  
+
+}
+       
+       
+       
+       
+       
+
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRespons.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRespons.java
new file mode 100644
index 0000000..0ef4d5a
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/HttpRespons.java
@@ -0,0 +1,184 @@
+package com.ruoyi.account.util;
+
+
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.RequestEntity;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+
+
+public class HttpRespons {
+	  String urlString;     
+      
+	    int defaultPort;     
+	      
+	    String file;     
+	      
+	    String host;     
+	      
+	    String path;     
+	      
+	    int port;     
+	      
+	    String protocol;     
+	      
+	    String query;     
+	      
+	    String ref;     
+	      
+	    String userInfo;     
+	      
+	    String contentEncoding;     
+	      
+	    String content;     
+	      
+	    String contentType;     
+	      
+	    int code;     
+	      
+	    String message;     
+	      
+	    String method;     
+	      
+	    int connectTimeout;     
+	      
+	    int readTimeout;     
+	      
+	    Vector<String> contentCollection;     
+	      
+	    public String getContent() {     
+	        return content;     
+	    }     
+	      
+	    public String getContentType() {     
+	        return contentType;     
+	    }     
+	      
+	    public int getCode() {     
+	        return code;     
+	    }     
+	      
+	    public String getMessage() {     
+	        return message;     
+	    }     
+	      
+	    public Vector<String> getContentCollection() {     
+	        return contentCollection;     
+	    }     
+	      
+	    public String getContentEncoding() {     
+	        return contentEncoding;     
+	    }     
+	      
+	    public String getMethod() {     
+	        return method;     
+	    }     
+	      
+	    public int getConnectTimeout() {     
+	        return connectTimeout;     
+	    }     
+	      
+	    public int getReadTimeout() {     
+	        return readTimeout;     
+	    }     
+	      
+	    public String getUrlString() {     
+	        return urlString;     
+	    }     
+	      
+	    public int getDefaultPort() {     
+	        return defaultPort;     
+	    }     
+	      
+	    public String getFile() {     
+	        return file;     
+	    }     
+	      
+	    public String getHost() {     
+	        return host;     
+	    }     
+	      
+	    public String getPath() {     
+	        return path;     
+	    }     
+	      
+	    public int getPort() {     
+	        return port;     
+	    }     
+	      
+	    public String getProtocol() {     
+	        return protocol;     
+	    }     
+	      
+	    public String getQuery() {     
+	        return query;     
+	    }     
+	      
+	    public String getRef() {     
+	        return ref;     
+	    }     
+	      
+	    public String getUserInfo() {     
+	        return userInfo;     
+	    } 
+	    
+	    
+	    public static String post(String params,String requestUrl) throws IOException {  
+//	        try {
+	           //HttpRequester request = new HttpRequester();  
+	           // request.setDefaultContentEncoding("utf-8"); 	
+	            byte[] requestBytes = params.getBytes("utf-8"); // 将参数转为二进制流
+	                   HttpClient httpClient = new HttpClient(); // 客户端实例化
+	                   PostMethod postMethod = new PostMethod(requestUrl);
+	                   //设置请求头Authorization
+//	                   postMethod.setRequestHeader("Authorization", "Basic " + authorization);
+	                   // 设置请求头  Content-Type
+	                   postMethod.setRequestHeader("Content-Type", "application/json");
+	                   InputStream inputStream = new ByteArrayInputStream(requestBytes, 0,requestBytes.length);
+	                   RequestEntity requestEntity = new InputStreamRequestEntity(inputStream,
+	                             requestBytes.length, "application/json; charset=utf-8"); // 请求体
+	                   postMethod.setRequestEntity(requestEntity);
+	                   httpClient.executeMethod(postMethod);// 执行请求
+	                   InputStream soapResponseStream = postMethod.getResponseBodyAsStream();// 获取返回的流
+	                   byte[] datas = null;
+	                    try {
+	                        datas = readInputStream(soapResponseStream);// 从输入流中读取数据
+	                    } catch (Exception e) {
+	                        e.printStackTrace();
+	                     }
+	                    String result = new String(datas, "UTF-8");// 将二进制流转为String
+	                     // 打印返回结果
+	                     // System.out.println(result);
+	             
+	                     return result;   
+	    }  
+	    
+	    
+	    /**
+	          * 从输入流中读取数据
+	          * 
+	          * @param inStream
+	          * @return
+	          * @throws Exception
+	    */
+	    public static byte[] readInputStream(InputStream inStream) throws Exception {
+	    	         ByteArrayOutputStream outStream = new ByteArrayOutputStream();
+	    	         byte[] buffer = new byte[1024];
+	    	         int len = 0;
+	    	         while ((len = inStream.read(buffer)) != -1) {
+	    	            outStream.write(buffer, 0, len);
+	    	         }
+	    	         byte[] data = outStream.toByteArray();
+	    	         outStream.close();
+	    	         inStream.close();
+	    	        return data;
+	    	     }
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/UUIDUtil.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/UUIDUtil.java
new file mode 100644
index 0000000..bbd739f
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/UUIDUtil.java
@@ -0,0 +1,103 @@
+package com.ruoyi.account.util;
+
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.UUID;
+
+/**
+ * 定义生成随机码的工具类
+ */
+public class UUIDUtil {
+
+    private int i = 1;
+
+
+    /**
+     * 定义生成原生的UUID随机码
+     *
+     * @return
+     */
+    public static String getNativeUUID() {
+        return UUID.randomUUID().toString();
+    }
+
+
+    /**
+     * 生成32位随机码
+     *
+     * @return
+     */
+    public static String getRandomCode() {
+        return UUIDUtil.getNativeUUID().replaceAll("-", "");
+    }
+
+
+    /**
+     * 获取给定长度的随机码
+     *
+     * @param num
+     * @return
+     * @throws Exception
+     */
+    public static String getRandomCode(Integer num) throws Exception {
+        String str = null;
+        if (0 < num) {
+            if (num % 32 > 0) {
+                Integer s = num / 32;
+                Integer l = num % 32;
+                StringBuffer sb = new StringBuffer();
+                for (int i = 0; i < s; i++) {
+                    sb.append(UUIDUtil.getRandomCode());
+                }
+                sb.append(UUIDUtil.getRandomCode().substring(0, l));
+                str = sb.toString();
+            } else if (num % 32 == 0) {
+                Integer s = num / 32;
+                StringBuffer sb = new StringBuffer();
+                for (int i = 0; i < s; i++) {
+                    sb.append(UUIDUtil.getRandomCode());
+                }
+                str = sb.toString();
+            } else {
+                str = UUIDUtil.getRandomCode().substring(0, num);
+            }
+        } else {
+            throw new Exception("参数只能大于0");
+        }
+        return str;
+    }
+
+
+    /**
+     * 获取根据当前时间的字符串数据
+     *
+     * @return
+     */
+    public synchronized static String getTimeStr() {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmssS");
+        return simpleDateFormat.format(new Date());
+    }
+
+
+    /**
+     * @Description: 获取数字随机码
+     * @Author pzb
+     * @Date 2021/8/11 16:52
+     * @Param
+     * @Return
+     * @Exception
+     */
+    public static String getNumberRandom(Integer num) {
+        if (null == num) {
+            num = 32;
+        }
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < num; i++) {
+            sb.append(Double.valueOf(Math.random() * 10).intValue());
+        }
+        return sb.toString();
+    }
+
+
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/HttpUtilWithdraw.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/HttpUtilWithdraw.java
new file mode 100644
index 0000000..2a17261
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/HttpUtilWithdraw.java
@@ -0,0 +1,492 @@
+package com.ruoyi.account.util.withdraw;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.ruoyi.account.api.model.UserWithdraw;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.other.api.domain.ShopWithdraw;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.DefaultHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.client.HttpClients;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 三方提现工具类
+ */
+public class HttpUtilWithdraw {
+
+    //设置请求和传输超时时间
+    private static RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(60000).setConnectTimeout(60000).build();
+    //初始化需要用到的参数
+    private static final String CLIENT_TYPE = "1";
+    private static final String CLIENT_VERSION = "1.0.0";
+    private static final String APP_CONFIG_ID = "8597918391594056444";
+    private static final String API_KEY = "jo_pay_S4UIWYjWmy46d9yX9N2QWZffD";
+    private static final String API_SECRET = "cad03aaf2019530090d642aa9b2f0cbb";
+
+    private static final String STRING_KEY = "pay_open_api_vwHXa2ay1Dv7E${clientType}${clientVersion}${apiKey}${apiSecret}${timestamp}";
+    private static final String URL = "https://pay.new.jieoukeji.cn/jo-pay-open-api";
+    private static final String PATH = "/v1/safe/withdraw";//示例接口:获取银行卡信息
+    private static final Pattern VALUE_PATTERN = Pattern.compile("\\$\\{([^}]*)\\}");
+
+    public static void main(String[] args) throws IOException {
+        long timestamp = System.currentTimeMillis();
+        Map<String,String> headers = new HashMap<>(6);
+        headers.put("client-type",CLIENT_TYPE);
+        headers.put("client-version",CLIENT_VERSION);
+        headers.put("api-secret",API_SECRET);
+        headers.put("api-key",API_KEY);
+        headers.put("access-timestamp",String.valueOf(timestamp));
+        headers.put("Content-Type","application/json");
+        //拼接字符串,签名开头保留,${} 全替换为header参数
+        headers.put("access-sign",getSign(STRING_KEY,timestamp));
+        //开始请求API接口
+        Map<String, Object> param = new HashMap<>();
+        param.put("orderCode", "09127389681694");
+        param.put("cardNo", "6228480469852935177");
+        param.put("name", "周帅");
+        param.put("withdrawType", "1");
+        param.put("accountType", "00");
+        param.put("bankName", "中国农业银行");
+//        param.put("brachBankCode", "123546345674573457");
+        param.put("money", "0.1");
+        param.put("appConfigId", APP_CONFIG_ID);
+        try {
+            String results = post(URL+PATH,headers, param);
+            //返回结果JSON字符串
+            System.out.println(results);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+
+//        String url = "https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?_input_charset=utf-8&" +
+//                "cardNo=" + "6228480469852935177" + "&cardBinCheck=true";
+//        HashMap<String, String> hashMap = new HashMap<>();
+//        HttpRequester hr = new HttpRequester();
+//        HttpRespons HP = hr.sendPost(url, hashMap);
+//        System.out.println("接收返回参数:" + HP.getContent());
+//        JSONObject resPay = JSONObject.parseObject(HP.getContent());
+//        System.err.println(resPay);
+//        if (resPay.getString("validated") == null) {
+//            System.err.println("不合法的银行卡号");
+//        }
+//        String bankName = BankCode.getBankNameByCode("ABC"); // 返回ABC枚举实例
+//        System.err.println(bankName);
+    }
+
+    public static String withdraw(ShopWithdraw shopWithdraw, String bankName) {
+        long timestamp = System.currentTimeMillis();
+        Map<String, String> headers = new HashMap<>(6);
+        headers.put("client-type", CLIENT_TYPE);
+        headers.put("client-version", CLIENT_VERSION);
+        headers.put("api-secret", API_SECRET);
+        headers.put("api-key", API_KEY);
+        headers.put("access-timestamp", String.valueOf(timestamp));
+        headers.put("Content-Type", "application/json");
+        //拼接字符串,签名开头保留,${} 全替换为header参数
+        headers.put("access-sign", getSign(STRING_KEY, timestamp));
+        //开始请求API接口
+        Map<String, Object> param = new HashMap<>();
+        param.put("orderCode", shopWithdraw.getCode());
+        param.put("cardNo", shopWithdraw.getReceiverAccountNoEnc());
+        param.put("name", shopWithdraw.getReceiverNameEnc());
+        param.put("withdrawType", "1");
+        if (shopWithdraw.getReceiverAccountType().equals(204)) {
+            param.put("accountType", "01");
+            param.put("bankName", bankName);
+            param.put("brachBankCode", shopWithdraw.getReceiverBankChannelNo());
+        } else {
+            param.put("accountType", "00");
+        }
+        param.put("money", shopWithdraw.getMoney());
+        param.put("appConfigId", APP_CONFIG_ID);
+        try {
+            String results = post(URL + PATH, headers, param);
+            //返回结果JSON字符串
+            System.out.println(results);
+            JSONObject jsonObject = JSONObject.parseObject(results);
+            if (jsonObject.getString("result").equals("true")){
+                return "success";
+            }else{
+                return jsonObject.getString("message");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "打款失败";
+    }
+    public static String userWithdraw(UserWithdraw userWithdraw, String bankName) {
+        long timestamp = System.currentTimeMillis();
+        Map<String, String> headers = new HashMap<>(6);
+        headers.put("client-type", CLIENT_TYPE);
+        headers.put("client-version", CLIENT_VERSION);
+        headers.put("api-secret", API_SECRET);
+        headers.put("api-key", API_KEY);
+        headers.put("access-timestamp", String.valueOf(timestamp));
+        headers.put("Content-Type", "application/json");
+        //拼接字符串,签名开头保留,${} 全替换为header参数
+        headers.put("access-sign", getSign(STRING_KEY, timestamp));
+        //开始请求API接口
+        Map<String, Object> param = new HashMap<>();
+        param.put("orderCode", userWithdraw.getCode());
+        param.put("cardNo", userWithdraw.getReceiverAccountNoEnc());
+        param.put("name", userWithdraw.getReceiverNameEnc());
+        param.put("withdrawType", "1");
+        if (userWithdraw.getReceiverAccountType().equals(204)) {
+            param.put("accountType", "01");
+            param.put("bankName", bankName);
+            param.put("brachBankCode", userWithdraw.getReceiverBankChannelNo());
+        } else {
+            param.put("accountType", "00");
+        }
+        param.put("money", userWithdraw.getMoney());
+        param.put("appConfigId", APP_CONFIG_ID);
+        try {
+            String results = post(URL + PATH, headers, param);
+            //返回结果JSON字符串
+            System.out.println(results);
+            JSONObject jsonObject = JSONObject.parseObject(results);
+            if (jsonObject.getString("result").equals("true")){
+                return "success";
+            }else{
+                return jsonObject.getString("message");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "打款失败";
+    }
+
+    /**
+     * 发起post请求,请求参数以Map集合形式传入
+     *
+     * @param httpUrl
+     * @param body
+     * @return
+     * @throws Exception
+     */
+    public static String post(String httpUrl, Map<String, String> headers, Map<String, Object> body) {
+        CloseableHttpClient httpclient = createSSLClientDefault();
+        BufferedReader in;
+        HttpPost httpPost = new HttpPost(httpUrl);
+        try {
+            httpPost.setHeader("Accept", "application/json");
+            for (Map.Entry<String, String> headerMap : headers.entrySet()) {
+                httpPost.addHeader(headerMap.getKey(), headerMap.getValue());
+            }
+            httpPost.setConfig(requestConfig);
+            StringEntity entity = new StringEntity(JSON.toJSONString(body), StandardCharsets.UTF_8);
+            entity.setContentType("application/json");
+            httpPost.setEntity(entity);
+
+            CloseableHttpResponse response = httpclient.execute(httpPost);
+            InputStream content = response.getEntity().getContent();
+            in = new BufferedReader(new InputStreamReader(content, StandardCharsets.UTF_8));
+            StringBuilder sb = new StringBuilder();
+            String line;
+            while ((line = in.readLine()) != null) {
+                sb.append(line);
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                httpclient.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 发起get请求,请求参数以Map集合形式传入
+     *
+     * @param httpUrl
+     * @param params
+     * @return
+     * @throws Exception
+     */
+    public static String get(String httpUrl, Map<String, String> headers, Map<String, String> params) {
+        CloseableHttpClient httpclient = createSSLClientDefault();
+        BufferedReader in;
+        List<String> paramList = new ArrayList<>();
+        for (Map.Entry<String, String> param : params.entrySet()) {
+            paramList.add(param.getKey() + "=" + param.getValue());
+        }
+        HttpGet httpGet = new HttpGet(httpUrl + "?" + String.join("&", paramList));
+        try {
+            httpGet.setHeader("Accept", "application/json");
+            for (Map.Entry<String, String> headerMap : headers.entrySet()) {
+                httpGet.addHeader(headerMap.getKey(), headerMap.getValue());
+            }
+            httpGet.setConfig(requestConfig);
+
+            CloseableHttpResponse response = httpclient.execute(httpGet);
+            InputStream content = response.getEntity().getContent();
+            in = new BufferedReader(new InputStreamReader(content, StandardCharsets.UTF_8));
+            StringBuilder sb = new StringBuilder();
+            String line;
+            while ((line = in.readLine()) != null) {
+                sb.append(line);
+            }
+            return sb.toString();
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                httpclient.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    public static CloseableHttpClient createSSLClientDefault() {
+        try {
+            // SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+            // 在JSSE中,证书信任管理器类就是实现了接口X509TrustManager的类。我们可以自己实现该接口,让它信任我们指定的证书。
+            // 创建SSLContext对象,并使用我们指定的信任管理器初始化
+            // 信任所有
+            X509TrustManager x509mgr = new X509TrustManager() {
+                // 该方法检查客户端的证书,若不信任该证书则抛出异常
+                @Override
+                public void checkClientTrusted(X509Certificate[] xcs, String string) {
+                }
+
+                // 该方法检查服务端的证书,若不信任该证书则抛出异常
+                @Override
+                public void checkServerTrusted(X509Certificate[] xcs, String string) {
+                }
+
+                // 返回受信任的X509证书数组。
+                @Override
+                public X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+            };
+            SSLContext sslContext = SSLContext.getInstance(SSLConnectionSocketFactory.TLS);
+            sslContext.init(null, new TrustManager[]{x509mgr}, null);
+            // 创建HttpsURLConnection对象,并设置其SSLSocketFactory对象
+            SSLConnectionSocketFactory sslSf = new SSLConnectionSocketFactory(sslContext, new DefaultHostnameVerifier());
+            // HttpsURLConnection对象就可以正常连接HTTPS了,无论其证书是否经权威机构的验证,只要实现了接口X509TrustManager的类MyX509TrustManager信任该证书。
+            return HttpClients.custom().setSSLSocketFactory(sslSf).build();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        // 创建默认的httpClient实例.
+        return HttpClients.createDefault();
+    }
+
+    /**
+     * 获取签名前准备参数
+     *
+     * @param format
+     * @param timestamp
+     * @return
+     */
+    public static String getSign(String format, long timestamp) {
+        JSONObject dataSign = new JSONObject();
+        dataSign.put("clientType", CLIENT_TYPE);
+        dataSign.put("clientVersion", CLIENT_VERSION);
+        dataSign.put("apiSecret", API_SECRET);
+        dataSign.put("apiKey", API_KEY);
+        dataSign.put("timestamp", timestamp);
+        String formatData = getFormatData(dataSign, format);
+        return md5(formatData);
+    }
+
+    /**
+     * 拼接替换生成签名前字符串
+     *
+     * @return
+     */
+    public static String getFormatData(JSONObject data, String format) {
+
+        System.err.println(data);
+        System.err.println(format);
+        Matcher matcher = VALUE_PATTERN.matcher(format);
+        while (true) {
+            while (matcher.find()) {
+                String sign = matcher.group();
+                String key = matcher.group(1);
+                if (ObjectUtils.isNotEmpty(key)) {
+                    format = format.replace(sign, data.containsKey(key) && ObjectUtils.isNotEmpty(data.getString(key)) && !"null".equalsIgnoreCase(data.getString(key)) ? data.getString(key) : "");
+                } else {
+                    format = format.replace(sign, "");
+                }
+            }
+            return format;
+        }
+    }
+
+    /**
+     * 生成md5,小写
+     *
+     * @param message
+     * @return
+     */
+    public static String md5(String message) {
+        try {
+            // 1 创建一个提供信息摘要算法的对象,初始化为md5算法对象
+            MessageDigest md = MessageDigest.getInstance("MD5");
+
+            // 2 将消息变成byte数组
+            byte[] input = message.getBytes();
+
+            // 3 计算后获得字节数组,这就是那128位了
+            byte[] buff = md.digest(input);
+
+            // 4 把数组每一字节(一个字节占八位)换成16进制连成md5字符串
+            return byte2hex(buff);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 二进制转十六进制字符串
+     *
+     * @param bytes
+     * @return
+     */
+    private static String byte2hex(byte[] bytes) {
+        StringBuilder sign = new StringBuilder();
+        for (int i = 0; i < bytes.length; i++) {
+            String hex = Integer.toHexString(bytes[i] & 0xFF);
+            if (hex.length() == 1) {
+                sign.append("0");
+            }
+            sign.append(hex.toLowerCase());
+        }
+        return sign.toString();
+    }
+
+    /**
+     * 调用apiPost方法
+     *
+     * @return
+     */
+    public static HttpResponse doPost(String host, String path, String method,
+                                      Map<String, String> headers,
+                                      Map<String, String> querys,
+                                      String body)
+            throws Exception {
+        HttpClient httpClient = wrapClient(host);
+
+        HttpPost request = new HttpPost(buildUrl(host, path, querys));
+        for (Map.Entry<String, String> e : headers.entrySet()) {
+            request.addHeader(e.getKey(), e.getValue());
+        }
+
+        if (StringUtils.isNotBlank(body)) {
+            request.setEntity(new StringEntity(body, "utf-8"));
+        }
+        return httpClient.execute(request);
+    }
+
+    public static HttpClient wrapClient(String host) {
+        HttpClient httpClient = new DefaultHttpClient();
+        if (host.startsWith("https://")) {
+            sslClient(httpClient);
+        }
+
+        return httpClient;
+    }
+
+    public static String buildUrl(String host, String path, Map<String, String> querys) throws UnsupportedEncodingException {
+        StringBuilder sbUrl = new StringBuilder();
+        sbUrl.append(host);
+        if (!StringUtils.isBlank(path)) {
+            sbUrl.append(path);
+        }
+        if (null != querys) {
+            StringBuilder sbQuery = new StringBuilder();
+            for (Map.Entry<String, String> query : querys.entrySet()) {
+                if (0 < sbQuery.length()) {
+                    sbQuery.append("&");
+                }
+                if (StringUtils.isBlank(query.getKey()) && !StringUtils.isBlank(query.getValue())) {
+                    sbQuery.append(query.getValue());
+                }
+                if (!StringUtils.isBlank(query.getKey())) {
+                    sbQuery.append(query.getKey());
+                    if (!StringUtils.isBlank(query.getValue())) {
+                        sbQuery.append("=");
+                        sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8"));
+                    }
+                }
+            }
+            if (0 < sbQuery.length()) {
+                sbUrl.append("?").append(sbQuery);
+            }
+        }
+
+        return sbUrl.toString();
+    }
+
+    private static void sslClient(HttpClient httpClient) {
+        try {
+            SSLContext ctx = SSLContext.getInstance("TLS");
+            X509TrustManager tm = new X509TrustManager() {
+                @Override
+                public X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+
+                @Override
+                public void checkClientTrusted(X509Certificate[] xcs, String str) {
+
+                }
+
+                @Override
+                public void checkServerTrusted(X509Certificate[] xcs, String str) {
+
+                }
+            };
+            ctx.init(null, new TrustManager[]{tm}, null);
+            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
+            ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+            ClientConnectionManager ccm = httpClient.getConnectionManager();
+            SchemeRegistry registry = ccm.getSchemeRegistry();
+            registry.register(new Scheme("https", 443, ssf));
+        } catch (KeyManagementException ex) {
+            throw new RuntimeException(ex);
+        } catch (NoSuchAlgorithmException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/WithdrawCallBackDTO.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/WithdrawCallBackDTO.java
new file mode 100644
index 0000000..a6d56f8
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/util/withdraw/WithdrawCallBackDTO.java
@@ -0,0 +1,36 @@
+package com.ruoyi.account.util.withdraw;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 三方提现回调DTO
+ */
+@Data
+public class WithdrawCallBackDTO {
+
+    @ApiModelProperty(value = "数据签名,")
+    private String sign;
+    @ApiModelProperty(value = "打款订单号")
+    private String orderCode;
+    @ApiModelProperty(value = "交易流水号")
+    private String tradeNo;
+    @ApiModelProperty(value = "打款金额")
+    private BigDecimal money;
+    @ApiModelProperty(value = "订单状态 0待支付 1已支付 2处理中 4交易失败")
+    private Integer status;
+    @ApiModelProperty(value = "打款时间")
+    private LocalDateTime time;
+    @ApiModelProperty(value = "订单状态信息")
+    private String message;
+
+
+
+
+
+
+
+}
diff --git a/ruoyi-service/ruoyi-account/src/main/resources/mapper/account/UserWithdrawMapper.xml b/ruoyi-service/ruoyi-account/src/main/resources/mapper/account/UserWithdrawMapper.xml
new file mode 100644
index 0000000..87b0491
--- /dev/null
+++ b/ruoyi-service/ruoyi-account/src/main/resources/mapper/account/UserWithdrawMapper.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.account.mapper.UserWithdrawMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.account.api.model.UserWithdraw">
+        <id column="id" property="id" />
+        <result column="app_user_id" property="appUserId" />
+        <result column="money" property="money" />
+        <result column="integral" property="integral" />
+        <result column="audit_status" property="auditStatus" />
+        <result column="audit_user_id" property="auditUserId" />
+        <result column="audit_time" property="auditTime" />
+        <result column="audit_msg" property="auditMsg" />
+        <result column="status" property="status" />
+        <result column="arrival_time" property="arrivalTime" />
+        <result column="del_flag" property="delFlag" />
+        <result column="create_time" property="createTime" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, app_user_id, money, integral, audit_status, audit_user_id, audit_time, audit_msg, status, arrival_time, del_flag, create_time
+    </sql>
+    <select id="page" resultType="com.ruoyi.account.api.model.UserWithdraw">
+        select t1.*,t2.phone,t2.name from
+                                         t_user_withdraw t1
+                                         left join t_app_user t2 on t1.app_user_id = t2.id
+    </select>
+
+</mapper>

--
Gitblit v1.7.1