未发送的 任务 要 删除

发送的任务 券 发送时间执行 发放
This commit is contained in:
wangw 2025-10-17 16:09:19 +08:00
parent fc6aaf8b35
commit 8d41b4c2a9
7 changed files with 118 additions and 30 deletions

View File

@ -5,6 +5,7 @@ import com.czg.market.service.SmsPushEventService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@ -45,6 +46,16 @@ public class SmsPushEventController {
return CzgResult.success();
}
/**
* 更新
*/
@PutMapping
public CzgResult<Void> upPushEvent(@RequestBody @Validated(UpdateGroup.class) SmsPushEventDTO param) {
param.setShopId(StpKit.USER.getShopId());
pushEventService.upPushEvent(param);
return CzgResult.success();
}
/**
* 删除任务
*/

View File

@ -3,6 +3,7 @@ package com.czg.config;
import com.czg.account.service.ShopTableService;
import com.czg.market.entity.MkShopCouponRecord;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.service.SmsPushEventService;
import com.czg.order.service.OrderInfoService;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
@ -34,6 +35,8 @@ public class RedisKeyExpirationListener implements MessageListener {
private ShopTableService tableService;
@Resource
private MkShopCouponRecordService mkShopCouponRecordService;
@Resource
private SmsPushEventService smsPushEventService;
//redis key失效监听
@ -66,6 +69,10 @@ public class RedisKeyExpirationListener implements MessageListener {
.eq(MkShopCouponRecord::getStatus, 0)
.eq(MkShopCouponRecord::getId, Long.parseLong(couponId))
);
} else if (expiredKey.startsWith(RedisCst.classKeyExpired.EXPIRED_SMS)) {
log.info("监听到短信定时发放优惠券,sms_push_event任务Id: {}", expiredKey);
String eventId = expiredKey.substring(RedisCst.classKeyExpired.EXPIRED_SMS.length());
smsPushEventService.sendPushEventCoupon(eventId);
}
}
}

View File

@ -23,6 +23,8 @@ public interface RedisCst {
public static final String EXPIRED_TABLE = "expired:table:";
//优惠券过期
public static final String EXPIRED_COUPON = "expired:coupon:";
//短信定时发放 倒计时KEY
public static final String EXPIRED_SMS = "expired:sms:";
}

View File

@ -31,7 +31,7 @@ public class SmsPushEventDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@NotNull(message = "id不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private Long id;
private Long shopId;
@ -44,18 +44,18 @@ public class SmsPushEventDTO implements Serializable {
/**
* 模板ID
*/
@NotNull(message = "模板ID不能为空", groups = InsertGroup.class)
@NotNull(message = "模板ID不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private Long pushEventId;
/**
* 1 全部用户 2范围用户 3 指定用户 指定暂定一个用户
*/
@NotNull(message = "发送范围不能为空", groups = InsertGroup.class)
@NotNull(message = "发送范围不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private Long userType;
/**
* 预计人数
*/
@NotNull(message = "预计人数不能为空", groups = InsertGroup.class)
@NotNull(message = "预计人数不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private Long estimateNum;
/**
* 实际人数
@ -79,13 +79,13 @@ public class SmsPushEventDTO implements Serializable {
/**
* 发送内容
*/
@NotBlank(message = "发送内容不能为空", groups = InsertGroup.class)
@NotBlank(message = "发送内容不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private String content;
/**
* 发送参数json
* {"店铺名称":"火锅店","时间":"2025-02-17"}
*/
@NotBlank(message = "发送参数json不能为空", groups = InsertGroup.class)
@NotBlank(message = "发送参数json不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private String json;
/**
@ -96,7 +96,7 @@ public class SmsPushEventDTO implements Serializable {
/**
* 发送类型 1 立即发送 2定时发送
*/
@NotNull(message = "发送类型不能为空", groups = InsertGroup.class)
@NotNull(message = "发送类型不能为空", groups = {InsertGroup.class, UpdateGroup.class})
private Integer sendType;
/**

View File

@ -1,6 +1,5 @@
package com.czg.market.service;
import com.czg.BaseQueryParam;
import com.czg.market.dto.SmsPushEventDTO;
import com.czg.market.entity.SmsPushEvent;
import com.mybatisflex.core.paginate.Page;
@ -24,5 +23,15 @@ public interface SmsPushEventService extends IService<SmsPushEvent> {
*/
void addPushEvent(SmsPushEventDTO param);
/**
* 发送营销推送发送任务中的优惠券
*/
void sendPushEventCoupon(String eventId);
/**
* 更新营销推送发送任务
*/
void upPushEvent(SmsPushEventDTO param);
void deletePushEvent(Long id);
}

View File

@ -26,7 +26,7 @@ import java.util.Map;
* @since 2025-10-13
*/
@Service
public class MkConsumeCashbackRecordServiceImpl extends ServiceImpl<MkConsumeCashbackRecordMapper, MkConsumeCashbackRecord> implements MkConsumeCashbackRecordService{
public class MkConsumeCashbackRecordServiceImpl extends ServiceImpl<MkConsumeCashbackRecordMapper, MkConsumeCashbackRecord> implements MkConsumeCashbackRecordService {
@Override
public Map<String, Object> getRecord(Long mainShopId, Long shopId, String key, LocalDateTime startTime, LocalDateTime endTime) {
QueryWrapper queryWrapper = new MyQueryWrapper().eq(MkConsumeCashbackRecord::getMainShopId, mainShopId)
@ -76,7 +76,7 @@ public class MkConsumeCashbackRecordServiceImpl extends ServiceImpl<MkConsumeCas
BigDecimal amount = getOneAs(totalQuery.select("SUM(cashback_amount)"), BigDecimal.class);
Map<String, Object> map = BeanUtil.beanToMap(pageAs(PageUtil.buildPage(), queryWrapper, MkConsumeCashbackRecordVO.class));
map.put("totalAmount", amount);
map.put("totalAmount", amount == null ? BigDecimal.ZERO : amount);
return map;
}
}

View File

@ -8,6 +8,7 @@ import com.alibaba.fastjson2.JSONObject;
import com.czg.account.entity.ShopUser;
import com.czg.account.service.AShopUserService;
import com.czg.config.RabbitPublisher;
import com.czg.config.RedisCst;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkShopCouponGiftDTO;
import com.czg.market.dto.SmsPushEventDTO;
@ -15,6 +16,7 @@ import com.czg.market.entity.SmsPushEvent;
import com.czg.market.entity.SmsPushEventUser;
import com.czg.market.service.MkShopCouponRecordService;
import com.czg.market.service.SmsPushEventService;
import com.czg.service.RedisService;
import com.czg.service.market.mapper.SmsPushEventMapper;
import com.czg.service.market.mapper.SmsPushEventUserMapper;
import com.czg.utils.AssertUtil;
@ -49,6 +51,8 @@ public class SmsPushEventServiceImpl extends ServiceImpl<SmsPushEventMapper, Sms
private AShopUserService shopUserService;
@Resource
private RabbitPublisher rabbitPublisher;
@Resource
private RedisService redisService;
@Override
public Page<SmsPushEventDTO> getPushEventPage(Integer page, Integer size, Long shopId, Long id) {
@ -96,6 +100,38 @@ public class SmsPushEventServiceImpl extends ServiceImpl<SmsPushEventMapper, Sms
}
// 推送消息 进行 消息发送
rabbitPublisher.sendApplySmsMsg(pushEvent.getShopId() + "," + pushEvent.getId(), "sendMarkSms");
if (param.getSendType() == 1 && StrUtil.isNotBlank(param.getCoupon())) {
grantCoupon(param);
}
}
@Override
@Transactional
public void upPushEvent(SmsPushEventDTO param) {
AssertUtil.isNull(param.getUserType(), "请选择用户范围后进行推送");
if (param.getUserType() == 2 && param.getSmsPushEventUser() == null) {
throw new CzgException("范围推送时,必须指定用户范围");
} else if (param.getUserType() == 3 && param.getUserId() == null) {
throw new CzgException("指定推送时,必须指定用户");
}
AssertUtil.isNull(param.getPushEventId(), "请选择模板后进行推送");
AssertUtil.isNull(param.getContent(), "消息内容不能为空");
if (param.getSendType() == 2) {
AssertUtil.isNull(param.getSendTime(), "定时发送时,必须指定发送时间");
} else {
param.setSendTime(LocalDateTime.now());
}
SmsPushEvent pushEvent = BeanUtil.toBean(param, SmsPushEvent.class);
updateById(pushEvent);
eventUserMapper.deleteByQuery(new QueryWrapper().eq(SmsPushEventUser::getEventId, pushEvent.getId()));
if (param.getUserType() == 2) {
SmsPushEventUser eventUser = param.getSmsPushEventUser();
eventUser.setShopId(param.getShopId());
eventUser.setEventId(pushEvent.getId());
eventUserMapper.insert(eventUser);
}
// 推送消息 进行 消息发送
rabbitPublisher.sendApplySmsMsg(pushEvent.getShopId() + "," + pushEvent.getId(), "sendMarkSms");
//发放优惠券
CompletableFuture.runAsync(() -> {
try {
@ -106,29 +142,48 @@ public class SmsPushEventServiceImpl extends ServiceImpl<SmsPushEventMapper, Sms
});
}
@Override
public void sendPushEventCoupon(String eventId) {
SmsPushEventDTO pushEvent = getObjAs(new QueryWrapper().eq(SmsPushEvent::getId, eventId), SmsPushEventDTO.class);
AssertUtil.isNull(pushEvent, "券发放失败,推送事件不存在");
SmsPushEventUser eventUser = eventUserMapper.selectOneByQuery(
new QueryWrapper().eq(SmsPushEventUser::getEventId, eventId)
);
AssertUtil.isNull(eventUser, "券发放失败,推送事件用户群体不存在");
pushEvent.setSmsPushEventUser(eventUser);
if (pushEvent.getSendType() == 1 && StrUtil.isNotBlank(pushEvent.getCoupon())) {
grantCoupon(pushEvent);
}
}
// 发放优惠券
private void grantCoupon(SmsPushEventDTO param) {
if (StrUtil.isBlank(param.getCoupon())) {
return;
}
List<ShopUser> userList = shopUserService.getPushEventUserList(param.getSmsPushEventUser());
// 2. 将JSON字符串解析为JSONArray
JSONArray couponArray = JSON.parseArray(param.getCoupon());
//发放优惠券
CompletableFuture.runAsync(() -> {
try {
List<ShopUser> userList = shopUserService.getPushEventUserList(param.getSmsPushEventUser());
// 2. 将JSON字符串解析为JSONArray
JSONArray couponArray = JSON.parseArray(param.getCoupon());
// 3. 遍历JSONArray逐个获取JSONObject的字段值
for (int i = 0; i < couponArray.size(); i++) {
// 获取单个优惠券的JSONObject对象
JSONObject couponObj = couponArray.getJSONObject(i);
// 通过键名获取对应值需注意字段类型按需转换
Long id = couponObj.getLong("id");
Integer num = couponObj.getInteger("num");
MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO();
giftDTO.setShopId(param.getShopId());
giftDTO.setSourceId(param.getId());
giftDTO.setCouponId(id);
giftDTO.setSource("营销短信发放");
couponRecordService.batchReceiveCoupon(giftDTO, num, userList);
}
// 3. 遍历JSONArray逐个获取JSONObject的字段值
for (int i = 0; i < couponArray.size(); i++) {
// 获取单个优惠券的JSONObject对象
JSONObject couponObj = couponArray.getJSONObject(i);
// 通过键名获取对应值需注意字段类型按需转换
Long id = couponObj.getLong("id");
Integer num = couponObj.getInteger("num");
MkShopCouponGiftDTO giftDTO = new MkShopCouponGiftDTO();
giftDTO.setShopId(param.getShopId());
giftDTO.setSourceId(param.getId());
giftDTO.setCouponId(id);
giftDTO.setSource("营销短信发放");
couponRecordService.batchReceiveCoupon(giftDTO, num, userList);
}
} catch (Exception e) {
log.error("异步发放优惠券失败", e);
}
});
}
/**
@ -138,6 +193,10 @@ public class SmsPushEventServiceImpl extends ServiceImpl<SmsPushEventMapper, Sms
public void deletePushEvent(Long id) {
SmsPushEvent pushEvent = getById(id);
AssertUtil.isNull(pushEvent, "记录不存在");
if (pushEvent.getStatus() == 2) {
throw new CzgException("已发送的记录不能删除");
}
redisService.del(RedisCst.classKeyExpired.EXPIRED_SMS + id);
pushEvent.setIsDel(1);
updateById(pushEvent);
}