From c5df277e6c8941266e4dcb51b33ec47fb5de55f6 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Tue, 20 Jan 2026 16:58:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(task):=20=E6=B7=BB=E5=8A=A0=E4=BC=98?= =?UTF-8?q?=E6=83=A0=E5=88=B8=E8=BF=87=E6=9C=9F=E6=8F=90=E9=86=92=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 实现优惠券过期提醒功能,每天20点执行 - 实现优惠券临期提醒功能,每天8点执行 - 集成微信订阅消息通知服务 - 查询指定时间范围内已领取的优惠券记录 - 构建优惠券信息变量并触发通知 - 添加异常处理和日志记录机制 --- .../task/CouponExpireNotificationTask.java | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/main/java/com/ycwl/basic/task/CouponExpireNotificationTask.java diff --git a/src/main/java/com/ycwl/basic/task/CouponExpireNotificationTask.java b/src/main/java/com/ycwl/basic/task/CouponExpireNotificationTask.java new file mode 100644 index 00000000..05e596ee --- /dev/null +++ b/src/main/java/com/ycwl/basic/task/CouponExpireNotificationTask.java @@ -0,0 +1,110 @@ +package com.ycwl.basic.task; + +import cn.hutool.core.date.DateUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ycwl.basic.mapper.MemberMapper; +import com.ycwl.basic.model.pc.member.resp.MemberRespVO; +import com.ycwl.basic.model.pc.notify.req.WechatSubscribeNotifyTriggerRequest; +import com.ycwl.basic.pricing.entity.PriceCouponClaimRecord; +import com.ycwl.basic.pricing.entity.PriceCouponConfig; +import com.ycwl.basic.pricing.enums.CouponStatus; +import com.ycwl.basic.pricing.mapper.PriceCouponClaimRecordMapper; +import com.ycwl.basic.pricing.mapper.PriceCouponConfigMapper; +import com.ycwl.basic.service.notify.WechatSubscribeNotifyTriggerService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Profile; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; + +@Component +@EnableScheduling +@Slf4j +@Profile("prod") +public class CouponExpireNotificationTask { + + @Autowired + private PriceCouponClaimRecordMapper couponClaimRecordMapper; + + @Autowired + private MemberMapper memberMapper; + + @Autowired + private WechatSubscribeNotifyTriggerService notifyTriggerService; + @Autowired + private PriceCouponConfigMapper priceCouponConfigMapper; + + @Scheduled(cron = "0 0 20 * * *") + public void sendCouponExpireNotification() { + log.info("开始执行优惠券过期提醒定时任务"); + processNotification("COUPON_EXPIRE", -2); + log.info("优惠券过期提醒定时任务执行结束"); + } + + @Scheduled(cron = "0 0 8 * * *") + public void sendCouponPreExpireNotification() { + log.info("开始执行优惠券临期提醒定时任务"); + processNotification("COUPON_PRE_EXPIRE", -2); + log.info("优惠券临期提醒定时任务执行结束"); + } + + private void processNotification(String notifyType, int offsetDays) { + // 获取指定偏移天数(例如-2 days)的开始和结束时间 + Date date = DateUtil.offsetDay(new Date(), offsetDays); + Date beginTime = DateUtil.beginOfDay(date); + Date endTime = DateUtil.endOfDay(date); + + log.info("查询时间范围: {} - {}", beginTime, endTime); + + // 查询该时间段内创建的优惠券记录 + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(); + queryWrapper.between(PriceCouponClaimRecord::getCreateTime, beginTime, endTime); + queryWrapper.eq(PriceCouponClaimRecord::getStatus, CouponStatus.CLAIMED); + + List couponRecords = couponClaimRecordMapper.selectList(queryWrapper); + + if (couponRecords == null || couponRecords.isEmpty()) { + log.info("未找到符合条件的优惠券记录"); + return; + } + + log.info("找到 {} 条优惠券记录", couponRecords.size()); + + for (PriceCouponClaimRecord record : couponRecords) { + try { + MemberRespVO member = memberMapper.getById(record.getUserId()); + if (member == null || member.getOpenId() == null) { + continue; + } + PriceCouponConfig coupon = priceCouponConfigMapper.selectValidCouponById(record.getCouponId()); + + HashMap variables = new HashMap<>(); + variables.put("couponName", coupon.getCouponName()); + variables.put("couponValue", coupon.getDiscountValue()); + variables.put("couponType", coupon.getCouponType().getDescription()); + // 优惠券有效期到第二天的结束,从领取开始的时候算 + variables.put("couponStartTime", DateUtil.format(record.getCreateTime(), "yyyy-MM-dd HH:mm")); + variables.put("couponExpireTime", DateUtil.format(DateUtil.endOfDay(DateUtil.offsetDay(record.getCreateTime(), 2)), "yyyy-MM-dd HH:mm")); + + WechatSubscribeNotifyTriggerRequest request = WechatSubscribeNotifyTriggerRequest.builder() + .memberId(record.getUserId()) + .openId(member.getOpenId()) + .bizId(String.valueOf(record.getId())) + .variables(variables) + .build(); + + // 触发消息 + notifyTriggerService.trigger(notifyType, request); + + } catch (Exception e) { + log.error("发送通知失败, type: {}, recordId: {}", notifyType, record.getId(), e); + } + } + } +}