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;
|
|
/**
|
* 事故任务超时检查定时任务
|
*
|
* <p>每分钟执行一次,判断事故任务是否超时并发送通知。</p>
|
*
|
* @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<XpTask> tasks = queryTimeoutAccidentTasks(now);
|
if (CollectionUtils.isEmpty(tasks)) {
|
log.info("未找到超时事故任务,跳过执行");
|
return;
|
}
|
|
Set<Long> vehicleIds = tasks.stream()
|
.map(XpTask::getVehicleId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
Map<Long, XpVehicle> vehicleMap = notificationSupport.fetchVehicles(vehicleIds);
|
|
Set<Long> allUserIds = new HashSet<>();
|
for (XpTask task : tasks) {
|
allUserIds.addAll(notificationSupport.parseUserIds(task.getHandleUserId()));
|
}
|
Map<Long, XpOperationsUser> userMap = notificationSupport.fetchOperationUsers(allUserIds);
|
|
int notifiedTaskCount = 0;
|
int notificationCount = 0;
|
int pushCount = 0;
|
List<XpOperationsUserNotification> allNotifications = new ArrayList<>();
|
|
for (XpTask task : tasks) {
|
try {
|
if (task == null || task.getId() == null) {
|
continue;
|
}
|
Set<Long> 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<XpOperationsUser> 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<XpTask> queryTimeoutAccidentTasks(LocalDateTime now) {
|
return taskMapper.selectList(new LambdaQueryWrapper<XpTask>()
|
.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<XpTask>()
|
.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());
|
}
|
}
|