package com.xiaopeng.maintenance.schedule;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xiaopeng.api.feignClient.account.XpOperationUserNotificationClient;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.model.account.XpOperationsUserNotification;
import com.xiaopeng.api.model.maintenance.XpTask;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.maintenance.TaskScheduleConstants;
import com.xiaopeng.common.core.enums.NotificationTypeEnum;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.maintenance.mapper.XpTaskMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.CollectionUtils;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 事故任务超时检查定时任务
*
*
每分钟执行一次,判断事故任务是否超时并发送通知。
*
* @author mitao
* @since 2026-03-14
*/
@Deprecated
public class AccidentTaskTimeoutCheckScheduleTask {
private static final Logger log = LoggerFactory.getLogger(AccidentTaskTimeoutCheckScheduleTask.class);
private static final String TASK_NAME = "事故任务超时检查定时任务";
private static final String PUSH_TITLE = "事故超时警示";
private static final String CONTENT_TEMPLATE =
"车辆%s在%s发生的紧急事故已超时!";
@Autowired
private XpTaskMapper taskMapper;
@Autowired
private XpOperationUserNotificationClient xpOperationUserNotificationClient;
@Autowired
private AccidentTaskNotificationSupport notificationSupport;
/**
* 每分钟执行一次
*/
@Scheduled(cron = "0 * * * * ?")
public void executeAccidentTaskTimeoutCheck() {
log.info("========== 开始执行{} ==========", TASK_NAME);
try {
LocalDateTime now = LocalDateTime.now();
List tasks = queryTimeoutAccidentTasks(now);
if (CollectionUtils.isEmpty(tasks)) {
log.info("未找到超时事故任务,跳过执行");
return;
}
Set vehicleIds = tasks.stream()
.map(XpTask::getVehicleId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
Map vehicleMap = notificationSupport.fetchVehicles(vehicleIds);
Set allUserIds = new HashSet<>();
for (XpTask task : tasks) {
allUserIds.addAll(notificationSupport.parseUserIds(task.getHandleUserId()));
}
Map userMap = notificationSupport.fetchOperationUsers(allUserIds);
int notifiedTaskCount = 0;
int notificationCount = 0;
int pushCount = 0;
List allNotifications = new ArrayList<>();
for (XpTask task : tasks) {
try {
if (task == null || task.getId() == null) {
continue;
}
Set userIds = notificationSupport.parseUserIds(task.getHandleUserId());
if (CollectionUtils.isEmpty(userIds)) {
log.warn("事故任务ID={} 未配置有效处理人,跳过通知", task.getId());
continue;
}
int affectedRows = markTimeoutNoticeSent(task.getId(), now);
if (affectedRows <= 0) {
continue;
}
List users = userIds.stream()
.map(userMap::get)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(users)) {
log.warn("事故任务ID={} 未匹配到有效运维人员,跳过通知", task.getId());
continue;
}
String plateNumber = resolvePlateNumber(vehicleMap.get(task.getVehicleId()));
String vehicleLocation = StringUtils.defaultString(task.getVehicleLocation());
String content = String.format(CONTENT_TEMPLATE, plateNumber, vehicleLocation);
String bodyJson = notificationSupport.buildPushBodyJson(
content,
NotificationTypeEnum.ACCIDENT_TIMEOUT.getCode(),
task.getId()
);
allNotifications.addAll(notificationSupport.buildNotifications(
users,
NotificationTypeEnum.ACCIDENT_TIMEOUT.getCode(),
content,
task.getId(),
bodyJson
));
pushCount += notificationSupport.pushToUsersByDeviceType(users, PUSH_TITLE, bodyJson);
notifiedTaskCount++;
} catch (Exception e) {
log.error("处理超时事故任务通知失败,任务ID={}", task == null ? null : task.getId(), e);
}
}
if (!CollectionUtils.isEmpty(allNotifications)) {
xpOperationUserNotificationClient.addNotificationBatch(allNotifications);
notificationCount = allNotifications.size();
}
log.info("========== {} 执行完成,任务数: {},通知记录数: {},推送次数: {} ==========",
TASK_NAME, notifiedTaskCount, notificationCount, pushCount);
} catch (Exception e) {
log.error("{}执行失败", TASK_NAME, e);
}
}
/**
* 查询超时事故任务:endTime < now 且未发送超时通知
*/
private List queryTimeoutAccidentTasks(LocalDateTime now) {
return taskMapper.selectList(new LambdaQueryWrapper()
.eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ACCIDENT)
.in(XpTask::getStatus,
TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE,
TaskScheduleConstants.TASK_STATUS_PENDING)
.isNotNull(XpTask::getEndTime)
.lt(XpTask::getEndTime, now)
.eq(XpTask::getExpiredNoticeSent, 0));
}
/**
* 原子更新(抢占式)标记超时通知已发送
*/
private int markTimeoutNoticeSent(Long taskId, LocalDateTime now) {
return taskMapper.update(null, new LambdaUpdateWrapper()
.set(XpTask::getExpiredNoticeSent, 1)
.eq(XpTask::getId, taskId)
.eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ACCIDENT)
.in(XpTask::getStatus,
TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE,
TaskScheduleConstants.TASK_STATUS_PENDING)
.isNotNull(XpTask::getEndTime)
.lt(XpTask::getEndTime, now)
.eq(XpTask::getExpiredNoticeSent, 0));
}
private String resolvePlateNumber(XpVehicle vehicle) {
return vehicle == null ? "" : StringUtils.defaultString(vehicle.getPlateNumber());
}
}