zhangkaikai 2 lat temu
rodzic
commit
83520608cc

+ 69 - 8
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserMineController.java

@@ -25,6 +25,8 @@ import com.qs.mp.user.domain.UserCoin;
 import com.qs.mp.user.domain.UserCoinLog;
 import com.qs.mp.user.domain.UserCoupon;
 import com.qs.mp.user.domain.UserPrizeStorage;
+import com.qs.mp.user.domain.dto.CoinTransferParamDTO;
+import com.qs.mp.user.domain.param.CoinTransferParam;
 import com.qs.mp.user.domain.param.CouponChannelQueryParam;
 import com.qs.mp.user.domain.param.UserPrizeStorageUpdateParam;
 import com.qs.mp.user.domain.vo.UserCouponVO;
@@ -36,25 +38,20 @@ import com.qs.mp.user.service.IUserPrizeStorageService;
 import com.qs.mp.user.service.IUserTicketOrderItemService;
 import com.qs.mp.utils.SecurityUtils;
 import com.qs.mp.web.controller.common.BaseApiController;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.*;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-import io.swagger.annotations.ApiResponse;
-import io.swagger.annotations.ApiResponses;
+import java.util.Objects;
 import java.util.stream.Collectors;
 import lombok.AllArgsConstructor;
 import ma.glasnost.orika.MapperFacade;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.util.CollectionUtils;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 
 @RestController
@@ -263,6 +260,70 @@ public class UserMineController extends BaseApiController {
         return getDataTable(userCoinLogList);
     }
 
+    /**
+     * 根据手机号查询用户昵称
+     */
+    @PostMapping("/sysUser/mobile/{mobile}")
+    @ApiOperation(value = "根据手机号查询用户信息")
+    @ApiImplicitParams(
+            @ApiImplicitParam(name = "mobile", value = "手机号", required = true, dataType = "String", paramType = "path")
+    )
+    @ApiResponses(
+            @ApiResponse(code = 200, message = "成功", response = SysUser.class)
+    )
+    public AjaxResult sysUserInfoByMobile(@PathVariable("mobile") String mobile){
+        if (StringUtils.isBlank(mobile)) {
+            return AjaxResult.success();
+        }
+        SysUser user = userService.selectNickNameByPhoneNumber(mobile);
+        if (Objects.isNull(user)) {
+            return AjaxResult.error("未查询到用户");
+        }
+        return AjaxResult.success(user);
+    }
+
+    /**
+     * 盲豆转让
+     */
+    @PostMapping("/coin/transfer/save")
+    @ApiOperation(value = "盲豆转赠")
+    public AjaxResult transfer(@RequestBody CoinTransferParam coinTransferParam) {
+        // 自己为转让人
+        Long fromUserId = SecurityUtils.getUserId();
+        if (fromUserId == null) {
+            return AjaxResult.error("非法调用");
+        }
+        if (StringUtils.isBlank(coinTransferParam.getPhone())
+                || Objects.isNull(coinTransferParam.getTransferCoin())) {
+            return AjaxResult.error("转赠参数不能为空");
+        }
+
+        // 校验受赠人信息
+        SysUser toUser = userService.selectUserByPhoneNumber(coinTransferParam.getPhone());
+
+        // 查询转赠人信息
+        if (Objects.isNull(toUser)) {
+            return AjaxResult.error("未查询到受赠用户");
+        }
+        if (fromUserId.equals(toUser.getUserId())) {
+            return AjaxResult.error("不能转赠给自己");
+        }
+
+        CoinTransferParamDTO coinTransferParamDTO = new CoinTransferParamDTO();
+        coinTransferParamDTO.setFromUserId(fromUserId);
+        coinTransferParamDTO.setToUserId(toUser.getUserId());
+        coinTransferParamDTO.setToPhone(toUser.getPhonenumber());
+        coinTransferParamDTO.setFromPhone(coinTransferParam.getPhone());
+        coinTransferParamDTO.setRealTransferCoin(coinTransferParam.getTransferCoin() - 10);
+        coinTransferParamDTO.setDeductTransferCoin(10);
+
+
+
+        // 转赠盲豆
+        boolean flag = userCoinService.transfer(coinTransferParamDTO);
+
+        return AjaxResult.success(flag);
+    }
     /**
      * 我的实物奖品库
      */

+ 2 - 1
mp-common/src/main/java/com/qs/mp/common/enums/CoinLogTypeEnum.java

@@ -13,7 +13,8 @@ public enum CoinLogTypeEnum implements IEnum<Integer> {
   PRIZE(1, "盲票奖品"),
   EXCHANGE(2, "兑换商品"),
   MARKETING(3,"营销活动"),
-  RECOVERY(4,"商品兑换");
+  RECOVERY(4,"商品兑换"),
+  TRANSFER(5,"盲豆转赠");
 
 
   private final int value;

+ 5 - 1
mp-service/src/main/java/com/qs/mp/framework/redis/RedisLockKey.java

@@ -17,7 +17,11 @@ public enum RedisLockKey {
     MARKETING_JOIN_LOCK("marketing_join_lock_{0}", "活动参与锁"),
 
     MARKETING_LOTTERY_KEY("marketing_lottery_key_{0}","免费抽奖活动开奖"),
-    USER_TICKET_CASH_LOCK("user_ticket_cash_lock_{0}", "盲票兑奖锁");
+    USER_TICKET_CASH_LOCK("user_ticket_cash_lock_{0}", "盲票兑奖锁"),
+
+    USER_COIN_TRANSFER_LOCK("user_coin_transfer_lock_{0}", "盲豆转赠锁"),
+    ;
+
 
     public String keyTemplate;
     public String desc;

+ 1 - 0
mp-service/src/main/java/com/qs/mp/system/mapper/SysUserMapper.java

@@ -160,4 +160,5 @@ public interface SysUserMapper  extends BaseMapper<SysUser>
      */
     SysUser selectUserByPhoneNumber(@Param("phone") String phone);
 
+    SysUser selectNickNameByPhoneNumber(String phone);
 }

+ 5 - 0
mp-service/src/main/java/com/qs/mp/system/service/ISysUserService.java

@@ -236,4 +236,9 @@ public interface ISysUserService  extends IService<SysUser>
      * @return
      */
     SysUser selectUserByPhoneNumber(String phone);
+
+    /**
+     * 根据手机号查询用户昵称
+     */
+    SysUser selectNickNameByPhoneNumber(String phone);
 }

+ 5 - 2
mp-service/src/main/java/com/qs/mp/system/service/impl/SysUserServiceImpl.java

@@ -1,8 +1,6 @@
 package com.qs.mp.system.service.impl;
 
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.qs.mp.channel.domain.ChannelBankCard;
-import com.qs.mp.channel.mapper.ChannelBankCardMapper;
 import com.qs.mp.common.annotation.DataScope;
 import com.qs.mp.common.constant.UserConstants;
 import com.qs.mp.common.exception.ServiceException;
@@ -582,4 +580,9 @@ public class SysUserServiceImpl  extends ServiceImpl<SysUserMapper, SysUser> imp
     public SysUser selectUserByPhoneNumber(String phone) {
         return userMapper.selectUserByPhoneNumber(phone);
     }
+
+    @Override
+    public SysUser selectNickNameByPhoneNumber(String phone) {
+        return userMapper.selectNickNameByPhoneNumber(phone);
+    }
 }

+ 5 - 0
mp-service/src/main/java/com/qs/mp/user/domain/UserCoinLog.java

@@ -89,5 +89,10 @@ public class UserCoinLog implements Serializable {
   @TableField("updated_time")
   private Date updatedTime;
 
+  /**
+   * 盲豆受赠人手机号
+   */
+  @TableField("mobile")
+  private Integer mobile;
 
 }

+ 31 - 0
mp-service/src/main/java/com/qs/mp/user/domain/dto/CoinTransferParamDTO.java

@@ -0,0 +1,31 @@
+package com.qs.mp.user.domain.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 盲豆转赠
+ * @author zhangkaikai
+ * @create 2023-04-24 5:25 PM
+ **/
+
+@Data
+public class CoinTransferParamDTO {
+
+    // 转赠方id
+    private Long FromUserId;
+
+    // 受赠方id
+    private Long ToUserId;
+
+    // 转赠方手机
+    private String ToPhone;
+    // 受赠方手机
+    private String FromPhone;
+
+    // 实际转赠盲豆
+    private Integer realTransferCoin;
+
+    // 转赠损耗盲豆
+    private Integer deductTransferCoin;
+}

+ 24 - 0
mp-service/src/main/java/com/qs/mp/user/domain/param/CoinTransferParam.java

@@ -0,0 +1,24 @@
+package com.qs.mp.user.domain.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import lombok.Data;
+
+/**
+ * @author zhangkaikai
+ * @create 2023-04-21 4:01 PM
+ **/
+
+@ApiOperation("盲豆转赠入参类")
+@Data
+public class CoinTransferParam {
+
+
+    @ApiModelProperty("受赠用户手机号")
+    private String phone;
+
+    @ApiModelProperty("转赠盲豆数量")
+    private Integer transferCoin;
+
+
+}

+ 8 - 0
mp-service/src/main/java/com/qs/mp/user/service/IUserCoinService.java

@@ -3,6 +3,7 @@ package com.qs.mp.user.service;
 import com.qs.mp.common.enums.CoinLogTypeEnum;
 import com.qs.mp.user.domain.UserCoin;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.qs.mp.user.domain.dto.CoinTransferParamDTO;
 
 /**
  * <p>
@@ -29,4 +30,11 @@ public interface IUserCoinService extends IService<UserCoin> {
    * @param bizId
    */
   void consume(Long userId, Integer logCoin, String bizId);
+
+  /**
+   *
+   * @param coinTransferParamDTO 盲豆转赠参数
+   * @return
+   */
+  boolean transfer(CoinTransferParamDTO coinTransferParamDTO);
 }

+ 71 - 0
mp-service/src/main/java/com/qs/mp/user/service/impl/UserCoinServiceImpl.java

@@ -1,9 +1,15 @@
 package com.qs.mp.user.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.redis.DistributedLocker;
 import com.qs.mp.common.enums.CoinLogTypeEnum;
+import com.qs.mp.common.exception.ServiceException;
+import com.qs.mp.framework.redis.RedisLockKey;
 import com.qs.mp.user.domain.UserCoin;
 import com.qs.mp.user.domain.UserCoinLog;
+import com.qs.mp.user.domain.dto.CoinTransferParamDTO;
+import com.qs.mp.user.domain.param.CoinTransferParam;
 import com.qs.mp.user.mapper.UserCoinMapper;
 import com.qs.mp.user.service.IUserCoinLogService;
 import com.qs.mp.user.service.IUserCoinService;
@@ -28,6 +34,9 @@ public class UserCoinServiceImpl extends ServiceImpl<UserCoinMapper, UserCoin> i
   @Autowired
   private IUserCoinLogService userCoinLogService;
 
+  @Autowired
+  private DistributedLocker distributedLocker;
+
   @Override
   @Transactional(rollbackFor = Exception.class)
   public void produce(Long userId, Integer logCoin, String bizId, CoinLogTypeEnum coinLogTypeEnum) {
@@ -76,4 +85,66 @@ public class UserCoinServiceImpl extends ServiceImpl<UserCoinMapper, UserCoin> i
     userCoinLog.setRefId(bizId);
     userCoinLogService.save(userCoinLog);
   }
+
+  @Override
+  @Transactional
+  public boolean transfer(CoinTransferParamDTO coinTransferParamDTO) {
+
+    // 转赠限制规则
+    // 一天:受赠人每天受赠10次,上限2000
+    // 一周:受赠人每周受赠50次,上限6000
+    // 每月:受赠人每月受赠100次,上限15000
+    // 每季度:受赠人每季度受赠500次,上限30000
+
+
+
+    String LockKey = RedisLockKey.build(RedisLockKey.USER_COIN_TRANSFER_LOCK, coinTransferParamDTO.getFromUserId());
+    if (!distributedLocker.tryLock(LockKey)) {
+      throw new ServiceException("系统繁忙,请稍后再试");
+    }
+    try {
+      // 获取转赠方拥有盲豆数量
+      UserCoin userCoin = getById(coinTransferParamDTO.getFromUserId());
+      if (userCoin.getCoin() < (coinTransferParamDTO.getRealTransferCoin() + coinTransferParamDTO.getDeductTransferCoin())) {
+        throw new ServiceException("您的盲豆数量不足,不能转赠");
+      }
+      // 扣除转赠方盲豆
+      boolean rtn1 = update(new LambdaUpdateWrapper<UserCoin>().set(UserCoin::getCoin, userCoin.getCoin() - (coinTransferParamDTO.getRealTransferCoin() + coinTransferParamDTO.getDeductTransferCoin()))
+              .eq(UserCoin::getUserId, coinTransferParamDTO.getFromUserId()));
+      Assert.isTrue(rtn1, "扣除转赠方盲豆失败, userId:" + coinTransferParamDTO.getFromUserId());
+      // 增加受赠方盲豆
+      UserCoin toUserCoin = getById(coinTransferParamDTO.getToUserId());
+      boolean rtn2 = update(new LambdaUpdateWrapper<UserCoin>().set(UserCoin::getCoin, toUserCoin.getCoin() + coinTransferParamDTO.getRealTransferCoin())
+              .eq(UserCoin::getUserId, coinTransferParamDTO.getToUserId()));
+      Assert.isTrue(rtn2, "增加受赠方盲豆失败,userId:" + coinTransferParamDTO.getToUserId());
+
+      // 盲豆转赠日志
+      UserCoinLog userCoinFromLog = new UserCoinLog();
+      userCoinFromLog.setUserId(coinTransferParamDTO.getFromUserId());
+      userCoinFromLog.setType(CoinLogTypeEnum.TRANSFER);
+      userCoinFromLog.setMoney(userCoin.getCoin() - (coinTransferParamDTO.getRealTransferCoin() + coinTransferParamDTO.getDeductTransferCoin()));
+      userCoinFromLog.setLogMoney(-(coinTransferParamDTO.getRealTransferCoin() + coinTransferParamDTO.getDeductTransferCoin()));
+      userCoinFromLog.setIncomeExpense(CoinLogTypeEnum.EXPENSES);
+      userCoinFromLog.setLogText("盲豆转赠:(" + coinTransferParamDTO.getFromPhone() + ")" + ",转赠折损:" + coinTransferParamDTO.getDeductTransferCoin() + "盲豆");
+      userCoinFromLog.setBizTime(new Date());
+      userCoinFromLog.setCreatedTime(new Date());
+      userCoinFromLog.setUpdatedTime(new Date());
+      userCoinLogService.save(userCoinFromLog);
+
+      UserCoinLog userCoinToLog = new UserCoinLog();
+      userCoinToLog.setUserId(coinTransferParamDTO.getToUserId());
+      userCoinToLog.setType(CoinLogTypeEnum.TRANSFER);
+      userCoinToLog.setMoney(toUserCoin.getCoin() + coinTransferParamDTO.getRealTransferCoin());
+      userCoinToLog.setLogMoney(coinTransferParamDTO.getRealTransferCoin());
+      userCoinToLog.setIncomeExpense(CoinLogTypeEnum.INCOME);
+      userCoinToLog.setLogText("盲豆转赠:(" + coinTransferParamDTO.getFromPhone() + ")");
+      userCoinToLog.setBizTime(new Date());
+      userCoinToLog.setCreatedTime(new Date());
+      userCoinToLog.setUpdatedTime(new Date());
+      userCoinLogService.save(userCoinToLog);
+    } finally {
+      distributedLocker.unlock(LockKey);
+    }
+    return true;
+  }
 }

+ 4 - 0
mp-service/src/main/resources/mapper/system/SysUserMapper.xml

@@ -253,4 +253,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 		from sys_user
 		where phonenumber = #{phone}
     </select>
+	<select id="selectNickNameByPhoneNumber" resultType="com.qs.mp.system.domain.SysUser">
+		select nick_name from sys_user where phonenumber = #{phone}
+	</select>
+
 </mapper>