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.SmsHolidayMapper; import com.whdc.mapper.SmsSpecialistMapper; import com.whdc.model.entity.SmsLog; import com.whdc.model.entity.SmsHoliday; import com.whdc.model.entity.SmsSpecialist; import com.whdc.service.ISmsHolidayService; 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 SmsHolidayServiceImpl extends ServiceImpl implements ISmsHolidayService { @Autowired private SmsSpecialistMapper 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(SmsHoliday::getStatus, 1) // 1:有效 .le(SmsHoliday::getStartDate, today) // 开始日期小于等于今天 .ge(SmsHoliday::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 (SmsHoliday 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(SmsHoliday 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; } // 逐个发送个性化短信 int totalSpecialists = specialists.size(); log.info("开始向{}位专家发送主题日短信[{}]", totalSpecialists, smsTask.getSubjectName()); for (int i = 0; i < specialists.size(); i++) { SmsSpecialist specialist = specialists.get(i); // 替换模板中的占位符 String content = template.replace("{姓名}", specialist.getName()) .replace("{主题}", smsTask.getSubjectName()); try { log.info("正在发送第{}/{}位专家{}的主题日短信", i + 1, totalSpecialists, specialist.getName()); // 创建短信日志记录 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); // 如果不是最后一位专家,等待3秒再发送下一条 if (i < specialists.size() - 1) { try { log.info("等待3秒后发送下一条短信..."); Thread.sleep(3000); // 3秒间隔 } catch (InterruptedException ie) { Thread.currentThread().interrupt(); log.warn("短信发送间隔被中断"); break; } } } 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(content) .setRemark("主题日短信-" + smsTask.getSubjectName() + "-发送异常: " + e.getMessage()) .setSendTm(new java.util.Date()); smsLogMapper.insert(failedSmsLog); } catch (Exception logException) { log.error("保存发送失败的短信日志时发生异常: {}", logException.getMessage(), logException); } } } log.info("主题日短信任务[{}]发送完成", smsTask.getSubjectName()); // 标记任务今日已发送 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 (SmsHoliday 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(SmsSpecialist::getStatus, 1); // 1:有效 queryWrapper.isNotNull(SmsSpecialist::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); } } }