010-53388338

叮咚买菜优惠券系统设计:涵盖功能、数据库、逻辑及前端交互设计

分类:IT频道 时间:2026-02-21 19:20 浏览:16
概述
    一、功能概述    优惠券管理是电商系统中重要的营销工具,叮咚买菜系统的优惠券管理功能应包括优惠券创建、发放、使用、统计等全生命周期管理,支持多种优惠券类型和发放方式。    二、核心功能模块    1.优惠券类型管理  -满减券:满X元减Y元  -折扣券:订单享受X折优惠  -免运费券:免
内容
  
   一、功能概述
  
  优惠券管理是电商系统中重要的营销工具,叮咚买菜系统的优惠券管理功能应包括优惠券创建、发放、使用、统计等全生命周期管理,支持多种优惠券类型和发放方式。
  
   二、核心功能模块
  
   1. 优惠券类型管理
  - 满减券:满X元减Y元
  - 折扣券:订单享受X折优惠
  - 免运费券:免除配送费用
  - 品类专用券:针对特定商品类别的优惠券
  - 新人专享券:仅限新用户使用
  - 限时特惠券:指定时间段内有效
  
   2. 优惠券创建与配置
  ```java
  // 优惠券实体类示例
  public class CouponTemplate {
   private Long id;
   private String name; // 优惠券名称
   private String description; // 描述
   private Integer type; // 类型(1:满减,2:折扣,3:免运费...)
   private BigDecimal discountAmount; // 优惠金额
   private BigDecimal minOrderAmount; // 最低订单金额
   private BigDecimal discountRate; // 折扣率(仅折扣券使用)
   private Date startTime; // 生效时间
   private Date endTime; // 失效时间
   private Integer totalCount; // 发放总量
   private Integer remainingCount; // 剩余数量
   private Integer usageLimit; // 每人限领数量
   private String适用范围; // ALL/CATEGORY/PRODUCT
   private List categoryIds; // 适用品类ID
   private List productIds; // 适用商品ID
   // getters and setters...
  }
  ```
  
   3. 优惠券发放方式
  - 系统自动发放:
   - 新用户注册赠送
   - 用户生日赠送
   - 特定节日发放
  - 用户主动领取:
   - 优惠券中心领取
   - 活动页面领取
   - 分享链接领取
  - 后台手动发放:
   - 针对特定用户发放
   - 批量导入发放
  
   4. 优惠券使用流程
  1. 用户选择商品加入购物车
  2. 进入结算页面时系统自动匹配可用优惠券
  3. 用户选择使用或放弃使用优惠券
  4. 系统验证优惠券有效性
  5. 计算最终订单金额
  6. 更新优惠券状态为已使用
  
   5. 优惠券状态管理
  - 未使用:用户已领取但未使用
  - 已使用:订单结算时已使用
  - 已过期:超过有效期未使用
  - 已作废:管理员手动作废
  
   三、数据库设计
  
  ```sql
  -- 优惠券模板表
  CREATE TABLE coupon_template (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   name VARCHAR(100) NOT NULL,
   description VARCHAR(500),
   type TINYINT NOT NULL COMMENT 1:满减,2:折扣,3:免运费,
   discount_amount DECIMAL(10,2),
   min_order_amount DECIMAL(10,2),
   discount_rate DECIMAL(5,2),
   start_time DATETIME NOT NULL,
   end_time DATETIME NOT NULL,
   total_count INT NOT NULL,
   remaining_count INT NOT NULL,
   usage_limit INT DEFAULT 1,
   scope VARCHAR(20) NOT NULL COMMENT ALL/CATEGORY/PRODUCT,
   create_time DATETIME NOT NULL,
   update_time DATETIME NOT NULL
  );
  
  -- 优惠券模板关联品类表
  CREATE TABLE coupon_template_category (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   template_id BIGINT NOT NULL,
   category_id BIGINT NOT NULL,
   FOREIGN KEY (template_id) REFERENCES coupon_template(id)
  );
  
  -- 优惠券模板关联商品表
  CREATE TABLE coupon_template_product (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   template_id BIGINT NOT NULL,
   product_id BIGINT NOT NULL,
   FOREIGN KEY (template_id) REFERENCES coupon_template(id)
  );
  
  -- 用户优惠券表
  CREATE TABLE user_coupon (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   user_id BIGINT NOT NULL,
   template_id BIGINT NOT NULL,
   coupon_code VARCHAR(50) NOT NULL UNIQUE,
   status TINYINT NOT NULL COMMENT 0:未使用,1:已使用,2:已过期,3:已作废,
   order_id BIGINT COMMENT 关联订单ID,
   get_time DATETIME NOT NULL,
   use_time DATETIME,
   expire_time DATETIME NOT NULL,
   FOREIGN KEY (template_id) REFERENCES coupon_template(id)
  );
  ```
  
   四、关键业务逻辑实现
  
   1. 优惠券发放服务
  ```java
  @Service
  public class CouponService {
  
   @Autowired
   private CouponTemplateRepository templateRepository;
  
   @Autowired
   private UserCouponRepository userCouponRepository;
  
   @Transactional
   public void distributeCoupon(Long templateId, List userIds) {
   CouponTemplate template = templateRepository.findById(templateId)
   .orElseThrow(() -> new RuntimeException("优惠券模板不存在"));
  
   if (template.getRemainingCount() <= 0) {
   throw new RuntimeException("优惠券已发放完毕");
   }
  
   Date now = new Date();
   List coupons = new ArrayList<>();
  
   for (Long userId : userIds) {
   // 检查用户是否已达到领取上限
   long usedCount = userCouponRepository.countByUserIdAndTemplateIdAndStatus(
   userId, templateId, 0); // 0表示未使用
  
   if (usedCount >= template.getUsageLimit()) {
   continue; // 跳过已达上限的用户
   }
  
   UserCoupon coupon = new UserCoupon();
   coupon.setUserId(userId);
   coupon.setTemplateId(templateId);
   coupon.setCouponCode(generateCouponCode());
   coupon.setStatus(0); // 未使用
   coupon.setGetTime(now);
   coupon.setExpireTime(template.getEndTime());
   coupons.add(coupon);
   }
  
   if (!coupons.isEmpty()) {
   userCouponRepository.saveAll(coupons);
   template.setRemainingCount(template.getRemainingCount() - coupons.size());
   templateRepository.save(template);
   }
   }
  
   private String generateCouponCode() {
   // 生成唯一优惠券码逻辑
   return UUID.randomUUID().toString().replace("-", "").substring(0, 10).toUpperCase();
   }
  }
  ```
  
   2. 优惠券匹配与使用服务
  ```java
  @Service
  public class OrderService {
  
   @Autowired
   private UserCouponRepository userCouponRepository;
  
   @Autowired
   private CouponTemplateRepository templateRepository;
  
   public List findAvailableCoupons(Long userId, BigDecimal orderAmount, List categoryIds) {
   Date now = new Date();
  
   // 查询用户所有未使用且未过期的优惠券
   List availableCoupons = userCouponRepository.findByUserIdAndStatusAndExpireTimeAfter(
   userId, 0, now);
  
   return availableCoupons.stream()
   .filter(coupon -> {
   CouponTemplate template = templateRepository.findById(coupon.getTemplateId())
   .orElse(null);
   if (template == null) return false;
  
   // 检查最低订单金额
   if (template.getMinOrderAmount() != null &&
   orderAmount.compareTo(template.getMinOrderAmount()) < 0) {
   return false;
   }
  
   // 检查适用范围
   if ("ALL".equals(template.getScope())) {
   return true;
   } else if ("CATEGORY".equals(template.getScope())) {
   // 检查订单中是否包含适用品类的商品
   // 这里简化处理,实际应根据订单商品品类判断
   return !template.getCategoryIds().isEmpty();
   } else if ("PRODUCT".equals(template.getScope())) {
   // 检查订单中是否包含适用商品
   // 这里简化处理,实际应根据订单商品判断
   return !template.getProductIds().isEmpty();
   }
   return false;
   })
   .collect(Collectors.toList());
   }
  
   @Transactional
   public Order createOrderWithCoupon(OrderCreateRequest request, Long couponId) {
   // 验证优惠券有效性
   UserCoupon userCoupon = userCouponRepository.findByIdAndUserIdAndStatus(
   couponId, request.getUserId(), 0) // 0表示未使用
   .orElseThrow(() -> new RuntimeException("优惠券无效或已使用"));
  
   CouponTemplate template = templateRepository.findById(userCoupon.getTemplateId())
   .orElseThrow(() -> new RuntimeException("优惠券模板不存在"));
  
   // 验证最低订单金额
   if (template.getMinOrderAmount() != null &&
   request.getTotalAmount().compareTo(template.getMinOrderAmount()) < 0) {
   throw new RuntimeException("订单金额不满足优惠券使用条件");
   }
  
   // 计算优惠后金额
   BigDecimal finalAmount = request.getTotalAmount();
   if (template.getType() == 1) { // 满减券
   finalAmount = finalAmount.subtract(template.getDiscountAmount());
   } else if (template.getType() == 2) { // 折扣券
   finalAmount = finalAmount.multiply(template.getDiscountRate().divide(new BigDecimal("100")));
   } else if (template.getType() == 3) { // 免运费券
   // 假设运费在totalAmount中包含,实际应根据运费计算
   // 这里简化处理
   }
  
   // 创建订单...
   Order order = new Order();
   // 设置订单属性...
   order.setTotalAmount(request.getTotalAmount());
   order.setDiscountAmount(request.getTotalAmount().subtract(finalAmount));
   order.setFinalAmount(finalAmount);
  
   // 更新优惠券状态
   userCoupon.setStatus(1); // 已使用
   userCoupon.setUseTime(new Date());
   userCoupon.setOrderId(order.getId());
   userCouponRepository.save(userCoupon);
  
   return order;
   }
  }
  ```
  
   五、前端交互设计
  
   1. 优惠券中心页面
  - 展示用户所有可用、已使用、已过期优惠券
  - 支持按优惠券类型筛选
  - 显示优惠券有效期和使用条件
  - 提供"立即使用"按钮跳转到购物车
  
   2. 结算页面优惠券选择
  - 自动匹配并显示可用的优惠券
  - 支持手动输入优惠券码
  - 显示使用优惠券后的优惠金额和最终支付金额
  - 优惠券不可叠加使用时的提示
  
   3. 优惠券领取弹窗
  - 活动页面或商品详情页的优惠券领取入口
  - 领取成功/失败提示
  - 优惠券详情展示
  
   六、安全与性能考虑
  
  1. 并发控制:
   - 优惠券发放时使用数据库乐观锁防止超发
   - 高并发场景下考虑使用Redis分布式锁
  
  2. 防刷机制:
   - 限制单个用户领取优惠券的频率
   - 识别并阻止机器人领取
  
  3. 性能优化:
   - 优惠券匹配时使用缓存减少数据库查询
   - 批量发放优惠券时使用异步处理
  
  4. 数据一致性:
   - 使用事务确保优惠券发放和库存更新的原子性
   - 订单创建和优惠券状态更新的原子性
  
   七、扩展功能建议
  
  1. 优惠券分享功能:用户可分享优惠券链接给好友
  2. 优惠券组合使用:支持特定优惠券组合使用
  3. 优惠券数据分析:统计优惠券领取、使用情况,分析营销效果
  4. AB测试:不同用户群体发放不同优惠券测试效果
  5. 优惠券预览:在发放前预览优惠券样式和效果
  
  以上方案可根据叮咚买菜的实际业务需求和技术栈进行调整和优化。
评论
  • 下一篇

  • Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 8192 bytes) in /www/wwwroot/www.sjwxsc.com/config/function.php on line 274