提现免审核额度

This commit is contained in:
墨大叔 2024-09-04 14:27:09 +08:00
parent 9ed15965f0
commit 5426294462
27 changed files with 577 additions and 88 deletions

View File

@ -146,4 +146,23 @@ public class SmUser extends BaseEntity
@ApiModelProperty("提现服务费费")
@JsonView(JsonViewProfile.App.class)
private BigDecimal withdrawServiceRate;
@Excel(name = "真实姓名")
@ApiModelProperty("真实姓名")
@JsonView(JsonViewProfile.AppMch.class)
private String realName;
@Excel(name = "身份证号")
@ApiModelProperty("身份证号")
@Sensitive(desensitizedType = DesensitizedType.ID_CARD)
private String realIdCard;
@Excel(name = "实名认证手机号")
@ApiModelProperty("实名认证手机号")
@Sensitive(desensitizedType = DesensitizedType.PHONE)
private String realPhone;
@ApiModelProperty("是否已经实名认证")
@JsonView(JsonViewProfile.App.class)
private Boolean isReal;
}

View File

@ -119,7 +119,7 @@ public class CollectionUtils extends org.springframework.util.CollectionUtils {
for(int i = 0; i < l1.size(); i ++) {
Object o1 = l1.get(i);
Object o2 = l2.get(i);
if (!Objects.equals(o1, o2)) {
if (!o1.equals(o2)) {
return false;
}
}

View File

@ -0,0 +1,20 @@
package com.ruoyi.common.valid.realName;
import lombok.Data;
/**
* @author wjh
* 2024/8/30
*/
@Data
public class RealNameResponseBody {
private String code;
private String taskNo;
private String msg;
private RealNameResponseData data;
}

View File

@ -0,0 +1,21 @@
package com.ruoyi.common.valid.realName;
import lombok.Data;
/**
* @author wjh
* 2024/8/30
*/
@Data
public class RealNameResponseData {
// 0:一致1:不一致2: 查无记录
private String result;
//结果描述
private String desc;
// 性别
private String sex;
// 出生年月
private String birthday;
//地址
private String address;
}

View File

@ -0,0 +1,56 @@
package com.ruoyi.common.valid.realName;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.http.AliHttpUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 实名认证工具类
* @author wjh
* 2024/8/30
*/
public class RealNameValidUtils {
public static final String APP_KEY = SpringUtils.getRequiredProperty("realName.appKey");
public static final String APP_CODE = SpringUtils.getRequiredProperty("realName.appCode");
public static final String APP_SECRET = SpringUtils.getRequiredProperty("realName.appSecret");
public static RealNameResponseData getMobile3Info(String idCard, String mobile, String name) {
String host = "https://jmmobeck3.market.alicloudapi.com";
String path = "/mobile/3-validate-beckoning";
String method = "POST";
Map<String, String> headers = new HashMap<String, String>();
//最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
headers.put("Authorization", "APPCODE " + APP_CODE);
//根据API的要求定义相对应的Content-Type
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
Map<String, String> querys = new HashMap<String, String>();
Map<String, String> bodys = new HashMap<String, String>();
bodys.put("idcard", idCard);
bodys.put("mobile", mobile);
bodys.put("name", name);
try {
HttpResponse res = AliHttpUtils.doPost(host, path, method, headers, querys, bodys);
RealNameResponseBody body = JSON.parseObject(EntityUtils.toString(res.getEntity()), RealNameResponseBody.class);
ServiceUtil.assertion(body.getCode() == null || !body.getCode().equals("200"), body.getMsg());
return body.getData();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 校验手机号三要素是否一致
public static boolean validMobile3Info(String idCard, String mobile, String name) {
RealNameResponseData mobile3Info = getMobile3Info(idCard, mobile, name);
return mobile3Info != null && mobile3Info.getResult() != null && mobile3Info.getResult().equals("0");
}
}

View File

@ -156,4 +156,25 @@ public class PermissionService
{
return permissions.contains(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
}
public boolean hasAllPermi(Set<String> permissions) {
if (com.ruoyi.common.utils.collection.CollectionUtils.isEmptyElement(permissions))
{
return true;
}
LoginUser loginUser = SecurityUtils.getLoginUser();
if (StringUtils.isNull(loginUser) || com.ruoyi.common.utils.collection.CollectionUtils.isEmpty(loginUser.getPermissions()))
{
return false;
}
Set<String> authorities = loginUser.getPermissions();
for (String permission : permissions)
{
if (StringUtils.hasText(permission) && !hasPermissions(authorities, permission))
{
return false;
}
}
return true;
}
}

View File

@ -317,11 +317,11 @@ public class SysLoginService
smUserService.insertSmUser(newUser);
// 添加微信账户
Account accountData = new Account();
accountData.setUserId(newUser.getUserId());
accountData.setAccountNo(newUser.getWxOpenId());
accountData.setAccountType(AccountType.WECHAT.getType());
accountService.insertSmAccount(accountData);
// Account accountData = new Account();
// accountData.setUserId(newUser.getUserId());
// accountData.setAccountNo(newUser.getWxOpenId());
// accountData.setAccountType(AccountType.WECHAT.getType());
// accountService.insertSmAccount(accountData);
return newUser;
}

View File

@ -2,6 +2,8 @@ package com.ruoyi.system.domain;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.ruoyi.common.annotation.Excel;
@ -37,6 +39,17 @@ public class SysConfig extends BaseEntity
@Excel(name = "系统内置", readConverterExp = "Y=是,N=否")
private String configType;
@ApiModelProperty("权限")
private String permission;
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
public Long getConfigId()
{
return configId;

View File

@ -0,0 +1,22 @@
package com.ruoyi.system.domain.dto;
import com.ruoyi.system.domain.SysConfig;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @author wjh
* 2024/8/28
*/
@Data
public class SysConfigQuery extends SysConfig {
@ApiModelProperty("配置键值列表")
private List<String> configKeys;
@ApiModelProperty("配置ID列表")
private List<Long> configIds;
}

View File

@ -16,7 +16,10 @@ public enum ConfigKey {
SERVICE_FEE_RATE("sm.transactionBill.serviceFee", "充值服务费费率"),
WITHDRAW_SERVICE_FEE_RATE("sm.transactionBill.widthDraw.serviceFee", "提现服务费费率"),
WECHAT_APPROVAL("sys.wechat.approval", "微信小程序敏感内容展示");
WECHAT_APPROVAL("sys.wechat.approval", "微信小程序敏感内容展示"),
DAILY_WITHDRAW_AMOUNT("daily.withdraw.amount", "单日单用户提现限额(元)"),
DAILY_WITHDRAW_COUNT("daily.withdraw.count", "单日单用户提现次数(次)"),
NOVERIFY_WITHDRAW_SINGLE("noverify.withdraw.single", "提现单笔免审核额度(元)");
private final String key;
private final String msg;

View File

@ -2,6 +2,8 @@ package com.ruoyi.system.mapper;
import java.util.List;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.domain.dto.SysConfigQuery;
import org.apache.ibatis.annotations.Param;
/**
* 参数配置 数据层
@ -32,7 +34,7 @@ public interface SysConfigMapper
* @param config 参数配置信息
* @return 参数配置集合
*/
public List<SysConfig> selectConfigList(SysConfig config);
public List<SysConfig> selectConfigList(SysConfigQuery config);
/**
* 根据键名查询参数配置信息
@ -73,4 +75,6 @@ public interface SysConfigMapper
* @return 结果
*/
public int deleteConfigByIds(Long[] configIds);
int batchUpdateValue(@Param("list") List<SysConfig> list);
}

View File

@ -1,8 +1,10 @@
package com.ruoyi.system.service;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.domain.dto.SysConfigQuery;
import com.ruoyi.system.domain.enums.config.ConfigKey;
/**
@ -41,7 +43,7 @@ public interface ISysConfigService
* @param config 参数配置信息
* @return 参数配置集合
*/
public List<SysConfig> selectConfigList(SysConfig config);
public List<SysConfig> selectConfigList(SysConfigQuery config);
/**
* 新增参数配置
@ -100,4 +102,9 @@ public interface ISysConfigService
* @param key
*/
boolean getBoolean(ConfigKey key);
List<SysConfig> selectByIds(List<Long> configIds);
int batchUpdateValue(List<SysConfig> list);
}

View File

@ -2,10 +2,13 @@ package com.ruoyi.system.service.impl;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.system.domain.dto.SysConfigQuery;
import com.ruoyi.system.domain.enums.config.ConfigKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -20,6 +23,7 @@ import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysConfig;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.service.ISysConfigService;
import org.springframework.transaction.support.TransactionTemplate;
/**
* 参数配置 服务层实现
@ -35,6 +39,9 @@ public class SysConfigServiceImpl implements ISysConfigService
@Autowired
private RedisCache redisCache;
@Autowired
private TransactionTemplate transactionTemplate;
/**
* 项目启动时初始化参数到缓存
*/
@ -107,7 +114,7 @@ public class SysConfigServiceImpl implements ISysConfigService
* @return 参数配置集合
*/
@Override
public List<SysConfig> selectConfigList(SysConfig config)
public List<SysConfig> selectConfigList(SysConfigQuery config)
{
return configMapper.selectConfigList(config);
}
@ -178,7 +185,7 @@ public class SysConfigServiceImpl implements ISysConfigService
@Override
public void loadingConfigCache()
{
List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig());
List<SysConfig> configsList = configMapper.selectConfigList(new SysConfigQuery());
for (SysConfig config : configsList)
{
redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
@ -237,6 +244,37 @@ public class SysConfigServiceImpl implements ISysConfigService
return "true".equals(selectConfigByKey(key.getKey()));
}
@Override
public List<SysConfig> selectByIds(List<Long> configIds) {
if (CollectionUtils.isEmptyElement(configIds)) {
return Collections.emptyList();
}
SysConfigQuery query = new SysConfigQuery();
query.setConfigIds(configIds);
return selectConfigList(query);
}
@Override
public int batchUpdateValue(List<SysConfig> list) {
if (CollectionUtils.isEmptyElement(list)) {
return 0;
}
Integer result = transactionTemplate.execute(status -> {
int update = configMapper.batchUpdateValue(list);
ServiceUtil.assertion(update != list.size(), "更新失败");
return update;
});
if (result != null && result == list.size()) {
for (SysConfig sysConfig : list) {
redisCache.deleteObject(getCacheKey(sysConfig.getConfigKey()));
}
}
return result == null ? 0 : result;
}
/**
* 设置cache key
*

View File

@ -4,20 +4,21 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.system.mapper.SysConfigMapper">
<resultMap type="SysConfig" id="SysConfigResult">
<id property="configId" column="config_id" />
<result property="configName" column="config_name" />
<result property="configKey" column="config_key" />
<result property="configValue" column="config_value" />
<result property="configType" column="config_type" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<resultMap type="SysConfig" id="SysConfigResult" autoMapping="true"/>
<sql id="selectConfigVo">
select config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark
select
config_id,
config_name,
config_key,
config_value,
config_type,
create_by,
create_time,
update_by,
update_time,
remark,
permission
from sys_config
</sql>
@ -38,7 +39,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="sqlwhereSearch"/>
</select>
<select id="selectConfigList" parameterType="SysConfig" resultMap="SysConfigResult">
<select id="selectConfigList" parameterType="SysConfigQuery" resultMap="SysConfigResult">
<include refid="selectConfigVo"/>
<where>
<if test="configName != null and configName != ''">
@ -56,6 +57,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
</if>
<if test="configKeys != null and configKeys.size() > 0">
AND config_key in
<foreach collection="configKeys" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
<if test="configIds != null and configIds.size() > 0">
AND config_id in
<foreach collection="configIds" item="item" open="(" separator="," close=")">
#{item}
</foreach>
</if>
</where>
</select>
@ -77,6 +90,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="configType != null and configType != '' ">config_type,</if>
<if test="createBy != null and createBy != ''">create_by,</if>
<if test="remark != null and remark != ''">remark,</if>
<if test="permission != null">permission,</if>
create_time
)values(
<if test="configName != null and configName != ''">#{configName},</if>
@ -85,6 +99,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="configType != null and configType != ''">#{configType},</if>
<if test="createBy != null and createBy != ''">#{createBy},</if>
<if test="remark != null and remark != ''">#{remark},</if>
<if test="permission != null">#{permission},</if>
sysdate()
)
</insert>
@ -98,11 +113,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="configType != null and configType != ''">config_type = #{configType},</if>
<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
<if test="remark != null">remark = #{remark},</if>
<if test="permission != null">permission = #{permission},</if>
update_time = sysdate()
</set>
where config_id = #{configId}
</update>
<update id="batchUpdateValue">
update sys_config
<trim prefix="SET" suffixOverrides=",">
<foreach open="config_value = CASE config_id" collection="list" item="item" close="END,">
<choose>
<when test="item.configValue != null">
WHEN #{item.configId} THEN #{item.configValue}
</when>
<otherwise>
WHEN #{item.configId} THEN config_value
</otherwise>
</choose>
</foreach>
</trim>
WHERE config_id IN
<foreach open="(" collection="list" item="item" close=")" separator=",">
#{item.configId}
</foreach>
</update>
<delete id="deleteConfigById" parameterType="Long">
delete from sys_config where config_id = #{configId}
</delete>

View File

@ -56,4 +56,12 @@ public enum TransactionBillStatus {
public static boolean isCancel(String status) {
return asList(CANCELED, SYS_CANCELED).contains(status);
}
/**
* 限额统计的提现状态
*/
public static List<String> countOfLimit() {
return asList(WITHDRAW_SUCCESS, WITHDRAW_APPROVING, WITHDRAW_FAIL, WITHDRAW_PASSED, WITHDRAW_PAYING);
}
}

View File

@ -184,4 +184,11 @@ public interface TransactionBillMapper
* 简单查询数量
*/
int selectSimpleCount(@Param("query") TransactionBillQuery query);
/**
* 查询订单总金额
* @param query
* @return
*/
BigDecimal selectSumOfMoney(@Param("query") TransactionBillQuery query);
}

View File

@ -305,6 +305,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</where>
</select>
<select id="selectSumOfMoney" resultType="java.math.BigDecimal">
select sum(stb.money)
from <include refid="rechargeTables"/>
<where>
<include refid="searchCondition"/>
</where>
</select>
<insert id="insertSmTransactionBill" parameterType="TransactionBill" useGeneratedKeys="true" keyProperty="billId">
insert into sm_transaction_bill
<trim prefix="(" suffix=")" suffixOverrides=",">

View File

@ -276,4 +276,11 @@ public interface TransactionBillService
* 计算订单金额
*/
BigDecimal calcAmount(Long billId, LocalDateTime now, BigDecimal totalEle);
/**
* 查询订单总金额
* @param query
* @return
*/
BigDecimal selectSumOfMoney(TransactionBillQuery query);
}

View File

@ -54,6 +54,8 @@ import com.ruoyi.ss.user.domain.SmUserVo;
import com.ruoyi.common.enums.ServiceType;
import com.ruoyi.ss.user.service.ISmUserService;
import com.ruoyi.common.pay.wx.service.WxPayService;
import com.ruoyi.system.domain.enums.config.ConfigKey;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.task.bill.BillDelayedManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@ -142,6 +144,9 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
@Autowired
private IotService iotService;
@Autowired
private ISysConfigService sysConfigService;
/**
* 查询充值记录
*
@ -382,6 +387,37 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
SmUserVo user = bo.getUser();
AccountVO account = bo.getAccount();
ServiceUtil.assertion(user == null, "用户不存在");
ServiceUtil.assertion(user.getIsReal() == null || !user.getIsReal(), "用户未实名认证,无法提现");
// 判断今天提现成功和正在审核中的提现是否超过限额
String dailyLimitStr = sysConfigService.selectConfigByKey(ConfigKey.DAILY_WITHDRAW_AMOUNT.getKey());
String dailyLimitCountStr = sysConfigService.selectConfigByKey(ConfigKey.DAILY_WITHDRAW_COUNT.getKey());
if (StringUtils.hasText(dailyLimitStr) || StringUtils.hasText(dailyLimitCountStr)) {
// 查询条件
TransactionBillQuery query = new TransactionBillQuery();
query.setType(TransactionBillType.WITHDRAW.getType());
query.setStatusList(TransactionBillStatus.countOfLimit());
query.setCreateDate(DateUtils.getNowDate());
query.setUserId(user.getUserId());
// 每日限额
if (StringUtils.hasText(dailyLimitStr)) {
BigDecimal dailyLimit = new BigDecimal(dailyLimitStr);
BigDecimal current = this.selectSumOfMoney(query);
if (current == null) {
current = BigDecimal.ZERO;
}
ServiceUtil.assertion(current.add(dto.getMoney()).compareTo(dailyLimit) > 0, "当前用户提现金额已超过每日限额:" + dailyLimit + "");
}
// 每日限次
if (StringUtils.hasText(dailyLimitCountStr)) {
int dailyLimitCount = Integer.parseInt(dailyLimitCountStr);
int count = this.selectSimpleCount(query);
ServiceUtil.assertion(count + 1 > dailyLimitCount, "当前用户提现次数已超过每日限制:" + dailyLimitCount + "");
}
}
// 处理提现手续费
ServiceUtil.assertion(channel == null, "提现渠道不存在");
ServiceUtil.assertion(channel.getEnabled() == null || !channel.getEnabled(), "提现渠道不可用");
@ -428,6 +464,25 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
return insert;
});
// 异步操作当提现申请金额免审核且为线上打款时直接通过
try {
String noverifyAmountStr = sysConfigService.selectConfigByKey(ConfigKey.NOVERIFY_WITHDRAW_SINGLE.getKey());
if (StringUtils.hasText(noverifyAmountStr)) {
BigDecimal noverifyAmount = new BigDecimal(noverifyAmountStr);
if (noverifyAmount.compareTo(bill.getMoney()) >= 0) {
scheduledExecutorService.schedule(() -> {
WithdrawApprovalDTO passDto = new WithdrawApprovalDTO();
passDto.setBillId(bill.getBillId());
passDto.setWithdrawType(WithdrawType.ONLINE.getType());
passDto.setRemark("免审核通过");
this.passWithdraw(passDto);
}, 0, TimeUnit.SECONDS);
}
}
} catch (Exception e) {
log.error(e.getMessage());
}
return bill.getBillNo();
} finally {
redisLock.unlock(RedisLockKey.ADD_WITHDRAW, userId);
@ -531,23 +586,30 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
* 审核操作
*/
private int approvalWithdraw(WithdrawApprovalDTO dto, TransactionBillStatus status) {
TransactionBill data = new TransactionBill();
data.setStatus(status.getStatus());
data.setRemark(dto.getRemark());
data.setPayPicture(dto.getPayPicture());
data.setWithdrawType(dto.getWithdrawType());
data.setOfflineImage(dto.getOfflineImage());
Integer result = transactionTemplate.execute(s -> {
TransactionBill data = new TransactionBill();
data.setStatus(status.getStatus());
data.setRemark(dto.getRemark());
data.setPayPicture(dto.getPayPicture());
data.setWithdrawType(dto.getWithdrawType());
data.setOfflineImage(dto.getOfflineImage());
// 线下打款并且状态为已打款则修改支付时间为当前
if (WithdrawType.OFFLINE.getType().equals(dto.getWithdrawType()) && TransactionBillStatus.WITHDRAW_SUCCESS.equals(status)) {
data.setPayTime(DateUtils.getNowDate());
}
// 线下打款并且状态为已打款则修改支付时间为当前
if (WithdrawType.OFFLINE.getType().equals(dto.getWithdrawType()) && TransactionBillStatus.WITHDRAW_SUCCESS.equals(status)) {
data.setPayTime(DateUtils.getNowDate());
}
TransactionBillQuery query = new TransactionBillQuery();
query.setBillId(dto.getBillId());
query.setType(TransactionBillType.WITHDRAW.getType());
query.setStatus(TransactionBillStatus.WITHDRAW_APPROVING.getStatus());
return this.updateByQuery(data, query);
TransactionBillQuery query = new TransactionBillQuery();
query.setBillId(dto.getBillId());
query.setType(TransactionBillType.WITHDRAW.getType());
query.setStatus(TransactionBillStatus.WITHDRAW_APPROVING.getStatus());
int update = this.updateByQuery(data, query);
ServiceUtil.assertion(update != 1, "提现审核失败");
return update;
});
return result == null ? 0 : result;
}
@Override
@ -962,6 +1024,11 @@ public class TransactionBillServiceImpl implements TransactionBillService, After
return totalAmount;
}
@Override
public BigDecimal selectSumOfMoney(TransactionBillQuery query) {
return transactionBillMapper.selectSumOfMoney(query);
}
private BigDecimal calcRefundAmount(TransactionBillVO order, LocalDateTime endTime, BigDecimal totalEle) {
// 智能收费时长计费
if (SuitFeeType.TIME.getType().equals(order.getSuitFeeType())) {

View File

@ -0,0 +1,37 @@
package com.ruoyi.ss.user.domain.dto;
import com.ruoyi.common.utils.RegexpUtils;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* @author wjh
* 2024/8/26
*/
@Data
public class UserRealNameDTO {
@ApiModelProperty("用户ID")
private Long userId;
@ApiModelProperty("姓名")
@NotBlank(message = "姓名不允许为空")
@Size(max = 20, message = "姓名长度不能超过20")
private String realName;
@ApiModelProperty("身份证")
@NotBlank(message = "身份证不允许为空")
@Size(max = 18, message = "身份证长度不能超过18")
@Pattern(regexp = RegexpUtils.IDENTITY_CARD_REGEXP, message = "身份证号格式错误")
private String realIdCard;
@ApiModelProperty("手机号")
@NotBlank(message = "手机号不允许为空")
@Pattern(regexp = RegexpUtils.MOBILE_PHONE_REGEXP, message = "手机号格式错误")
private String realPhone;
}

View File

@ -41,6 +41,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
su.service_type,
su.withdraw_service_type,
su.withdraw_service_rate,
su.real_name,
su.real_id_card,
su.real_phone,
su.is_real,
(select sum(stb.money) from sm_transaction_bill stb where stb.user_id = su.user_id and stb.type = '1' and stb.status = '2') as recharge_amount,
(select sum(stb.arrival_amount) from sm_transaction_bill stb where stb.user_id = su.user_id and stb.type = '2' and stb.status = '14') as with_drawl_amount,
(select sum(stb.arrival_amount) from sm_transaction_bill stb where stb.mch_id = su.user_id and stb.type = '1' and stb.status = '2') as total_income
@ -151,6 +155,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serviceType != null">service_type,</if>
<if test="withdrawServiceType != null">withdraw_service_type,</if>
<if test="withdrawServiceRate != null">withdraw_service_rate,</if>
<if test="realName != null">real_name,</if>
<if test="realIdCard != null">real_id_card,</if>
<if test="realPhone != null">real_phone,</if>
<if test="isReal != null">is_real,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="userName != null and userName != ''">#{userName},</if>
@ -180,6 +188,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serviceType != null">#{serviceType},</if>
<if test="withdrawServiceType != null">#{withdrawServiceType},</if>
<if test="withdrawServiceRate != null">#{withdrawServiceRate},</if>
<if test="realName != null">#{realName},</if>
<if test="realIdCard != null">#{realIdCard},</if>
<if test="realPhone != null">#{realPhone},</if>
<if test="isReal != null">#{isReal},</if>
</trim>
</insert>
@ -219,6 +231,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="serviceType != null">service_type = #{serviceType},</if>
<if test="withdrawServiceType != null">withdraw_service_type = #{withdrawServiceType},</if>
<if test="withdrawServiceRate != null">withdraw_service_rate = #{withdrawServiceRate},</if>
<if test="realName != null">real_name = #{realName},</if>
<if test="realIdCard != null">real_id_card = #{realIdCard},</if>
<if test="realPhone != null">real_phone = #{realPhone},</if>
<if test="isReal != null">is_real = #{isReal},</if>
</trim>
where user_id = #{userId}
</update>

View File

@ -5,6 +5,7 @@ import com.ruoyi.common.enums.UserType;
import com.ruoyi.ss.recordBalance.domain.enums.RecordBalanceBstType;
import com.ruoyi.ss.user.domain.SmUserQuery;
import com.ruoyi.ss.user.domain.SmUserVo;
import com.ruoyi.ss.user.domain.dto.UserRealNameDTO;
import java.math.BigDecimal;
import java.util.List;
@ -203,4 +204,9 @@ public interface ISmUserService
* 查询用户总余额
*/
BigDecimal selectSumOfBalance(SmUserQuery smUserQuery);
/**
* 实名认证
*/
int realName(UserRealNameDTO dto);
}

View File

@ -6,6 +6,7 @@ import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.common.valid.realName.RealNameValidUtils;
import com.ruoyi.ss.device.domain.DeviceQuery;
import com.ruoyi.ss.device.domain.vo.DeviceVO;
import com.ruoyi.ss.device.service.DeviceService;
@ -16,6 +17,7 @@ import com.ruoyi.ss.store.domain.StoreVo;
import com.ruoyi.ss.store.service.StoreService;
import com.ruoyi.ss.user.domain.SmUserQuery;
import com.ruoyi.ss.user.domain.SmUserVo;
import com.ruoyi.ss.user.domain.dto.UserRealNameDTO;
import com.ruoyi.ss.user.mapper.SmUserMapper;
import com.ruoyi.ss.user.service.ISmUserService;
import org.springframework.beans.factory.annotation.Autowired;
@ -275,6 +277,26 @@ public class SmUserServiceImpl implements ISmUserService
return smUserMapper.selectSumOfBalance(query);
}
@Override
public int realName(UserRealNameDTO dto) {
SmUserVo user = selectSmUserByUserId(dto.getUserId());
ServiceUtil.assertion(user == null, "用户信息不存在");
ServiceUtil.assertion(user.getIsReal() != null && user.getIsReal(), "您已进行过实名认证,无需再次认证");
// 调用第三方API三要素验证
boolean check = RealNameValidUtils.validMobile3Info(dto.getRealIdCard(), dto.getRealPhone(), dto.getRealName());
ServiceUtil.assertion(!check, "请输入正确的身份信息:姓名、身份证、手机号需要一致");
// 修改实名信息
SmUser data = new SmUserQuery();
data.setUserId(dto.getUserId());
data.setRealName(dto.getRealName());
data.setRealIdCard(dto.getRealIdCard());
data.setRealPhone(dto.getRealPhone());
data.setIsReal(true);
return smUserMapper.updateSmUser(data);
}
/**
* 逻辑删除前校验
* @param userIds

View File

@ -8,6 +8,7 @@ import com.ruoyi.common.enums.UserType;
import com.ruoyi.common.utils.ServiceUtil;
import com.ruoyi.ss.user.domain.bo.SmUserBO;
import com.ruoyi.ss.user.domain.SmUserVo;
import com.ruoyi.ss.user.domain.dto.UserRealNameDTO;
import com.ruoyi.ss.user.service.ISmUserService;
import com.ruoyi.ss.user.service.UserAssembler;
import com.ruoyi.system.domain.enums.verificationCode.CodeBusinessType;
@ -15,10 +16,8 @@ import com.ruoyi.system.service.IVerificationCodeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.Collections;
import java.util.List;
@ -44,7 +43,7 @@ public class AppUserController extends BaseController {
@ApiOperation("获取当前登录前台用户的信息")
@GetMapping("/userInfo")
@JsonView(JsonViewProfile.App.class)
@JsonView(JsonViewProfile.AppMch.class)
public AjaxResult userInfo() {
// 查询
SmUserVo user = userService.selectSmUserByUserId(getUserId());
@ -69,5 +68,11 @@ public class AppUserController extends BaseController {
return AjaxResult.success(userService.updatePassword(getUserId(), bo.getPassword()));
}
@ApiOperation("用户实名认证")
@PutMapping("/realName")
public AjaxResult realName(@RequestBody @Validated UserRealNameDTO dto) {
dto.setUserId(getUserId());
return toAjax(userService.realName(dto));
}
}

View File

@ -1,7 +1,14 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.collection.CollectionUtils;
import com.ruoyi.framework.web.service.PermissionService;
import com.ruoyi.system.domain.dto.SysConfigQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
@ -34,12 +41,15 @@ public class SysConfigController extends BaseController
@Autowired
private ISysConfigService configService;
@Autowired
private PermissionService permissionService;
/**
* 获取参数配置列表
*/
@PreAuthorize("@ss.hasPermi('system:config:list')")
@GetMapping("/list")
public TableDataInfo list(SysConfig config)
public TableDataInfo list(SysConfigQuery config)
{
startPage();
List<SysConfig> list = configService.selectConfigList(config);
@ -49,7 +59,7 @@ public class SysConfigController extends BaseController
@Log(title = "参数管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasPermi('system:config:export')")
@PostMapping("/export")
public void export(HttpServletResponse response, SysConfig config)
public void export(HttpServletResponse response, SysConfigQuery config)
{
List<SysConfig> list = configService.selectConfigList(config);
ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
@ -130,4 +140,35 @@ public class SysConfigController extends BaseController
configService.resetConfigCache();
return success();
}
/**
* 根据参数键名列表查询参数值
*/
@GetMapping(value = "/configKeys/{configKeys}")
public AjaxResult getConfigKeys(@PathVariable List<String> configKeys)
{
SysConfigQuery query = new SysConfigQuery();
query.setConfigKeys(configKeys);
return success(configService.selectConfigList(query));
}
/**
* 批量修改参数配置
*/
@Log(title = "参数管理", businessType = BusinessType.UPDATE)
@PutMapping("/batchUpdateValue")
public AjaxResult batchUpdateValue(@Validated @RequestBody List<SysConfig> list) {
// 权限校验
Set<String> permissions = configService.selectByIds(CollectionUtils.map(list, SysConfig::getConfigId))
.stream()
.map(SysConfig::getPermission)
.filter(StringUtils::hasText)
.collect(Collectors.toSet());
if (!permissionService.hasAllPermi(permissions)) {
return error("修改参数失败,权限不足");
}
return toAjax(configService.batchUpdateValue(list));
}
}

View File

@ -43,7 +43,7 @@ spring:
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
database: 4
# 密码
password:
# 连接超时时间

View File

@ -48,6 +48,11 @@ bankValid:
appKey: 204590328
appCode: 32b6c6445b1a42ed862dd4202392c47d
appSecret: td0vIGZRy9GxIrpfnIrxSXFXVW34JxDh
# 实名认证
realName:
appKey: 204590328
appCode: 32b6c6445b1a42ed862dd4202392c47d
appSecret: td0vIGZRy9GxIrpfnIrxSXFXVW34JxDh
# 项目相关配置
ruoyi: