From c96fbe6b0aeb413a17c429133ee6d81d138144b9 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期二, 09 六月 2026 10:58:52 +0800
Subject: [PATCH] Merge branch '1.0' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi into 1.0

---
 xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java |  171 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 144 insertions(+), 27 deletions(-)

diff --git a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java
index ca9a930..33ca266 100644
--- a/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java
+++ b/xp-robotaxi-maintenance-boot/src/main/java/com/xiaopeng/maintenance/schedule/InsuranceInspectionScheduleTask.java
@@ -2,17 +2,21 @@
 
 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;
@@ -20,6 +24,7 @@
 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;
@@ -62,6 +67,12 @@
 
     @Autowired
     private XpOperationUserClient xpOperationUserClient;
+
+    @Autowired
+    private XpFleetOperationsClient xpFleetOperationsClient;
+
+    @Autowired
+    private VehicleLocationFillService vehicleLocationFillService;
 
     /**
      * 每天凌晨1点执行一次
@@ -127,13 +138,14 @@
      */
     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();
@@ -144,16 +156,30 @@
 
         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;
     }
@@ -162,11 +188,15 @@
      * 检查并创建保险到期任务
      *
      * @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;
@@ -186,10 +216,13 @@
 
         return createTasksForExpireType(
                 needWarnVehicles,
-                operationUserIds,
+                roleOperationUserIds,
                 taskRule,
                 TaskScheduleConstants.TASK_TYPE_INSURANCE_EXPIRE,
-                "保险即将到期"
+                "保险即将到期",
+                vehicleIdToFleetIdCache,
+                fleetIdToOperationUserIdsCache,
+                positionByVin
         );
     }
 
@@ -197,11 +230,15 @@
      * 检查并创建年检到期任务
      *
      * @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;
@@ -221,10 +258,13 @@
 
         return createTasksForExpireType(
                 needWarnVehicles,
-                operationUserIds,
+                roleOperationUserIds,
                 taskRule,
                 TaskScheduleConstants.TASK_TYPE_INSPECTION_EXPIRE,
-                "年检即将到期"
+                "年检即将到期",
+                vehicleIdToFleetIdCache,
+                fleetIdToOperationUserIdsCache,
+                positionByVin
         );
     }
 
@@ -232,11 +272,15 @@
      * 检查并创建运营资质到期任务
      *
      * @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;
@@ -256,10 +300,13 @@
 
         return createTasksForExpireType(
                 needWarnVehicles,
-                operationUserIds,
+                roleOperationUserIds,
                 taskRule,
                 TaskScheduleConstants.TASK_TYPE_QUALIFICATION_EXPIRE,
-                "运营资质即将到期"
+                "运营资质即将到期",
+                vehicleIdToFleetIdCache,
+                fleetIdToOperationUserIdsCache,
+                positionByVin
         );
     }
 
@@ -310,23 +357,33 @@
      * 为指定到期类型创建任务
      *
      * @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();
 
             // 生成任务编号
@@ -343,6 +400,8 @@
 
             // 设置车辆信息
             task.setVehicleId(vehicle.getId());
+            String vin = SensitiveDataCryptoUtil.decryptIfPossible(vehicle.getVehicleVin());
+            vehicleLocationFillService.fillFromVin(task, vin, positionByVin);
 
             // 设置任务时限 常规任务限时3天
             task.setEndTime(LocalDateTime.now().plusDays(3));
@@ -350,7 +409,7 @@
             // 设置任务状态为待到达
             task.setStatus(TaskScheduleConstants.TASK_STATUS_PENDING);
 
-            // 设置任务接收人(配置角色下的所有运维人员都可以看到)
+            // 设置任务接收人(车辆所属车队关联人员与配置角色人员取交集)
             task.setHandleUserId(belongUserIds);
             task.setReportTime(LocalDateTime.now());
             task.setReportUserId(0L);
@@ -367,10 +426,68 @@
             }
             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列表
      *

--
Gitblit v1.7.1