feat: 消息推送

This commit is contained in:
2026-07-27 11:17:15 +08:00
parent 784350bb42
commit d4e7e4282b
8 changed files with 825 additions and 0 deletions
@@ -0,0 +1,104 @@
package com.budwk.app.zhgh.pointsmall.message.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.annotation.SLog;
import com.budwk.app.base.result.Result;
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessageTemplate;
import com.budwk.app.zhgh.pointsmall.message.param.PointsMallMessagePageParam;
import com.budwk.app.zhgh.pointsmall.message.param.PointsMallMessageTemplatePageParam;
import com.budwk.app.zhgh.pointsmall.message.service.PointsMallMessageService;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import java.util.List;
@IocBean
@Ok("json:full")
@At("/platform/zhgh/points-mall/message")
public class PointsMallMessageController {
@Inject
private PointsMallMessageService pointsMallMessageService;
@At("")
@Ok("beetl:/platform/zhgh/points-mall/message/index.html")
@SaCheckPermission("points.mall.message")
public void index() {
}
@At
@SaCheckPermission("points.mall.message")
public Result pageData(PointsMallMessageTemplatePageParam param) {
return Result.success(pointsMallMessageService.templatePage(param));
}
@At
@SaCheckPermission("points.mall.message")
public Result list() {
return Result.success(pointsMallMessageService.templateList());
}
@At
@SaCheckPermission("points.mall.message")
public Result get(@Param("id") String id) {
return Result.success(pointsMallMessageService.fetch(id));
}
@At
@SLog(tag = "消息推送", msg = "保存消息模板")
@SaCheckPermission("points.mall.message")
public Result doSave(PointsMallMessageTemplate template) {
try {
pointsMallMessageService.saveTemplate(template);
return Result.success();
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
@At
@SLog(tag = "消息推送", msg = "删除消息模板")
@SaCheckPermission("points.mall.message")
public Result doDelete(@Param("ids") String ids) {
List<String> idList = StrUtil.split(ids, ',');
if (idList.isEmpty()) {
return Result.error("请选择需要删除的数据");
}
try {
return Result.success(pointsMallMessageService.deleteTemplate(idList));
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
@At
@SaCheckPermission("points.mall.message")
public Result recordPage(PointsMallMessagePageParam param) {
return Result.success(pointsMallMessageService.messagePage(param));
}
@At
@SLog(tag = "消息推送", msg = "重新推送消息")
@SaCheckPermission("points.mall.message")
public Result resend(@Param("ids") String ids) {
List<String> idList = StrUtil.split(ids, ',');
try {
pointsMallMessageService.resend(idList);
return Result.success();
} catch (IllegalArgumentException e) {
return Result.error(e.getMessage());
}
}
@At
@SLog(tag = "消息推送", msg = "一键推送消息")
@SaCheckPermission("points.mall.message")
public Result resendAll(PointsMallMessagePageParam param) {
pointsMallMessageService.resendAll(param);
return Result.success();
}
}
@@ -0,0 +1,77 @@
package com.budwk.app.zhgh.pointsmall.message.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.ColDefine;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.io.Serializable;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@Table("points_mall_message")
@Comment("积分商城消息记录")
public class PointsMallMessage extends BaseModel implements Serializable {
@Name
@Column
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("业务唯一号")
@ColDefine(type = ColType.VARCHAR, width = 128)
private String uniqueNo;
@Column
@Comment("推送类型")
@ColDefine(type = ColType.VARCHAR, width = 50)
private String pushType;
@Column
@Comment("模板ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
private String templateId;
@Column
@Comment("目标用户")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String touser;
@Column
@Comment("目标部门")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String toparty;
@Column
@Comment("目标标签")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String totag;
@Column
@Comment("推送内容")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String content;
@Column
@Comment("内容链接")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String contentLink;
@Column
@Comment("计划推送时间")
private Date planPushTime;
@Column
@Comment("状态")
private Integer status;
}
@@ -0,0 +1,85 @@
package com.budwk.app.zhgh.pointsmall.message.models;
import com.budwk.app.base.model.BaseModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.nutz.dao.entity.annotation.ColDefine;
import org.nutz.dao.entity.annotation.ColType;
import org.nutz.dao.entity.annotation.Column;
import org.nutz.dao.entity.annotation.Comment;
import org.nutz.dao.entity.annotation.Default;
import org.nutz.dao.entity.annotation.Name;
import org.nutz.dao.entity.annotation.Table;
import org.nutz.dao.interceptor.annotation.PrevInsert;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = true)
@Table("points_mall_message_template")
@Comment("积分商城消息模板")
public class PointsMallMessageTemplate extends BaseModel implements Serializable {
@Name
@Column
@Comment("ID")
@ColDefine(type = ColType.VARCHAR, width = 32)
@PrevInsert(uu32 = true)
private String id;
@Column
@Comment("模板名称")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String name;
@Column
@Comment("模板类型")
private Integer type;
@Column
@Comment("内容模板")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String content;
@Column
@Comment("内容链接")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String contentLink;
@Column
@Comment("状态:0禁用,1启用")
@Default("1")
private Integer status;
@Column
@Comment("扩展参数")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String extParam;
@Column
@Comment("是否发放积分")
@Default("0")
private Integer isSendPoints;
@Column
@Comment("发放积分")
@Default("0")
@ColDefine(customType = "decimal(18,2)")
private BigDecimal sendPoints;
@Column
@Comment("目标机构列表")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String deptIdList;
@Column
@Comment("目标工会列表")
@ColDefine(type = ColType.VARCHAR, customType = "mediumtext")
private String unionIdList;
@Column
@Comment("节日日期")
@ColDefine(type = ColType.VARCHAR, width = 100)
private String festivalDate;
}
@@ -0,0 +1,16 @@
package com.budwk.app.zhgh.pointsmall.message.param;
import com.budwk.app.base.param.PageForm;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class PointsMallMessagePageParam extends PageForm {
private String templateId;
private String touser;
private String statuses;
private String createTimeStart;
private String createTimeEnd;
}
@@ -0,0 +1,14 @@
package com.budwk.app.zhgh.pointsmall.message.param;
import com.budwk.app.base.param.PageForm;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class PointsMallMessageTemplatePageParam extends PageForm {
private String name;
private Integer type;
private Integer status;
}
@@ -0,0 +1,27 @@
package com.budwk.app.zhgh.pointsmall.message.service;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.BaseService;
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessage;
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessageTemplate;
import com.budwk.app.zhgh.pointsmall.message.param.PointsMallMessagePageParam;
import com.budwk.app.zhgh.pointsmall.message.param.PointsMallMessageTemplatePageParam;
import java.util.List;
public interface PointsMallMessageService extends BaseService<PointsMallMessageTemplate> {
Pagination<PointsMallMessageTemplate> templatePage(PointsMallMessageTemplatePageParam param);
List<PointsMallMessageTemplate> templateList();
void saveTemplate(PointsMallMessageTemplate template);
int deleteTemplate(List<String> ids);
Pagination<PointsMallMessage> messagePage(PointsMallMessagePageParam param);
void resend(List<String> ids);
void resendAll(PointsMallMessagePageParam param);
}
@@ -0,0 +1,157 @@
package com.budwk.app.zhgh.pointsmall.message.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.budwk.app.base.page.Pagination;
import com.budwk.app.base.service.impl.BaseServiceImpl;
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessage;
import com.budwk.app.zhgh.pointsmall.message.models.PointsMallMessageTemplate;
import com.budwk.app.zhgh.pointsmall.message.param.PointsMallMessagePageParam;
import com.budwk.app.zhgh.pointsmall.message.param.PointsMallMessageTemplatePageParam;
import com.budwk.app.zhgh.pointsmall.message.service.PointsMallMessageService;
import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.ioc.loader.annotation.IocBean;
import java.util.Arrays;
import java.util.List;
@IocBean(args = {"refer:dao"})
public class PointsMallMessageServiceImpl extends BaseServiceImpl<PointsMallMessageTemplate> implements PointsMallMessageService {
public PointsMallMessageServiceImpl(Dao dao) {
super(dao);
}
@Override
public Pagination<PointsMallMessageTemplate> templatePage(PointsMallMessageTemplatePageParam param) {
Cnd cnd = templateCnd(param);
cnd.desc("createdAt");
return listPage(param.getPageNumber(), param.getPageSize(), PointsMallMessageTemplate.class, cnd);
}
@Override
public List<PointsMallMessageTemplate> templateList() {
return query(Cnd.where("delFlag", "=", false).and("status", "=", 1).desc("createdAt"));
}
@Override
public void saveTemplate(PointsMallMessageTemplate template) {
checkTemplate(template);
if (template.getStatus() == null) {
template.setStatus(1);
}
if (template.getIsSendPoints() == null) {
template.setIsSendPoints(0);
}
if (StrUtil.isBlank(template.getId())) {
insert(template);
} else {
updateIgnoreNull(template);
}
}
@Override
public int deleteTemplate(List<String> ids) {
if (CollUtil.isEmpty(ids)) {
return 0;
}
List<String> canDelete = ids.stream()
.filter(id -> dao().count("points_mall_message_schedule", Cnd.where("templateId", "=", id).and("delFlag", "=", false)) == 0)
.filter(id -> {
PointsMallMessageTemplate template = fetch(id);
return template != null && !Integer.valueOf(5).equals(template.getType());
})
.toList();
if (canDelete.isEmpty()) {
throw new IllegalArgumentException("模板正在使用中或为业务消息,无法删除");
}
dao().update(PointsMallMessageTemplate.class, Chain.make("delFlag", true), Cnd.where("id", "in", canDelete));
return canDelete.size();
}
@Override
public Pagination<PointsMallMessage> messagePage(PointsMallMessagePageParam param) {
Cnd cnd = Cnd.where("delFlag", "=", false);
if (StrUtil.isNotBlank(param.getTemplateId())) {
cnd.and("templateId", "=", param.getTemplateId());
}
if (StrUtil.isNotBlank(param.getTouser())) {
cnd.and("touser", "like", "%" + param.getTouser() + "%");
}
List<Integer> statuses = splitStatuses(param.getStatuses());
if (CollUtil.isNotEmpty(statuses)) {
cnd.and("status", "in", statuses);
}
if (StrUtil.isNotBlank(param.getCreateTimeStart())) {
cnd.and("createdAt", ">=", DateUtil.parse(param.getCreateTimeStart()).getTime());
}
if (StrUtil.isNotBlank(param.getCreateTimeEnd())) {
cnd.and("createdAt", "<=", DateUtil.parse(param.getCreateTimeEnd()).getTime());
}
cnd.desc("createdAt");
return listPage(param.getPageNumber(), param.getPageSize(), PointsMallMessage.class, cnd);
}
@Override
public void resend(List<String> ids) {
if (CollUtil.isEmpty(ids)) {
throw new IllegalArgumentException("请选择消息记录");
}
dao().update(PointsMallMessage.class, Chain.make("status", 2), Cnd.where("id", "in", ids).and("status", "in", Arrays.asList(0, 3)));
}
@Override
public void resendAll(PointsMallMessagePageParam param) {
Cnd cnd = Cnd.where("delFlag", "=", false).and("status", "in", Arrays.asList(0, 3));
if (StrUtil.isNotBlank(param.getTemplateId())) {
cnd.and("templateId", "=", param.getTemplateId());
}
if (StrUtil.isNotBlank(param.getTouser())) {
cnd.and("touser", "like", "%" + param.getTouser() + "%");
}
dao().update(PointsMallMessage.class, Chain.make("status", 2), cnd);
}
private Cnd templateCnd(PointsMallMessageTemplatePageParam param) {
Cnd cnd = Cnd.where("delFlag", "=", false);
if (StrUtil.isNotBlank(param.getName())) {
cnd.and("name", "like", "%" + param.getName() + "%");
}
if (param.getType() != null) {
cnd.and("type", "=", param.getType());
}
if (param.getStatus() != null) {
cnd.and("status", "=", param.getStatus());
}
return cnd;
}
private void checkTemplate(PointsMallMessageTemplate template) {
if (template == null) {
throw new IllegalArgumentException("模板信息不能为空");
}
if (StrUtil.isBlank(template.getName())) {
throw new IllegalArgumentException("模板名称不能为空");
}
if (template.getType() == null) {
throw new IllegalArgumentException("模板类型不能为空");
}
if (StrUtil.isBlank(template.getContent())) {
throw new IllegalArgumentException("模板内容不能为空");
}
}
private List<Integer> splitStatuses(String statuses) {
if (StrUtil.isBlank(statuses)) {
return List.of();
}
return Arrays.stream(statuses.split(","))
.map(String::trim)
.filter(StrUtil::isNotBlank)
.map(Integer::valueOf)
.toList();
}
}