短信推送任务

This commit is contained in:
wangw 2025-10-14 17:57:32 +08:00
parent 19b410aadd
commit 4062cdea57
11 changed files with 520 additions and 2 deletions

View File

@ -0,0 +1,60 @@
package com.czg.controller.admin;
import com.czg.BaseQueryParam;
import com.czg.market.dto.SmsPushEventDTO;
import com.czg.market.dto.SmsShopTemplateDTO;
import com.czg.market.service.SmsPushEventService;
import com.czg.market.service.SmsShopTemplateService;
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;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 短信推送任务
*
* @author ww
* @description
*/
@Slf4j
@RestController
@RequestMapping("/admin/pushEvent")
public class SmsPushEventController {
@Resource
private SmsPushEventService pushEventService;
/**
* 列表
*/
@GetMapping
public CzgResult<Page<SmsPushEventDTO>> getPushEventPage(@RequestParam BaseQueryParam param, @RequestParam(required = false) Long id) {
Page<SmsPushEventDTO> data = pushEventService.getPushEventPage(param, StpKit.USER.getShopId(), id);
return CzgResult.success(data);
}
/**
* 新增
*/
@PostMapping
public CzgResult<Void> addPushEvent(@RequestBody @Validated(InsertGroup.class) SmsPushEventDTO param) {
param.setShopId(StpKit.USER.getShopId());
pushEventService.addPushEvent(param);
return CzgResult.success();
}
/**
* 删除任务
*/
@DeleteMapping("/{id}")
public CzgResult<Void> deletePushEvent(@PathVariable Long id) {
pushEventService.deletePushEvent(id);
return CzgResult.success();
}
}

View File

@ -1,8 +1,6 @@
package com.czg.controller.admin;
import com.czg.config.RabbitPublisher;
import com.czg.market.dto.SmsShopTemplateDTO;
import com.czg.market.service.ShopCouponService;
import com.czg.market.service.SmsShopTemplateService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;

View File

@ -0,0 +1,109 @@
package com.czg.market.dto;
import java.io.Serializable;
import java.time.LocalDateTime;
import com.alibaba.fastjson2.annotation.JSONField;
import java.io.Serial;
import com.czg.market.entity.SmsPushEventUser;
import com.czg.validator.group.InsertGroup;
import com.czg.validator.group.UpdateGroup;
import com.mybatisflex.annotation.Column;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 营销推送发送记录 实体类
*
* @author ww
* @since 2025-10-14
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class SmsPushEventDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
private Long id;
private Long shopId;
/**
* 推送类型 1 模版推送 2短信推送 无用 暂留
*/
private Integer pushType;
/**
* 模板ID
*/
@NotNull(message = "模板ID不能为空", groups = InsertGroup.class)
private Long pushEventId;
/**
* 1 全部用户 2范围用户 3 指定用户 指定暂定一个用户
*/
@NotNull(message = "发送范围不能为空", groups = InsertGroup.class)
private Long userType;
/**
* 指定用户时 使用
*/
private String userId;
/**
* 0待发送 1 发送中 2发送成功 -1失败
*/
private Integer status;
/**
* 发送内容
*/
@NotBlank(message = "发送内容不能为空", groups = InsertGroup.class)
private String content;
/**
* 赠送券信息[{"id":"268700","num":12,"title":"邀新10元优惠券"}]
*/
private String coupon;
/**
* 发送类型 1 立即发送 2定时发送
*/
@NotNull(message = "发送类型不能为空", groups = InsertGroup.class)
private Integer sendType;
/**
* 发送时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime sendTime;
/**
* 创建时间
*/
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime;
@JSONField(format = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime;
/**
* 失败原因
*/
private String error;
/**
* 发送的用户信息选项
* userType为2时 使用
*/
@Column(ignore = true)
private SmsPushEventUser smsPushEventUser;
}

View File

@ -0,0 +1,101 @@
package com.czg.market.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 营销推送发送记录 实体类
*
* @author ww
* @since 2025-10-14
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sms_push_event")
public class SmsPushEvent implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id(keyType = KeyType.Auto)
private Long id;
private Long shopId;
/**
* 推送类型 1 模版推送 2短信推送 无用 暂留
*/
private Integer pushType;
/**
* 模板ID
*/
private Long pushEventId;
/**
* 1 全部用户 2范围用户 3 指定用户 指定暂定一个用户
*/
private Long userType;
/**
* 指定用户时 使用
*/
private String userId;
/**
* 0待发送 1 发送中 2发送成功 -1失败
*/
private Integer status;
/**
* 发送内容
*/
private String content;
/**
* 赠送券信息[{"id":"268700","num":12,"title":"邀新10元优惠券"}]
*/
private String coupon;
/**
* 发送类型 1 立即发送 2定时发送
*/
private Integer sendType;
/**
* 发送时间
*/
private LocalDateTime sendTime;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
/**
* 失败原因
*/
private String error;
/**
* 是否删除 0 未删除 1 删除
*/
private Integer isDel;
}

View File

@ -0,0 +1,81 @@
package com.czg.market.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 营销推送任务 实体类
*
* @author ww
* @since 2025-10-14
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sms_push_event_user")
public class SmsPushEventUser implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id(keyType = KeyType.Auto)
private Long id;
/**
* sms_user_push_event的id
*/
private Long eventId;
private Long shopId;
/**
* 性别 0未知 1男 2女
*/
private String gender;
/**
* 下单时间 0今天 1昨天 2两周内 3两周前
*/
private String orderTimes;
/**
* 下单时间 0从未下单 其它数字表示下过几单
*/
private String orderHistory;
/**
* 充值过 0否 1是
*/
private String isRecharge;
/**
* 会员 0非会员 1会员
*/
private String vip;
/**
* 预留 短信推送用 会员等级 0 全部会员 1仅限等级 2以上等级
*/
private String vipLevel;
/**
* 预留 短信推送用 会员等级ID
*/
private Long vipLevelId;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,29 @@
package com.czg.market.service;
import com.czg.BaseQueryParam;
import com.czg.market.dto.ShopCouponDTO;
import com.czg.market.dto.SmsPushEventDTO;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import com.czg.market.entity.SmsPushEvent;
/**
* 营销推送发送记录 服务层
*
* @author ww
* @since 2025-10-14
*/
public interface SmsPushEventService extends IService<SmsPushEvent> {
/**
* 分页查询营销推送发送记录列表
*/
Page<SmsPushEventDTO> getPushEventPage(BaseQueryParam param, Long shopId, Long id);
/**
* 添加营销推送发送任务
*/
void addPushEvent(SmsPushEventDTO param);
void deletePushEvent(Long id);
}

View File

@ -0,0 +1,14 @@
package com.czg.service.market.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.market.entity.SmsPushEvent;
/**
* 营销推送发送记录 映射层
*
* @author ww
* @since 2025-10-14
*/
public interface SmsPushEventMapper extends BaseMapper<SmsPushEvent> {
}

View File

@ -0,0 +1,14 @@
package com.czg.service.market.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.market.entity.SmsPushEventUser;
/**
* 营销推送任务 映射层
*
* @author ww
* @since 2025-10-14
*/
public interface SmsPushEventUserMapper extends BaseMapper<SmsPushEventUser> {
}

View File

@ -0,0 +1,98 @@
package com.czg.service.market.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.czg.BaseQueryParam;
import com.czg.config.RabbitPublisher;
import com.czg.exception.CzgException;
import com.czg.market.dto.ShopCouponDTO;
import com.czg.market.dto.SmsPushEventDTO;
import com.czg.market.entity.ShopCoupon;
import com.czg.market.entity.SmsPushEventUser;
import com.czg.service.market.mapper.SmsPushEventUserMapper;
import com.czg.utils.AssertUtil;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.market.entity.SmsPushEvent;
import com.czg.market.service.SmsPushEventService;
import com.czg.service.market.mapper.SmsPushEventMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
/**
* 营销推送发送记录 服务层实现
*
* @author ww
* @since 2025-10-14
*/
@Service
public class SmsPushEventServiceImpl extends ServiceImpl<SmsPushEventMapper, SmsPushEvent> implements SmsPushEventService {
@Resource
private SmsPushEventUserMapper eventUserMapper;
@Resource
private RabbitPublisher rabbitPublisher;
@Override
public Page<SmsPushEventDTO> getPushEventPage(BaseQueryParam param, Long shopId, Long id) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq(SmsPushEvent::getShopId, shopId)
.eq(SmsPushEvent::getId, id)
.eq(SmsPushEvent::getIsDel, 0)
.orderBy(SmsPushEvent::getCreateTime).desc();
Page<SmsPushEventDTO> page = pageAs(new Page<>(param.getPage(), param.getSize()), queryWrapper, SmsPushEventDTO.class);
for (SmsPushEventDTO record : page.getRecords()) {
if (record.getUserType() != 2) {
continue;
}
SmsPushEventUser eventUser = eventUserMapper.selectOneByQuery(
new QueryWrapper().eq(SmsPushEventUser::getEventId, record.getId())
);
record.setSmsPushEventUser(eventUser);
}
return page;
}
@Override
@Transactional
public void addPushEvent(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);
save(pushEvent);
if (param.getUserType() == 2) {
SmsPushEventUser eventUser = param.getSmsPushEventUser();
eventUser.setShopId(param.getShopId());
eventUser.setEventId(pushEvent.getId());
eventUserMapper.insert(eventUser);
}
// 推送消息 进行 阿里模板申请
rabbitPublisher.sendWechatTemplateMsg(pushEvent.getShopId() + "," + pushEvent.getId());
}
/**
* 逻辑删除记录
*/
@Override
public void deletePushEvent(Long id) {
SmsPushEvent pushEvent = getById(id);
AssertUtil.isNull(pushEvent, "记录不存在");
pushEvent.setIsDel(1);
updateById(pushEvent);
}
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.market.mapper.SmsPushEventMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.market.mapper.SmsPushEventUserMapper">
</mapper>