领取优惠券

文章目录

概要

领券的本质就是新增一条记录到user_coupon表,去记录用户和领券的优惠券之间的关系,使用状态等信息。那因此请求的需要两个参数:

  • 用户id

  • 优惠券id

不过,用户id我们可以自己获取,因此前端只要传递优惠券id即可。只传一个参数,我们可以直接用路径占位符传参。

返回值就更不需要了,因此接口信息非常简单,如下:

需求分析以及接口设计

技术细节

不过,需要注意的是,优惠券并不是任何人来了都可以领取的,我们需要做一系列的校验:

  • 校验优惠券是否存在,不存在无法领取

  • 校验优惠券的发放时间,是不是正在发放中

  • 校验优惠券剩余库存是否充足

  • 校验优惠券的每人限领数量

只有全部校验通过,才可以领取优惠券,而领券要做两件事:

  • 新增一个记录到user_coupon表

  • 更新coupon表中已经领取的数量,别忘了在coupon表中是有一些统计字段的

      更新发行数量(已领取数量),不仅仅起到统计作用,同时也可以帮助我们判断库存是否充足。

      issue_num >= total_num时,那就证明库存已经不足了。

      1.Controller层

      package com.tianji.promotion.controller;
      
      import com.tianji.promotion.service.IUserCouponService;
      import io.swagger.annotations.Api;
      import io.swagger.annotations.ApiOperation;
      import io.swagger.annotations.ApiParam;
      import lombok.RequiredArgsConstructor;
      import org.springframework.web.bind.annotation.*;
      
      import java.util.List;
      
      @RestController
      @RequiredArgsConstructor
      @RequestMapping("/user-coupons")
      @Api(tags = "优惠券相关接口")
      public class UserCouponController {
      
          private final IUserCouponService userCouponService;
      
          @ApiOperation("领取优惠券接口")
          @PostMapping("/{couponId}/receive")
          public void receiveCoupon(@PathVariable("couponId") Long couponId){
              userCouponService.receiveCoupon(couponId);
          }
      }

      2.Service层:

      package com.tianji.promotion.service.impl;
      
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.tianji.common.exceptions.BizIllegalException;
      import com.tianji.common.exceptions.DbException;
      import com.tianji.common.utils.BeanUtils;
      import com.tianji.common.utils.CollUtils;
      import com.tianji.common.utils.NumberUtils;
      import com.tianji.common.utils.UserContext;
      import com.tianji.promotion.constants.PromotionConstants;
      import com.tianji.promotion.domain.dto.UserCouponDTO;
      import com.tianji.promotion.domain.po.Coupon;
      import com.tianji.promotion.domain.po.UserCoupon;
      import com.tianji.promotion.enums.UserCouponStatus;
      import com.tianji.promotion.mapper.CouponMapper;
      import com.tianji.promotion.mapper.UserCouponMapper;
      import com.tianji.promotion.service.IUserCouponService;
      import com.tianji.promotion.utils.CodeUtil;
      import lombok.RequiredArgsConstructor;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      
      import java.time.LocalDateTime;
      import java.util.*;
      import java.util.stream.Collectors;
      
      @Service
      @RequiredArgsConstructor
      public class UserCouponServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon> implements IUserCouponService {
      
          private final CouponMapper couponMapper;
      
          @Override
          @Transactional
          public void receiveCoupon(Long couponId) {
              // 1.查询优惠券
              Coupon coupon = couponMapper.selectById(couponId);
              if (coupon == null) {
                  throw new BadRequestException("优惠券不存在");
              }
              // 2.校验发放时间
              LocalDateTime now = LocalDateTime.now();
              if (now.isBefore(coupon.getIssueBeginTime()) || now.isAfter(coupon.getIssueEndTime())) {
                  throw new BadRequestException("优惠券发放已经结束或尚未开始");
              }
              // 3.校验库存
              if (coupon.getIssueNum() >= coupon.getTotalNum()) {
                  throw new BadRequestException("优惠券库存不足");
              }
              Long userId = UserContext.getUser();
              // 4.校验每人限领数量
              // 4.1.统计当前用户对当前优惠券的已经领取的数量
              Integer count = lambdaQuery()
                      .eq(UserCoupon::getUserId(), userId)
                      .eq(UserCoupon::getCouponId(), couponId)
                      .count();
              // 4.2.校验限领数量
              if(count != null && count >= coupon.getUserLimit()){
                  throw new BadRequestException("超出领取数量");
              }
              // 5.更新优惠券的已经发放的数量 + 1
              couponMapper.incrIssueNum(coupon.getId());
              // 6.新增一个用户券
              saveUserCoupon(coupon, userId);
          }
      
          private void saveUserCoupon(Coupon coupon, Long userId) {
              // 1.基本信息
              UserCoupon uc = new UserCoupon();
              uc.setUserId(userId);
              uc.setCouponId(coupon.getId());
              // 2.有效期信息
              LocalDateTime termBeginTime = coupon.getTermBeginTime();
              LocalDateTime termEndTime = coupon.getTermEndTime();
              if (termBeginTime == null) {
                  termBeginTime = LocalDateTime.now();
                  termEndTime = termBeginTime.plusDays(coupon.getTermDays());
              }
              uc.setTermBeginTime(termBeginTime);
              uc.setTermEndTime(termEndTime);
              // 3.保存
              save(uc);
          }
      }

      3.Mapper层

      package com.tianji.promotion.mapper;
      
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.tianji.promotion.domain.po.Coupon;
      import org.apache.ibatis.annotations.Param;
      import org.apache.ibatis.annotations.Update;
      
      
      public interface CouponMapper extends BaseMapper<Coupon> {
          @Update("UPDATE coupon SET issue_num = issue_num + 1 WHERE id = #{couponId}")
          int incrIssueNum(@Param("couponId") Long couponId);
      }

      ### 实现弹窗领取优惠券 在 `uni-app` 中实现弹出窗口以供用户领取优惠券可以通过使用内置的组件和 API 来完成。具体来说,可以利用 `uni-popup` 组件来创建弹窗效果,并结合按钮触发该弹窗显示。 #### 使用 `uni-popup` 创建弹窗 为了简化开发流程并提高效率,推荐采用官方提供的 `uni-popup` 组件[^2]。此组件允许开发者轻松构建各种类型的对话框,包括但不限于提示框、确认框以及自定义内容区域等。 下面是一个简单的例子展示如何设置一个用于发放优惠券的弹窗: ```html <template> <view class="content"> <!-- 触发弹窗 --> <button type="primary" @click="showPopup">点击领取优惠券</button> <!-- 弹窗部分 --> <uni-popup ref="popup" type="center"> <view style="padding: 20px; text-align:center;"> <text>恭喜您获得了一张满减优惠券!</text><br/> <image src="/static/coupon.png"></image><br/><br/> <!-- 这里放置一张代表优惠券的图片 --> <button size="mini" @click="closePopup">关闭</button> </view> </uni-popup> </view> </template> <script> export default { methods: { showPopup() { this.$refs.popup.open(); }, closePopup() { this.$refs.popup.close(); } } } </script> ``` 这段代码展示了基本结构:当用户按下“点击领取优惠券”的按钮时,将会打开一个居中的弹窗,在其中包含了祝贺语句及虚拟表示形式的一张优惠券图像。同时提供了另一个小型按钮让用户能够手动关闭这个弹窗。 #### 关于依赖项配置 对于涉及到类型检查或其他高级编辑器特性的情况,可能还需要适当调整项目的 TypeScript 或 Vue 编译选项,确保引入必要的声明文件如 `@uni-helper/uni-app-types`,以便更好地支持 IDE 提示等功能[^1]。
      评论
      成就一亿技术人!
      拼手气红包6.0元
      还能输入1000个字符
       
      红包 添加红包
      表情包 插入表情
       条评论被折叠 查看
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

      当前余额3.43前往充值 >
      需支付:10.00
      成就一亿技术人!
      领取后你会自动成为博主和红包主的粉丝 规则
      hope_wisdom
      发出的红包
      实付
      使用余额支付
      点击重新获取
      扫码支付
      钱包余额 0

      抵扣说明:

      1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
      2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

      余额充值