package com.ruoyi.app.flashdelivery.task; import com.ruoyi.app.flashdelivery.service.FlashDeliveryApplicationService; import com.ruoyi.system.domain.flash.FlashDeliveryOrder; import org.springframework.stereotype.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Date; /** * 提供闪送订单的 Quartz 收口任务:送达超时自动完成、预约取件超时自动取消。 * 由若依任务调度分别调用本 Bean 的公开方法,避免使用应用内 {@code @Scheduled} 造成重复执行。 */ @Component("flashDeliveryAutoCompleteTask") public class FlashDeliveryAutoCompleteTask { private static final Logger log = LoggerFactory.getLogger(FlashDeliveryAutoCompleteTask.class); private final FlashDeliveryApplicationService service; public FlashDeliveryAutoCompleteTask(FlashDeliveryApplicationService service) { this.service = service; } public void completeDeliveredOrders() { Date deadline = Date.from(Instant.now().minus(24, ChronoUnit.HOURS)); // 分批处理避免单次扫描过多;条件更新保证与用户确认/平台完成并发时只有一方成功。 for (FlashDeliveryOrder order : service.autoCompleteCandidates(deadline, 200)) { try { service.complete(null, "SYSTEM", order.getId()); } catch (RuntimeException exception) { log.error("Flash delivery auto-complete failed, orderId={}", order.getId(), exception); } } } /** * 每分钟扫描已过预约取件结束时间但仍未接单的订单。接单和取消均走条件更新, * 因此任务延迟或并发执行不会取消已经被骑手接取的订单。 */ public void cancelExpiredScheduledOrders() { Date now = new Date(); for (FlashDeliveryOrder order : service.expiredScheduledCandidates(now, 200)) { try { service.cancelExpiredScheduledOrder(order.getId(), now); } catch (RuntimeException exception) { log.error("Flash delivery scheduled expiry failed, orderId={}", order.getId(), exception); } } } }