diff --git a/src/main/java/com/whdc/service/ISmsTaskService.java b/src/main/java/com/whdc/service/ISmsTaskService.java index d3f3b70..f6f9357 100644 --- a/src/main/java/com/whdc/service/ISmsTaskService.java +++ b/src/main/java/com/whdc/service/ISmsTaskService.java @@ -2,12 +2,34 @@ package com.whdc.service; import com.baomidou.mybatisplus.extension.service.IService; import com.whdc.model.entity.SmsTask; +import com.whdc.model.entity.Specialist; + +import java.util.List; /** - * 短信任务服务接口 + * 主题日短信服务接口 * * @author lyf * @since 2025-09-23 */ public interface ISmsTaskService extends IService { + /** + * 查询当前活动中的主题日短信任务 + */ + List listActiveTasks(); + + /** + * 查询需要执行的今日主题日任务 + */ + List listTodayTasks(); + + /** + * 发送主题日短信 + */ + void sendThemeSms(SmsTask smsTask); + + /** + * 批量发送主题日短信 + */ + void sendBatchThemeSms(List smsTasks); } \ No newline at end of file diff --git a/src/main/java/com/whdc/service/impl/SmsTaskServiceImpl.java b/src/main/java/com/whdc/service/impl/SmsTaskServiceImpl.java index f504e93..92e09fb 100644 --- a/src/main/java/com/whdc/service/impl/SmsTaskServiceImpl.java +++ b/src/main/java/com/whdc/service/impl/SmsTaskServiceImpl.java @@ -1,17 +1,273 @@ package com.whdc.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.whdc.mapper.SmsLogMapper; import com.whdc.mapper.SmsTaskMapper; +import com.whdc.mapper.SpecialistMapper; +import com.whdc.model.entity.SmsLog; import com.whdc.model.entity.SmsTask; +import com.whdc.model.entity.Specialist; import com.whdc.service.ISmsTaskService; +import com.whdc.utils.SmsHelper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; + /** - * 短信任务服务实现类 + * 主题日短信服务实现类 * * @author lyf * @since 2025-09-23 */ @Service +@Slf4j public class SmsTaskServiceImpl extends ServiceImpl implements ISmsTaskService { + + @Autowired + private SpecialistMapper specialistMapper; + + @Autowired + private SmsLogMapper smsLogMapper; + + @Autowired + private SmsHelper smsHelper; + + // 记录每个任务今日是否已发送短信 - 使用并发Map保证线程安全 + private final Map taskSmsSentToday = new ConcurrentHashMap<>(); + + @Override + public List listActiveTasks() { + try { + LocalDate today = LocalDate.now(); + + // 查询当前活动中的主题日短信任务 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper + .eq(SmsTask::getStatus, 1) // 1:有效 + .le(SmsTask::getStartDate, today) // 开始日期小于等于今天 + .ge(SmsTask::getEndDate, today); // 结束日期大于等于今天 + + List tasks = this.list(queryWrapper); + return tasks != null ? tasks : Collections.emptyList(); + } catch (Exception e) { + log.error("查询活动中的主题日短信任务失败: {}", e.getMessage(), e); + return Collections.emptyList(); + } + } + + @Override + public List listTodayTasks() { + try { + // 获取当前活动中的任务 + List activeTasks = listActiveTasks(); + if (activeTasks.isEmpty()) { + return Collections.emptyList(); + } + + LocalDate today = LocalDate.now(); + List todayTasks = new java.util.ArrayList<>(); + + // 筛选今天需要执行的任务 + for (SmsTask task : activeTasks) { + // 检查是否已经发送过 + AtomicBoolean sentFlag = taskSmsSentToday.computeIfAbsent(task.getId(), k -> new AtomicBoolean(false)); + if (sentFlag.get()) { + continue; // 今日已发送,跳过 + } + + // 检查执行时间 + String executionTime = task.getExecutionTmStr(); + if (executionTime == null || executionTime.trim().isEmpty()) { + log.warn("主题日任务{}执行时间未配置", task.getSubjectName()); + continue; + } + + // 检查当前时间是否达到执行时间 + LocalDateTime now = LocalDateTime.now(); + try { + String todayWithExecutionTime = today.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " " + executionTime; + LocalDateTime scheduledTime = LocalDateTime.parse( + todayWithExecutionTime, + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + ); + + if (now.isEqual(scheduledTime) || now.isAfter(scheduledTime)) { + todayTasks.add(task); + } + } catch (Exception e) { + log.error("主题日任务{}执行时间格式解析失败: {}", task.getSubjectName(), executionTime, e); + } + } + + return todayTasks; + } catch (Exception e) { + log.error("查询今日主题日任务失败: {}", e.getMessage(), e); + return Collections.emptyList(); + } + } + + @Override + public void sendThemeSms(SmsTask smsTask) { + if (smsTask == null) { + log.warn("主题日短信任务为空"); + return; + } + + // 获取所有有效专家 + List specialists = getValidSpecialists(); + if (specialists.isEmpty()) { + log.info("没有有效专家,跳过主题日短信发送"); + return; + } + + String template = smsTask.getTemplate(); + if (template == null || template.trim().isEmpty()) { + log.warn("主题日任务{}模板内容为空", smsTask.getSubjectName()); + return; + } + + // 逐个发送个性化短信 + for (Specialist specialist : specialists) { + try { + // 替换模板中的占位符 + String content = template.replace("{姓名}", specialist.getName()) + .replace("{称呼}", specialist.getTitle() != null ? specialist.getTitle() : "") + .replace("{主题}", smsTask.getSubjectName()); + + // 创建短信日志记录 + SmsLog smsLog = new SmsLog(); + smsLog.setName(specialist.getName()) + .setPhone(specialist.getPhone()) + .setContent(content) + .setRemark("主题日短信-" + smsTask.getSubjectName()) + .setSendTm(new java.util.Date()); + + // 使用SmsHelper发送个性化短信 + List phoneList = Collections.singletonList(specialist.getPhone()); + String sendResult = smsHelper.send(phoneList, content); + log.info("向专家{}发送主题日短信[{}]结果: {}", specialist.getName(), smsTask.getSubjectName(), sendResult); + + // 根据发送结果设置备注 + if ("发送成功".equals(sendResult)) { + smsLog.setRemark("主题日短信-" + smsTask.getSubjectName() + "-发送成功"); + } else { + smsLog.setRemark("主题日短信-" + smsTask.getSubjectName() + "-发送失败: " + sendResult); + } + + // 保存短信日志记录 + smsLogMapper.insert(smsLog); + + } catch (Exception e) { + log.error("向专家{}发送主题日短信[{}]时发生异常: {}", specialist.getName(), smsTask.getSubjectName(), e.getMessage(), e); + + // 即使发送失败,也保存短信记录 + try { + SmsLog failedSmsLog = new SmsLog(); + failedSmsLog.setName(specialist.getName()) + .setPhone(specialist.getPhone()) + .setContent(template.replace("{姓名}", specialist.getName()) + .replace("{称呼}", specialist.getTitle() != null ? specialist.getTitle() : "") + .replace("{主题}", smsTask.getSubjectName())) + .setRemark("主题日短信-" + smsTask.getSubjectName() + "-发送异常: " + e.getMessage()) + .setSendTm(new java.util.Date()); + smsLogMapper.insert(failedSmsLog); + } catch (Exception logException) { + log.error("保存发送失败的短信日志时发生异常: {}", logException.getMessage(), logException); + } + } + } + + // 标记任务今日已发送 + AtomicBoolean sentFlag = taskSmsSentToday.computeIfAbsent(smsTask.getId(), k -> new AtomicBoolean(false)); + sentFlag.set(true); + log.info("主题日短信任务[{}]发送完成", smsTask.getSubjectName()); + } + + @Override + public void sendBatchThemeSms(List smsTasks) { + if (smsTasks == null || smsTasks.isEmpty()) { + log.info("没有需要发送的主题日短信任务"); + return; + } + + log.info("开始批量发送{}个主题日短信任务", smsTasks.size()); + for (SmsTask task : smsTasks) { + try { + sendThemeSms(task); + } catch (Exception e) { + log.error("发送主题日短信任务[{}]失败: {}", task.getSubjectName(), e.getMessage(), e); + } + } + log.info("批量主题日短信任务发送完成"); + } + + /** + * 获取所有有效专家 + */ + private List getValidSpecialists() { + try { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(Specialist::getStatus, 1); // 1:有效 + queryWrapper.isNotNull(Specialist::getPhone); // 手机号不为空 + + List specialists = specialistMapper.selectList(queryWrapper); + return specialists != null ? specialists : Collections.emptyList(); + } catch (Exception e) { + log.error("查询有效专家失败: {}", e.getMessage(), e); + return Collections.emptyList(); + } + } + + /** + * 定时检查并发送主题日短信 + * 每分钟执行一次 + */ + @Scheduled(cron = "0 * * * * ?") + public void checkAndSendThemeSms() { + try { + // 查询今日需要执行的主题日任务 + List todayTasks = listTodayTasks(); + + if (todayTasks.isEmpty()) { + log.debug("今日没有需要执行的主题日短信任务"); + return; + } + + log.info("检测到{}个主题日短信任务需要执行", todayTasks.size()); + + // 批量发送主题日短信 + sendBatchThemeSms(todayTasks); + + } catch (Exception e) { + log.error("定时检查主题日短信任务执行异常: {}", e.getMessage(), e); + } + } + + /** + * 重置每日发送状态 + * 每天凌晨00:00:01执行 + */ + @Scheduled(cron = "1 0 0 * * ?") + public void resetDailySendStatus() { + try { + // 重置所有任务的发送状态 + for (AtomicBoolean sentFlag : taskSmsSentToday.values()) { + sentFlag.set(false); + } + log.info("主题日短信每日发送状态已重置"); + } catch (Exception e) { + log.error("重置主题日短信每日发送状态异常: {}", e.getMessage(), e); + } + } } \ No newline at end of file