feat: 新增消息推送初始化逻辑

This commit is contained in:
tangwei 2026-07-09 10:40:08 +08:00
parent 2f92eeef1a
commit dfca986d97
22 changed files with 1082 additions and 0 deletions

View File

@ -0,0 +1,117 @@
package com.yfd.platform.system.controller;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.annotation.Log;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.system.domain.PushConfig;
import com.yfd.platform.system.domain.PushConfigTargetRequest;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.domain.PushHistoryDetail;
import com.yfd.platform.system.service.IPushConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
@RestController
@RequestMapping("/system/pushConfig")
@Tag(name = "推送配置")
public class PushConfigController {
@Resource
private IPushConfigService pushConfigService;
@Operation(summary = "查询推送配置列表")
@GetMapping("/getPushConfigList")
public ResponseResult getPushConfigList(Page<PushConfig> page,
String categoryName,
String messageType,
Integer targetType,
Integer status) {
return ResponseResult.successData(pushConfigService.getPushConfigPage(page, categoryName, messageType, targetType, status));
}
@Operation(summary = "根据ID查询推送配置")
@GetMapping("/getPushConfigById")
public ResponseResult getPushConfigById(@RequestParam String id) {
return ResponseResult.successData(pushConfigService.getById(id));
}
@Log(module = "推送配置", value = "新增推送配置")
@Operation(summary = "新增推送配置")
@PostMapping("/addPushConfig")
public ResponseResult addPushConfig(@RequestBody PushConfig pushConfig) {
return pushConfigService.addPushConfig(pushConfig) ? ResponseResult.success() : ResponseResult.error("新增失败");
}
@Log(module = "推送配置", value = "修改推送配置")
@Operation(summary = "修改推送配置")
@PostMapping("/updatePushConfig")
public ResponseResult updatePushConfig(@RequestBody PushConfig pushConfig) {
return pushConfigService.updatePushConfig(pushConfig) ? ResponseResult.success() : ResponseResult.error("修改失败");
}
@Log(module = "推送配置", value = "删除推送配置")
@Operation(summary = "删除推送配置")
@PostMapping("/deletePushConfig")
public ResponseResult deletePushConfig(@RequestParam String ids) {
return pushConfigService.deletePushConfig(ids) ? ResponseResult.success() : ResponseResult.error("删除失败");
}
@Log(module = "推送配置", value = "设置推送配置状态")
@Operation(summary = "设置推送配置状态")
@PostMapping("/setPushConfigStatus")
public ResponseResult setPushConfigStatus(@RequestParam String id, @RequestParam Integer status) {
return pushConfigService.setPushConfigStatus(id, status) ? ResponseResult.success() : ResponseResult.error("设置失败");
}
@Log(module = "推送配置", value = "保存推送目标")
@Operation(summary = "保存推送目标")
@PostMapping("/savePushTargets")
public ResponseResult savePushTargets(@RequestBody PushConfigTargetRequest request) {
return pushConfigService.savePushTargets(request) ? ResponseResult.success() : ResponseResult.error("保存失败");
}
@Operation(summary = "查询推送目标")
@GetMapping("/getPushTargets")
public ResponseResult getPushTargets(@RequestParam String configId) {
return ResponseResult.successData(pushConfigService.getPushTargets(configId));
}
@Log(module = "推送配置", value = "立即执行推送配置")
@Operation(summary = "立即执行推送配置")
@PostMapping("/execution")
public ResponseResult execution(@RequestParam String configId) {
return pushConfigService.executeNow(configId) ? ResponseResult.success() : ResponseResult.error("执行失败");
}
@Operation(summary = "查询推送历史主表")
@GetMapping("/getPushHistoryList")
public ResponseResult getPushHistoryList(Page<PushHistory> page,
String configId,
Integer status,
String messageTypeCode,
String startTime,
String endTime) {
Date start = StrUtil.isBlank(startTime) ? null : DateUtil.parse(startTime);
Date end = StrUtil.isBlank(endTime) ? null : DateUtil.parse(endTime);
return ResponseResult.successData(pushConfigService.getPushHistoryPage(page, configId, status, messageTypeCode, start, end));
}
@Operation(summary = "查询推送历史明细")
@GetMapping("/getPushHistoryDetailList")
public ResponseResult getPushHistoryDetailList(Page<PushHistoryDetail> page,
String historyId,
Integer status) {
return ResponseResult.successData(pushConfigService.getPushHistoryDetailPage(page, historyId, status));
}
}

View File

@ -0,0 +1,59 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_CONFIG")
public class PushConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String categoryCode;
private String categoryName;
private String baseIdList;
private String baseNameList;
private String messageType;
private String cronExpression;
private Integer targetType;
private Integer isSms;
private Long pushCount;
private Long dailyPushCount;
private Date finishTime;
private Integer status;
private Date createdAt;
private Date updatedAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,21 @@
package com.yfd.platform.system.domain;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class PushConfigTargetRequest implements Serializable {
private static final long serialVersionUID = 1L;
private String configId;
/**
* 0-用户1-角色
*/
private Integer type;
private List<String> userRoleIds;
}

View File

@ -0,0 +1,23 @@
package com.yfd.platform.system.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class PushConfigTargetVo implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
private String configId;
private Integer type;
private String userRoleId;
private String targetName;
private String targetPhone;
}

View File

@ -0,0 +1,39 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_CONFIG_USER")
public class PushConfigUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String configId;
private Integer type;
private String userRoleId;
private Date createdAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,63 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_HISTORY")
public class PushHistory implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String configId;
private Date planTime;
private String messageTypeCode;
private String messageTypeName;
private String title;
private String content;
private Long pushedCount;
private Long successCount;
private Long failCount;
private Long pendingCount;
private String sendChannel;
private Integer status;
private String source;
private String relation;
private Date createdAt;
private Date updatedAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,47 @@
package com.yfd.platform.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
@TableName("PUSH_HISTORY_DETAIL")
public class PushHistoryDetail implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
private String historyId;
private String targetName;
private String targetPhone;
private Integer status;
private String sendChannel;
private Date sendTime;
private String errorMsg;
private Date createdAt;
private String recordUser;
private String modifyUser;
private Date modifyTime;
private Integer isDeleted;
private String deleteUser;
private Date deleteTime;
}

View File

@ -0,0 +1,17 @@
package com.yfd.platform.system.domain;
import lombok.Data;
import java.io.Serializable;
@Data
public class PushTargetUserVo implements Serializable {
private static final long serialVersionUID = 1L;
private String userId;
private String targetName;
private String targetPhone;
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushConfig;
public interface PushConfigMapper extends BaseMapper<PushConfig> {
}

View File

@ -0,0 +1,18 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushConfigTargetVo;
import com.yfd.platform.system.domain.PushConfigUser;
import com.yfd.platform.system.domain.PushTargetUserVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface PushConfigUserMapper extends BaseMapper<PushConfigUser> {
List<PushTargetUserVo> selectAllActiveUsers();
List<PushTargetUserVo> selectTargetUsersByConfigId(@Param("configId") String configId);
List<PushConfigTargetVo> selectConfigTargets(@Param("configId") String configId);
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushHistoryDetail;
public interface PushHistoryDetailMapper extends BaseMapper<PushHistoryDetail> {
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.system.domain.PushHistory;
public interface PushHistoryMapper extends BaseMapper<PushHistory> {
}

View File

@ -0,0 +1,48 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushConfig;
import com.yfd.platform.system.domain.PushConfigTargetRequest;
import com.yfd.platform.system.domain.PushConfigTargetVo;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.domain.PushHistoryDetail;
import java.util.Date;
import java.util.List;
public interface IPushConfigService extends IService<PushConfig> {
Page<PushConfig> getPushConfigPage(Page<PushConfig> page,
String categoryName,
String messageType,
Integer targetType,
Integer status);
boolean addPushConfig(PushConfig pushConfig);
boolean updatePushConfig(PushConfig pushConfig);
boolean deletePushConfig(String ids);
boolean setPushConfigStatus(String id, Integer status);
boolean savePushTargets(PushConfigTargetRequest request);
List<PushConfigTargetVo> getPushTargets(String configId);
Page<PushHistory> getPushHistoryPage(Page<PushHistory> page,
String configId,
Integer status,
String messageTypeCode,
Date startTime,
Date endTime);
Page<PushHistoryDetail> getPushHistoryDetailPage(Page<PushHistoryDetail> page,
String historyId,
Integer status);
boolean executeNow(String configId);
void executePushConfig(String configId);
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushConfigUser;
public interface IPushConfigUserService extends IService<PushConfigUser> {
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushHistoryDetail;
public interface IPushHistoryDetailService extends IService<PushHistoryDetail> {
}

View File

@ -0,0 +1,7 @@
package com.yfd.platform.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.system.domain.PushHistory;
public interface IPushHistoryService extends IService<PushHistory> {
}

View File

@ -0,0 +1,16 @@
package com.yfd.platform.system.service.impl;
import com.yfd.platform.system.service.IPushConfigService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
@Service("pushConfigQuartzExecutor")
public class PushConfigQuartzExecutor {
@Resource
private IPushConfigService pushConfigService;
public void execute(String configId) {
pushConfigService.executePushConfig(configId);
}
}

View File

@ -0,0 +1,463 @@
package com.yfd.platform.system.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.common.exception.BizException;
import com.yfd.platform.system.domain.PushConfig;
import com.yfd.platform.system.domain.PushConfigTargetRequest;
import com.yfd.platform.system.domain.PushConfigTargetVo;
import com.yfd.platform.system.domain.PushConfigUser;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.domain.PushHistoryDetail;
import com.yfd.platform.system.domain.PushTargetUserVo;
import com.yfd.platform.system.domain.QuartzJob;
import com.yfd.platform.system.mapper.PushConfigMapper;
import com.yfd.platform.system.mapper.PushConfigUserMapper;
import com.yfd.platform.system.service.IPushConfigService;
import com.yfd.platform.system.service.IPushConfigUserService;
import com.yfd.platform.system.service.IPushHistoryDetailService;
import com.yfd.platform.system.service.IPushHistoryService;
import com.yfd.platform.system.service.IQuartzJobService;
import com.yfd.platform.utils.QuartzManage;
import com.yfd.platform.utils.SecurityUtils;
import jakarta.annotation.Resource;
import org.quartz.CronExpression;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@Service
public class PushConfigServiceImpl extends ServiceImpl<PushConfigMapper, PushConfig> implements IPushConfigService {
private static final String QUARTZ_BIZ_TYPE = "PUSH_CONFIG";
private static final String DEFAULT_SEND_CHANNEL = "SMS";
private static final String DEFAULT_SOURCE = "PUSH_CONFIG";
@Resource
private PushConfigUserMapper pushConfigUserMapper;
@Resource
private IPushConfigUserService pushConfigUserService;
@Resource
private IPushHistoryService pushHistoryService;
@Resource
private IPushHistoryDetailService pushHistoryDetailService;
@Resource
private IQuartzJobService quartzJobService;
@Resource
private QuartzManage quartzManage;
@Override
public Page<PushConfig> getPushConfigPage(Page<PushConfig> page,
String categoryName,
String messageType,
Integer targetType,
Integer status) {
LambdaQueryWrapper<PushConfig> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PushConfig::getIsDeleted, 0)
.like(StrUtil.isNotBlank(categoryName), PushConfig::getCategoryName, categoryName)
.like(StrUtil.isNotBlank(messageType), PushConfig::getMessageType, messageType)
.eq(targetType != null, PushConfig::getTargetType, targetType)
.eq(status != null, PushConfig::getStatus, status)
.orderByDesc(PushConfig::getUpdatedAt, PushConfig::getCreatedAt);
return this.page(page, wrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addPushConfig(PushConfig pushConfig) {
validatePushConfig(pushConfig, false);
Date now = new Date();
pushConfig.setCreatedAt(now);
pushConfig.setUpdatedAt(now);
pushConfig.setModifyTime(now);
pushConfig.setRecordUser(currentUserIdOrSystem());
pushConfig.setModifyUser(currentUserIdOrSystem());
pushConfig.setIsDeleted(0);
pushConfig.setStatus(pushConfig.getStatus() == null ? 1 : pushConfig.getStatus());
pushConfig.setIsSms(pushConfig.getIsSms() == null ? 0 : pushConfig.getIsSms());
pushConfig.setPushCount(pushConfig.getPushCount() == null ? 0L : pushConfig.getPushCount());
pushConfig.setDailyPushCount(pushConfig.getDailyPushCount() == null ? 0L : pushConfig.getDailyPushCount());
boolean saved = this.save(pushConfig);
if (saved) {
syncQuartzJob(pushConfig);
}
return saved;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean updatePushConfig(PushConfig pushConfig) {
validatePushConfig(pushConfig, true);
PushConfig dbConfig = getAvailableConfig(pushConfig.getId());
dbConfig.setCategoryCode(pushConfig.getCategoryCode());
dbConfig.setCategoryName(pushConfig.getCategoryName());
dbConfig.setBaseIdList(pushConfig.getBaseIdList());
dbConfig.setBaseNameList(pushConfig.getBaseNameList());
dbConfig.setMessageType(pushConfig.getMessageType());
dbConfig.setCronExpression(pushConfig.getCronExpression());
dbConfig.setTargetType(pushConfig.getTargetType());
dbConfig.setIsSms(pushConfig.getIsSms() == null ? 0 : pushConfig.getIsSms());
dbConfig.setStatus(pushConfig.getStatus() == null ? dbConfig.getStatus() : pushConfig.getStatus());
dbConfig.setUpdatedAt(new Date());
dbConfig.setModifyTime(new Date());
dbConfig.setModifyUser(currentUserIdOrSystem());
boolean updated = this.updateById(dbConfig);
if (updated) {
if (Objects.equals(dbConfig.getTargetType(), 1)) {
softDeleteTargets(dbConfig.getId(), currentUserIdOrSystem(), new Date());
}
syncQuartzJob(dbConfig);
}
return updated;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean deletePushConfig(String ids) {
if (StrUtil.isBlank(ids)) {
throw new BizException("参数不能为空.");
}
Date now = new Date();
String userId = currentUserIdOrSystem();
for (String id : ids.split(",")) {
String configId = StrUtil.trim(id);
if (StrUtil.isBlank(configId)) {
continue;
}
PushConfig config = getAvailableConfig(configId);
config.setIsDeleted(1);
config.setDeleteUser(userId);
config.setDeleteTime(now);
config.setModifyUser(userId);
config.setModifyTime(now);
config.setUpdatedAt(now);
this.updateById(config);
softDeleteTargets(configId, userId, now);
deleteQuartzJob(configId);
}
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean setPushConfigStatus(String id, Integer status) {
if (StrUtil.isBlank(id) || status == null) {
throw new BizException("参数不能为空.");
}
PushConfig config = getAvailableConfig(id);
config.setStatus(status);
config.setUpdatedAt(new Date());
config.setModifyTime(new Date());
config.setModifyUser(currentUserIdOrSystem());
boolean updated = this.updateById(config);
if (updated) {
syncQuartzJob(config);
}
return updated;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean savePushTargets(PushConfigTargetRequest request) {
validatePushTargetRequest(request);
PushConfig config = getAvailableConfig(request.getConfigId());
validateTargetTypeMatch(config.getTargetType(), request.getType());
Date now = new Date();
String userId = currentUserIdOrSystem();
softDeleteTargets(config.getId(), userId, now);
if (request.getUserRoleIds() == null || request.getUserRoleIds().isEmpty()) {
return true;
}
List<PushConfigUser> list = new ArrayList<>();
for (String userRoleId : request.getUserRoleIds()) {
String targetId = StrUtil.trim(userRoleId);
if (StrUtil.isBlank(targetId)) {
continue;
}
PushConfigUser relation = new PushConfigUser();
relation.setConfigId(config.getId());
relation.setType(request.getType());
relation.setUserRoleId(targetId);
relation.setCreatedAt(now);
relation.setRecordUser(userId);
relation.setModifyUser(userId);
relation.setModifyTime(now);
relation.setIsDeleted(0);
list.add(relation);
}
return list.isEmpty() || pushConfigUserService.saveBatch(list);
}
@Override
public List<PushConfigTargetVo> getPushTargets(String configId) {
if (StrUtil.isBlank(configId)) {
return Collections.emptyList();
}
return pushConfigUserMapper.selectConfigTargets(configId);
}
@Override
public Page<PushHistory> getPushHistoryPage(Page<PushHistory> page,
String configId,
Integer status,
String messageTypeCode,
Date startTime,
Date endTime) {
LambdaQueryWrapper<PushHistory> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PushHistory::getIsDeleted, 0)
.eq(StrUtil.isNotBlank(configId), PushHistory::getConfigId, configId)
.eq(status != null, PushHistory::getStatus, status)
.eq(StrUtil.isNotBlank(messageTypeCode), PushHistory::getMessageTypeCode, messageTypeCode)
.ge(startTime != null, PushHistory::getPlanTime, startTime)
.le(endTime != null, PushHistory::getPlanTime, endTime)
.orderByDesc(PushHistory::getPlanTime, PushHistory::getCreatedAt);
return pushHistoryService.page(page, wrapper);
}
@Override
public Page<PushHistoryDetail> getPushHistoryDetailPage(Page<PushHistoryDetail> page,
String historyId,
Integer status) {
LambdaQueryWrapper<PushHistoryDetail> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PushHistoryDetail::getIsDeleted, 0)
.eq(StrUtil.isNotBlank(historyId), PushHistoryDetail::getHistoryId, historyId)
.eq(status != null, PushHistoryDetail::getStatus, status)
.orderByDesc(PushHistoryDetail::getCreatedAt, PushHistoryDetail::getSendTime);
return pushHistoryDetailService.page(page, wrapper);
}
@Override
public boolean executeNow(String configId) {
executePushConfig(configId);
return true;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void executePushConfig(String configId) {
PushConfig config = getAvailableConfig(configId);
List<PushTargetUserVo> targets = resolveTargets(config);
Date now = new Date();
String operator = currentUserIdOrSystem();
PushHistory history = new PushHistory();
history.setConfigId(config.getId());
history.setPlanTime(now);
history.setMessageTypeCode(config.getCategoryCode());
history.setMessageTypeName(config.getCategoryName());
history.setTitle(buildDefaultTitle(config));
history.setContent(buildDefaultContent(config));
history.setPushedCount(0L);
history.setSuccessCount(0L);
history.setFailCount(0L);
history.setPendingCount((long) targets.size());
history.setSendChannel(DEFAULT_SEND_CHANNEL);
history.setStatus(0);
history.setSource(DEFAULT_SOURCE);
history.setRelation(StrUtil.blankToDefault(config.getBaseNameList(), config.getCategoryName()));
history.setCreatedAt(now);
history.setUpdatedAt(now);
history.setRecordUser(operator);
history.setModifyUser(operator);
history.setModifyTime(now);
history.setIsDeleted(0);
pushHistoryService.save(history);
if (!targets.isEmpty()) {
List<PushHistoryDetail> detailList = new ArrayList<>();
for (PushTargetUserVo target : targets) {
PushHistoryDetail detail = new PushHistoryDetail();
detail.setHistoryId(history.getId());
detail.setTargetName(target.getTargetName());
detail.setTargetPhone(target.getTargetPhone());
detail.setStatus(0);
detail.setSendChannel(DEFAULT_SEND_CHANNEL);
detail.setCreatedAt(now);
detail.setRecordUser(operator);
detail.setModifyUser(operator);
detail.setModifyTime(now);
detail.setIsDeleted(0);
detailList.add(detail);
}
pushHistoryDetailService.saveBatch(detailList);
}
}
private void validatePushConfig(PushConfig pushConfig, boolean requireId) {
if (pushConfig == null) {
throw new BizException("参数不能为空.");
}
if (requireId && StrUtil.isBlank(pushConfig.getId())) {
throw new BizException("配置ID不能为空.");
}
if (StrUtil.isBlank(pushConfig.getCategoryCode())) {
throw new BizException("消息类别编码不能为空.");
}
if (StrUtil.isBlank(pushConfig.getCategoryName())) {
throw new BizException("消息类别名称不能为空.");
}
if (StrUtil.isBlank(pushConfig.getMessageType())) {
throw new BizException("消息类型不能为空.");
}
if (StrUtil.isBlank(pushConfig.getCronExpression()) || !CronExpression.isValidExpression(pushConfig.getCronExpression())) {
throw new BizException("cron表达式格式错误.");
}
if (pushConfig.getTargetType() == null || (pushConfig.getTargetType() != 1 && pushConfig.getTargetType() != 2 && pushConfig.getTargetType() != 3)) {
throw new BizException("推送目标类型不正确.");
}
}
private void validatePushTargetRequest(PushConfigTargetRequest request) {
if (request == null) {
throw new BizException("参数不能为空.");
}
if (StrUtil.isBlank(request.getConfigId())) {
throw new BizException("推送配置ID不能为空.");
}
if (request.getType() == null || (request.getType() != 0 && request.getType() != 1)) {
throw new BizException("绑定类型不正确.");
}
}
private void validateTargetTypeMatch(Integer targetType, Integer relationType) {
if (targetType == null) {
return;
}
if (targetType == 1) {
throw new BizException("当前配置为所有人推送,无需绑定目标.");
}
if (targetType == 2 && !Objects.equals(relationType, 0)) {
throw new BizException("按人推送只能绑定用户.");
}
if (targetType == 3 && !Objects.equals(relationType, 1)) {
throw new BizException("按角色推送只能绑定角色.");
}
}
private PushConfig getAvailableConfig(String id) {
List<PushConfig> list = this.list(new LambdaQueryWrapper<PushConfig>()
.eq(PushConfig::getId, id)
.eq(PushConfig::getIsDeleted, 0));
PushConfig config = list.isEmpty() ? null : list.get(0);
if (config == null) {
throw new BizException("推送配置不存在.");
}
return config;
}
private void softDeleteTargets(String configId, String userId, Date now) {
LambdaUpdateWrapper<PushConfigUser> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(PushConfigUser::getConfigId, configId)
.eq(PushConfigUser::getIsDeleted, 0)
.set(PushConfigUser::getIsDeleted, 1)
.set(PushConfigUser::getDeleteUser, userId)
.set(PushConfigUser::getDeleteTime, now)
.set(PushConfigUser::getModifyUser, userId)
.set(PushConfigUser::getModifyTime, now);
pushConfigUserService.update(updateWrapper);
}
private void syncQuartzJob(PushConfig config) {
QuartzJob quartzJob = getPushQuartzJob(config.getId());
Date now = new Date();
if (quartzJob == null) {
quartzJob = new QuartzJob();
quartzJob.setCustom1(QUARTZ_BIZ_TYPE);
quartzJob.setCustom2(config.getId());
}
quartzJob.setJobName("推送配置-" + config.getCategoryName());
quartzJob.setJobClass("pushConfigQuartzExecutor");
quartzJob.setJobMethod("execute");
quartzJob.setJobCron(config.getCronExpression());
quartzJob.setJobParams(config.getId());
quartzJob.setDescription("推送配置定时任务-" + config.getMessageType());
quartzJob.setStatus(Objects.equals(config.getStatus(), 1) ? "1" : "0");
quartzJob.setLastmodifier(currentUsernameOrSystem());
quartzJob.setLastmodifydate(new java.sql.Timestamp(now.getTime()));
if (StrUtil.isBlank(quartzJob.getId())) {
quartzJobService.save(quartzJob);
quartzManage.addJob(quartzJob);
} else {
quartzJobService.updateById(quartzJob);
quartzManage.updateJobCron(quartzJob);
}
}
private void deleteQuartzJob(String configId) {
QuartzJob quartzJob = getPushQuartzJob(configId);
if (quartzJob != null) {
quartzManage.deleteJob(quartzJob);
quartzJobService.removeById(quartzJob.getId());
}
}
private QuartzJob getPushQuartzJob(String configId) {
List<QuartzJob> list = quartzJobService.list(new LambdaQueryWrapper<QuartzJob>()
.eq(QuartzJob::getCustom1, QUARTZ_BIZ_TYPE)
.eq(QuartzJob::getCustom2, configId));
return list.isEmpty() ? null : list.get(0);
}
private List<PushTargetUserVo> resolveTargets(PushConfig config) {
List<PushTargetUserVo> rawTargets;
if (Objects.equals(config.getTargetType(), 1)) {
rawTargets = pushConfigUserMapper.selectAllActiveUsers();
} else {
rawTargets = pushConfigUserMapper.selectTargetUsersByConfigId(config.getId());
}
if (rawTargets == null || rawTargets.isEmpty()) {
return Collections.emptyList();
}
Map<String, PushTargetUserVo> targetMap = new LinkedHashMap<>();
for (PushTargetUserVo target : rawTargets) {
if (target == null || StrUtil.isBlank(target.getUserId()) || StrUtil.isBlank(target.getTargetPhone())) {
continue;
}
targetMap.putIfAbsent(target.getUserId(), target);
}
return new ArrayList<>(targetMap.values());
}
private String buildDefaultTitle(PushConfig config) {
return StrUtil.format("【{}】默认推送标题", StrUtil.blankToDefault(config.getCategoryName(), "消息通知"));
}
private String buildDefaultContent(PushConfig config) {
return StrUtil.format("【{}】默认推送内容,消息类型:{},执行时间:{}",
StrUtil.blankToDefault(config.getCategoryName(), "消息通知"),
StrUtil.blankToDefault(config.getMessageType(), "未配置"),
DateUtil.formatDateTime(new Date()));
}
private String currentUserIdOrSystem() {
try {
return SecurityUtils.getUserId();
} catch (Exception ex) {
return "system";
}
}
private String currentUsernameOrSystem() {
try {
return SecurityUtils.getCurrentUsername();
} catch (Exception ex) {
return "system";
}
}
}

View File

@ -0,0 +1,11 @@
package com.yfd.platform.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.system.domain.PushConfigUser;
import com.yfd.platform.system.mapper.PushConfigUserMapper;
import com.yfd.platform.system.service.IPushConfigUserService;
import org.springframework.stereotype.Service;
@Service
public class PushConfigUserServiceImpl extends ServiceImpl<PushConfigUserMapper, PushConfigUser> implements IPushConfigUserService {
}

View File

@ -0,0 +1,11 @@
package com.yfd.platform.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.system.domain.PushHistoryDetail;
import com.yfd.platform.system.mapper.PushHistoryDetailMapper;
import com.yfd.platform.system.service.IPushHistoryDetailService;
import org.springframework.stereotype.Service;
@Service
public class PushHistoryDetailServiceImpl extends ServiceImpl<PushHistoryDetailMapper, PushHistoryDetail> implements IPushHistoryDetailService {
}

View File

@ -0,0 +1,11 @@
package com.yfd.platform.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.system.domain.PushHistory;
import com.yfd.platform.system.mapper.PushHistoryMapper;
import com.yfd.platform.system.service.IPushHistoryService;
import org.springframework.stereotype.Service;
@Service
public class PushHistoryServiceImpl extends ServiceImpl<PushHistoryMapper, PushHistory> implements IPushHistoryService {
}

View File

@ -0,0 +1,76 @@
<?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.yfd.platform.system.mapper.PushConfigUserMapper">
<select id="selectAllActiveUsers" resultType="com.yfd.platform.system.domain.PushTargetUserVo">
SELECT
u.ID AS userId,
NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME)) AS targetName,
u.PHONE AS targetPhone
FROM SYS_USER u
WHERE u.STATUS = 1
AND u.PHONE IS NOT NULL
AND TRIM(u.PHONE) IS NOT NULL
</select>
<select id="selectTargetUsersByConfigId" resultType="com.yfd.platform.system.domain.PushTargetUserVo">
SELECT DISTINCT
t.userId,
t.targetName,
t.targetPhone
FROM (
SELECT
u.ID AS userId,
NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME)) AS targetName,
u.PHONE AS targetPhone
FROM PUSH_CONFIG_USER pcu
INNER JOIN SYS_USER u ON u.ID = pcu.USER_ROLE_ID
WHERE pcu.CONFIG_ID = #{configId}
AND pcu.TYPE = 0
AND NVL(pcu.IS_DELETED, 0) = 0
AND u.STATUS = 1
AND u.PHONE IS NOT NULL
AND TRIM(u.PHONE) IS NOT NULL
UNION ALL
SELECT
u.ID AS userId,
NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME)) AS targetName,
u.PHONE AS targetPhone
FROM PUSH_CONFIG_USER pcu
INNER JOIN SYS_ROLE_USERS sru ON sru.ROLEID = pcu.USER_ROLE_ID
INNER JOIN SYS_USER u ON u.ID = sru.USERID
WHERE pcu.CONFIG_ID = #{configId}
AND pcu.TYPE = 1
AND NVL(pcu.IS_DELETED, 0) = 0
AND u.STATUS = 1
AND u.PHONE IS NOT NULL
AND TRIM(u.PHONE) IS NOT NULL
) t
</select>
<select id="selectConfigTargets" resultType="com.yfd.platform.system.domain.PushConfigTargetVo">
SELECT
pcu.ID AS id,
pcu.CONFIG_ID AS configId,
pcu.TYPE AS type,
pcu.USER_ROLE_ID AS userRoleId,
CASE
WHEN pcu.TYPE = 0 THEN NVL(u.REAL_NAME, NVL(u.NICKNAME, u.USERNAME))
ELSE r.ROLENAME
END AS targetName,
CASE
WHEN pcu.TYPE = 0 THEN u.PHONE
ELSE NULL
END AS targetPhone
FROM PUSH_CONFIG_USER pcu
LEFT JOIN SYS_USER u ON pcu.TYPE = 0 AND u.ID = pcu.USER_ROLE_ID
LEFT JOIN SYS_ROLE r ON pcu.TYPE = 1 AND r.ID = pcu.USER_ROLE_ID
WHERE pcu.CONFIG_ID = #{configId}
AND NVL(pcu.IS_DELETED, 0) = 0
ORDER BY pcu.CREATED_AT DESC, pcu.ID DESC
</select>
</mapper>