一、功能概述
优惠券管理是电商系统中重要的营销工具,叮咚买菜系统的优惠券管理功能应包括优惠券的创建、发放、使用、统计等全生命周期管理,以支持各种促销活动和用户激励。
二、核心功能模块
1. 优惠券类型管理
- 满减券:满指定金额减固定金额
- 折扣券:按比例折扣(如8折)
- 无门槛券:可直接使用的固定金额券
- 运费券:减免配送费用的专用券
- 品类券:限定商品品类使用的优惠券
2. 优惠券生命周期管理
- 创建优惠券:
- 优惠券名称、面值、使用条件
- 有效期设置(固定日期/领取后N天内有效)
- 发放总量和每人限领数量
- 适用范围(全平台/特定商品/特定品类)
- 发放方式:
- 主动领取(用户自行领取)
- 系统自动发放(新用户注册、特定行为触发)
- 分享发放(用户分享后获得)
- 订单完成后发放(如评价返券)
- 使用管理:
- 优惠券核销(下单时自动应用)
- 退款处理(订单退款后优惠券状态更新)
- 防刷机制(防止优惠券被恶意使用)
3. 优惠券统计与分析
- 发放数量、使用数量、剩余数量统计
- 优惠券使用率分析
- 优惠券带来的订单金额和利润分析
- 用户领取和使用行为分析
三、技术实现方案
1. 数据库设计
```sql
-- 优惠券模板表
CREATE TABLE coupon_template (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL COMMENT 优惠券名称,
type TINYINT NOT NULL COMMENT 1-满减券 2-折扣券 3-无门槛券 4-运费券 5-品类券,
amount DECIMAL(10,2) NOT NULL COMMENT 优惠券面额,
condition_amount DECIMAL(10,2) DEFAULT NULL COMMENT 使用条件金额,
discount DECIMAL(3,2) DEFAULT NULL COMMENT 折扣率(0-1),
total_count INT NOT NULL COMMENT 发放总量,
limit_per_user INT DEFAULT 1 COMMENT 每人限领数量,
start_time DATETIME NOT NULL COMMENT 有效期开始时间,
end_time DATETIME NOT NULL COMMENT 有效期结束时间,
status TINYINT NOT NULL DEFAULT 1 COMMENT 1-启用 0-禁用,
create_time DATETIME NOT NULL,
update_time DATETIME NOT NULL,
适用范围 JSON COMMENT 适用商品/品类ID列表
);
-- 用户优惠券表
CREATE TABLE user_coupon (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL COMMENT 用户ID,
template_id BIGINT NOT NULL COMMENT 优惠券模板ID,
coupon_code VARCHAR(32) NOT NULL COMMENT 优惠券码,
status TINYINT NOT NULL DEFAULT 0 COMMENT 0-未使用 1-已使用 2-已过期 3-已作废,
order_id BIGINT DEFAULT NULL COMMENT 使用订单ID,
get_time DATETIME NOT NULL COMMENT 领取时间,
use_time DATETIME DEFAULT NULL COMMENT 使用时间,
expire_time DATETIME NOT NULL COMMENT 过期时间,
UNIQUE KEY uk_coupon_code (coupon_code)
);
```
2. 核心服务实现
优惠券发放服务
```java
public class CouponService {
// 发放优惠券给用户
public ResultVO issueCoupon(Long userId, Long templateId, Integer quantity) {
// 1. 验证优惠券模板是否存在且可用
CouponTemplate template = couponTemplateMapper.selectById(templateId);
if (template == null || template.getStatus() == 0) {
return ResultVO.error("优惠券不存在或已禁用");
}
// 2. 检查用户是否已达到领取上限
int userReceivedCount = userCouponMapper.countByUserIdAndTemplateId(userId, templateId);
if (userReceivedCount >= template.getLimitPerUser()) {
return ResultVO.error("您已达到该优惠券的领取上限");
}
// 3. 检查优惠券库存
if (template.getTotalCount() <= 0) {
return ResultVO.error("优惠券已发放完毕");
}
// 4. 生成用户优惠券记录
List coupons = new ArrayList<>();
for (int i = 0; i < quantity; i++) {
UserCoupon coupon = new UserCoupon();
coupon.setUserId(userId);
coupon.setTemplateId(templateId);
coupon.setCouponCode(generateCouponCode());
coupon.setStatus(0);
coupon.setGetTime(new Date());
coupon.setExpireTime(calculateExpireTime(template));
coupons.add(coupon);
}
// 5. 批量插入并更新模板库存
userCouponMapper.batchInsert(coupons);
couponTemplateMapper.decreaseStock(templateId, quantity);
return ResultVO.success("优惠券领取成功");
}
private String generateCouponCode() {
// 生成唯一优惠券码
return UUID.randomUUID().toString().replace("-", "").toUpperCase().substring(0, 8);
}
private Date calculateExpireTime(CouponTemplate template) {
// 根据模板有效期计算过期时间
// 实现略...
}
}
```
优惠券使用服务
```java
public class OrderService {
// 下单时使用优惠券
public ResultVO placeOrder(OrderDTO orderDTO) {
// 1. 验证优惠券有效性
UserCoupon userCoupon = userCouponMapper.selectById(orderDTO.getCouponId());
if (userCoupon == null || userCoupon.getStatus() != 0) {
return ResultVO.error("优惠券无效或已使用");
}
CouponTemplate template = couponTemplateMapper.selectById(userCoupon.getTemplateId());
if (template == null) {
return ResultVO.error("优惠券模板不存在");
}
// 2. 检查使用条件
if (orderDTO.getTotalAmount().compareTo(template.getConditionAmount()) < 0) {
return ResultVO.error("订单金额不满足优惠券使用条件");
}
// 3. 计算优惠金额
BigDecimal discountAmount = calculateDiscount(orderDTO.getTotalAmount(), template);
// 4. 更新优惠券状态
userCoupon.setStatus(1); // 已使用
userCoupon.setUseTime(new Date());
userCoupon.setOrderId(orderDTO.getOrderId());
userCouponMapper.updateById(userCoupon);
// 5. 继续订单处理流程...
// 实现略...
}
private BigDecimal calculateDiscount(BigDecimal orderAmount, CouponTemplate template) {
switch (template.getType()) {
case 1: // 满减券
return template.getAmount();
case 2: // 折扣券
return orderAmount.multiply(BigDecimal.valueOf(1 - template.getDiscount()))
.setScale(2, RoundingMode.HALF_UP);
case 3: // 无门槛券
return template.getAmount();
// 其他类型处理...
default:
return BigDecimal.ZERO;
}
}
}
```
3. 定时任务处理
```java
@Component
public class CouponExpireJob {
@Scheduled(cron = "0 0 0 * * ?") // 每天凌晨执行
public void checkExpiredCoupons() {
// 查询所有已过期但未使用的优惠券
Date now = new Date();
List expiredCoupons = userCouponMapper.selectExpiredCoupons(now);
for (UserCoupon coupon : expiredCoupons) {
coupon.setStatus(2); // 标记为已过期
userCouponMapper.updateById(coupon);
}
}
}
```
四、前端交互设计
1. 优惠券领取页面
- 展示可领取的优惠券列表
- 显示优惠券面值、使用条件、有效期
- 提供"立即领取"按钮
- 显示用户已领取的优惠券数量和限制
2. 我的优惠券页面
- 分类展示:未使用/已使用/已过期
- 显示优惠券关键信息:面值、有效期、使用条件
- 提供优惠券使用说明
3. 下单页面优惠券选择
- 自动匹配适用的优惠券
- 显示优惠金额和最终支付金额
- 支持手动选择/取消选择优惠券
五、安全与性能考虑
1. 防刷机制:
- 限制单个用户领取同一优惠券的次数
- 限制单个IP的领取频率
- 验证码验证(高频操作时)
2. 并发控制:
- 优惠券库存使用乐观锁或分布式锁控制
- 发放接口限流
3. 数据一致性:
- 使用事务保证优惠券发放和库存更新的原子性
- 最终一致性方案处理分布式环境下的数据同步
4. 性能优化:
- 优惠券适用性计算缓存
- 热门优惠券预加载
- 异步处理非实时性要求高的操作
六、测试要点
1. 功能测试:
- 各种类型优惠券的创建和发放
- 优惠券使用条件的正确判断
- 优惠券过期自动处理
- 退款后优惠券的返还逻辑
2. 边界测试:
- 刚好满足使用条件的订单
- 优惠券库存为1时的并发领取
- 有效期最后时刻的使用
3. 异常测试:
- 使用已过期优惠券
- 使用已使用过的优惠券
- 领取已发放完毕的优惠券
七、扩展功能建议
1. 优惠券分享功能:用户可将优惠券分享给好友
2. 优惠券组合使用:支持多张优惠券叠加使用
3. 优惠券推荐:根据用户购买历史推荐适用优惠券
4. 优惠券A/B测试:不同用户群体发放不同优惠券测试效果
5. 优惠券数据分析:跟踪优惠券领取、使用、转化情况
通过以上方案,叮咚买菜系统可以实现一个完整、高效、安全的优惠券管理系统,支持各种营销活动,提升用户活跃度和购买转化率。