diff --git a/backend/src/main/java/com/yfd/platform/system/controller/PushConfigController.java b/backend/src/main/java/com/yfd/platform/system/controller/PushConfigController.java new file mode 100644 index 00000000..74cbdb19 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/controller/PushConfigController.java @@ -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 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 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 page, + String historyId, + Integer status) { + return ResponseResult.successData(pushConfigService.getPushHistoryDetailPage(page, historyId, status)); + } +} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/PushConfig.java b/backend/src/main/java/com/yfd/platform/system/domain/PushConfig.java new file mode 100644 index 00000000..5c4bd18a --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/PushConfig.java @@ -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; +} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/PushConfigTargetRequest.java b/backend/src/main/java/com/yfd/platform/system/domain/PushConfigTargetRequest.java new file mode 100644 index 00000000..9f4adf4f --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/PushConfigTargetRequest.java @@ -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 userRoleIds; +} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/PushConfigTargetVo.java b/backend/src/main/java/com/yfd/platform/system/domain/PushConfigTargetVo.java new file mode 100644 index 00000000..1a57d647 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/PushConfigTargetVo.java @@ -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; +} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/PushConfigUser.java b/backend/src/main/java/com/yfd/platform/system/domain/PushConfigUser.java new file mode 100644 index 00000000..3c840926 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/PushConfigUser.java @@ -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; +} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/PushHistory.java b/backend/src/main/java/com/yfd/platform/system/domain/PushHistory.java new file mode 100644 index 00000000..28f2abcd --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/PushHistory.java @@ -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; +} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/PushHistoryDetail.java b/backend/src/main/java/com/yfd/platform/system/domain/PushHistoryDetail.java new file mode 100644 index 00000000..2a186778 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/PushHistoryDetail.java @@ -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; +} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/PushTargetUserVo.java b/backend/src/main/java/com/yfd/platform/system/domain/PushTargetUserVo.java new file mode 100644 index 00000000..2c31f7f4 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/domain/PushTargetUserVo.java @@ -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; +} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/PushConfigMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/PushConfigMapper.java new file mode 100644 index 00000000..567f1538 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/mapper/PushConfigMapper.java @@ -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 { +} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/PushConfigUserMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/PushConfigUserMapper.java new file mode 100644 index 00000000..00093ee7 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/mapper/PushConfigUserMapper.java @@ -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 { + + List selectAllActiveUsers(); + + List selectTargetUsersByConfigId(@Param("configId") String configId); + + List selectConfigTargets(@Param("configId") String configId); +} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/PushHistoryDetailMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/PushHistoryDetailMapper.java new file mode 100644 index 00000000..9ac4f8ca --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/mapper/PushHistoryDetailMapper.java @@ -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 { +} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/PushHistoryMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/PushHistoryMapper.java new file mode 100644 index 00000000..9ae2ad8b --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/mapper/PushHistoryMapper.java @@ -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 { +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IPushConfigService.java b/backend/src/main/java/com/yfd/platform/system/service/IPushConfigService.java new file mode 100644 index 00000000..a1688de6 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/IPushConfigService.java @@ -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 { + + Page getPushConfigPage(Page 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 getPushTargets(String configId); + + Page getPushHistoryPage(Page page, + String configId, + Integer status, + String messageTypeCode, + Date startTime, + Date endTime); + + Page getPushHistoryDetailPage(Page page, + String historyId, + Integer status); + + boolean executeNow(String configId); + + void executePushConfig(String configId); +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IPushConfigUserService.java b/backend/src/main/java/com/yfd/platform/system/service/IPushConfigUserService.java new file mode 100644 index 00000000..683b8783 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/IPushConfigUserService.java @@ -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 { +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IPushHistoryDetailService.java b/backend/src/main/java/com/yfd/platform/system/service/IPushHistoryDetailService.java new file mode 100644 index 00000000..dfc002a4 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/IPushHistoryDetailService.java @@ -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 { +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IPushHistoryService.java b/backend/src/main/java/com/yfd/platform/system/service/IPushHistoryService.java new file mode 100644 index 00000000..00a11f46 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/IPushHistoryService.java @@ -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 { +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigQuartzExecutor.java b/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigQuartzExecutor.java new file mode 100644 index 00000000..dd9fe86e --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigQuartzExecutor.java @@ -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); + } +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigServiceImpl.java new file mode 100644 index 00000000..df558a96 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigServiceImpl.java @@ -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 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 getPushConfigPage(Page page, + String categoryName, + String messageType, + Integer targetType, + Integer status) { + LambdaQueryWrapper 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 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 getPushTargets(String configId) { + if (StrUtil.isBlank(configId)) { + return Collections.emptyList(); + } + return pushConfigUserMapper.selectConfigTargets(configId); + } + + @Override + public Page getPushHistoryPage(Page page, + String configId, + Integer status, + String messageTypeCode, + Date startTime, + Date endTime) { + LambdaQueryWrapper 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 getPushHistoryDetailPage(Page page, + String historyId, + Integer status) { + LambdaQueryWrapper 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 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 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 list = this.list(new LambdaQueryWrapper() + .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 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 list = quartzJobService.list(new LambdaQueryWrapper() + .eq(QuartzJob::getCustom1, QUARTZ_BIZ_TYPE) + .eq(QuartzJob::getCustom2, configId)); + return list.isEmpty() ? null : list.get(0); + } + + private List resolveTargets(PushConfig config) { + List 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 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"; + } + } +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigUserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigUserServiceImpl.java new file mode 100644 index 00000000..efbb7387 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/PushConfigUserServiceImpl.java @@ -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 implements IPushConfigUserService { +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/PushHistoryDetailServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/PushHistoryDetailServiceImpl.java new file mode 100644 index 00000000..e62d87a6 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/PushHistoryDetailServiceImpl.java @@ -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 implements IPushHistoryDetailService { +} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/PushHistoryServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/PushHistoryServiceImpl.java new file mode 100644 index 00000000..37648db7 --- /dev/null +++ b/backend/src/main/java/com/yfd/platform/system/service/impl/PushHistoryServiceImpl.java @@ -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 implements IPushHistoryService { +} diff --git a/backend/src/main/resources/mapper/system/PushConfigUserMapper.xml b/backend/src/main/resources/mapper/system/PushConfigUserMapper.xml new file mode 100644 index 00000000..9035ec58 --- /dev/null +++ b/backend/src/main/resources/mapper/system/PushConfigUserMapper.xml @@ -0,0 +1,76 @@ + + + + + + + + + + +