| | |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.xiaopeng.api.feignClient.account.XpOperationUserClient; |
| | | import com.xiaopeng.api.feignClient.vehicleConvoy.XpFleetOperationsClient; |
| | | 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.api.vo.automaticPilot.VehiclePosition; |
| | | import com.xiaopeng.common.core.domain.R; |
| | | import com.xiaopeng.api.vo.maintenance.TaskScheduleConstants; |
| | | import com.xiaopeng.common.core.utils.SensitiveDataCryptoUtil; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleMapper; |
| | | import com.xiaopeng.maintenance.mapper.XpTaskRuleRoleMapper; |
| | | import com.xiaopeng.maintenance.service.VehicleLocationFillService; |
| | | import com.xiaopeng.maintenance.utils.UUIDUtil; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.util.CollectionUtils; |
| | | import org.springframework.util.StringUtils; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.time.LocalDate; |
| | |
| | | |
| | | @Autowired |
| | | private XpOperationUserClient xpOperationUserClient; |
| | | |
| | | @Autowired |
| | | private XpFleetOperationsClient xpFleetOperationsClient; |
| | | |
| | | @Autowired |
| | | private VehicleLocationFillService vehicleLocationFillService; |
| | | |
| | | /** |
| | | * 每天凌晨1点执行一次 |
| | |
| | | */ |
| | | private int createExpireTasks(XpTaskRule taskRule) { |
| | | // 1. 获取任务接收角色的运维人员 |
| | | List<Long> operationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_INSURANCE); |
| | | if (CollectionUtils.isEmpty(operationUserIds)) { |
| | | List<Long> roleOperationUserIds = getOperationUserIdsByRoleType(TaskScheduleConstants.RULE_ROLE_TYPE_INSURANCE); |
| | | if (CollectionUtils.isEmpty(roleOperationUserIds)) { |
| | | log.warn("未找到年检/保险任务接收角色的运维人员"); |
| | | return 0; |
| | | } |
| | | |
| | | log.info("找到 {} 个运维人员可接收年检/保险任务", operationUserIds.size()); |
| | | Set<Long> roleOperationUserIdSet = new HashSet<>(roleOperationUserIds); |
| | | log.info("找到 {} 个运维人员可接收年检/保险任务", roleOperationUserIdSet.size()); |
| | | |
| | | // 2. 获取所有运营中的车辆 |
| | | List<XpVehicle> vehicles = getOperatingVehicles(); |
| | |
| | | |
| | | log.info("找到 {} 辆运营中的车辆", vehicles.size()); |
| | | |
| | | Map<String, VehiclePosition> positionByVin = vehicleLocationFillService.loadPositionByVin( |
| | | vehicles.stream() |
| | | .map(XpVehicle::getVehicleVin) |
| | | .filter(StringUtils::hasLength) |
| | | .distinct() |
| | | .collect(Collectors.toList()) |
| | | ); |
| | | |
| | | Map<Long, Long> vehicleIdToFleetIdCache = new HashMap<>(); |
| | | Map<Long, Set<Long>> fleetIdToOperationUserIdsCache = new HashMap<>(); |
| | | |
| | | int totalCreatedCount = 0; |
| | | |
| | | // 3. 检查保险到期 |
| | | totalCreatedCount += checkAndCreateInsuranceExpireTasks(vehicles, operationUserIds, taskRule); |
| | | totalCreatedCount += checkAndCreateInsuranceExpireTasks(vehicles, roleOperationUserIdSet, taskRule, |
| | | vehicleIdToFleetIdCache, fleetIdToOperationUserIdsCache, positionByVin); |
| | | |
| | | // 4. 检查年检到期 |
| | | totalCreatedCount += checkAndCreateInspectionExpireTasks(vehicles, operationUserIds, taskRule); |
| | | totalCreatedCount += checkAndCreateInspectionExpireTasks(vehicles, roleOperationUserIdSet, taskRule, |
| | | vehicleIdToFleetIdCache, fleetIdToOperationUserIdsCache, positionByVin); |
| | | |
| | | // 5. 检查运营资质到期 |
| | | totalCreatedCount += checkAndCreateQualificationExpireTasks(vehicles, operationUserIds, taskRule); |
| | | totalCreatedCount += checkAndCreateQualificationExpireTasks(vehicles, roleOperationUserIdSet, taskRule, |
| | | vehicleIdToFleetIdCache, fleetIdToOperationUserIdsCache, positionByVin); |
| | | |
| | | return totalCreatedCount; |
| | | } |
| | |
| | | * 检查并创建保险到期任务 |
| | | * |
| | | * @param vehicles 车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param roleOperationUserIds 配置角色下的运维人员ID集合 |
| | | * @param taskRule 任务规则 |
| | | * @param vehicleIdToFleetIdCache 车辆->车队缓存 |
| | | * @param fleetIdToOperationUserIdsCache 车队->人员缓存 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int checkAndCreateInsuranceExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | private int checkAndCreateInsuranceExpireTasks(List<XpVehicle> vehicles, Set<Long> roleOperationUserIds, XpTaskRule taskRule, |
| | | Map<Long, Long> vehicleIdToFleetIdCache, Map<Long, Set<Long>> fleetIdToOperationUserIdsCache, |
| | | Map<String, VehiclePosition> positionByVin) { |
| | | if (taskRule.getInsuranceExpires() == null || taskRule.getInsuranceExpires() <= 0) { |
| | | log.info("保险到期提醒天数未配置,跳过保险到期检查"); |
| | | return 0; |
| | |
| | | |
| | | return createTasksForExpireType( |
| | | needWarnVehicles, |
| | | operationUserIds, |
| | | roleOperationUserIds, |
| | | taskRule, |
| | | TaskScheduleConstants.TASK_TYPE_INSURANCE_EXPIRE, |
| | | "保险即将到期" |
| | | "保险即将到期", |
| | | vehicleIdToFleetIdCache, |
| | | fleetIdToOperationUserIdsCache, |
| | | positionByVin |
| | | ); |
| | | } |
| | | |
| | |
| | | * 检查并创建年检到期任务 |
| | | * |
| | | * @param vehicles 车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param roleOperationUserIds 配置角色下的运维人员ID集合 |
| | | * @param taskRule 任务规则 |
| | | * @param vehicleIdToFleetIdCache 车辆->车队缓存 |
| | | * @param fleetIdToOperationUserIdsCache 车队->人员缓存 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int checkAndCreateInspectionExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | private int checkAndCreateInspectionExpireTasks(List<XpVehicle> vehicles, Set<Long> roleOperationUserIds, XpTaskRule taskRule, |
| | | Map<Long, Long> vehicleIdToFleetIdCache, Map<Long, Set<Long>> fleetIdToOperationUserIdsCache, |
| | | Map<String, VehiclePosition> positionByVin) { |
| | | if (taskRule.getInsuranceInspectionExpires() == null || taskRule.getInsuranceInspectionExpires() <= 0) { |
| | | log.info("年检到期提醒天数未配置,跳过年检到期检查"); |
| | | return 0; |
| | |
| | | |
| | | return createTasksForExpireType( |
| | | needWarnVehicles, |
| | | operationUserIds, |
| | | roleOperationUserIds, |
| | | taskRule, |
| | | TaskScheduleConstants.TASK_TYPE_INSPECTION_EXPIRE, |
| | | "年检即将到期" |
| | | "年检即将到期", |
| | | vehicleIdToFleetIdCache, |
| | | fleetIdToOperationUserIdsCache, |
| | | positionByVin |
| | | ); |
| | | } |
| | | |
| | |
| | | * 检查并创建运营资质到期任务 |
| | | * |
| | | * @param vehicles 车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param roleOperationUserIds 配置角色下的运维人员ID集合 |
| | | * @param taskRule 任务规则 |
| | | * @param vehicleIdToFleetIdCache 车辆->车队缓存 |
| | | * @param fleetIdToOperationUserIdsCache 车队->人员缓存 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int checkAndCreateQualificationExpireTasks(List<XpVehicle> vehicles, List<Long> operationUserIds, XpTaskRule taskRule) { |
| | | private int checkAndCreateQualificationExpireTasks(List<XpVehicle> vehicles, Set<Long> roleOperationUserIds, XpTaskRule taskRule, |
| | | Map<Long, Long> vehicleIdToFleetIdCache, Map<Long, Set<Long>> fleetIdToOperationUserIdsCache, |
| | | Map<String, VehiclePosition> positionByVin) { |
| | | if (taskRule.getOperationQualificationExpires() == null || taskRule.getOperationQualificationExpires() <= 0) { |
| | | log.info("运营资质到期提醒天数未配置,跳过运营资质到期检查"); |
| | | return 0; |
| | |
| | | |
| | | return createTasksForExpireType( |
| | | needWarnVehicles, |
| | | operationUserIds, |
| | | roleOperationUserIds, |
| | | taskRule, |
| | | TaskScheduleConstants.TASK_TYPE_QUALIFICATION_EXPIRE, |
| | | "运营资质即将到期" |
| | | "运营资质即将到期", |
| | | vehicleIdToFleetIdCache, |
| | | fleetIdToOperationUserIdsCache, |
| | | positionByVin |
| | | ); |
| | | } |
| | | |
| | |
| | | * 为指定到期类型创建任务 |
| | | * |
| | | * @param vehicles 需要提醒的车辆列表 |
| | | * @param operationUserIds 运维人员ID列表 |
| | | * @param roleOperationUserIds 配置角色下的运维人员ID集合 |
| | | * @param taskRule 任务规则 |
| | | * @param taskTypeId 任务类型ID |
| | | * @param taskDescription 任务描述 |
| | | * @param vehicleIdToFleetIdCache 车辆->车队缓存 |
| | | * @param fleetIdToOperationUserIdsCache 车队->人员缓存 |
| | | * @return 创建的任务数量 |
| | | */ |
| | | private int createTasksForExpireType(List<XpVehicle> vehicles, List<Long> operationUserIds, |
| | | XpTaskRule taskRule, String taskTypeId, String taskDescription) { |
| | | private int createTasksForExpireType(List<XpVehicle> vehicles, Set<Long> roleOperationUserIds, |
| | | XpTaskRule taskRule, String taskTypeId, String taskDescription, |
| | | Map<Long, Long> vehicleIdToFleetIdCache, |
| | | Map<Long, Set<Long>> fleetIdToOperationUserIdsCache, |
| | | Map<String, VehiclePosition> positionByVin) { |
| | | List<XpTask> tasksToSave = new ArrayList<>(); |
| | | SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); |
| | | |
| | | // 将所有配置角色的运维人员ID拼接,任务分配给该角色下的所有运维人员 |
| | | String belongUserIds = operationUserIds.stream() |
| | | .map(String::valueOf) |
| | | .collect(Collectors.joining(",")); |
| | | int skippedCount = 0; |
| | | |
| | | for (XpVehicle vehicle : vehicles) { |
| | | List<Long> handleUserIds = resolveHandleUserIds(vehicle.getId(), taskTypeId, roleOperationUserIds, |
| | | vehicleIdToFleetIdCache, fleetIdToOperationUserIdsCache); |
| | | if (CollectionUtils.isEmpty(handleUserIds)) { |
| | | skippedCount++; |
| | | continue; |
| | | } |
| | | |
| | | String belongUserIds = handleUserIds.stream().map(String::valueOf).collect(Collectors.joining(",")); |
| | | |
| | | XpTask task = new XpTask(); |
| | | |
| | | // 生成任务编号 |
| | |
| | | |
| | | // 设置车辆信息 |
| | | task.setVehicleId(vehicle.getId()); |
| | | String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin()); |
| | | vehicleLocationFillService.fillFromVin(task, vin, positionByVin); |
| | | |
| | | // 设置任务时限 常规任务限时3天 |
| | | task.setEndTime(LocalDateTime.now().plusDays(3)); |
| | |
| | | // 设置任务状态为待到达 |
| | | task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING); |
| | | |
| | | // 设置任务接收人(配置角色下的所有运维人员都可以看到) |
| | | // 设置任务接收人(车辆所属车队关联人员与配置角色人员取交集) |
| | | task.setHandleUserId(belongUserIds); |
| | | task.setReportTime(LocalDateTime.now()); |
| | | task.setReportUserId(0L); |
| | |
| | | } |
| | | log.info("成功创建 {} 个{}提醒任务", tasksToSave.size(), taskDescription); |
| | | } |
| | | if (skippedCount > 0) { |
| | | log.warn("{}提醒任务:跳过 {} 辆车(无可分配处理人)", taskDescription, skippedCount); |
| | | } |
| | | |
| | | return tasksToSave.size(); |
| | | } |
| | | |
| | | private List<Long> resolveHandleUserIds(Long vehicleId, String taskTypeId, Set<Long> roleOperationUserIds, |
| | | Map<Long, Long> vehicleIdToFleetIdCache, |
| | | Map<Long, Set<Long>> fleetIdToOperationUserIdsCache) { |
| | | if (vehicleId == null) { |
| | | log.warn("定时任务分配处理人失败:vehicleId为空,taskTypeId={}", taskTypeId); |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | Long fleetId = vehicleIdToFleetIdCache.get(vehicleId); |
| | | if (!vehicleIdToFleetIdCache.containsKey(vehicleId)) { |
| | | try { |
| | | R<Long> fleetIdResult = xpVehicleClient.findFleetIdByVehicleId(vehicleId); |
| | | fleetId = fleetIdResult != null ? fleetIdResult.getData() : null; |
| | | } catch (Exception e) { |
| | | log.error("根据车辆查询车队失败,vehicleId={}, taskTypeId={}", vehicleId, taskTypeId, e); |
| | | fleetId = null; |
| | | } |
| | | vehicleIdToFleetIdCache.put(vehicleId, fleetId); |
| | | } |
| | | |
| | | if (fleetId == null) { |
| | | log.warn("定时任务跳过:车辆未关联车队,vehicleId={}, taskTypeId={}", vehicleId, taskTypeId); |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | Set<Long> fleetOperationUserIds = fleetIdToOperationUserIdsCache.get(fleetId); |
| | | if (!fleetIdToOperationUserIdsCache.containsKey(fleetId)) { |
| | | try { |
| | | R<List<Long>> opsResult = xpFleetOperationsClient.getOperationsIdsByFleetId(fleetId); |
| | | List<Long> opsIds = opsResult != null ? opsResult.getData() : null; |
| | | fleetOperationUserIds = CollectionUtils.isEmpty(opsIds) ? Collections.emptySet() : new HashSet<>(opsIds); |
| | | } catch (Exception e) { |
| | | log.error("根据车队查询关联人员失败,fleetId={}, vehicleId={}, taskTypeId={}", fleetId, vehicleId, taskTypeId, e); |
| | | fleetOperationUserIds = Collections.emptySet(); |
| | | } |
| | | fleetIdToOperationUserIdsCache.put(fleetId, fleetOperationUserIds); |
| | | } |
| | | |
| | | if (CollectionUtils.isEmpty(fleetOperationUserIds)) { |
| | | log.warn("定时任务跳过:车队未关联人员,fleetId={}, vehicleId={}, taskTypeId={}", fleetId, vehicleId, taskTypeId); |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | List<Long> finalUserIds = fleetOperationUserIds.stream() |
| | | .filter(roleOperationUserIds::contains) |
| | | .sorted() |
| | | .collect(Collectors.toList()); |
| | | if (CollectionUtils.isEmpty(finalUserIds)) { |
| | | log.warn("定时任务跳过:车队人员与角色人员无交集,fleetId={}, vehicleId={}, taskTypeId={}", fleetId, vehicleId, taskTypeId); |
| | | return Collections.emptyList(); |
| | | } |
| | | |
| | | return finalUserIds; |
| | | } |
| | | |
| | | /** |
| | | * 根据角色类型获取运维人员ID列表 |
| | | * |