111
This commit is contained in:
@@ -9,7 +9,7 @@ import org.springframework.web.bind.annotation.*;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 福利接口
|
||||
* 福利中心接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/bonus")
|
||||
@@ -19,28 +19,52 @@ public class BonusController {
|
||||
private BonusService bonusService;
|
||||
|
||||
/**
|
||||
* 查询是否已领取新人福利
|
||||
* 获取福利中心状态
|
||||
*/
|
||||
@GetMapping("/status")
|
||||
public Result<Map<String, Object>> getStatus() {
|
||||
Long userId = UserContext.getUserId();
|
||||
if (userId == null) {
|
||||
return Result.unauthorized("请先登录");
|
||||
}
|
||||
return Result.success(bonusService.getStatus(userId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取新人福利
|
||||
*/
|
||||
@PostMapping("/claim")
|
||||
public Result<Map<String, Object>> claim() {
|
||||
@GetMapping("/welfare")
|
||||
public Result<Map<String, Object>> getWelfareStatus() {
|
||||
Long userId = UserContext.getUserId();
|
||||
if (userId == null) {
|
||||
return Result.unauthorized("请先登录");
|
||||
}
|
||||
try {
|
||||
return Result.success(bonusService.claim(userId));
|
||||
return Result.success(bonusService.getWelfareStatus(userId));
|
||||
} catch (Exception e) {
|
||||
return Result.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取奖励
|
||||
* body: { type: "new_user"|"referral", referredUserId?, milestone? }
|
||||
*/
|
||||
@PostMapping("/claim")
|
||||
public Result<Map<String, Object>> claim(@RequestBody Map<String, Object> params) {
|
||||
Long userId = UserContext.getUserId();
|
||||
if (userId == null) {
|
||||
return Result.unauthorized("请先登录");
|
||||
}
|
||||
|
||||
String type = (String) params.get("type");
|
||||
if (type == null || type.isEmpty()) {
|
||||
return Result.fail("请指定奖励类型");
|
||||
}
|
||||
|
||||
try {
|
||||
if ("new_user".equals(type)) {
|
||||
return Result.success("领取成功", bonusService.claimNewUserBonus(userId));
|
||||
} else if ("referral".equals(type)) {
|
||||
Object referredUserIdObj = params.get("referredUserId");
|
||||
Object milestoneObj = params.get("milestone");
|
||||
if (referredUserIdObj == null || milestoneObj == null) {
|
||||
return Result.fail("缺少参数");
|
||||
}
|
||||
Long referredUserId = Long.valueOf(referredUserIdObj.toString());
|
||||
int milestone = Integer.parseInt(milestoneObj.toString());
|
||||
return Result.success("领取成功", bonusService.claimReferralBonus(userId, referredUserId, milestone));
|
||||
} else {
|
||||
return Result.fail("无效的奖励类型");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return Result.fail(e.getMessage());
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ public class FundController {
|
||||
BigDecimal amount = request.getAmount();
|
||||
String remark = request.getRemark();
|
||||
|
||||
if (amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return Result.fail("充值金额必须大于0");
|
||||
if (amount == null || amount.compareTo(new BigDecimal("1000")) < 0) {
|
||||
return Result.fail("单笔充值金额不能低于1000 USDT");
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -85,12 +85,6 @@ public class FundController {
|
||||
return Result.unauthorized("请先登录");
|
||||
}
|
||||
|
||||
// KYC校验:提现前必须完成实名认证
|
||||
User user = userService.getById(userId);
|
||||
if (user == null || user.getKycStatus() == null || user.getKycStatus() != 2) {
|
||||
return Result.fail("KYC_REQUIRED", "请先完成实名认证");
|
||||
}
|
||||
|
||||
BigDecimal amount = request.getAmount();
|
||||
String withdrawAddress = request.getWithdrawAddress();
|
||||
String withdrawContact = request.getWithdrawContact();
|
||||
|
||||
@@ -19,12 +19,15 @@ public class UserController {
|
||||
private UserService userService;
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
* 用户注册(multipart:含身份证图片和可选推广码)
|
||||
*/
|
||||
@PostMapping("/register")
|
||||
public Result<Map<String, Object>> register(@RequestBody Map<String, String> params) {
|
||||
String username = params.get("username");
|
||||
String password = params.get("password");
|
||||
public Result<Map<String, Object>> register(
|
||||
@RequestPart("username") String username,
|
||||
@RequestPart("password") String password,
|
||||
@RequestPart(value = "referralCode", required = false) String referralCode,
|
||||
@RequestPart("front") MultipartFile front,
|
||||
@RequestPart("back") MultipartFile back) {
|
||||
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
return Result.fail("用户名不能为空");
|
||||
@@ -34,7 +37,8 @@ public class UserController {
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> result = userService.register(username.trim(), password);
|
||||
Map<String, Object> result = userService.register(
|
||||
username.trim(), password, referralCode, front, back);
|
||||
return Result.success("注册成功", result);
|
||||
} catch (Exception e) {
|
||||
return Result.fail(e.getMessage());
|
||||
@@ -109,12 +113,29 @@ public class UserController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取推广码
|
||||
*/
|
||||
@GetMapping("/referral-code")
|
||||
public Result<String> getReferralCode() {
|
||||
Long userId = UserContext.getUserId();
|
||||
if (userId == null) {
|
||||
return Result.unauthorized("请先登录");
|
||||
}
|
||||
|
||||
try {
|
||||
String code = userService.getReferralCode(userId);
|
||||
return Result.success(code);
|
||||
} catch (Exception e) {
|
||||
return Result.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登录
|
||||
*/
|
||||
@PostMapping("/logout")
|
||||
public Result<Void> logout() {
|
||||
// 客户端清除Token即可
|
||||
return Result.success("退出成功", null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,12 @@ public class User implements Serializable {
|
||||
/** 身份证反面照URL */
|
||||
private String idCardBack;
|
||||
|
||||
/** 推广码 */
|
||||
private String referralCode;
|
||||
|
||||
/** 推广人用户ID */
|
||||
private Long referredBy;
|
||||
|
||||
/** 状态: 0-禁用 1-正常 */
|
||||
private Integer status;
|
||||
|
||||
|
||||
@@ -4,25 +4,35 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.it.rattan.monisuo.entity.AccountFlow;
|
||||
import com.it.rattan.monisuo.entity.AccountFund;
|
||||
import com.it.rattan.monisuo.entity.User;
|
||||
import com.it.rattan.monisuo.mapper.AccountFlowMapper;
|
||||
import com.it.rattan.monisuo.mapper.AccountFundMapper;
|
||||
import com.it.rattan.monisuo.mapper.UserMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 福利服务
|
||||
* 福利中心服务
|
||||
*
|
||||
* 规则:
|
||||
* 1. 首充福利:新用户首次充值完成后可领取100u(一次性)
|
||||
* 2. 推广奖励:被推广人累计充值每满1000u,推广人领100u(多次触发,最高8次/人)
|
||||
*/
|
||||
@Service
|
||||
public class BonusService {
|
||||
|
||||
private static final BigDecimal BONUS_AMOUNT = new BigDecimal("50");
|
||||
private static final String BONUS_REMARK = "新人福利";
|
||||
private static final BigDecimal BONUS_AMOUNT = new BigDecimal("100");
|
||||
private static final BigDecimal MILESTONE_UNIT = new BigDecimal("1000");
|
||||
private static final int MAX_MILESTONES = 8;
|
||||
|
||||
private static final String NEW_USER_REMARK = "新人首充福利";
|
||||
private static final String REFERRAL_REMARK_PREFIX = "邀请奖励-";
|
||||
|
||||
@Autowired
|
||||
private AccountFundMapper accountFundMapper;
|
||||
@@ -33,52 +43,113 @@ public class BonusService {
|
||||
@Autowired
|
||||
private AssetService assetService;
|
||||
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
|
||||
/**
|
||||
* 查询领取状态
|
||||
* 获取福利中心状态
|
||||
*/
|
||||
public Map<String, Object> getStatus(Long userId) {
|
||||
public Map<String, Object> getWelfareStatus(Long userId) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("amount", BONUS_AMOUNT);
|
||||
result.put("claimed", hasClaimed(userId));
|
||||
|
||||
// 用户推广码
|
||||
User user = userMapper.selectById(userId);
|
||||
result.put("referralCode", user != null ? user.getReferralCode() : null);
|
||||
|
||||
// 首充福利状态
|
||||
AccountFund fund = assetService.getOrCreateFundAccount(userId);
|
||||
BigDecimal totalDeposit = fund.getTotalDeposit() != null ? fund.getTotalDeposit() : BigDecimal.ZERO;
|
||||
boolean hasDeposited = totalDeposit.compareTo(BigDecimal.ZERO) > 0;
|
||||
boolean newUserClaimed = hasClaimedByRemark(userId, NEW_USER_REMARK);
|
||||
|
||||
Map<String, Object> newUserBonus = new HashMap<>();
|
||||
newUserBonus.put("amount", BONUS_AMOUNT);
|
||||
newUserBonus.put("eligible", hasDeposited && !newUserClaimed);
|
||||
newUserBonus.put("claimed", newUserClaimed);
|
||||
newUserBonus.put("deposited", hasDeposited);
|
||||
result.put("newUserBonus", newUserBonus);
|
||||
|
||||
// 推广奖励状态
|
||||
List<Map<String, Object>> referralRewards = new ArrayList<>();
|
||||
|
||||
// 查找该用户推广的所有人
|
||||
LambdaQueryWrapper<User> referredWrapper = new LambdaQueryWrapper<>();
|
||||
referredWrapper.eq(User::getReferredBy, userId);
|
||||
List<User> referredUsers = userMapper.selectList(referredWrapper);
|
||||
|
||||
for (User referred : referredUsers) {
|
||||
Map<String, Object> referralInfo = new HashMap<>();
|
||||
referralInfo.put("userId", referred.getId());
|
||||
referralInfo.put("username", referred.getUsername());
|
||||
|
||||
// 被推广人的累计充值
|
||||
AccountFund referredFund = assetService.getOrCreateFundAccount(referred.getId());
|
||||
BigDecimal referredTotalDeposit = referredFund.getTotalDeposit() != null
|
||||
? referredFund.getTotalDeposit() : BigDecimal.ZERO;
|
||||
referralInfo.put("totalDeposit", referredTotalDeposit);
|
||||
|
||||
// 计算里程碑数
|
||||
int earnedMilestones = referredTotalDeposit.divide(MILESTONE_UNIT, 0, RoundingMode.DOWN).intValue();
|
||||
earnedMilestones = Math.min(earnedMilestones, MAX_MILESTONES);
|
||||
|
||||
// 查询已领取的里程碑
|
||||
Set<Integer> claimedMilestones = getClaimedMilestones(userId, referred.getId());
|
||||
|
||||
List<Map<String, Object>> milestones = new ArrayList<>();
|
||||
for (int i = 1; i <= MAX_MILESTONES; i++) {
|
||||
Map<String, Object> m = new HashMap<>();
|
||||
m.put("milestone", i);
|
||||
m.put("amount", BONUS_AMOUNT);
|
||||
m.put("threshold", MILESTONE_UNIT.multiply(new BigDecimal(i)));
|
||||
m.put("earned", i <= earnedMilestones);
|
||||
m.put("claimed", claimedMilestones.contains(i));
|
||||
m.put("claimable", i <= earnedMilestones && !claimedMilestones.contains(i));
|
||||
milestones.add(m);
|
||||
}
|
||||
referralInfo.put("milestones", milestones);
|
||||
|
||||
// 可领取数量
|
||||
int claimable = (int) milestones.stream()
|
||||
.filter(m -> Boolean.TRUE.equals(m.get("claimable")))
|
||||
.count();
|
||||
referralInfo.put("claimableCount", claimable);
|
||||
|
||||
referralRewards.add(referralInfo);
|
||||
}
|
||||
result.put("referralRewards", referralRewards);
|
||||
|
||||
// 总可领取数量
|
||||
int totalClaimable = (Boolean.TRUE.equals(newUserBonus.get("eligible")) ? 1 : 0);
|
||||
totalClaimable += referralRewards.stream()
|
||||
.mapToInt(r -> r.get("claimableCount") instanceof Number
|
||||
? ((Number) r.get("claimableCount")).intValue() : 0)
|
||||
.sum();
|
||||
result.put("totalClaimable", totalClaimable);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取新人福利
|
||||
* 领取首充福利
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> claim(Long userId) {
|
||||
// 检查是否已领取
|
||||
if (hasClaimed(userId)) {
|
||||
throw new RuntimeException("您已领取过新人福利");
|
||||
public Map<String, Object> claimNewUserBonus(Long userId) {
|
||||
if (hasClaimedByRemark(userId, NEW_USER_REMARK)) {
|
||||
throw new RuntimeException("您已领取过首充福利");
|
||||
}
|
||||
|
||||
// 获取资金账户
|
||||
AccountFund fund = assetService.getOrCreateFundAccount(userId);
|
||||
BigDecimal totalDeposit = fund.getTotalDeposit() != null ? fund.getTotalDeposit() : BigDecimal.ZERO;
|
||||
if (totalDeposit.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new RuntimeException("尚未完成充值,无法领取");
|
||||
}
|
||||
|
||||
BigDecimal balanceBefore = fund.getBalance();
|
||||
BigDecimal balanceAfter = balanceBefore.add(BONUS_AMOUNT);
|
||||
|
||||
// 更新余额
|
||||
fund.setBalance(balanceAfter);
|
||||
fund.setTotalDeposit(fund.getTotalDeposit().add(BONUS_AMOUNT));
|
||||
accountFundMapper.update(null, new LambdaUpdateWrapper<AccountFund>()
|
||||
.eq(AccountFund::getId, fund.getId())
|
||||
.set(AccountFund::getBalance, balanceAfter)
|
||||
.set(AccountFund::getTotalDeposit, fund.getTotalDeposit())
|
||||
.set(AccountFund::getUpdateTime, LocalDateTime.now()));
|
||||
|
||||
// 记录流水
|
||||
AccountFlow flow = new AccountFlow();
|
||||
flow.setUserId(userId);
|
||||
flow.setFlowNo(com.it.rattan.monisuo.util.OrderNoUtil.flowNo());
|
||||
flow.setFlowType(1); // 充值类型
|
||||
flow.setAmount(BONUS_AMOUNT);
|
||||
flow.setBalanceBefore(balanceBefore);
|
||||
flow.setBalanceAfter(balanceAfter);
|
||||
flow.setCoinCode("USDT");
|
||||
flow.setRemark(BONUS_REMARK);
|
||||
flow.setCreateTime(LocalDateTime.now());
|
||||
accountFlowMapper.insert(flow);
|
||||
updateFundBalance(fund, balanceAfter);
|
||||
assetService.createFlow(userId, 1, BONUS_AMOUNT, balanceBefore, balanceAfter,
|
||||
"USDT", null, NEW_USER_REMARK);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("amount", BONUS_AMOUNT);
|
||||
@@ -87,12 +158,96 @@ public class BonusService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已领取(通过流水记录判断)
|
||||
* 领取推广奖励
|
||||
*/
|
||||
private boolean hasClaimed(Long userId) {
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Map<String, Object> claimReferralBonus(Long referrerId, Long referredUserId, int milestone) {
|
||||
if (milestone < 1 || milestone > MAX_MILESTONES) {
|
||||
throw new RuntimeException("无效的里程碑");
|
||||
}
|
||||
|
||||
// 验证推广关系
|
||||
User referred = userMapper.selectById(referredUserId);
|
||||
if (referred == null || !referrerId.equals(referred.getReferredBy())) {
|
||||
throw new RuntimeException("推广关系不存在");
|
||||
}
|
||||
|
||||
// 检查里程碑是否已达到
|
||||
AccountFund referredFund = assetService.getOrCreateFundAccount(referredUserId);
|
||||
BigDecimal referredTotalDeposit = referredFund.getTotalDeposit() != null
|
||||
? referredFund.getTotalDeposit() : BigDecimal.ZERO;
|
||||
int earnedMilestones = referredTotalDeposit
|
||||
.divide(MILESTONE_UNIT, 0, RoundingMode.DOWN).intValue();
|
||||
if (milestone > earnedMilestones) {
|
||||
throw new RuntimeException("该里程碑尚未达到");
|
||||
}
|
||||
|
||||
// 检查是否已领取
|
||||
String remark = REFERRAL_REMARK_PREFIX + referredUserId + "-" + milestone;
|
||||
if (hasClaimedByRemark(referrerId, remark)) {
|
||||
throw new RuntimeException("该里程碑奖励已领取");
|
||||
}
|
||||
|
||||
// 发放奖励
|
||||
AccountFund referrerFund = assetService.getOrCreateFundAccount(referrerId);
|
||||
BigDecimal balanceBefore = referrerFund.getBalance();
|
||||
BigDecimal balanceAfter = balanceBefore.add(BONUS_AMOUNT);
|
||||
|
||||
updateFundBalance(referrerFund, balanceAfter);
|
||||
assetService.createFlow(referrerId, 1, BONUS_AMOUNT, balanceBefore, balanceAfter,
|
||||
"USDT", null, remark);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("amount", BONUS_AMOUNT);
|
||||
result.put("balance", balanceAfter);
|
||||
result.put("referredUserId", referredUserId);
|
||||
result.put("milestone", milestone);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新资金账户余额
|
||||
*/
|
||||
private void updateFundBalance(AccountFund fund, BigDecimal newBalance) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
LambdaUpdateWrapper<AccountFund> wrapper = new LambdaUpdateWrapper<>();
|
||||
wrapper.eq(AccountFund::getId, fund.getId())
|
||||
.set(AccountFund::getBalance, newBalance)
|
||||
.set(AccountFund::getUpdateTime, now);
|
||||
accountFundMapper.update(null, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否已通过 remark 领取过
|
||||
*/
|
||||
private boolean hasClaimedByRemark(Long userId, String remark) {
|
||||
LambdaQueryWrapper<AccountFlow> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AccountFlow::getUserId, userId)
|
||||
.eq(AccountFlow::getRemark, BONUS_REMARK);
|
||||
.eq(AccountFlow::getRemark, remark);
|
||||
return accountFlowMapper.selectCount(wrapper) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取已领取的推广里程碑集合
|
||||
*/
|
||||
private Set<Integer> getClaimedMilestones(Long referrerId, Long referredUserId) {
|
||||
String prefix = REFERRAL_REMARK_PREFIX + referredUserId + "-";
|
||||
LambdaQueryWrapper<AccountFlow> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(AccountFlow::getUserId, referrerId)
|
||||
.likeRight(AccountFlow::getRemark, prefix);
|
||||
List<AccountFlow> flows = accountFlowMapper.selectList(wrapper);
|
||||
|
||||
Set<Integer> milestones = new HashSet<>();
|
||||
for (AccountFlow flow : flows) {
|
||||
String remark = flow.getRemark();
|
||||
if (remark != null && remark.startsWith(prefix)) {
|
||||
try {
|
||||
int m = Integer.parseInt(remark.substring(prefix.length()));
|
||||
milestones.add(m);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return milestones;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,8 +53,18 @@ public class FundService {
|
||||
*/
|
||||
@Transactional
|
||||
public Map<String, Object> deposit(Long userId, BigDecimal amount, String remark) {
|
||||
if (amount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new RuntimeException("充值金额必须大于0");
|
||||
if (amount.compareTo(new BigDecimal("1000")) < 0) {
|
||||
throw new RuntimeException("单笔充值金额不能低于1000 USDT");
|
||||
}
|
||||
|
||||
// 检查累计充值上限
|
||||
AccountFund fund = accountFundMapper.selectOne(
|
||||
new LambdaQueryWrapper<AccountFund>().eq(AccountFund::getUserId, userId));
|
||||
if (fund != null) {
|
||||
BigDecimal totalAfterDeposit = fund.getTotalDeposit().add(amount);
|
||||
if (totalAfterDeposit.compareTo(new BigDecimal("8000")) > 0) {
|
||||
throw new RuntimeException("累计充值金额不能超过8000 USDT");
|
||||
}
|
||||
}
|
||||
|
||||
User user = userMapper.selectById(userId);
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.it.rattan.monisuo.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.it.rattan.monisuo.context.UserContext;
|
||||
import com.it.rattan.monisuo.entity.AccountFund;
|
||||
import com.it.rattan.monisuo.entity.User;
|
||||
import com.it.rattan.monisuo.mapper.AccountFundMapper;
|
||||
@@ -18,6 +17,7 @@ import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* 用户服务
|
||||
@@ -32,12 +32,14 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
private AccountFundMapper accountFundMapper;
|
||||
|
||||
private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
private static final String CHARS = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
* 用户注册(含KYC和推广码)
|
||||
*/
|
||||
@Transactional
|
||||
public Map<String, Object> register(String username, String password) {
|
||||
public Map<String, Object> register(String username, String password, String referralCode,
|
||||
MultipartFile frontFile, MultipartFile backFile) throws IOException {
|
||||
// 检查用户名是否存在
|
||||
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(User::getUsername, username);
|
||||
@@ -53,6 +55,40 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
user.setKycStatus(0);
|
||||
user.setStatus(1);
|
||||
user.setCreateTime(LocalDateTime.now());
|
||||
|
||||
// 生成唯一推广码
|
||||
user.setReferralCode(generateReferralCode());
|
||||
|
||||
// 处理推广码:如果填了推广码,查找推广人
|
||||
if (referralCode != null && !referralCode.trim().isEmpty()) {
|
||||
LambdaQueryWrapper<User> refWrapper = new LambdaQueryWrapper<>();
|
||||
refWrapper.eq(User::getReferralCode, referralCode.trim());
|
||||
User referrer = userMapper.selectOne(refWrapper);
|
||||
if (referrer == null) {
|
||||
throw new RuntimeException("推广码不存在");
|
||||
}
|
||||
user.setReferredBy(referrer.getId());
|
||||
}
|
||||
|
||||
// 保存身份证图片
|
||||
if (frontFile != null && !frontFile.isEmpty() && backFile != null && !backFile.isEmpty()) {
|
||||
try {
|
||||
String uploadDir = System.getProperty("user.dir") + File.separator + "uploads" + File.separator + "kyc";
|
||||
File dir = new File(uploadDir);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdirs();
|
||||
}
|
||||
String timestamp = String.valueOf(System.currentTimeMillis());
|
||||
String frontName = saveFile(frontFile, dir, "reg_" + timestamp + "_front");
|
||||
String backName = saveFile(backFile, dir, "reg_" + timestamp + "_back");
|
||||
user.setIdCardFront("/uploads/kyc/" + frontName);
|
||||
user.setIdCardBack("/uploads/kyc/" + backName);
|
||||
user.setKycStatus(2); // 虚拟KYC:提交即自动通过
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("身份证图片保存失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
userMapper.insert(user);
|
||||
|
||||
// 初始化资金账户
|
||||
@@ -67,8 +103,6 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
|
||||
// 生成Token
|
||||
String token = JwtUtil.createToken(user.getId(), username, "user");
|
||||
|
||||
// 更新Token
|
||||
user.setToken(token);
|
||||
userMapper.updateById(user);
|
||||
|
||||
@@ -82,7 +116,6 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
* 用户登录
|
||||
*/
|
||||
public Map<String, Object> login(String username, String password) {
|
||||
// 查询用户
|
||||
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(User::getUsername, username);
|
||||
User user = userMapper.selectOne(wrapper);
|
||||
@@ -90,19 +123,14 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
if (user == null) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
}
|
||||
|
||||
if (user.getStatus() == 0) {
|
||||
throw new RuntimeException("账号已被禁用");
|
||||
}
|
||||
|
||||
if (!passwordEncoder.matches(password, user.getPassword())) {
|
||||
throw new RuntimeException("密码错误");
|
||||
}
|
||||
|
||||
// 生成新Token
|
||||
String token = JwtUtil.createToken(user.getId(), username, "user");
|
||||
|
||||
// 更新登录信息
|
||||
user.setToken(token);
|
||||
user.setLastLoginTime(LocalDateTime.now());
|
||||
userMapper.updateById(user);
|
||||
@@ -135,7 +163,6 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
}
|
||||
|
||||
try {
|
||||
// 上传目录:项目工作目录下的 uploads/kyc/
|
||||
String uploadDir = System.getProperty("user.dir") + File.separator + "uploads" + File.separator + "kyc";
|
||||
File dir = new File(uploadDir);
|
||||
if (!dir.exists()) {
|
||||
@@ -146,10 +173,9 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
String frontPath = saveFile(frontFile, dir, userId + "_front_" + timestamp);
|
||||
String backPath = saveFile(backFile, dir, userId + "_back_" + timestamp);
|
||||
|
||||
// 存储相对访问路径
|
||||
user.setIdCardFront("/uploads/kyc/" + frontPath);
|
||||
user.setIdCardBack("/uploads/kyc/" + backPath);
|
||||
user.setKycStatus(2); // 虚拟KYC:提交即自动通过
|
||||
user.setKycStatus(2);
|
||||
user.setUpdateTime(LocalDateTime.now());
|
||||
userMapper.updateById(user);
|
||||
} catch (IOException e) {
|
||||
@@ -157,6 +183,37 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户推广码
|
||||
*/
|
||||
public String getReferralCode(Long userId) {
|
||||
User user = userMapper.selectById(userId);
|
||||
if (user == null) {
|
||||
throw new RuntimeException("用户不存在");
|
||||
}
|
||||
return user.getReferralCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一推广码
|
||||
*/
|
||||
private String generateReferralCode() {
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
StringBuilder sb = new StringBuilder(8);
|
||||
for (int j = 0; j < 8; j++) {
|
||||
sb.append(CHARS.charAt(random.nextInt(CHARS.length())));
|
||||
}
|
||||
String code = sb.toString();
|
||||
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(User::getReferralCode, code);
|
||||
if (userMapper.selectCount(wrapper) == 0) {
|
||||
return code;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("生成推广码失败,请重试");
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存上传文件,返回保存的文件名
|
||||
*/
|
||||
@@ -186,6 +243,7 @@ public class UserService extends ServiceImpl<UserMapper, User> {
|
||||
info.put("email", user.getEmail());
|
||||
info.put("kycStatus", user.getKycStatus());
|
||||
info.put("status", user.getStatus());
|
||||
info.put("referralCode", user.getReferralCode());
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user