package com.xiaopeng.maintenance.schedule; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.xiaopeng.api.feignClient.account.XpOperationUserClient; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.account.XpOperationsRole; import com.xiaopeng.api.model.maintenance.XpTask; import com.xiaopeng.api.model.maintenance.XpTaskRule; import com.xiaopeng.api.model.maintenance.XpTaskRuleRole; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.maintenance.constant.TaskScheduleConstants; import com.xiaopeng.maintenance.mapper.XpTaskMapper; import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; import com.xiaopeng.maintenance.utils.UUIDUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import java.text.SimpleDateFormat; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.*; import java.util.stream.Collectors; /** * 日常整备定时任务 *

* 根据任务规则配置,在指定时间自动创建日常整备任务, * 并下发给关联角色的运维人员 *

* * @author mitao * @since 2026-02-27 */ @Component public class RoutinePreparationScheduleTask { private static final Logger log = LoggerFactory.getLogger(RoutinePreparationScheduleTask.class); /** * 任务名称 */ private static final String TASK_NAME = "日常整备定时任务"; @Autowired private XpTaskRuleMapper taskRuleMapper; @Autowired private XpTaskRuleRoleMapper taskRuleRoleMapper; @Autowired private XpTaskMapper taskMapper; @Autowired private XpVehicleClient xpVehicleClient; @Autowired private XpOperationUserClient xpOperationUserClient; /** * 每分钟检查一次是否需要执行任务下发 *

* 检查逻辑: * 1. 获取任务规则配置 * 2. 判断日常整备功能是否启用(周期值 > 0) * 3. 判断当前时间是否为配置的任务下发时间 * 4. 查询所有运营中的车辆 * 5. 根据整备周期判断是否需要创建任务 * 6. 创建任务并分配给相关角色的运维人员 *

*/ @Scheduled(cron = "0 * * * * ?") public void executePreparationTask() { log.info("========== 开始执行日常整备定时任务检查 =========="); // 1. 获取任务规则配置 XpTaskRule taskRule = getTaskRule(); if (taskRule == null) { log.info("未找到任务规则配置,跳过执行"); return; } // 2. 判断日常整备功能是否启用(周期值 > 0 表示启用) if (!isEnabled(taskRule)) { log.info("日常整备功能未启用(周期值未配置或为0),跳过执行"); return; } // 3. 判断当前时间是否为配置的任务下发时间 if (!isExecuteTime(taskRule.getRoutineMaintenanceTime())) { log.debug("当前时间不是任务下发时间,跳过执行"); return; } // 计算整备周期(天数) int cycleDays = calculateCycleDays(taskRule.getRoutineMaintenanceCycle(), taskRule.getRoutineMaintenanceTimeType()); log.info("开始执行日常整备任务下发,整备周期: {}天, 紧急程度: P{}", cycleDays, taskRule.getRoutineMaintenanceLevel()); try { // 执行任务创建 int createdCount = createPreparationTasks(taskRule, cycleDays); log.info("========== 日常整备定时任务执行完成,创建任务数: {} ==========", createdCount); } catch (Exception e) { log.error("日常整备定时任务执行失败", e); } } /** * 获取任务规则配置 * * @return 任务规则 */ private XpTaskRule getTaskRule() { return taskRuleMapper.selectOne(new LambdaQueryWrapper().last("limit 1")); } /** * 判断日常整备功能是否启用 *

* 根据周期值判断:周期值 > 0 则认为启用 *

* * @param taskRule 任务规则 * @return 是否启用 */ private boolean isEnabled(XpTaskRule taskRule) { return taskRule.getRoutineMaintenanceCycle() != null && taskRule.getRoutineMaintenanceCycle() > 0; } /** * 判断当前时间是否为任务下发时间 *

* 精确到分钟级别的时间匹配 *

* * @param executeTime 配置的执行时间 * @return 是否应该执行 */ private boolean isExecuteTime(LocalTime executeTime) { if (executeTime == null) { log.warn("任务下发时间未配置"); return false; } LocalTime now = LocalTime.now(); // 精确到分钟匹配 return executeTime.getHour() == now.getHour() && executeTime.getMinute() == now.getMinute(); } /** * 计算整备周期天数 *

* 根据周期类型转换为天数: * - 类型1:天,直接返回周期数值 * - 类型2:月,按30天/月计算 *

* * @param cycleTime 周期数值 * @param cycleTimeType 周期类型:1=天, 2=月 * @return 周期天数 */ private int calculateCycleDays(Integer cycleTime, Integer cycleTimeType) { // 默认周期为1 if (cycleTime == null || cycleTime <= 0) { cycleTime = 1; } // 默认为天 if (cycleTimeType == null || cycleTimeType == 1) { return cycleTime; } else { // 月(按30天计算) return cycleTime * 30; } } /** * 创建日常整备任务 * * @param taskRule 任务规则配置 * @param cycleDays 整备周期(天数) * @return 创建的任务数量 */ private int createPreparationTasks(XpTaskRule taskRule, int cycleDays) { // 1. 获取任务接收角色的运维人员 List operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_PREPARATION); if (CollectionUtils.isEmpty(operationUserIds)) { log.warn("未找到日常整备任务接收角色的运维人员"); return 0; } log.info("找到 {} 个运维人员可接收日常整备任务", operationUserIds.size()); // 2. 获取所有运营中的车辆 List vehicles = getOperatingVehicles(); if (CollectionUtils.isEmpty(vehicles)) { log.info("没有运营中的车辆,无需创建整备任务"); return 0; } log.info("找到 {} 辆运营中的车辆", vehicles.size()); // 3. 过滤出今日需要整备的车辆 List needPreparationVehicles = filterVehiclesNeedPreparation(vehicles, cycleDays); if (CollectionUtils.isEmpty(needPreparationVehicles)) { log.info("今日没有需要整备的车辆"); return 0; } log.info("过滤后有 {} 辆车辆需要今日整备", needPreparationVehicles.size()); // 4. 创建任务并分配给运维人员 return createTasksAndAssign(needPreparationVehicles, operationUserIds, taskRule); } /** * 根据角色类型获取运维人员ID列表 * * @param roleType 角色类型 * @return 运维人员ID列表 */ private List getOperationUserIdsByRoleType(Integer roleType) { // 1. 获取该类型对应的角色ID List ruleRoles = taskRuleRoleMapper.selectList( new LambdaQueryWrapper() .eq(XpTaskRuleRole::getRuleType, roleType) ); if (CollectionUtils.isEmpty(ruleRoles)) { return Collections.emptyList(); } // 2. 获取角色对应的运维人员 Set userIds = new HashSet<>(); for (XpTaskRuleRole ruleRole : ruleRoles) { try { R> result = xpOperationUserClient.getXpOperationsRoleByRoleId(ruleRole.getRoleId()); if (result != null && result.getData() != null) { userIds.addAll( result.getData().stream() .map(XpOperationsRole::getOperationsUserId) .collect(Collectors.toList()) ); } } catch (Exception e) { log.error("获取角色[{}]对应的运维人员失败", ruleRole.getRoleId(), e); } } return new ArrayList<>(userIds); } /** * 获取所有运营中的车辆 * * @return 车辆列表 */ private List getOperatingVehicles() { try { R> result = xpVehicleClient.listVehicle(); if (result != null && result.getData() != null) { // 过滤运营中的车辆 (vehicleType=2 表示运营, operatingStatus=1 表示运营中) return result.getData().stream() .filter(v -> v.getVehicleType() != null && v.getVehicleType() == 2) .filter(v -> v.getOperatingStatus() != null && v.getOperatingStatus() == 1) .collect(Collectors.toList()); } } catch (Exception e) { log.error("获取车辆列表失败", e); } return Collections.emptyList(); } /** * 过滤出需要整备的车辆 *

* 根据整备周期判断:查询车辆上次整备任务时间, * 如果距今天数 >= 配置周期,则需要整备 *

* * @param vehicles 所有车辆 * @param cycleDays 整备周期(天数) * @return 需要整备的车辆列表 */ private List filterVehiclesNeedPreparation(List vehicles, int cycleDays) { LocalDate today = LocalDate.now(); List needPreparationVehicles = new ArrayList<>(); for (XpVehicle vehicle : vehicles) { // 查询该车辆最近一次整备任务 XpTask lastTask = taskMapper.selectOne( new LambdaQueryWrapper() .eq(XpTask::getVehicleId, vehicle.getId()) .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_PREPARATION) .orderByDesc(XpTask::getCreateTime) .last("limit 1") ); // 如果从未整备过,需要整备 if (lastTask == null || lastTask.getCreateTime() == null) { needPreparationVehicles.add(vehicle); continue; } // 计算距离上次整备的天数 LocalDate lastPreparationDate = lastTask.getCreateTime().toLocalDate(); long daysSinceLastPreparation = java.time.temporal.ChronoUnit.DAYS.between(lastPreparationDate, today); // 如果距离上次整备天数 >= 配置周期,则需要整备 if (daysSinceLastPreparation >= cycleDays) { needPreparationVehicles.add(vehicle); } } return needPreparationVehicles; } /** * 创建任务并分配给运维人员 * * @param vehicles 需要整备的车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @return 创建的任务数量 */ private int createTasksAndAssign(List vehicles, List operationUserIds, XpTaskRule taskRule) { List tasksToSave = new ArrayList<>(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); // 将所有配置角色的运维人员ID拼接,任务分配给该角色下的所有运维人员 String belongUserIds = operationUserIds.stream() .map(String::valueOf) .collect(Collectors.joining(",")); for (XpVehicle vehicle : vehicles) { XpTask task = new XpTask(); // 生成任务编号 String taskCode = sdf.format(new Date()) + UUIDUtil.getNumberRandom(5); task.setTaskCode(taskCode); // 设置任务基本信息 task.setTaskCategory(TaskScheduleConstants.TASK_CATEGORY_ROUTINE); task.setTaskTypeId(TaskScheduleConstants.TASK_TYPE_PREPARATION); task.setTaskUrgencyLevel(taskRule.getRoutineMaintenanceLevel() != null ? taskRule.getRoutineMaintenanceLevel() : TaskScheduleConstants.URGENCY_LEVEL_P2); task.setTaskDescription("系统自动下发的日常整备任务"); // 设置车辆信息 task.setVehicleId(vehicle.getId()); // 设置任务时限 if (taskRule.getProcessingTimeLimit() != null) { task.setEndTime(LocalDateTime.now().plusMinutes(taskRule.getProcessingTimeLimit())); } // 设置任务状态为待到达 task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE); // 设置任务接收人(配置角色下的所有运维人员都可以看到) task.setBelongUserIds(belongUserIds); // 设置创建信息 task.setReportTime(LocalDateTime.now()); task.setCreateBy(TaskScheduleConstants.SCHEDULE_CREATOR); tasksToSave.add(task); } // 批量保存任务 if (!CollectionUtils.isEmpty(tasksToSave)) { for (XpTask task : tasksToSave) { taskMapper.insert(task); } log.info("成功创建 {} 个日常整备任务", tasksToSave.size()); } return tasksToSave.size(); } }