xp-robotaxi-account-boot/src/main/resources/mapper/account/SysUserMapper.xml
@@ -115,7 +115,7 @@ <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult"> select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1 </select> <select id="getList" resultMap="SysUserResult"> <select id="getList" resultType="com.xiaopeng.api.model.account.SysUser"> select su.*,sr.role_name, sur.role_id from sys_user su left join sys_user_role sur on su.id= sur.user_id left join sys_role sr on sr.id = sur.role_id where 1=1 xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/account/SysUser.java
@@ -86,6 +86,10 @@ @TableField(exist = false) private Long deptId; @ApiModelProperty(value = "角色名称") @TableField(exist = false) private String roleName; public boolean isAdmin() { return isAdmin(this.id); xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/constant/TaskScheduleConstants.java
New file @@ -0,0 +1,169 @@ package com.xiaopeng.maintenance.constant; /** * 定时任务常量类 * * @author mitao * @since 2026-02-27 */ public class TaskScheduleConstants { private TaskScheduleConstants() { // 私有构造函数,防止实例化 } /** * 任务类别 - 常规任务 */ public static final Integer TASK_CATEGORY_ROUTINE = 1; /** * 任务类别 - 事故任务 */ public static final Integer TASK_CATEGORY_ACCIDENT = 2; /** * 任务类型 - 车辆检查 */ public static final String TASK_TYPE_DETECTION = "1"; /** * 任务类型 - 车辆充电 */ public static final String TASK_TYPE_CHARGING = "2"; /** * 任务类型 - 车辆整备 */ public static final String TASK_TYPE_PREPARATION = "3"; /** * 任务类型 - 整备洗车 */ public static final String TASK_TYPE_CLEAN = "4"; /** * 任务类型 - 车辆维修 */ public static final String TASK_TYPE_REPAIR = "5"; /** * 任务类型 - 车辆保养 */ public static final String TASK_TYPE_MAINTENANCE = "6"; /** * 任务类型 - 车辆保险到期 */ public static final String TASK_TYPE_INSURANCE_EXPIRE = "7"; /** * 任务类型 - 车辆年检到期 */ public static final String TASK_TYPE_INSPECTION_EXPIRE = "8"; /** * 任务类型 - 车辆运营资质到期 */ public static final String TASK_TYPE_QUALIFICATION_EXPIRE = "9"; /** * 任务状态 - 待到达 */ public static final Integer TASK_STATUS_PENDING_ARRIVE = 0; /** * 任务状态 - 待处理 */ public static final Integer TASK_STATUS_PENDING = 1; /** * 任务状态 - 已完成 */ public static final Integer TASK_STATUS_COMPLETED = 2; /** * 任务状态 - 已取消 */ public static final Integer TASK_STATUS_CANCELLED = 3; /** * 任务规则角色类型 - 车辆日常检测任务接收角色 */ public static final Integer RULE_ROLE_TYPE_INSPECTION = 1; /** * 任务规则角色类型 - 车辆每日收车 */ public static final Integer RULE_ROLE_TYPE_COLLECTION = 2; /** * 任务规则角色类型 - 车辆保养周期任务接收角色 */ public static final Integer RULE_ROLE_TYPE_MAINTENANCE = 3; /** * 任务规则角色类型 - 充电策略任务接收角色 */ public static final Integer RULE_ROLE_TYPE_CHARGING = 4; /** * 任务规则角色类型 - 车身清洁任务接收角色 */ public static final Integer RULE_ROLE_TYPE_CLEAN = 5; /** * 任务规则角色类型 - 日常整备任务接收角色 */ public static final Integer RULE_ROLE_TYPE_PREPARATION = 6; /** * 任务规则角色类型 - 年检/保险策略任务接收角色 */ public static final Integer RULE_ROLE_TYPE_INSURANCE = 7; /** * 任务规则角色类型 - 事故任务上报角色 */ public static final Integer RULE_ROLE_TYPE_ACCIDENT_REPORT = 8; /** * 任务规则角色类型 - 事故任务处理角色 */ public static final Integer RULE_ROLE_TYPE_ACCIDENT_HANDLE = 9; /** * 定时任务执行状态 - 成功 */ public static final Integer SCHEDULE_STATUS_SUCCESS = 1; /** * 定时任务执行状态 - 失败 */ public static final Integer SCHEDULE_STATUS_FAILED = 0; /** * 定时任务创建者名称 */ public static final String SCHEDULE_CREATOR = "系统定时任务"; /** * 任务紧急程度 - P0 */ public static final Integer URGENCY_LEVEL_P0 = 0; /** * 任务紧急程度 - P1 */ public static final Integer URGENCY_LEVEL_P1 = 1; /** * 任务紧急程度 - P2 */ public static final Integer URGENCY_LEVEL_P2 = 2; /** * 任务紧急程度 - P3 */ public static final Integer URGENCY_LEVEL_P3 = 3; } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java
New file @@ -0,0 +1,433 @@ 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.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; /** * 年检/保险策略定时任务 * <p> * 根据任务规则配置,在车辆保险、年检、运营资质即将到期时自动创建提醒任务, * 并下发给关联角色的运维人员 * </p> * * @author mitao * @since 2026-02-27 */ @Component public class InsuranceInspectionScheduleTask { private static final Logger log = LoggerFactory.getLogger(InsuranceInspectionScheduleTask.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点执行一次 * <p> * 检查逻辑: * 1. 获取任务规则配置 * 2. 判断年检/保险策略功能是否启用 * 3. 获取所有运营中的车辆 * 4. 分别检查三种到期情况并创建任务: * - 保险到期 * - 年检到期 * - 运营资质到期 * </p> */ @Scheduled(cron = "0 0 1 * * ?") public void executeInsuranceInspectionTask() { log.info("========== 开始执行年检/保险策略定时任务检查 =========="); // 1. 获取任务规则配置 XpTaskRule taskRule = getTaskRule(); if (taskRule == null) { log.info("未找到任务规则配置,跳过执行"); return; } // 2. 判断年检/保险策略功能是否启用 if (!Boolean.TRUE.equals(taskRule.getInsurance())) { log.info("年检/保险策略功能未启用,跳过执行"); return; } log.info("开始执行年检/保险策略任务下发,保险提前{}天, 年检提前{}天, 运营资质提前{}天, 紧急程度: P{}", taskRule.getInsuranceExpires(), taskRule.getInsuranceInspectionExpires(), taskRule.getOperationQualificationExpires(), taskRule.getInsuranceLevel()); try { // 执行任务创建 int createdCount = createExpireTasks(taskRule); log.info("========== 年检/保险策略定时任务执行完成,创建任务数: {} ==========", createdCount); } catch (Exception e) { log.error("年检/保险策略定时任务执行失败", e); } } /** * 获取任务规则配置 * * @return 任务规则 */ private XpTaskRule getTaskRule() { return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); } /** * 创建到期提醒任务 * * @param taskRule 任务规则配置 * @return 创建的任务数量 */ private int createExpireTasks(XpTaskRule taskRule) { // 1. 获取任务接收角色的运维人员 List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_INSURANCE); if (CollectionUtils.isEmpty(operationUserIds)) { log.warn("未找到年检/保险任务接收角色的运维人员"); return 0; } log.info("找到 {} 个运维人员可接收年检/保险任务", operationUserIds.size()); // 2. 获取所有运营中的车辆 List<XpVehicle> vehicles = getOperatingVehicles(); if (CollectionUtils.isEmpty(vehicles)) { log.info("没有运营中的车辆,无需创建到期提醒任务"); return 0; } log.info("找到 {} 辆运营中的车辆", vehicles.size()); int totalCreatedCount = 0; // 3. 检查保险到期 totalCreatedCount += checkAndCreateInsuranceExpireTasks(vehicles, operationUserIds, taskRule); // 4. 检查年检到期 totalCreatedCount += checkAndCreateInspectionExpireTasks(vehicles, operationUserIds, taskRule); // 5. 检查运营资质到期 totalCreatedCount += checkAndCreateQualificationExpireTasks(vehicles, operationUserIds, taskRule); return totalCreatedCount; } /** * 检查并创建保险到期任务 * * @param vehicles 车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @return 创建的任务数量 */ private int checkAndCreateInsuranceExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { if (taskRule.getInsuranceExpires() == null || taskRule.getInsuranceExpires() <= 0) { log.info("保险到期提醒天数未配置,跳过保险到期检查"); return 0; } List<XpVehicle> needWarnVehicles = vehicles.stream() .filter(v -> isWithinExpireWarningDays(v.getInsuranceEndTime(), taskRule.getInsuranceExpires())) .filter(v -> !hasUnfinishedTask(v.getId(), TaskScheduleConstants.TASK_TYPE_INSURANCE_EXPIRE)) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(needWarnVehicles)) { log.info("没有需要保险到期提醒的车辆"); return 0; } log.info("找到 {} 辆车辆需要保险到期提醒", needWarnVehicles.size()); return createTasksForExpireType( needWarnVehicles, operationUserIds, taskRule, TaskScheduleConstants.TASK_TYPE_INSURANCE_EXPIRE, "保险即将到期" ); } /** * 检查并创建年检到期任务 * * @param vehicles 车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @return 创建的任务数量 */ private int checkAndCreateInspectionExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { if (taskRule.getInsuranceInspectionExpires() == null || taskRule.getInsuranceInspectionExpires() <= 0) { log.info("年检到期提醒天数未配置,跳过年检到期检查"); return 0; } List<XpVehicle> needWarnVehicles = vehicles.stream() .filter(v -> isWithinExpireWarningDays(v.getAnnualInspectionDate(), taskRule.getInsuranceInspectionExpires())) .filter(v -> !hasUnfinishedTask(v.getId(), TaskScheduleConstants.TASK_TYPE_INSPECTION_EXPIRE)) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(needWarnVehicles)) { log.info("没有需要年检到期提醒的车辆"); return 0; } log.info("找到 {} 辆车辆需要年检到期提醒", needWarnVehicles.size()); return createTasksForExpireType( needWarnVehicles, operationUserIds, taskRule, TaskScheduleConstants.TASK_TYPE_INSPECTION_EXPIRE, "年检即将到期" ); } /** * 检查并创建运营资质到期任务 * * @param vehicles 车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @return 创建的任务数量 */ private int checkAndCreateQualificationExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { if (taskRule.getOperationQualificationExpires() == null || taskRule.getOperationQualificationExpires() <= 0) { log.info("运营资质到期提醒天数未配置,跳过运营资质到期检查"); return 0; } List<XpVehicle> needWarnVehicles = vehicles.stream() .filter(v -> isWithinExpireWarningDays(v.getQualificationExpireTime(), taskRule.getOperationQualificationExpires())) .filter(v -> !hasUnfinishedTask(v.getId(), TaskScheduleConstants.TASK_TYPE_QUALIFICATION_EXPIRE)) .collect(Collectors.toList()); if (CollectionUtils.isEmpty(needWarnVehicles)) { log.info("没有需要运营资质到期提醒的车辆"); return 0; } log.info("找到 {} 辆车辆需要运营资质到期提醒", needWarnVehicles.size()); return createTasksForExpireType( needWarnVehicles, operationUserIds, taskRule, TaskScheduleConstants.TASK_TYPE_QUALIFICATION_EXPIRE, "运营资质即将到期" ); } /** * 判断是否在到期提醒范围内 * * @param expireTime 到期时间 * @param daysBeforeExpire 提前X天提醒 * @return 是否需要提醒 */ private boolean isWithinExpireWarningDays(LocalDateTime expireTime, Integer daysBeforeExpire) { if (expireTime == null || daysBeforeExpire == null || daysBeforeExpire <= 0) { return false; } LocalDate today = LocalDate.now(); LocalDate expireDate = expireTime.toLocalDate(); long daysUntilExpire = ChronoUnit.DAYS.between(today, expireDate); // 距离到期天数 <= 配置的提前天数,且未过期(daysUntilExpire >= 0) return daysUntilExpire >= 0 && daysUntilExpire <= daysBeforeExpire; } /** * 检查是否已存在未完成的同类型任务 * <p> * 避免重复创建到期提醒任务 * </p> * * @param vehicleId 车辆ID * @param taskTypeId 任务类型ID * @return 是否存在未完成任务 */ private boolean hasUnfinishedTask(Long vehicleId, String taskTypeId) { XpTask existingTask = taskMapper.selectOne( new LambdaQueryWrapper<XpTask>() .eq(XpTask::getVehicleId, vehicleId) .eq(XpTask::getTaskTypeId, taskTypeId) .in(XpTask::getStatus, TaskScheduleConstants.TASK_STATUS_PENDING_ARRIVE, TaskScheduleConstants.TASK_STATUS_PENDING) .last("limit 1") ); return existingTask != null; } /** * 为指定到期类型创建任务 * * @param vehicles 需要提醒的车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @param taskTypeId 任务类型ID * @param taskDescription 任务描述 * @return 创建的任务数量 */ private int createTasksForExpireType(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule, String taskTypeId, String taskDescription) { List<XpTask> 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(taskTypeId); task.setTaskUrgencyLevel(taskRule.getInsuranceLevel() != null ? taskRule.getInsuranceLevel() : TaskScheduleConstants.URGENCY_LEVEL_P2); task.setTaskDescription("系统自动下发的" + taskDescription + "提醒任务"); // 设置车辆信息 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(), taskDescription); } return tasksToSave.size(); } /** * 根据角色类型获取运维人员ID列表 * * @param roleType 角色类型 * @return 运维人员ID列表 */ private List<Long> getOperationUserIdsByRoleType(Integer roleType) { // 1. 获取该类型对应的角色ID List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( new LambdaQueryWrapper<XpTaskRuleRole>() .eq(XpTaskRuleRole::getRuleType, roleType) ); if (CollectionUtils.isEmpty(ruleRoles)) { return Collections.emptyList(); } // 2. 获取角色对应的运维人员 Set<Long> userIds = new HashSet<>(); for (XpTaskRuleRole ruleRole : ruleRoles) { try { R<List<XpOperationsRole>> 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<XpVehicle> getOperatingVehicles() { try { R<List<XpVehicle>> 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(); } } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/RoutinePreparationScheduleTask.java
New file @@ -0,0 +1,395 @@ 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; /** * 日常整备定时任务 * <p> * 根据任务规则配置,在指定时间自动创建日常整备任务, * 并下发给关联角色的运维人员 * </p> * * @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; /** * 每分钟检查一次是否需要执行任务下发 * <p> * 检查逻辑: * 1. 获取任务规则配置 * 2. 判断日常整备功能是否启用(周期值 > 0) * 3. 判断当前时间是否为配置的任务下发时间 * 4. 查询所有运营中的车辆 * 5. 根据整备周期判断是否需要创建任务 * 6. 创建任务并分配给相关角色的运维人员 * </p> */ @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<XpTaskRule>().last("limit 1")); } /** * 判断日常整备功能是否启用 * <p> * 根据周期值判断:周期值 > 0 则认为启用 * </p> * * @param taskRule 任务规则 * @return 是否启用 */ private boolean isEnabled(XpTaskRule taskRule) { return taskRule.getRoutineMaintenanceCycle() != null && taskRule.getRoutineMaintenanceCycle() > 0; } /** * 判断当前时间是否为任务下发时间 * <p> * 精确到分钟级别的时间匹配 * </p> * * @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(); } /** * 计算整备周期天数 * <p> * 根据周期类型转换为天数: * - 类型1:天,直接返回周期数值 * - 类型2:月,按30天/月计算 * </p> * * @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<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_PREPARATION); if (CollectionUtils.isEmpty(operationUserIds)) { log.warn("未找到日常整备任务接收角色的运维人员"); return 0; } log.info("找到 {} 个运维人员可接收日常整备任务", operationUserIds.size()); // 2. 获取所有运营中的车辆 List<XpVehicle> vehicles = getOperatingVehicles(); if (CollectionUtils.isEmpty(vehicles)) { log.info("没有运营中的车辆,无需创建整备任务"); return 0; } log.info("找到 {} 辆运营中的车辆", vehicles.size()); // 3. 过滤出今日需要整备的车辆 List<XpVehicle> 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<Long> getOperationUserIdsByRoleType(Integer roleType) { // 1. 获取该类型对应的角色ID List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( new LambdaQueryWrapper<XpTaskRuleRole>() .eq(XpTaskRuleRole::getRuleType, roleType) ); if (CollectionUtils.isEmpty(ruleRoles)) { return Collections.emptyList(); } // 2. 获取角色对应的运维人员 Set<Long> userIds = new HashSet<>(); for (XpTaskRuleRole ruleRole : ruleRoles) { try { R<List<XpOperationsRole>> 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<XpVehicle> getOperatingVehicles() { try { R<List<XpVehicle>> 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(); } /** * 过滤出需要整备的车辆 * <p> * 根据整备周期判断:查询车辆上次整备任务时间, * 如果距今天数 >= 配置周期,则需要整备 * </p> * * @param vehicles 所有车辆 * @param cycleDays 整备周期(天数) * @return 需要整备的车辆列表 */ private List<XpVehicle> filterVehiclesNeedPreparation(List<XpVehicle> vehicles, int cycleDays) { LocalDate today = LocalDate.now(); List<XpVehicle> needPreparationVehicles = new ArrayList<>(); for (XpVehicle vehicle : vehicles) { // 查询该车辆最近一次整备任务 XpTask lastTask = taskMapper.selectOne( new LambdaQueryWrapper<XpTask>() .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<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { List<XpTask> 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(); } } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleCleanScheduleTask.java
New file @@ -0,0 +1,395 @@ 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; /** * 车身清洁定时任务 * <p> * 根据任务规则配置,在指定时间自动创建车身清洁任务, * 并下发给关联角色的运维人员 * </p> * * @author mitao * @since 2026-02-27 */ @Component public class VehicleCleanScheduleTask { private static final Logger log = LoggerFactory.getLogger(VehicleCleanScheduleTask.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; /** * 每分钟检查一次是否需要执行任务下发 * <p> * 检查逻辑: * 1. 获取任务规则配置 * 2. 判断车身清洁功能是否启用(周期值 > 0) * 3. 判断当前时间是否为配置的任务下发时间 * 4. 查询所有运营中的车辆 * 5. 根据清洁周期判断是否需要创建任务 * 6. 创建任务并分配给相关角色的运维人员 * </p> */ @Scheduled(cron = "0 * * * * ?") public void executeCleanTask() { 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.getVehicleCleanTime())) { log.debug("当前时间不是任务下发时间,跳过执行"); return; } // 计算清洁周期(天数) int cycleDays = calculateCycleDays(taskRule.getVehicleCleanCycle(), taskRule.getVehicleCleanTimeType()); log.info("开始执行车身清洁任务下发,清洁周期: {}天, 紧急程度: P{}", cycleDays, taskRule.getVehicleCleanLevel()); try { // 执行任务创建 int createdCount = createCleanTasks(taskRule, cycleDays); log.info("========== 车身清洁定时任务执行完成,创建任务数: {} ==========", createdCount); } catch (Exception e) { log.error("车身清洁定时任务执行失败", e); } } /** * 获取任务规则配置 * * @return 任务规则 */ private XpTaskRule getTaskRule() { return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); } /** * 判断车身清洁功能是否启用 * <p> * 根据周期值判断:周期值 > 0 则认为启用 * </p> * * @param taskRule 任务规则 * @return 是否启用 */ private boolean isEnabled(XpTaskRule taskRule) { return taskRule.getVehicleCleanCycle() != null && taskRule.getVehicleCleanCycle() > 0; } /** * 判断当前时间是否为任务下发时间 * <p> * 精确到分钟级别的时间匹配 * </p> * * @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(); } /** * 计算清洁周期天数 * <p> * 根据周期类型转换为天数: * - 类型1:天,直接返回周期数值 * - 类型2:月,按30天/月计算 * </p> * * @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 createCleanTasks(XpTaskRule taskRule, int cycleDays) { // 1. 获取任务接收角色的运维人员 List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_CLEAN); if (CollectionUtils.isEmpty(operationUserIds)) { log.warn("未找到车身清洁任务接收角色的运维人员"); return 0; } log.info("找到 {} 个运维人员可接收车身清洁任务", operationUserIds.size()); // 2. 获取所有运营中的车辆 List<XpVehicle> vehicles = getOperatingVehicles(); if (CollectionUtils.isEmpty(vehicles)) { log.info("没有运营中的车辆,无需创建清洁任务"); return 0; } log.info("找到 {} 辆运营中的车辆", vehicles.size()); // 3. 过滤出今日需要清洁的车辆 List<XpVehicle> needCleanVehicles = filterVehiclesNeedClean(vehicles, cycleDays); if (CollectionUtils.isEmpty(needCleanVehicles)) { log.info("今日没有需要清洁的车辆"); return 0; } log.info("过滤后有 {} 辆车辆需要今日清洁", needCleanVehicles.size()); // 4. 创建任务并分配给运维人员 return createTasksAndAssign(needCleanVehicles, operationUserIds, taskRule); } /** * 根据角色类型获取运维人员ID列表 * * @param roleType 角色类型 * @return 运维人员ID列表 */ private List<Long> getOperationUserIdsByRoleType(Integer roleType) { // 1. 获取该类型对应的角色ID List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( new LambdaQueryWrapper<XpTaskRuleRole>() .eq(XpTaskRuleRole::getRuleType, roleType) ); if (CollectionUtils.isEmpty(ruleRoles)) { return Collections.emptyList(); } // 2. 获取角色对应的运维人员 Set<Long> userIds = new HashSet<>(); for (XpTaskRuleRole ruleRole : ruleRoles) { try { R<List<XpOperationsRole>> 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<XpVehicle> getOperatingVehicles() { try { R<List<XpVehicle>> 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(); } /** * 过滤出需要清洁的车辆 * <p> * 根据清洁周期判断:查询车辆上次清洁任务时间, * 如果距今天数 >= 配置周期,则需要清洁 * </p> * * @param vehicles 所有车辆 * @param cycleDays 清洁周期(天数) * @return 需要清洁的车辆列表 */ private List<XpVehicle> filterVehiclesNeedClean(List<XpVehicle> vehicles, int cycleDays) { LocalDate today = LocalDate.now(); List<XpVehicle> needCleanVehicles = new ArrayList<>(); for (XpVehicle vehicle : vehicles) { // 查询该车辆最近一次清洁任务 XpTask lastTask = taskMapper.selectOne( new LambdaQueryWrapper<XpTask>() .eq(XpTask::getVehicleId, vehicle.getId()) .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_CLEAN) .orderByDesc(XpTask::getCreateTime) .last("limit 1") ); // 如果从未清洁过,需要清洁 if (lastTask == null || lastTask.getCreateTime() == null) { needCleanVehicles.add(vehicle); continue; } // 计算距离上次清洁的天数 LocalDate lastCleanDate = lastTask.getCreateTime().toLocalDate(); long daysSinceLastClean = java.time.temporal.ChronoUnit.DAYS.between(lastCleanDate, today); // 如果距离上次清洁天数 >= 配置周期,则需要清洁 if (daysSinceLastClean >= cycleDays) { needCleanVehicles.add(vehicle); } } return needCleanVehicles; } /** * 创建任务并分配给运维人员 * * @param vehicles 需要清洁的车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @return 创建的任务数量 */ private int createTasksAndAssign(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { List<XpTask> 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_CLEAN); task.setTaskUrgencyLevel(taskRule.getVehicleCleanLevel() != null ? taskRule.getVehicleCleanLevel() : 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(); } } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleCollectionScheduleTask.java
New file @@ -0,0 +1,188 @@ package com.xiaopeng.maintenance.schedule; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient; import com.xiaopeng.api.model.maintenance.XpTaskRule; import com.xiaopeng.api.model.vehicleConvoy.XpVehicle; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; 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.time.LocalTime; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; /** * 车辆收车定时任务 * <p> * 根据任务规则配置,在指定时间自动向所有车辆发起收车指令 * </p> * * @author mitao * @since 2026-02-27 */ @Component public class VehicleCollectionScheduleTask { private static final Logger log = LoggerFactory.getLogger(VehicleCollectionScheduleTask.class); /** * 任务名称 */ private static final String TASK_NAME = "车辆收车定时任务"; @Autowired private XpTaskRuleMapper taskRuleMapper; @Autowired private XpVehicleClient xpVehicleClient; /** * 每分钟检查一次是否需要执行收车任务 * <p> * 检查逻辑: * 1. 获取任务规则配置 * 2. 判断收车功能是否启用 * 3. 判断当前时间是否为配置的收车时间 * 4. 获取所有运营中的车辆 * 5. 向每辆车发送收车指令 * </p> */ @Scheduled(cron = "0 * * * * ?") public void executeCollectionTask() { log.info("========== 开始执行车辆收车定时任务检查 =========="); // 1. 获取任务规则配置 XpTaskRule taskRule = getTaskRule(); if (taskRule == null) { log.info("未找到任务规则配置,跳过执行"); return; } // 2. 判断收车功能是否启用 if (!Boolean.TRUE.equals(taskRule.getVehicleCollection())) { log.info("车辆收车功能未启用,跳过执行"); return; } // 3. 判断当前时间是否为收车时间 if (!isExecuteTime(taskRule.getVehicleCollectionTime())) { log.debug("当前时间不是收车时间,跳过执行"); return; } log.info("开始执行车辆收车任务"); try { // 执行收车逻辑 int processedCount = executeVehicleCollection(); log.info("========== 车辆收车定时任务执行完成,处理车辆数: {} ==========", processedCount); } catch (Exception e) { log.error("车辆收车定时任务执行失败", e); } } /** * 获取任务规则配置 * * @return 任务规则 */ private XpTaskRule getTaskRule() { return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); } /** * 判断当前时间是否为收车时间 * <p> * 精确到分钟级别的时间匹配 * </p> * * @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(); } /** * 执行车辆收车逻辑 * * @return 处理的车辆数量 */ private int executeVehicleCollection() { // 1. 获取所有运营中的车辆 List<XpVehicle> vehicles = getOperatingVehicles(); if (CollectionUtils.isEmpty(vehicles)) { log.info("没有运营中的车辆,无需执行收车"); return 0; } log.info("找到 {} 辆运营中的车辆需要收车", vehicles.size()); // 2. 向每辆车发送收车指令 int processedCount = 0; for (XpVehicle vehicle : vehicles) { try { sendCollectionCommand(vehicle); processedCount++; } catch (Exception e) { log.error("向车辆[{}]发送收车指令失败", vehicle.getPlateNumber(), e); } } return processedCount; } /** * 获取所有运营中的车辆 * * @return 车辆列表 */ private List<XpVehicle> getOperatingVehicles() { try { R<List<XpVehicle>> 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(); } /** * 向车辆发送收车指令 * <p> * TODO: 具体发送收车指令的实现 * 可能需要: * 1. 调用车辆控制接口发送收车指令 * 2. 更新车辆状态为"已收车" * </p> * * @param vehicle 车辆信息 */ private void sendCollectionCommand(XpVehicle vehicle) { // TODO: 具体发送收车指令的实现 log.info("向车辆[{}]发送收车指令", vehicle.getPlateNumber()); } } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleInspectionScheduleTask.java
New file @@ -0,0 +1,355 @@ 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; /** * 车辆日常检测定时任务 * <p> * 根据任务规则配置,在指定时间自动创建车辆日常检测任务, * 并下发给关联角色的运维人员 * </p> * * @author mitao * @since 2026-02-27 */ @Component public class VehicleInspectionScheduleTask { private static final Logger log = LoggerFactory.getLogger(VehicleInspectionScheduleTask.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; /** * 每分钟检查一次是否需要执行任务下发 * <p> * 检查逻辑: * 1. 获取任务规则配置 * 2. 判断日常检测功能是否启用 * 3. 判断当前时间是否为配置的任务下发时间 * 4. 查询所有运营中的车辆 * 5. 根据检测频次判断是否需要创建任务 * 6. 创建任务并分配给相关角色的运维人员 * </p> */ @Scheduled(cron = "0 * * * * ?") public void executeInspectionTask() { log.info("========== 开始执行车辆日常检测定时任务检查 =========="); // 1. 获取任务规则配置 XpTaskRule taskRule = getTaskRule(); if (taskRule == null) { log.info("未找到任务规则配置,跳过执行"); return; } // 2. 判断日常检测功能是否启用 if (!Boolean.TRUE.equals(taskRule.getVehicleInspection())) { log.info("车辆日常检测功能未启用,跳过执行"); return; } // 3. 判断当前时间是否为配置的任务下发时间 if (!isExecuteTime(taskRule.getVehicleInspectionTime())) { log.debug("当前时间不是任务下发时间,跳过执行"); return; } log.info("开始执行车辆日常检测任务下发,检测频次: 每{}天/次, 紧急程度: P{}", taskRule.getVehicleInspectionFrequency(), taskRule.getVehicleInspectionLevel()); try { // 执行任务创建 int createdCount = createInspectionTasks(taskRule); log.info("========== 车辆日常检测定时任务执行完成,创建任务数: {} ==========", createdCount); } catch (Exception e) { log.error("车辆日常检测定时任务执行失败", e); } } /** * 获取任务规则配置 * * @return 任务规则 */ private XpTaskRule getTaskRule() { return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); } /** * 判断当前时间是否为任务下发时间 * <p> * 精确到分钟级别的时间匹配 * </p> * * @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(); } /** * 创建车辆日常检测任务 * * @param taskRule 任务规则配置 * @return 创建的任务数量 */ private int createInspectionTasks(XpTaskRule taskRule) { // 1. 获取任务接收角色的运维人员 List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_INSPECTION); if (CollectionUtils.isEmpty(operationUserIds)) { log.warn("未找到车辆日常检测任务接收角色的运维人员"); return 0; } log.info("找到 {} 个运维人员可接收日常检测任务", operationUserIds.size()); // 2. 获取所有运营中的车辆 List<XpVehicle> vehicles = getOperatingVehicles(); if (CollectionUtils.isEmpty(vehicles)) { log.info("没有运营中的车辆,无需创建检测任务"); return 0; } log.info("找到 {} 辆运营中的车辆", vehicles.size()); // 3. 过滤出今日需要检测的车辆 List<XpVehicle> needInspectionVehicles = filterVehiclesNeedInspection(vehicles, taskRule.getVehicleInspectionFrequency()); if (CollectionUtils.isEmpty(needInspectionVehicles)) { log.info("今日没有需要检测的车辆"); return 0; } log.info("过滤后有 {} 辆车辆需要今日检测", needInspectionVehicles.size()); // 4. 创建任务并分配给运维人员 return createTasksAndAssign(needInspectionVehicles, operationUserIds, taskRule); } /** * 根据角色类型获取运维人员ID列表 * * @param roleType 角色类型 * @return 运维人员ID列表 */ private List<Long> getOperationUserIdsByRoleType(Integer roleType) { // 1. 获取该类型对应的角色ID List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( new LambdaQueryWrapper<XpTaskRuleRole>() .eq(XpTaskRuleRole::getRuleType, roleType) ); if (CollectionUtils.isEmpty(ruleRoles)) { return Collections.emptyList(); } // 2. 获取角色对应的运维人员 Set<Long> userIds = new HashSet<>(); for (XpTaskRuleRole ruleRole : ruleRoles) { try { R<List<XpOperationsRole>> 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<XpVehicle> getOperatingVehicles() { try { R<List<XpVehicle>> 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(); } /** * 过滤出需要检测的车辆 * <p> * 根据检测频次判断:vehicleInspectionFrequency 表示每X天检测一次 * 查询车辆上次检测时间,如果距今天数 >= 频次配置,则需要检测 * </p> * * @param vehicles 所有车辆 * @param inspectionFrequency 检测频次(天) * @return 需要检测的车辆列表 */ private List<XpVehicle> filterVehiclesNeedInspection(List<XpVehicle> vehicles, Integer inspectionFrequency) { // 默认每天检测一次 if (inspectionFrequency == null || inspectionFrequency <= 0) { inspectionFrequency = 1; } LocalDate today = LocalDate.now(); List<XpVehicle> needInspectionVehicles = new ArrayList<>(); for (XpVehicle vehicle : vehicles) { // 查询该车辆最近一次检测任务 XpTask lastTask = taskMapper.selectOne( new LambdaQueryWrapper<XpTask>() .eq(XpTask::getVehicleId, vehicle.getId()) .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_DETECTION) .orderByDesc(XpTask::getCreateTime) .last("limit 1") ); // 如果从未检测过,需要检测 if (lastTask == null || lastTask.getCreateTime() == null) { needInspectionVehicles.add(vehicle); continue; } // 计算距离上次检测的天数 LocalDate lastInspectionDate = lastTask.getCreateTime().toLocalDate(); long daysSinceLastInspection = java.time.temporal.ChronoUnit.DAYS.between(lastInspectionDate, today); // 如果距离上次检测天数 >= 频次配置,则需要检测 if (daysSinceLastInspection >= inspectionFrequency) { needInspectionVehicles.add(vehicle); } } return needInspectionVehicles; } /** * 创建任务并分配给运维人员 * * @param vehicles 需要检测的车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @return 创建的任务数量 */ private int createTasksAndAssign(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { List<XpTask> 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_DETECTION); task.setTaskUrgencyLevel(taskRule.getVehicleInspectionLevel() != null ? taskRule.getVehicleInspectionLevel() : 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(); } } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/VehicleMaintenanceScheduleTask.java
New file @@ -0,0 +1,381 @@ 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; /** * 车辆保养周期定时任务 * <p> * 根据任务规则配置,在指定时间自动创建车辆保养任务, * 并下发给关联角色的运维人员 * </p> * * @author mitao * @since 2026-02-27 */ @Component public class VehicleMaintenanceScheduleTask { private static final Logger log = LoggerFactory.getLogger(VehicleMaintenanceScheduleTask.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; /** * 每分钟检查一次是否需要执行任务下发 * <p> * 检查逻辑: * 1. 获取任务规则配置 * 2. 判断保养周期功能是否启用 * 3. 判断当前时间是否为配置的任务下发时间 * 4. 查询所有运营中的车辆 * 5. 根据保养周期判断是否需要创建任务 * 6. 创建任务并分配给相关角色的运维人员 * </p> */ @Scheduled(cron = "0 * * * * ?") public void executeMaintenanceTask() { log.info("========== 开始执行车辆保养周期定时任务检查 =========="); // 1. 获取任务规则配置 XpTaskRule taskRule = getTaskRule(); if (taskRule == null) { log.info("未找到任务规则配置,跳过执行"); return; } // 2. 判断保养周期功能是否启用 if (!Boolean.TRUE.equals(taskRule.getMaintenanceCycle())) { log.info("车辆保养周期功能未启用,跳过执行"); return; } // 3. 判断当前时间是否为配置的任务下发时间 if (!isExecuteTime(taskRule.getMaintenanceCycleTaskTime())) { log.debug("当前时间不是任务下发时间,跳过执行"); return; } // 计算保养周期(天数) int cycleDays = calculateCycleDays(taskRule.getMaintenanceCycleTime(), taskRule.getMaintenanceCycleTimeType()); log.info("开始执行车辆保养周期任务下发,保养周期: {}天, 紧急程度: P{}", cycleDays, taskRule.getMaintenanceCycleLevel()); try { // 执行任务创建 int createdCount = createMaintenanceTasks(taskRule, cycleDays); log.info("========== 车辆保养周期定时任务执行完成,创建任务数: {} ==========", createdCount); } catch (Exception e) { log.error("车辆保养周期定时任务执行失败", e); } } /** * 获取任务规则配置 * * @return 任务规则 */ private XpTaskRule getTaskRule() { return taskRuleMapper.selectOne(new LambdaQueryWrapper<XpTaskRule>().last("limit 1")); } /** * 判断当前时间是否为任务下发时间 * <p> * 精确到分钟级别的时间匹配 * </p> * * @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(); } /** * 计算保养周期天数 * <p> * 根据周期类型转换为天数: * - 类型1:天,直接返回周期数值 * - 类型2:月,按30天/月计算 * </p> * * @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 createMaintenanceTasks(XpTaskRule taskRule, int cycleDays) { // 1. 获取任务接收角色的运维人员 List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_MAINTENANCE); if (CollectionUtils.isEmpty(operationUserIds)) { log.warn("未找到车辆保养任务接收角色的运维人员"); return 0; } log.info("找到 {} 个运维人员可接收保养任务", operationUserIds.size()); // 2. 获取所有运营中的车辆 List<XpVehicle> vehicles = getOperatingVehicles(); if (CollectionUtils.isEmpty(vehicles)) { log.info("没有运营中的车辆,无需创建保养任务"); return 0; } log.info("找到 {} 辆运营中的车辆", vehicles.size()); // 3. 过滤出今日需要保养的车辆 List<XpVehicle> needMaintenanceVehicles = filterVehiclesNeedMaintenance(vehicles, cycleDays); if (CollectionUtils.isEmpty(needMaintenanceVehicles)) { log.info("今日没有需要保养的车辆"); return 0; } log.info("过滤后有 {} 辆车辆需要今日保养", needMaintenanceVehicles.size()); // 4. 创建任务并分配给运维人员 return createTasksAndAssign(needMaintenanceVehicles, operationUserIds, taskRule); } /** * 根据角色类型获取运维人员ID列表 * * @param roleType 角色类型 * @return 运维人员ID列表 */ private List<Long> getOperationUserIdsByRoleType(Integer roleType) { // 1. 获取该类型对应的角色ID List<XpTaskRuleRole> ruleRoles = taskRuleRoleMapper.selectList( new LambdaQueryWrapper<XpTaskRuleRole>() .eq(XpTaskRuleRole::getRuleType, roleType) ); if (CollectionUtils.isEmpty(ruleRoles)) { return Collections.emptyList(); } // 2. 获取角色对应的运维人员 Set<Long> userIds = new HashSet<>(); for (XpTaskRuleRole ruleRole : ruleRoles) { try { R<List<XpOperationsRole>> 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<XpVehicle> getOperatingVehicles() { try { R<List<XpVehicle>> 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(); } /** * 过滤出需要保养的车辆 * <p> * 根据保养周期判断:查询车辆上次保养任务时间, * 如果距今天数 >= 配置周期,则需要保养 * </p> * * @param vehicles 所有车辆 * @param cycleDays 保养周期(天数) * @return 需要保养的车辆列表 */ private List<XpVehicle> filterVehiclesNeedMaintenance(List<XpVehicle> vehicles, int cycleDays) { LocalDate today = LocalDate.now(); List<XpVehicle> needMaintenanceVehicles = new ArrayList<>(); for (XpVehicle vehicle : vehicles) { // 查询该车辆最近一次保养任务 XpTask lastTask = taskMapper.selectOne( new LambdaQueryWrapper<XpTask>() .eq(XpTask::getVehicleId, vehicle.getId()) .eq(XpTask::getTaskCategory, TaskScheduleConstants.TASK_CATEGORY_ROUTINE) .eq(XpTask::getTaskTypeId, TaskScheduleConstants.TASK_TYPE_MAINTENANCE) .orderByDesc(XpTask::getCreateTime) .last("limit 1") ); // 如果从未保养过,需要保养 if (lastTask == null || lastTask.getCreateTime() == null) { needMaintenanceVehicles.add(vehicle); continue; } // 计算距离上次保养的天数 LocalDate lastMaintenanceDate = lastTask.getCreateTime().toLocalDate(); long daysSinceLastMaintenance = java.time.temporal.ChronoUnit.DAYS.between(lastMaintenanceDate, today); // 如果距离上次保养天数 >= 配置周期,则需要保养 if (daysSinceLastMaintenance >= cycleDays) { needMaintenanceVehicles.add(vehicle); } } return needMaintenanceVehicles; } /** * 创建任务并分配给运维人员 * * @param vehicles 需要保养的车辆列表 * @param operationUserIds 运维人员ID列表 * @param taskRule 任务规则 * @return 创建的任务数量 */ private int createTasksAndAssign(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { List<XpTask> 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_MAINTENANCE); task.setTaskUrgencyLevel(taskRule.getMaintenanceCycleLevel() != null ? taskRule.getMaintenanceCycleLevel() : 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(); } } xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/service/impl/XpTaskServiceImpl.java
@@ -209,7 +209,7 @@ Map<Integer, List<XpOperationsUser>> operationUserMap = data.stream().collect(Collectors.groupingBy(XpOperationsUser::getDeviceType)); for (Map.Entry<Integer, List<XpOperationsUser>> integerListEntry : operationUserMap.entrySet()) { List<XpOperationsUser> value = integerListEntry.getValue(); pushAliMessage(data, content, xpTask); pushAliMessage(value, content, xpTask); } } } @@ -227,7 +227,7 @@ param.put("content", content); param.put("strategy", NotificationTypeEnum.ACCIDENT_NEW.getCode()); param.put("type", TaskTypeNotificationEnum.ACCIDENT_TASK.getCode()); param.put("id", xpTask.getId()); param.put("id", xpTask.getId().toString()); xpAliPushMessageClient.pushMessage(AliPushMessageDTO.builder() .body(JSONObject.toJSONString(param)) .account(account).title("车辆事故警示")