2025-09-23 10:22:38 +08:00
|
|
|
|
package com.whdc.service.impl;
|
|
|
|
|
|
|
2025-09-23 11:07:50 +08:00
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
2025-09-26 17:35:05 +08:00
|
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
2025-09-23 10:22:38 +08:00
|
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
2025-09-23 11:07:50 +08:00
|
|
|
|
import com.whdc.mapper.SmsLogMapper;
|
2025-09-26 11:02:40 +08:00
|
|
|
|
import com.whdc.mapper.SmsHolidayMapper;
|
|
|
|
|
|
import com.whdc.mapper.SmsSpecialistMapper;
|
2025-09-26 17:35:05 +08:00
|
|
|
|
import com.whdc.model.dto.SmsHolidayPageDto;
|
2025-09-23 11:07:50 +08:00
|
|
|
|
import com.whdc.model.entity.SmsLog;
|
2025-09-26 11:02:40 +08:00
|
|
|
|
import com.whdc.model.entity.SmsHoliday;
|
|
|
|
|
|
import com.whdc.model.entity.SmsSpecialist;
|
|
|
|
|
|
import com.whdc.service.ISmsHolidayService;
|
2025-09-23 11:07:50 +08:00
|
|
|
|
import com.whdc.utils.SmsHelper;
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
2025-09-23 10:22:38 +08:00
|
|
|
|
import org.springframework.stereotype.Service;
|
2025-09-26 17:35:05 +08:00
|
|
|
|
import org.springframework.util.StringUtils;
|
2025-09-23 10:22:38 +08:00
|
|
|
|
|
2025-09-23 11:07:50 +08:00
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
2025-09-28 16:52:49 +08:00
|
|
|
|
import java.util.ArrayList;
|
2025-09-23 11:07:50 +08:00
|
|
|
|
import java.util.Collections;
|
|
|
|
|
|
import java.util.List;
|
2025-09-28 16:52:49 +08:00
|
|
|
|
import java.util.Set;
|
|
|
|
|
|
import java.util.HashSet;
|
2025-09-23 11:07:50 +08:00
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
|
2025-09-23 10:22:38 +08:00
|
|
|
|
/**
|
2025-09-23 11:07:50 +08:00
|
|
|
|
* 主题日短信服务实现类
|
2025-09-23 10:22:38 +08:00
|
|
|
|
*
|
|
|
|
|
|
* @author lyf
|
|
|
|
|
|
* @since 2025-09-23
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Service
|
2025-09-23 11:07:50 +08:00
|
|
|
|
@Slf4j
|
2025-09-26 11:02:40 +08:00
|
|
|
|
public class SmsHolidayServiceImpl extends ServiceImpl<SmsHolidayMapper, SmsHoliday> implements ISmsHolidayService {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
2025-09-26 17:35:05 +08:00
|
|
|
|
public Page<SmsHoliday> page(SmsHolidayPageDto dto) {
|
|
|
|
|
|
LambdaQueryWrapper<SmsHoliday> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
|
|
|
|
|
|
|
// 添加查询条件
|
|
|
|
|
|
if (StringUtils.hasText(dto.getSubjectName())) {
|
|
|
|
|
|
queryWrapper.like(SmsHoliday::getSubjectName, dto.getSubjectName());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 默认按创建时间降序排列
|
|
|
|
|
|
queryWrapper.orderByDesc(SmsHoliday::getCreateTm);
|
|
|
|
|
|
|
|
|
|
|
|
return page(dto.getPage(), queryWrapper);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 11:07:50 +08:00
|
|
|
|
@Autowired
|
2025-09-26 11:02:40 +08:00
|
|
|
|
private SmsSpecialistMapper specialistMapper;
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private SmsLogMapper smsLogMapper;
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private SmsHelper smsHelper;
|
|
|
|
|
|
|
2025-09-28 16:52:49 +08:00
|
|
|
|
// 记录任务发送状态 - 使用原子变量保证线程安全
|
|
|
|
|
|
private final AtomicBoolean sending = new AtomicBoolean(false);
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-09-26 11:02:40 +08:00
|
|
|
|
public List<SmsHoliday> listActiveTasks() {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
try {
|
|
|
|
|
|
LocalDate today = LocalDate.now();
|
|
|
|
|
|
|
|
|
|
|
|
// 查询当前活动中的主题日短信任务
|
2025-09-26 11:02:40 +08:00
|
|
|
|
LambdaQueryWrapper<SmsHoliday> queryWrapper = new LambdaQueryWrapper<>();
|
2025-09-23 11:07:50 +08:00
|
|
|
|
queryWrapper
|
2025-09-26 11:02:40 +08:00
|
|
|
|
.eq(SmsHoliday::getStatus, 1) // 1:有效
|
|
|
|
|
|
.le(SmsHoliday::getStartDate, today) // 开始日期小于等于今天
|
|
|
|
|
|
.ge(SmsHoliday::getEndDate, today); // 结束日期大于等于今天
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
2025-09-26 11:02:40 +08:00
|
|
|
|
List<SmsHoliday> tasks = this.list(queryWrapper);
|
2025-09-23 11:07:50 +08:00
|
|
|
|
return tasks != null ? tasks : Collections.emptyList();
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("查询活动中的主题日短信任务失败: {}", e.getMessage(), e);
|
|
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-09-26 11:02:40 +08:00
|
|
|
|
public List<SmsHoliday> listTodayTasks() {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
try {
|
|
|
|
|
|
// 获取当前活动中的任务
|
2025-09-26 11:02:40 +08:00
|
|
|
|
List<SmsHoliday> activeTasks = listActiveTasks();
|
2025-09-23 11:07:50 +08:00
|
|
|
|
if (activeTasks.isEmpty()) {
|
|
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LocalDate today = LocalDate.now();
|
2025-09-26 11:02:40 +08:00
|
|
|
|
List<SmsHoliday> todayTasks = new java.util.ArrayList<>();
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
|
|
|
|
|
// 筛选今天需要执行的任务
|
2025-09-26 11:02:40 +08:00
|
|
|
|
for (SmsHoliday task : activeTasks) {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
// 检查执行时间
|
|
|
|
|
|
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
|
2025-09-26 11:02:40 +08:00
|
|
|
|
public void sendThemeSms(SmsHoliday smsTask) {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
if (smsTask == null) {
|
|
|
|
|
|
log.warn("主题日短信任务为空");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 16:52:49 +08:00
|
|
|
|
// 获取所有有效专家(节日短信专用)
|
|
|
|
|
|
List<SmsSpecialist> specialists = getValidSpecialistsForHoliday();
|
2025-09-23 11:07:50 +08:00
|
|
|
|
if (specialists.isEmpty()) {
|
|
|
|
|
|
log.info("没有有效专家,跳过主题日短信发送");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
String template = smsTask.getTemplate();
|
|
|
|
|
|
if (template == null || template.trim().isEmpty()) {
|
|
|
|
|
|
log.warn("主题日任务{}模板内容为空", smsTask.getSubjectName());
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 逐个发送个性化短信
|
2025-09-25 14:51:21 +08:00
|
|
|
|
int totalSpecialists = specialists.size();
|
|
|
|
|
|
log.info("开始向{}位专家发送主题日短信[{}]", totalSpecialists, smsTask.getSubjectName());
|
|
|
|
|
|
|
2025-09-28 16:52:49 +08:00
|
|
|
|
// 去重
|
|
|
|
|
|
Set<String> distinct = new HashSet<>();
|
2025-09-25 14:51:21 +08:00
|
|
|
|
for (int i = 0; i < specialists.size(); i++) {
|
2025-09-26 11:02:40 +08:00
|
|
|
|
SmsSpecialist specialist = specialists.get(i);
|
2025-09-28 16:52:49 +08:00
|
|
|
|
if (distinct.contains(specialist.getPhone())) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-25 14:51:21 +08:00
|
|
|
|
// 替换模板中的占位符
|
|
|
|
|
|
String content = template.replace("{姓名}", specialist.getName())
|
|
|
|
|
|
.replace("{主题}", smsTask.getSubjectName());
|
2025-09-23 11:07:50 +08:00
|
|
|
|
try {
|
2025-09-25 14:51:21 +08:00
|
|
|
|
log.info("正在发送第{}/{}位专家{}的主题日短信", i + 1, totalSpecialists, specialist.getName());
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
|
|
|
|
|
// 创建短信日志记录
|
|
|
|
|
|
SmsLog smsLog = new SmsLog();
|
|
|
|
|
|
smsLog.setName(specialist.getName())
|
|
|
|
|
|
.setPhone(specialist.getPhone())
|
|
|
|
|
|
.setContent(content)
|
|
|
|
|
|
.setRemark("主题日短信-" + smsTask.getSubjectName())
|
|
|
|
|
|
.setSendTm(new java.util.Date());
|
|
|
|
|
|
|
|
|
|
|
|
// 使用SmsHelper发送个性化短信
|
|
|
|
|
|
List<String> phoneList = Collections.singletonList(specialist.getPhone());
|
|
|
|
|
|
String sendResult = smsHelper.send(phoneList, content);
|
2025-09-28 16:52:49 +08:00
|
|
|
|
|
|
|
|
|
|
// 更新专家的flagHolidaySentToday
|
|
|
|
|
|
specialist.setFlagHolidaySentToday(1);
|
|
|
|
|
|
specialistMapper.updateById(specialist);
|
|
|
|
|
|
distinct.add(specialist.getPhone());
|
|
|
|
|
|
|
2025-09-23 11:07:50 +08:00
|
|
|
|
log.info("向专家{}发送主题日短信[{}]结果: {}", specialist.getName(), smsTask.getSubjectName(), sendResult);
|
|
|
|
|
|
|
|
|
|
|
|
// 根据发送结果设置备注
|
|
|
|
|
|
if ("发送成功".equals(sendResult)) {
|
|
|
|
|
|
smsLog.setRemark("主题日短信-" + smsTask.getSubjectName() + "-发送成功");
|
|
|
|
|
|
} else {
|
|
|
|
|
|
smsLog.setRemark("主题日短信-" + smsTask.getSubjectName() + "-发送失败: " + sendResult);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-28 16:52:49 +08:00
|
|
|
|
// 应唐科要求,每次发送短讯要抄送给唐威,陈锋
|
|
|
|
|
|
carbonCopy(content);
|
|
|
|
|
|
|
2025-09-23 11:07:50 +08:00
|
|
|
|
// 保存短信日志记录
|
|
|
|
|
|
smsLogMapper.insert(smsLog);
|
|
|
|
|
|
|
2025-09-25 14:51:21 +08:00
|
|
|
|
// 如果不是最后一位专家,等待3秒再发送下一条
|
|
|
|
|
|
if (i < specialists.size() - 1) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
log.info("等待3秒后发送下一条短信...");
|
|
|
|
|
|
Thread.sleep(3000); // 3秒间隔
|
|
|
|
|
|
} catch (InterruptedException ie) {
|
|
|
|
|
|
Thread.currentThread().interrupt();
|
|
|
|
|
|
log.warn("短信发送间隔被中断");
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 11:07:50 +08:00
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("向专家{}发送主题日短信[{}]时发生异常: {}", specialist.getName(), smsTask.getSubjectName(), e.getMessage(), e);
|
|
|
|
|
|
|
|
|
|
|
|
// 即使发送失败,也保存短信记录
|
|
|
|
|
|
try {
|
|
|
|
|
|
SmsLog failedSmsLog = new SmsLog();
|
|
|
|
|
|
failedSmsLog.setName(specialist.getName())
|
|
|
|
|
|
.setPhone(specialist.getPhone())
|
2025-09-25 14:51:21 +08:00
|
|
|
|
.setContent(content)
|
2025-09-23 11:07:50 +08:00
|
|
|
|
.setRemark("主题日短信-" + smsTask.getSubjectName() + "-发送异常: " + e.getMessage())
|
|
|
|
|
|
.setSendTm(new java.util.Date());
|
|
|
|
|
|
smsLogMapper.insert(failedSmsLog);
|
|
|
|
|
|
} catch (Exception logException) {
|
|
|
|
|
|
log.error("保存发送失败的短信日志时发生异常: {}", logException.getMessage(), logException);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-25 14:51:21 +08:00
|
|
|
|
log.info("主题日短信任务[{}]发送完成", smsTask.getSubjectName());
|
2025-09-23 11:07:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2025-09-26 11:02:40 +08:00
|
|
|
|
public void sendBatchThemeSms(List<SmsHoliday> smsTasks) {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
if (smsTasks == null || smsTasks.isEmpty()) {
|
|
|
|
|
|
log.info("没有需要发送的主题日短信任务");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log.info("开始批量发送{}个主题日短信任务", smsTasks.size());
|
2025-09-26 11:02:40 +08:00
|
|
|
|
for (SmsHoliday task : smsTasks) {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
try {
|
|
|
|
|
|
sendThemeSms(task);
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("发送主题日短信任务[{}]失败: {}", task.getSubjectName(), e.getMessage(), e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
log.info("批量主题日短信任务发送完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-09-28 16:52:49 +08:00
|
|
|
|
* 抄送
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void carbonCopy(String content) {
|
|
|
|
|
|
List<String> phoneList = new ArrayList<>();
|
|
|
|
|
|
phoneList.add("18154318312"); //唐威
|
|
|
|
|
|
phoneList.add("13247155309"); //陈锋
|
|
|
|
|
|
phoneList.add("15671545233"); //李
|
|
|
|
|
|
smsHelper.send(phoneList, content);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 每天0点重置所有专家的flagHolidaySentToday为0
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Scheduled(cron = "0 0 0 * * ?")
|
|
|
|
|
|
public void resetFlagHolidaySentToday() {
|
|
|
|
|
|
specialistMapper.resetFlagHolidaySentToday();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取所有有效专家(节日短信专用)
|
2025-09-23 11:07:50 +08:00
|
|
|
|
*/
|
2025-09-28 16:52:49 +08:00
|
|
|
|
private List<SmsSpecialist> getValidSpecialistsForHoliday() {
|
2025-09-23 11:07:50 +08:00
|
|
|
|
try {
|
2025-09-26 11:02:40 +08:00
|
|
|
|
LambdaQueryWrapper<SmsSpecialist> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
|
queryWrapper.eq(SmsSpecialist::getStatus, 1); // 1:有效
|
2025-09-28 16:52:49 +08:00
|
|
|
|
queryWrapper.eq(SmsSpecialist::getFlagHolidaySentToday, 0); // 未发送节日短信
|
2025-09-26 11:02:40 +08:00
|
|
|
|
queryWrapper.isNotNull(SmsSpecialist::getPhone); // 手机号不为空
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
2025-09-26 11:02:40 +08:00
|
|
|
|
List<SmsSpecialist> specialists = specialistMapper.selectList(queryWrapper);
|
2025-09-23 11:07:50 +08:00
|
|
|
|
return specialists != null ? specialists : Collections.emptyList();
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("查询有效专家失败: {}", e.getMessage(), e);
|
|
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 定时检查并发送主题日短信
|
|
|
|
|
|
* 每分钟执行一次
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Scheduled(cron = "0 * * * * ?")
|
|
|
|
|
|
public void checkAndSendThemeSms() {
|
|
|
|
|
|
try {
|
2025-09-28 16:52:49 +08:00
|
|
|
|
// 如果其他线程正在执行,跳过
|
|
|
|
|
|
if (sending.get()) {
|
|
|
|
|
|
log.debug("其他线程正在执行主题日短信发送任务");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-23 11:07:50 +08:00
|
|
|
|
// 查询今日需要执行的主题日任务
|
2025-09-26 11:02:40 +08:00
|
|
|
|
List<SmsHoliday> todayTasks = listTodayTasks();
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
|
|
|
|
|
if (todayTasks.isEmpty()) {
|
2025-09-28 10:16:24 +08:00
|
|
|
|
log.info("今日没有需要执行的主题日短信任务");
|
2025-09-23 11:07:50 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
log.info("检测到{}个主题日短信任务需要执行", todayTasks.size());
|
|
|
|
|
|
|
|
|
|
|
|
// 批量发送主题日短信
|
2025-09-28 16:52:49 +08:00
|
|
|
|
try {
|
|
|
|
|
|
sendBatchThemeSms(todayTasks);
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
sending.set(false);
|
|
|
|
|
|
}
|
2025-09-23 11:07:50 +08:00
|
|
|
|
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("定时检查主题日短信任务执行异常: {}", e.getMessage(), e);
|
2025-09-28 16:52:49 +08:00
|
|
|
|
sending.set(false);
|
2025-09-23 11:07:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-23 10:22:38 +08:00
|
|
|
|
}
|