From 9adef3dd7723930d44f72713c3cf28e50b002055 Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期三, 01 四月 2026 15:45:19 +0800
Subject: [PATCH] Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi

---
 xp-robotaxi-remote-driving-boot/pom.xml                                                                           |    4 
 xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages.properties                                       |    3 
 xp-robotaxi-order-boot/pom.xml                                                                                    |    4 
 xp-robotaxi-automatic-pilot-boot/pom.xml                                                                          |    4 
 xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java      |  303 +++++++++++++++----
 xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java |   24 
 xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrajectoryDensifier.java               |  148 +++++++++
 xp-robotaxi-maintenance-boot/pom.xml                                                                              |    9 
 xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java           |    2 
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/dto/XpTestPlanAddDTO.java                         |    6 
 xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java      |   14 
 xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/CancelOrderSceneEnum.java          |   31 ++
 xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/controller/PushOrderRouteController.java     |   53 ++-
 xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/MapMatchingUtil.java                   |   15 
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/AbstractJob.java                                 |    4 
 xp-robotaxi-operation-boot/pom.xml                                                                                |    4 
 xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpTestPlanServiceImpl.java           |    7 
 xp-robotaxi-payment-boot/pom.xml                                                                                  |    4 
 xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java                               |    9 
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/EndTripJob.java                                  |   89 +++--
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java                      |   28 +
 xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java   |   26 +
 xp-robotaxi-push-message-boot/pom.xml                                                                             |    4 
 xp-robotaxi-vehicle-convoy-boot/pom.xml                                                                           |    4 
 xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrackPoint.java                        |   26 +
 xp-robotaxi-itinerary-boot/pom.xml                                                                                |    4 
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpTestOrderController.java                     |    2 
 xp-robotaxi-account-boot/pom.xml                                                                                  |    4 
 xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpTestOrderServiceImpl.java                  |   37 +
 xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpTestPlanPoint.java                               |    3 
 xp-robotaxi-map-boot/pom.xml                                                                                      |    4 
 xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/PushOrderDto.java                               |    6 
 32 files changed, 696 insertions(+), 189 deletions(-)

diff --git a/xp-robotaxi-account-boot/pom.xml b/xp-robotaxi-account-boot/pom.xml
index 7334e2a..8223ed1 100644
--- a/xp-robotaxi-account-boot/pom.xml
+++ b/xp-robotaxi-account-boot/pom.xml
@@ -119,6 +119,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/PushOrderDto.java b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/PushOrderDto.java
index c10d4c1..2fa1af6 100644
--- a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/PushOrderDto.java
+++ b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/PushOrderDto.java
@@ -12,6 +12,9 @@
 @AllArgsConstructor
 @NoArgsConstructor
 public class PushOrderDto {
+    @ApiModelProperty("任务id")
+    private String taskId;
+
     @ApiModelProperty("车辆vin")
     private String vin;
 
@@ -41,4 +44,7 @@
      * 订单操作类型
      */
     private OrderOperationType operation_type;
+
+    @ApiModelProperty("取消场景")
+    private String cancelScene;
 }
diff --git a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpTestPlanPoint.java b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpTestPlanPoint.java
index 18a7e8a..5f90909 100644
--- a/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpTestPlanPoint.java
+++ b/xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpTestPlanPoint.java
@@ -44,9 +44,6 @@
     @ApiModelProperty(value = "是否停车 0-否 1-是")
     private Integer stopFlag;
 
-    @ApiModelProperty(value = "测试订单id")
-    private Long testOrderId;
-
     @ApiModelProperty(value = "测试订单类型(1=测试单,2=巡游单)")
     private Long testOrderType;
 
diff --git a/xp-robotaxi-automatic-pilot-boot/pom.xml b/xp-robotaxi-automatic-pilot-boot/pom.xml
index da3ab04..944d2da 100644
--- a/xp-robotaxi-automatic-pilot-boot/pom.xml
+++ b/xp-robotaxi-automatic-pilot-boot/pom.xml
@@ -116,6 +116,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
index a60ebd0..c8612f4 100644
--- a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
+++ b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -26,6 +26,7 @@
 import com.xiaopeng.api.vo.order.OrderTrajectoryVo;
 import com.xiaopeng.automaticPilot.util.XPUUtil;
 import com.xiaopeng.common.core.domain.R;
+import com.xiaopeng.common.core.enums.CancelOrderSceneEnum;
 import com.xiaopeng.common.core.enums.OrderStatusEnum;
 import com.xiaopeng.common.core.enums.PushMessageTypeEnum;
 import com.xiaopeng.common.core.utils.StringUtils;
@@ -265,13 +266,7 @@
         if(null != mqttPublishDto && mqttPublishDto.getCode() == 200){
             JSONObject jsonObject = new JSONObject();
             jsonObject.put("event", SystemEventType.CREATE_ORDER);
-            if(dto.getOrderId().contains("XU")){
-                jsonObject.put("orderType",  com.xiaopeng.api.vo.OrderType.CRUISE_ORDER);
-            }else if(dto.getOrderId().contains("TEST")){
-                jsonObject.put("orderType",  com.xiaopeng.api.vo.OrderType.TEST_ORDER);
-            }else {
-                jsonObject.put("orderType",  com.xiaopeng.api.vo.OrderType.USER_ORDER);
-            }
+            jsonObject.put("orderType",  dto.getOrderType());
             jsonObject.put("orderId", dto.getOrderId());
             jsonObject.put("vin", dto.getVin());
             redisService.setCacheObject("CREATE_ORDER:" + dto.getOrderId().toString(), jsonObject.toJSONString(),30L, TimeUnit.MINUTES);
@@ -282,9 +277,10 @@
 
     @PostMapping("/inner/cancelOrder")
     R<Boolean> cancelOrder(@RequestBody PushOrderDto dto) {
+        String taskId = StringUtils.isNotEmpty(dto.getTaskId()) ? dto.getTaskId() : snowflake.nextId() + "";
         OrderOperation.Builder operationBuilder = OrderOperation.newBuilder();
         operationBuilder.setOrderId(dto.getOrderId().toString());
-        operationBuilder.setTaskId(snowflake.nextId() + "");
+        operationBuilder.setTaskId(taskId);
         if (dto.getOperation_type() != null) {
             operationBuilder.setOperationType(OrderOperationType.forNumber(dto.getOperation_type().getNumber()));
         }
@@ -294,8 +290,16 @@
 
         if (mqttPublishDto.getCode() == 200) {
             if(!dto.getOrderId().contains("XU")){
-                // 正常订单处理
-                redisService.setCacheObject(String.valueOf(sequence), "cancelOrder_" + dto.getOrderId() + "_" + dto.getVin(), 30l, TimeUnit.MINUTES);
+                Map<String, Object> cancelContext = new HashMap<>();
+                cancelContext.put("orderId", dto.getOrderId());
+                cancelContext.put("vin", dto.getVin());
+                cancelContext.put("cancelScene", StringUtils.isNotEmpty(dto.getCancelScene())
+                        ? dto.getCancelScene()
+                        : CancelOrderSceneEnum.NORMAL_CANCEL.getCode());
+                redisService.setCacheObject("CANCEL_ORDER_CONTEXT:" + taskId,
+                        JSONObject.toJSONString(cancelContext), 30L, TimeUnit.MINUTES);
+                log.info("记录取消订单上下文成功,orderId: {}, vin: {}, taskId: {}, cancelScene: {}",
+                        dto.getOrderId(), dto.getVin(), taskId, cancelContext.get("cancelScene"));
             }
             return R.ok(true);
         }
diff --git a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
index 73ad12f..b79d9e2 100644
--- a/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
+++ b/xp-robotaxi-automatic-pilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -42,6 +42,7 @@
 import com.xiaopeng.common.core.constant.CacheConstants;
 import com.xiaopeng.common.core.constant.Constants;
 import com.xiaopeng.common.core.domain.R;
+import com.xiaopeng.common.core.enums.CancelOrderSceneEnum;
 import com.xiaopeng.common.core.enums.OrderStatusEnum;
 import com.xiaopeng.common.core.enums.PushMessageTypeEnum;
 import com.xiaopeng.common.core.utils.StringUtils;
@@ -71,6 +72,8 @@
 @Slf4j
 @Service
 public class KafkaConsumerService {
+    private static final String CANCEL_ORDER_CONTEXT_PREFIX = "CANCEL_ORDER_CONTEXT:";
+
 
     @Resource
     private XpMapClient xpMapClient;
@@ -441,6 +444,7 @@
                 }
             }else if(orderId.contains("TEST")){
                 //测试订单故障则取消订单
+                testOrderClient.updateOrderStatus(Long.parseLong(orderId.substring(4)), 0);
                 XpTestOrder testOrder = testOrderClient.queryOrderById(Long.parseLong(orderId.substring(4))).getData();
                 vehicle = xpVehicleClient.queryById(testOrder.getVehicleId()).getData();
                 if (vehicle != null) {
@@ -591,6 +595,79 @@
 
 
             vehicleId = xpCruiseOrder.getVehicleId();
+        } else if(orderId.contains("TEST")){
+            R<XpTestOrder> cruiseOrder = testOrderClient.queryOrderById(Long.parseLong(orderId.substring(4)));
+            XpTestOrder testOrder = cruiseOrder.getData();
+            //区分测试单和测试巡游单
+            if(1 == testOrder.getOrderType()){
+                orderType = OrderType.TEST_ORDER;
+                //驶往上车点的行程
+                if (3 == testOrder.getStatus()) {
+                    //查询司机当前位置到起点的线路
+                    origin.setLongitude(longitude);
+                    origin.setLatitude(latitude);
+                    destination.setLongitude(testOrder.getStartLon());
+                    destination.setLatitude(testOrder.getStartLat());
+
+                    OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
+                    dto.setOrderId(Long.parseLong(orderId.substring(4)));
+                    dto.setOrigin(origin);
+                    dto.setDestination(destination);
+                    dto.setRouteType(1);
+                    R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
+                    if (200 != routeVoR.getCode()) {
+                        throw new RuntimeException("获取订单线路和运费失败");
+                    }
+                    RouteVo routeVo = routeVoR.getData();
+                    routeID = routeVo.getRouteID();
+                    //缓存数据,用于后续推给乘客导航线路
+                    redisService.setCacheObject("TEST_ORDER_NAVIGATION_START_DATA:" + testOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
+                }
+                //驶往下车点的行程
+                if (6 == testOrder.getStatus()) {
+                    origin.setLongitude(longitude);
+                    origin.setLatitude(latitude);
+                    destination.setLongitude(testOrder.getEndLon());
+                    destination.setLatitude(testOrder.getEndLat());
+
+                    OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
+                    dto.setOrderId(Long.parseLong(orderId.substring(4)));
+                    dto.setOrigin(origin);
+                    dto.setDestination(destination);
+                    dto.setRouteType(2);
+                    R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
+                    if (200 != routeVoR.getCode()) {
+                        throw new RuntimeException("获取订单线路和运费失败");
+                    }
+                    RouteVo routeVo = routeVoR.getData();
+                    routeID = routeVo.getRouteID();
+                    //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据
+                    redisService.setCacheObject("TEST_ORDER_NAVIGATION_END_DATA:" + testOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
+                }
+
+            }else{
+                orderType = OrderType.TEST_CRUISE_ORDER;
+
+                //构建导航数据给到车端
+                origin.setLongitude(longitude);
+                origin.setLatitude(latitude);
+                destination.setLongitude(testOrder.getEndLon());
+                destination.setLatitude(testOrder.getEndLat());
+
+                OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
+                dto.setOrderId(Long.parseLong(orderId.substring(4)));
+                dto.setOrigin(origin);
+                dto.setDestination(destination);
+                dto.setRouteType(3);
+                R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
+                if (200 != routeVoR.getCode()) {
+                    throw new RuntimeException("获取订单线路和运费失败");
+                }
+                RouteVo routeVo = routeVoR.getData();
+                routeID = routeVo.getRouteID();
+
+                vehicleId = testOrder.getVehicleId();
+            }
         } else {
             orderType = OrderType.USER_ORDER;
             //正常单
@@ -701,77 +778,100 @@
                 vehicleId = xpCruiseOrder.getVehicleId();
             }
         } else if(orderId.contains("TEST")){
-            orderType = OrderType.TEST_ORDER;
-            //正常单
-            R<XpTestOrder> xpOrderR = testOrderClient.queryOrderById(Long.parseLong(orderId.substring(4)));
-            if (200 != xpOrderR.getCode()) {
-                throw new RuntimeException("订单不存在 " + orderId);
-            }
-            XpTestOrder xpOrder = xpOrderR.getData();
-            XpVehicle xpVehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
-            //驶往上车点的行程
-            if (orderPhase.equals(OrderPhase.ROUTE_TO_PICKUP)) {
-                //直接取缓存中的导航数据推送给车端和乘客
-                Object cacheObject = redisService.getCacheObject("TEST_ORDER_NAVIGATION_START_DATA:" + xpOrder.getVehicleId());
-                if(null == cacheObject){
-                    //没有缓存数据,重新规划线路
-                    //查询车辆位置
-                    VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
-                    if (Objects.isNull(vehiclePosition)) {
-                        throw new RuntimeException("车辆位置信息不存在");
+            R<XpTestOrder> cruiseOrder = testOrderClient.queryOrderById(Long.parseLong(orderId.substring(4)));
+            XpTestOrder testOrder = cruiseOrder.getData();
+            XpVehicle xpVehicle = xpVehicleClient.queryById(testOrder.getVehicleId()).getData();
+            //区分测试单和测试巡游单
+            if(1 == testOrder.getOrderType()){
+                orderType = OrderType.TEST_ORDER;
+                //驶往上车点的行程
+                if (orderPhase.equals(OrderPhase.ROUTE_TO_PICKUP)) {
+                    //直接取缓存中的导航数据推送给车端和乘客
+                    Object cacheObject = redisService.getCacheObject("TEST_ORDER_NAVIGATION_START_DATA:" + testOrder.getVehicleId());
+                    if(null == cacheObject){
+                        //没有缓存数据,重新规划线路
+                        //查询车辆位置
+                        VehiclePosition vehiclePosition = mongoTemplate.findOne(new Query(Criteria.where("vin").is(xpVehicle.getVehicleVin())), VehiclePosition.class);
+                        if (Objects.isNull(vehiclePosition)) {
+                            throw new RuntimeException("车辆位置信息不存在");
+                        }
+                        origin.setLongitude(vehiclePosition.getPoint().getX());
+                        origin.setLatitude(vehiclePosition.getPoint().getY());
+                        destination.setLongitude(testOrder.getStartLon());
+                        destination.setLatitude(testOrder.getStartLat());
+                        OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
+                        dto.setOrderId(Long.parseLong(orderId.substring(4)));
+                        dto.setOrigin(origin);
+                        dto.setDestination(destination);
+                        dto.setRouteType(2);
+                        R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
+                        if (200 != routeVoR.getCode()) {
+                            throw new RuntimeException("获取订单线路和运费失败");
+                        }
+                        RouteVo routeVo = routeVoR.getData();
+                        routeID = routeVo.getRouteID();
+                        //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据
+                        redisService.setCacheObject("TEST_ORDER_NAVIGATION_START_DATA:" + testOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
+                    }else{
+                        RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class);
+                        routeID = routeVo.getRouteID();
                     }
-                    origin.setLongitude(vehiclePosition.getPoint().getX());
-                    origin.setLatitude(vehiclePosition.getPoint().getY());
-                    destination.setLongitude(xpOrder.getStartLon());
-                    destination.setLatitude(xpOrder.getStartLat());
+                }
+                //驶往下车点的行程
+                if (orderPhase.equals(OrderPhase.ROUTE_TO_DESTINATION)) {
+                    //直接取缓存中的导航数据推送给车端和乘客
+                    Object cacheObject = redisService.getCacheObject("TEST_ORDER_NAVIGATION_END_DATA:" + testOrder.getVehicleId());
+                    if(null == cacheObject){
+                        //没有缓存数据,重新规划线路
+                        //查询起点到终点的线路
+                        origin.setLongitude(testOrder.getStartLon());
+                        origin.setLatitude(testOrder.getStartLat());
+                        destination.setLongitude(testOrder.getEndLon());
+                        destination.setLatitude(testOrder.getEndLat());
+                        OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
+                        dto.setOrderId(Long.parseLong(orderId.substring(4)));
+                        dto.setOrigin(origin);
+                        dto.setDestination(destination);
+                        dto.setRouteType(2);
+                        R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
+                        if (200 != routeVoR.getCode()) {
+                            throw new RuntimeException("获取订单线路和运费失败");
+                        }
+                        RouteVo routeVo = routeVoR.getData();
+                        routeID = routeVo.getRouteID();
+                        //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据
+                        redisService.setCacheObject("TEST_ORDER_NAVIGATION_END_DATA:" + testOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
+                    }else{
+                        RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class);
+                        routeID = routeVo.getRouteID();
+                    }
+                }
+
+            }else{
+                orderType = OrderType.TEST_CRUISE_ORDER;
+
+                //巡游单
+                if (orderPhase.equals(OrderPhase.ROUTE_TO_CRUISE)) {
+                    /* 构建导航数据给到车端 */
+                    origin.setLongitude(testOrder.getStartLon());
+                    origin.setLatitude(testOrder.getStartLat());
+                    destination.setLongitude(testOrder.getEndLon());
+                    destination.setLatitude(testOrder.getEndLat());
+
                     OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
-                    dto.setOrderId(Long.parseLong(orderId));
+                    dto.setOrderId(Long.parseLong(orderId.substring(4)));
                     dto.setOrigin(origin);
                     dto.setDestination(destination);
-                    dto.setRouteType(2);
+                    dto.setRouteType(3);
                     R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
                     if (200 != routeVoR.getCode()) {
                         throw new RuntimeException("获取订单线路和运费失败");
                     }
                     RouteVo routeVo = routeVoR.getData();
                     routeID = routeVo.getRouteID();
-                    //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据
-                    redisService.setCacheObject("TEST_ORDER_NAVIGATION_START_DATA:" + xpOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
-                }else{
-                    RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class);
-                    routeID = routeVo.getRouteID();
                 }
             }
-            //驶往下车点的行程
-            if (orderPhase.equals(OrderPhase.ROUTE_TO_DESTINATION)) {
-                //直接取缓存中的导航数据推送给车端和乘客
-                Object cacheObject = redisService.getCacheObject("TEST_ORDER_NAVIGATION_END_DATA:" + xpOrder.getVehicleId());
-                if(null == cacheObject){
-                    //没有缓存数据,重新规划线路
-                    //查询起点到终点的线路
-                    origin.setLongitude(xpOrder.getStartLon());
-                    origin.setLatitude(xpOrder.getStartLat());
-                    destination.setLongitude(xpOrder.getEndLon());
-                    destination.setLatitude(xpOrder.getEndLat());
-                    OrderRouteAndFareDto dto = new OrderRouteAndFareDto();
-                    dto.setOrderId(Long.parseLong(orderId));
-                    dto.setOrigin(origin);
-                    dto.setDestination(destination);
-                    dto.setRouteType(2);
-                    R<RouteVo> routeVoR = xpMapClient.getOrderDistanceAndDuration(dto);
-                    if (200 != routeVoR.getCode()) {
-                        throw new RuntimeException("获取订单线路和运费失败");
-                    }
-                    RouteVo routeVo = routeVoR.getData();
-                    routeID = routeVo.getRouteID();
-                    //缓存导航数据,用于后面的逻辑中给乘客端推送导航数据
-                    redisService.setCacheObject("TEST_ORDER_NAVIGATION_END_DATA:" + xpOrder.getVehicleId(), JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
-                }else{
-                    RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class);
-                    routeID = routeVo.getRouteID();
-                }
-            }
-            vehicleId = xpOrder.getVehicleId();
+            vehicleId = testOrder.getVehicleId();
         }else{
             orderType = OrderType.USER_ORDER;
             //正常单
@@ -1024,10 +1124,6 @@
                 case ORDER_DROPOFF_COMPLETED:
                     //下车完成,不需要处理状态,由后续的乘客主动触发或者定时任务触发
                     log.info("乘客已下车,不做任何处理:{}", orderId);
-//                    if(!orderId.contains("XU")){
-//                        buildPushOrderStatus(orderId, OrderStatusEnum.APPROVAL_REJECTION, sequence);
-//                        xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.APPROVAL_REJECTION.getCode());
-//                    }
                     break;
                 case ORDER_COMPLETED:
                     //已完成
@@ -1069,17 +1165,36 @@
                 case ORDER_CANCELLED:
                     //已取消
                     if(!orderId.contains("XU")){
+                        String taskId = orderStatusInfo.getTaskId();
+                        JSONObject cancelContext = getCancelOrderContext(taskId);
+                        if (shouldSkipCancelForReassign(cancelContext)) {
+                            log.info("改派旧车取消回调,跳过订单取消处理,orderId: {}, taskId: {}, cancelScene: {}, context: {}",
+                                    orderId, taskId, cancelContext.getString("cancelScene"), cancelContext);
+                            //响应消息
+                            responseMessage(sequence, cancelContext.getString("vin"));
+                            return;
+                        }
                         if(orderId.contains("TEST")){
                             //判断订单状态,已经取消的不作处理
-                            Object cacheObject = redisService.getCacheObject("ORDER_STATUS:" + orderId.substring(4));
+                            Object cacheObject = redisService.getCacheObject("TEST_ORDER_STATUS:" + orderId.substring(4));
                             if(null != cacheObject){
                                 int order_status = Integer.parseInt(cacheObject.toString());
                                 if(0 == order_status){
                                     return;
                                 }
                             }
+                            XpTestOrder testOrder = testOrderClient.queryOrderById(Long.valueOf(orderId.substring(4))).getData();
+                            if(testOrder.getStatus() == 0 || testOrder.getStatus() >= 8){
+                                return;
+                            }
                             //行程中取消订单,按照行程结束处理
-                            testOrderClient.updateOrderStatus(Long.parseLong(orderId.substring(4)), OrderStatusEnum.SEE_OFF_GUESTS.getCode());
+                            if(testOrder.getStatus() > 5 && testOrder.getStatus() < 8){
+                                testOrderClient.updateOrderStatus(Long.parseLong(orderId.substring(4)), OrderStatusEnum.SEE_OFF_GUESTS.getCode());
+                                redisService.setCacheObject("TEST_ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS);
+                            }else{
+                                testOrderClient.updateOrderStatus(Long.parseLong(orderId.substring(4)), OrderStatusEnum.CANCELED.getCode());
+                                redisService.setCacheObject("TEST_ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.CANCELED.getCode(), 24L, TimeUnit.HOURS);
+                            }
                         }else{
                             //判断订单状态,已经取消的不作处理
                             Object cacheObject = redisService.getCacheObject("ORDER_STATUS:" + orderId);
@@ -1089,9 +1204,20 @@
                                     return;
                                 }
                             }
-                            //行程中取消订单,按照行程结束处理
-                            buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS, sequence);
-                            xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode());
+                            XpOrder xpOrder = xpOrderClient.queryOrderById(Long.parseLong(orderId)).getData();
+                            if(xpOrder.getStatus() == 0 || xpOrder.getStatus() >= 8){
+                                return;
+                            }
+                            if(xpOrder.getStatus() > 5 && xpOrder.getStatus() < 8){
+                                //行程中取消订单,按照行程结束处理
+                                buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS, sequence);
+                                xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode());
+                                redisService.setCacheObject("ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS);
+                            }else{
+                                buildPushOrderStatus(orderId, OrderStatusEnum.CANCELED, sequence);
+                                xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.CANCELED.getCode());
+                                redisService.setCacheObject("ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.CANCELED.getCode(), 24L, TimeUnit.HOURS);
+                            }
                         }
                     }
                     break;
@@ -1132,8 +1258,16 @@
                             }
                         }
                     }else if(orderId.contains("TEST")){
-                        //测试巡游单处理逻辑
-                        testOrderClient.updateOrderStatus(Long.parseLong(orderId.substring(4)), OrderStatusEnum.COMPLETED.getCode());
+                        //测试巡游单完成状态
+                        XpTestOrder testOrder = testOrderClient.queryOrderById(Long.parseLong(orderId.substring(4))).getData();
+                        if(testOrder.getOrderType() == 2){
+                            XpVehicle xpVehicle = xpVehicleClient.queryById(testOrder.getVehicleId()).getData();
+                            //响应消息
+                            responseMessage(sequence, xpVehicle.getVehicleVin());
+                            //测试巡游单处理逻辑
+                            testOrderClient.updateOrderStatus(Long.parseLong(orderId.substring(4)), OrderStatusEnum.COMPLETED.getCode());
+                            redisService.setCacheObject("TEST_ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.COMPLETED.getCode(), 24L, TimeUnit.HOURS);
+                        }
                     }
                     break;
                 case ORDER_PAUSED:
@@ -1248,6 +1382,35 @@
     }
 
     /**
+     * 根据taskId获取订单取消的上下文信息
+     * @param taskId
+     * @return
+     */
+    private JSONObject getCancelOrderContext(String taskId) {
+        if (StringUtils.isEmpty(taskId)) {
+            return null;
+        }
+        Object cacheObject = redisService.getCacheObject(CANCEL_ORDER_CONTEXT_PREFIX + taskId);
+        if (cacheObject == null) {
+            return null;
+        }
+        return JSON.parseObject(cacheObject.toString());
+    }
+
+    /**
+     * 判断是否是改派旧车取消回调,是则跳过订单取消处理
+     * @param cancelContext
+     * @return
+     */
+    private boolean shouldSkipCancelForReassign(JSONObject cancelContext) {
+        if (cancelContext == null) {
+            return false;
+        }
+        return CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE == CancelOrderSceneEnum.fromCode(
+                cancelContext.getString("cancelScene"));
+    }
+
+    /**
      * 云端下发导航到XPU
      * @param requestId             XPU请求id
      * @param routeId               高德导航id
diff --git a/xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/CancelOrderSceneEnum.java b/xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/CancelOrderSceneEnum.java
new file mode 100644
index 0000000..aa84da2
--- /dev/null
+++ b/xp-robotaxi-common/xp-common-core/src/main/java/com/xiaopeng/common/core/enums/CancelOrderSceneEnum.java
@@ -0,0 +1,31 @@
+package com.xiaopeng.common.core.enums;
+
+import lombok.Getter;
+
+/**
+ * 取消订单场景
+ */
+public enum CancelOrderSceneEnum {
+
+    NORMAL_CANCEL("NORMAL_CANCEL"),
+    REASSIGN_OLD_VEHICLE("REASSIGN_OLD_VEHICLE");
+
+    @Getter
+    private final String code;
+
+    CancelOrderSceneEnum(String code) {
+        this.code = code;
+    }
+
+    public static CancelOrderSceneEnum fromCode(String code) {
+        if (code == null) {
+            return null;
+        }
+        for (CancelOrderSceneEnum scene : values()) {
+            if (scene.code.equals(code)) {
+                return scene;
+            }
+        }
+        return null;
+    }
+}
diff --git a/xp-robotaxi-itinerary-boot/pom.xml b/xp-robotaxi-itinerary-boot/pom.xml
index b5b31c0..640664f 100644
--- a/xp-robotaxi-itinerary-boot/pom.xml
+++ b/xp-robotaxi-itinerary-boot/pom.xml
@@ -112,6 +112,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-maintenance-boot/pom.xml b/xp-robotaxi-maintenance-boot/pom.xml
index 9b9987e..ad9cac3 100644
--- a/xp-robotaxi-maintenance-boot/pom.xml
+++ b/xp-robotaxi-maintenance-boot/pom.xml
@@ -154,6 +154,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
@@ -167,6 +171,11 @@
             <version>1.33</version>
         </dependency>
         <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>2.25.3</version>
+        </dependency>
+        <dependency>
             <groupId>com.xiaopeng.logan</groupId>
             <artifactId>xp-evi-oss-sdk</artifactId>
             <version>1.0.1-SNAPSHOT</version>
diff --git a/xp-robotaxi-map-boot/pom.xml b/xp-robotaxi-map-boot/pom.xml
index beb307b..100d103 100644
--- a/xp-robotaxi-map-boot/pom.xml
+++ b/xp-robotaxi-map-boot/pom.xml
@@ -204,6 +204,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java
index 182f38d..e230a15 100644
--- a/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java
+++ b/xp-robotaxi-map-boot/src/main/java/com/xiaopeng/map/controller/XpMapController.java
@@ -139,15 +139,6 @@
         if(routeVo==null){
             return R.fail("没有找到路线");
         }
-
-        // 存储redis
-        redisService.setCacheObject(CacheConstants.ORDER_ROUTE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo);
-        // 存储路线偏离缓存,后续进行轨迹截取
-//        redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo);
-
-        // 存储路线偏离缓存,后续进行轨迹截取
-        redisService.setCacheObject(CacheConstants.ORDER_ROUTE_CAPTURE + "_" + dto.getOrderId() + "_" +dto.getRouteType(), routeVo);
-
         return R.ok(routeVo);
     }
 
diff --git a/xp-robotaxi-operation-boot/pom.xml b/xp-robotaxi-operation-boot/pom.xml
index d73641b..10d12fd 100644
--- a/xp-robotaxi-operation-boot/pom.xml
+++ b/xp-robotaxi-operation-boot/pom.xml
@@ -192,6 +192,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/dto/XpTestPlanAddDTO.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/dto/XpTestPlanAddDTO.java
index e98e653..252ab8f 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/dto/XpTestPlanAddDTO.java
+++ b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/dto/XpTestPlanAddDTO.java
@@ -40,6 +40,12 @@
 
         @ApiModelProperty(value = "点位ID")
         private Long endTestPointId;
+
+        @ApiModelProperty("是否停车")
+        private Integer stopFlag;
+
+        @ApiModelProperty("订单类型(1=测试单,2=巡游单)")
+        private Long testOrderType;
     }
 
 }
diff --git a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpTestPlanServiceImpl.java b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpTestPlanServiceImpl.java
index 2418c05..32de1e0 100644
--- a/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpTestPlanServiceImpl.java
+++ b/xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpTestPlanServiceImpl.java
@@ -77,12 +77,12 @@
                 .list().stream().collect(Collectors.groupingBy(XpTestPlanVehicle::getTestPlanId)) : Collections.emptyMap();
         page.getRecords().forEach(plan -> {
             if(pointMap.size() > 0){
-                plan.setPointNum(pointMap.get(plan.getId()).size());
+                plan.setPointNum(null == pointMap.get(plan.getId()) ? 0 : pointMap.get(plan.getId()).size());
             }else{
                 plan.setPointNum(0);
             }
             if(vehicleMap.size() > 0){
-                plan.setVehicleNum(vehicleMap.get(plan.getId()).size());
+                plan.setVehicleNum(null == vehicleMap.get(plan.getId()) ? 0 : vehicleMap.get(plan.getId()).size());
             }else{
                 plan.setVehicleNum(0);
             }
@@ -217,6 +217,7 @@
                 vo.setEndTestPointName(point1.getPointName());
                 vo.setEndTestPointAddress(point1.getPointAddress());
             }
+            vo.setStopFlag(planPoint.getStopFlag());
             return vo;
         }).collect(Collectors.toList());
 
@@ -380,6 +381,8 @@
             point.setTestPlanId(planId);
             point.setStartTestPointId(pointDTO.getStartTestPointId());
             point.setEndTestPointId(pointDTO.getEndTestPointId());
+            point.setStopFlag(pointDTO.getStopFlag());
+            point.setTestOrderType(pointDTO.getTestOrderType());
             result.add(point);
         }
         return result;
diff --git a/xp-robotaxi-order-boot/pom.xml b/xp-robotaxi-order-boot/pom.xml
index b6759fe..7fa953a 100644
--- a/xp-robotaxi-order-boot/pom.xml
+++ b/xp-robotaxi-order-boot/pom.xml
@@ -119,6 +119,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpTestOrderController.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpTestOrderController.java
index ac8a695..a0fa8b5 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpTestOrderController.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/controller/XpTestOrderController.java
@@ -85,7 +85,7 @@
      * @param orderId 订单id
      * @return 订单详情
      */
-    @PostMapping("/inner/testOrder/queryOrderById")
+    @PostMapping("/inner/v1/testOrder/queryOrderById")
     public R<XpTestOrder> queryOrderById(@RequestParam Long orderId){
         XpTestOrder xpTestOrder = xpTestOrderService.getById(orderId);
         return R.ok(xpTestOrder);
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/AbstractJob.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/AbstractJob.java
index b66ea0b..0cbb1dd 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/AbstractJob.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/base/AbstractJob.java
@@ -1,6 +1,7 @@
 package com.xiaopeng.order.job.base;
 
 import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
+import com.xiaopeng.api.feignClient.order.XpTestOrderClient;
 import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
 import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
 import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
@@ -8,6 +9,7 @@
 import com.xiaopeng.order.service.IXpCruiseOrderService;
 import com.xiaopeng.order.service.IXpOrderService;
 import com.xiaopeng.order.job.utils.SpringContextsUtil;
+import com.xiaopeng.order.service.IXpTestOrderService;
 import com.xiaopeng.order.service.XpOrderTimeoutLogService;
 import org.quartz.Job;
 import org.quartz.JobExecutionContext;
@@ -28,6 +30,7 @@
 	protected OrderMissionClient orderMissionClient;
 	protected XpVehicleClient xpVehicleClient;
     protected UserVehicleClient userVehicleClient;
+    protected IXpTestOrderService testOrderService;
 	public AbstractJob(){
 		this.xpOrderService = SpringContextsUtil.getBean(IXpOrderService.class);
 		this.xpPushMessageClient = SpringContextsUtil.getBean(XpPushMessageClient.class);
@@ -36,6 +39,7 @@
         this.orderMissionClient = SpringContextsUtil.getBean(OrderMissionClient.class);
         this.xpVehicleClient = SpringContextsUtil.getBean(XpVehicleClient.class);
         this.userVehicleClient = SpringContextsUtil.getBean(UserVehicleClient.class);
+        this.testOrderService = SpringContextsUtil.getBean(IXpTestOrderService.class);
 	}
 
 	 
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/EndTripJob.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/EndTripJob.java
index 151dbb1..6a51bfe 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/EndTripJob.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/job/jobs/EndTripJob.java
@@ -5,7 +5,9 @@
 import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
 import com.xiaopeng.api.model.order.XpOrder;
 import com.xiaopeng.api.model.order.XpOrderTimeoutLog;
+import com.xiaopeng.api.model.order.XpTestOrder;
 import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
+import com.xiaopeng.api.vo.OrderType;
 import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo;
 import com.xiaopeng.common.core.constant.Constants;
 import com.xiaopeng.common.core.domain.R;
@@ -39,49 +41,60 @@
 			throws JobExecutionException {
 		JobDataMap maps = context.getMergedJobDataMap();
 		Long orderId = maps.getLong("id");
+        String orderType = maps.getString("orderType");
         try {
 			log.info("开始执行自动结束行程任务");
-			XpOrder xpOrder = xpOrderService.getById(orderId);
-            if(xpOrder.getStatus() == 7){
-                xpOrderService.endTrip(xpOrder.getId(), String.valueOf(xpOrder.getAppUserId()));
-                // 消息推送
-                Map<String, Object> params = new HashMap<>();
-                Map<String, Object> content = new HashMap<>();
-                content.put("orderId", xpOrder.getId().toString());
-                content.put("status", OrderStatusEnum.APPROVAL_REJECTION.getCode());
-                params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
-                params.put("content", com.alibaba.fastjson2.JSONObject.toJSONString(content));
-                params.put("timestamp", new Date().getTime() + "");
-                String message = JSONObject.toJSONString(params);
-                SendMessageDTO sendMessageDTO = new SendMessageDTO();
-                sendMessageDTO.setMessage(message);
-                sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId()));
-                R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
-                //推送失败,重试3次
-                if(stringR.getCode() != Constants.SUCCESS){
-                    ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
-                    executor.execute(() -> {
-                        for (int i = 0; i < 3; i++) {
-                            R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
-                            if(stringR1.getCode() == Constants.SUCCESS){
-                                break;
+            //用户订单
+            if(orderType.equals(OrderType.USER_ORDER)){
+                XpOrder xpOrder = xpOrderService.getById(orderId);
+                if(xpOrder.getStatus() == 7){
+                    xpOrderService.endTrip(xpOrder.getId(), String.valueOf(xpOrder.getAppUserId()));
+                    // 消息推送
+                    Map<String, Object> params = new HashMap<>();
+                    Map<String, Object> content = new HashMap<>();
+                    content.put("orderId", xpOrder.getId().toString());
+                    content.put("status", OrderStatusEnum.APPROVAL_REJECTION.getCode());
+                    params.put("type", PushMessageTypeEnum.ORDER_STATUS.getDesc());
+                    params.put("content", com.alibaba.fastjson2.JSONObject.toJSONString(content));
+                    params.put("timestamp", new Date().getTime() + "");
+                    String message = JSONObject.toJSONString(params);
+                    SendMessageDTO sendMessageDTO = new SendMessageDTO();
+                    sendMessageDTO.setMessage(message);
+                    sendMessageDTO.setAppUserId(String.valueOf(xpOrder.getAppUserId()));
+                    R<String> stringR = xpPushMessageClient.sendStatus(sendMessageDTO);
+                    //推送失败,重试3次
+                    if(stringR.getCode() != Constants.SUCCESS){
+                        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
+                        executor.execute(() -> {
+                            for (int i = 0; i < 3; i++) {
+                                R<String> stringR1 = xpPushMessageClient.sendStatus(sendMessageDTO);
+                                if(stringR1.getCode() == Constants.SUCCESS){
+                                    break;
+                                }
+                                try {
+                                    Thread.sleep(1000);
+                                } catch (InterruptedException e) {
+                                    throw new RuntimeException(e);
+                                }
+                                log.info("定时任务结束订单后,退订订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), xpOrder.getOrderNumber());
                             }
-                            try {
-                                Thread.sleep(1000);
-                            } catch (InterruptedException e) {
-                                throw new RuntimeException(e);
-                            }
-                            log.info("定时任务结束订单后,退订订单状态消息失败:{} {} {}", stringR1.getMsg(), JSON.toJSONString(sendMessageDTO), xpOrder.getOrderNumber());
-                        }
-                    });
+                        });
+                    }
+                }
+                log.info("结束执行自动结束行程任务");
+                // 添加超时记录
+                XpOrderTimeoutLog xpOrderTimeoutLog = new XpOrderTimeoutLog();
+                xpOrderTimeoutLog.setOrderId(xpOrder.getId());
+                xpOrderTimeoutLog.setUserId(xpOrder.getAppUserId());
+                xpOrderTimeoutLogService.save(xpOrderTimeoutLog);
+            }
+            //测试订单
+			if(orderType.equals(OrderType.TEST_ORDER)){
+                XpTestOrder xpTestOrder = testOrderService.getById(orderId);
+                if(xpTestOrder.getStatus() == 7) {
+                    testOrderService.endTrip(xpTestOrder.getId());
                 }
             }
-			log.info("结束执行自动结束行程任务");
-			// 添加超时记录
-			XpOrderTimeoutLog xpOrderTimeoutLog = new XpOrderTimeoutLog();
-			xpOrderTimeoutLog.setOrderId(xpOrder.getId());
-			xpOrderTimeoutLog.setUserId(xpOrder.getAppUserId());
-			xpOrderTimeoutLogService.save(xpOrderTimeoutLog);
 		}catch(Exception e){
 			e.printStackTrace();
 		}
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
index e645156..d2d3593 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -59,6 +59,7 @@
 import com.xiaopeng.common.core.constant.Constants;
 import com.xiaopeng.common.core.constant.HttpStatus;
 import com.xiaopeng.common.core.domain.R;
+import com.xiaopeng.common.core.enums.CancelOrderSceneEnum;
 import com.xiaopeng.common.core.enums.OrderStatusEnum;
 import com.xiaopeng.common.core.enums.PushMessageTypeEnum;
 import com.xiaopeng.common.core.exception.ServiceException;
@@ -962,11 +963,14 @@
 
                     // 6.1.1 取消原订单指令
                     PushOrderDto cancelDto = new PushOrderDto();
+                    cancelDto.setTaskId(IdUtil.getSnowflakeNextIdStr());
                     cancelDto.setOrderId(order.getId().toString());
                     cancelDto.setVin(oldVehicle.getVehicleVin());
                     cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
+                    cancelDto.setCancelScene(CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode());
                     orderMissionClient.cancelOrder(cancelDto);
-                    log.info("已取消原车辆订单指令,订单ID: {}, VIN: {}", orderId, oldVehicle.getVehicleVin());
+                    log.info("已取消原车辆订单指令,订单ID: {}, VIN: {}, taskId: {}, cancelScene: {}",
+                            orderId, oldVehicle.getVehicleVin(), cancelDto.getTaskId(), cancelDto.getCancelScene());
 
                     // 6.1.2 解绑乘客与原车辆关系
                     if (Objects.nonNull(order.getAppUserId())) {
@@ -1673,6 +1677,7 @@
                         new ImmutableMap.Builder<String, String>()
                                 .put("id", xpOrder.getId().toString())
                                 .put("appid", appid)
+                                .put("orderType", OrderType.USER_ORDER)
                                 .build();
                 QuartzManager.addJob(
                         EndTripJob.class,
@@ -1688,6 +1693,7 @@
                         new ImmutableMap.Builder<String, String>()
                                 .put("id", xpOrder.getId().toString())
                                 .put("appid", appid)
+                                .put("orderType", OrderType.USER_ORDER)
                                 .build();
                 QuartzManager.addJob(
                         AddCruiseMissionJob.class,
@@ -3025,7 +3031,25 @@
 
                 xpTestOrder.setStartTestPointId(null);
                 xpTestOrderService.updateById(xpTestOrder);
-                redisService.setCacheObject("ORDER_STATUS:" + xpTestOrder.getId(), 2, 24L, TimeUnit.HOURS);
+                redisService.setCacheObject("TEST_ORDER_STATUS:" + xpTestOrder.getId(), 2, 24L, TimeUnit.HOURS);
+            }
+        }
+        if (OrderType.TEST_CRUISE_ORDER.equals(orderType)) {
+            XpTestOrder xpTestOrder = xpTestOrderService.getById(orderId);
+            //订单为待接单状态
+            if (xpTestOrder.getStatus() < 4) {
+                xpTestOrder.setAcceptanceTime(LocalDateTime.now());
+                R<XpVehicle> byVehicleVin = xpVehicleClient.findByVehicleVin(dto.getXpVehicleVin());
+                XpVehicle vehicle = null;
+                if (byVehicleVin.getCode() == 200) {
+                    vehicle = byVehicleVin.getData();
+                    xpTestOrder.setVehicleId(vehicle.getId());
+                    xpTestOrder.setFleetId(vehicle.getFleetId());
+                }
+                xpTestOrder.setStatus(6);
+                xpTestOrder.setStartTestPointId(null);
+                xpTestOrderService.updateById(xpTestOrder);
+                redisService.setCacheObject("TEST_ORDER_STATUS:" + xpTestOrder.getId(), 6, 24L, TimeUnit.HOURS);
             }
         }
     }
diff --git a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpTestOrderServiceImpl.java b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpTestOrderServiceImpl.java
index 7cf9015..1b41300 100644
--- a/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpTestOrderServiceImpl.java
+++ b/xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpTestOrderServiceImpl.java
@@ -264,7 +264,7 @@
             xpOrder.setVehicleId(vehicleId);
             xpOrder.setFleetId(xpVehicle.getFleetId());
             this.save(xpOrder);
-            redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), 1, 24L, TimeUnit.HOURS);
+            redisService.setCacheObject("TEST_ORDER_STATUS:" + xpOrder.getId(), 1, 24L, TimeUnit.HOURS);
             //缓存导航数据,用于下单后推送导航给车端和乘客端
             redisService.setCacheObject("TEST_ORDER_NAVIGATION_END_DATA:" + vehicleId, JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
             //下发XPU消息
@@ -590,7 +590,6 @@
      * 取消订单
      */
     private void cancelOrder(XpTestOrder order) {
-        redisService.removeByPattern(order.getQueueName(), order.getOrderNumber());
         //判断还原车辆状态
         if (null == order.getVehicleId()) {
             Object cacheObject1 = redisService.getCacheObject("CREATE_ORDER:" + order.getId().toString());
@@ -671,7 +670,7 @@
         order.setDuration(new BigDecimal(duration).divide(new BigDecimal(60), 2, RoundingMode.HALF_EVEN).doubleValue());
         order.setStartTestPointId(null);
         this.updateById(order);
-        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 7, 24L, TimeUnit.HOURS);
+        redisService.setCacheObject("TEST_ORDER_STATUS:" + order.getId(), 7, 24L, TimeUnit.HOURS);
 
         //给XPU推送订单取消的报文
         PushOrderDto pushOrderDto = new PushOrderDto();
@@ -720,9 +719,9 @@
         // 运营状态:1=运营中 2=维修中 3=已收车 4=车辆异常
         // 当前模式:1=接单 2=测试
         // 模式状态:1=开始接单/开始测试 2=停止接单/停止测试
-        if (Objects.isNull(newVehicle.getStatus()) || newVehicle.getStatus() == 3) {
-            throw new ServiceException("新车辆保险或年检已过期,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_STATUS_INVALID);
-        }
+//        if (Objects.isNull(newVehicle.getStatus()) || newVehicle.getStatus() == 3) {
+//            throw new ServiceException("新车辆保险或年检已过期,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_STATUS_INVALID);
+//        }
         if (Objects.isNull(newVehicle.getOperatingStatus()) || newVehicle.getOperatingStatus() != 1) {
             throw new ServiceException("新车辆运营状态异常,无法接单", I18nKeyConstant.ORDER_REASSIGN_NEW_VEHICLE_OPERATING_STATUS_INVALID);
         }
@@ -911,6 +910,7 @@
                 case 6:
                     // 行程开始时间
                     xpOrder.setTripBegin(LocalDateTime.now());
+                    redisService.deleteObject("TEST_ORDER_NAVIGATION_START_DATA:" + xpOrder.getVehicleId());
                     break;
                 case 7:
                     xpOrder.setGetoffTime(LocalDateTime.now());
@@ -931,19 +931,36 @@
                     xpOrder.setMileageKilometers(new BigDecimal(reduce).divide(new BigDecimal(1000)).setScale(4, RoundingMode.HALF_EVEN).doubleValue());
                     long duration = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - xpOrder.getTripBegin().toEpochSecond(ZoneOffset.of("+8"));
                     xpOrder.setDuration(new BigDecimal(duration).divide(new BigDecimal(60), 2, RoundingMode.HALF_EVEN).doubleValue());
+
+                    //创建定时结束订单和等待结束后下发巡游单的定时任务
+                    Integer arriveTime = xpSystemSettingClient.getOrderFinishTime().getData();
+                    // 添加自动结束行程定时任务job
+                    Map<String, ? extends Object> endTripJobMaps =
+                            new ImmutableMap.Builder<String, String>()
+                                    .put("id", xpOrder.getId().toString())
+                                    .put("orderType", OrderType.TEST_ORDER)
+                                    .build();
+                    QuartzManager.addJob(
+                            EndTripJob.class,
+                            (EndTripJob.name + xpOrder.getId()).toUpperCase(),
+                            TimeJobType.END_TRIP,
+                            DateUtils.localDateTimeToDate(LocalDateTime.now().plusMinutes(arriveTime)),
+                            endTripJobMaps
+                    );
                     break;
             }
 
             xpOrder.setStatus(status);
             xpOrder.setStartTestPointId(null);
             this.updateById(xpOrder);
-            redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS);
+            redisService.setCacheObject("TEST_ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS);
         }else{
+            //测试巡游单,只需要修改状态
             if(status == 10){
                 xpOrder.setStatus(status);
                 xpOrder.setStartTestPointId(null);
                 this.updateById(xpOrder);
-                redisService.setCacheObject("ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS);
+                redisService.setCacheObject("TEST_ORDER_STATUS:" + xpOrder.getId(), status, 24L, TimeUnit.HOURS);
             }
         }
         return R.ok();
@@ -972,7 +989,7 @@
         order.setStartTestPointId(null);
         order.setTripEnd(LocalDateTime.now());
         baseMapper.updateById(order);
-        redisService.setCacheObject("ORDER_STATUS:" + order.getId(), 8, 24L, TimeUnit.HOURS);
+        redisService.setCacheObject("TEST_ORDER_STATUS:" + order.getId(), 8, 24L, TimeUnit.HOURS);
 
         // 根据订单所属开通城市id 查询定价
         R<XpPricing> pricingByCityId = xpPricingClient.getPricingByCid(order.getCityId());
@@ -1340,7 +1357,7 @@
     @Override
     public void saveVehicleLocation(OrderTrajectory orderTrajectory) {
         // 查询订单信息
-        Integer status = redisService.getCacheObject("ORDER_STATUS:" + orderTrajectory.getOrderId());
+        Integer status = redisService.getCacheObject("TEST_ORDER_STATUS:" + orderTrajectory.getOrderId());
         if(status < 6 || status > 8){
             return;
         }
diff --git a/xp-robotaxi-payment-boot/pom.xml b/xp-robotaxi-payment-boot/pom.xml
index 1e98154..d49cad8 100644
--- a/xp-robotaxi-payment-boot/pom.xml
+++ b/xp-robotaxi-payment-boot/pom.xml
@@ -118,6 +118,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-push-message-boot/pom.xml b/xp-robotaxi-push-message-boot/pom.xml
index c0dff74..6862b9e 100644
--- a/xp-robotaxi-push-message-boot/pom.xml
+++ b/xp-robotaxi-push-message-boot/pom.xml
@@ -106,6 +106,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/controller/PushOrderRouteController.java b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/controller/PushOrderRouteController.java
index 1142952..b6631d2 100644
--- a/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/controller/PushOrderRouteController.java
+++ b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/controller/PushOrderRouteController.java
@@ -17,6 +17,8 @@
 import com.xiaopeng.common.core.enums.PushMessageTypeEnum;
 import com.xiaopeng.common.redis.service.RedisService;
 import com.xiaopeng.pushMessage.utils.MapMatchingUtil;
+import com.xiaopeng.pushMessage.utils.TrackPoint;
+import com.xiaopeng.pushMessage.utils.TrajectoryDensifier;
 import io.swagger.annotations.Api;
 import lombok.extern.slf4j.Slf4j;
 import org.powermock.core.ListMap;
@@ -27,6 +29,7 @@
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.time.Instant;
 import java.util.*;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -50,7 +53,7 @@
      * 给乘客端推送剩余轨迹和剩余里程时长
      * @return
      */
-    @PostMapping("/inner/v1/order/pushOrderRoute")
+    @PostMapping("/logan/inner/v1/order/pushOrderRoute")
     public R<String> pushOrderRoute(@Validated @RequestBody PushOrderRouteDTO dto) {
         Integer routeType = dto.getRouteType();
         //正常订单
@@ -66,8 +69,33 @@
             }
             Object cacheObject = redisService.getCacheObject(key);
             RouteVo routeVo = JSON.parseObject(cacheObject.toString(), RouteVo.class);
-
+            log.info("缓存获取的轨迹 {}", JSON.toJSONString(routeVo));
             if(Objects.nonNull(routeVo)){
+                //开始对轨迹进行点位补全,然后更新缓存中的轨迹数据
+                if(xpOrder.getStatus() == 2 || xpOrder.getStatus() == 5){
+                    List<LonLatDto> polyline = routeVo.getPolyline();
+                    List<LonLatDto> new_polyline = new ArrayList<>();
+                    for (int i = 0; i < polyline.size(); i++) {
+                        if(i == polyline.size() - 1){
+                            new_polyline.add(polyline.get(i));
+                            break;
+                        }
+                        LonLatDto lonLatDto = polyline.get(i);
+                        LonLatDto lonLatDto1 = polyline.get(i + 1);
+                        //对两个点位进行坐标补全
+                        List<TrackPoint> track = new ArrayList<>();
+                        // 模拟数据:两个点相差 20 秒
+                        track.add(new TrackPoint(lonLatDto.getLatitude(), lonLatDto.getLongitude(), null));
+                        track.add(new TrackPoint(lonLatDto1.getLatitude(), lonLatDto1.getLongitude(), null));
+                        //10米补全一个点位
+                        List<TrackPoint> densified = TrajectoryDensifier.densifyByTime(track, 10);
+                        for (TrackPoint trackPoint : densified) {
+                            new_polyline.add(new LonLatDto(trackPoint.getLongitude(), trackPoint.getLatitude()));
+                        }
+                    }
+                    routeVo.setPolyline(new_polyline);
+                    redisService.setCacheObject(key, JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
+                }
                 Integer distance = dto.getDistance();
                 Integer duration = dto.getDuration();
                 // 计算实时点位到线段的最优截取
@@ -86,31 +114,16 @@
                 List<LonLatDto> lonLatDtos1 = remainingNavigation.get("served");
                 routeVo.setPolyline(lonLatDtos);
                 routeVo.setServed(lonLatDtos1);
-
+                log.info("线路截取后存储的轨迹 {}", JSON.toJSONString(routeVo));
                 // 存储最新路线偏离缓存,后续进行轨迹截取
                 redisService.setCacheObject(key, JSON.toJSONString(routeVo), 24L, TimeUnit.HOURS);
 
-                // 封装轨迹点位集合
-                List<Map<String, Object>> polyline = new ArrayList<>();
-                for (LonLatDto lonLatDto : lonLatDtos) {
-                    Map<String, Object> polylineMap = new HashMap<>();
-                    polylineMap.put("longitude",lonLatDto.getLongitude());
-                    polylineMap.put("latitude",lonLatDto.getLatitude());
-                    polyline.add(polylineMap);
-                }
-                List<Map<String, Object>> served = new ArrayList<>();
-                for (LonLatDto lonLatDto : lonLatDtos1) {
-                    Map<String, Object> polylineMap = new HashMap<>();
-                    polylineMap.put("longitude",lonLatDto.getLongitude());
-                    polylineMap.put("latitude",lonLatDto.getLatitude());
-                    served.add(polylineMap);
-                }
                 // 封装路由详情
                 Map<String, Object> route = new HashMap<>();
                 route.put("distance",distance);
                 route.put("duration",duration);
-                route.put("polyline",JSONObject.toJSONString(polyline));
-                route.put("served",JSONObject.toJSONString(served));
+                route.put("polyline",JSONObject.toJSONString(lonLatDtos));
+                route.put("served",JSONObject.toJSONString(lonLatDtos1));
 
                 Map<String, Object> content = new HashMap<>();
                 content.put("orderId",dto.getOrderId().toString());
diff --git a/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/MapMatchingUtil.java b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/MapMatchingUtil.java
index 7bddf2b..422ed98 100644
--- a/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/MapMatchingUtil.java
+++ b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/MapMatchingUtil.java
@@ -43,8 +43,6 @@
                 return map;
             }
             //大于5米的情况,将车子当前位置添加进结果中
-            lonLatDto = new LonLatDto(longitude, latitude);
-            polyline.add(0, lonLatDto);
             map.put("unserved", polyline);
             map.put("served", Collections.emptyList());
             return map;
@@ -65,6 +63,9 @@
     public static Map<String, List<LonLatDto>> getRecentlyPoint(List<LonLatDto> polyline, Double longitude, Double latitude){
         Map<String, List<LonLatDto>> map = new HashMap<>();
         for (int i = 0; i < polyline.size(); i++) {
+            if(i == polyline.size() - 1){
+                break;
+            }
             LonLatDto lonLatDto1 = polyline.get(i);
 
             GlobalCoordinates source1 = new GlobalCoordinates(lonLatDto1.getLatitude(), lonLatDto1.getLongitude());
@@ -86,17 +87,15 @@
 
             //判断当前位置是否处于两个点位之间
             if((distance1 + distance2) == distance3 || (distance1 + distance2) <= distance3 + 5){
-                //剩余未服务的点位
-                List<LonLatDto> lonLatDtos = polyline.subList(i + 1, polyline.size());
-                lonLatDtos.add(0, new LonLatDto(longitude, latitude));
-                //已经服务的点位,给到前端处理
-                List<LonLatDto> lonLatDtos1 = polyline.subList(0, i + 1);
+                //剩余未服务的点位(创建新副本避免修改原列表)
+                List<LonLatDto> lonLatDtos = new ArrayList<>(polyline.subList(i + 1, polyline.size()));
+                //已经服务的点位,给到前端处理(创建新副本避免修改原列表)
+                List<LonLatDto> lonLatDtos1 = new ArrayList<>(polyline.subList(0, i + 1));
                 map.put("unserved", lonLatDtos);
                 map.put("served", lonLatDtos1);
                 return map;
             }
         }
-        polyline.add(0, new LonLatDto(longitude, latitude));
         map.put("unserved", polyline);
         map.put("served", Collections.emptyList());
         return map;
diff --git a/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrackPoint.java b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrackPoint.java
new file mode 100644
index 0000000..896d4db
--- /dev/null
+++ b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrackPoint.java
@@ -0,0 +1,26 @@
+package com.xiaopeng.pushMessage.utils;
+
+import java.time.Instant;
+
+public class TrackPoint {
+
+    private double latitude;  // 纬度
+    private double longitude; // 经度
+    private Instant timestamp; // 时间戳
+
+    public TrackPoint(double latitude, double longitude, Instant timestamp) {
+        this.latitude = latitude;
+        this.longitude = longitude;
+        this.timestamp = timestamp;
+    }
+
+    public double getLatitude() { return latitude; }
+    public double getLongitude() { return longitude; }
+    public Instant getTimestamp() { return timestamp; }
+
+    @Override
+    public String toString() {
+        return String.format("Point[%.6f, %.6f, %s]", latitude, longitude, timestamp);
+    }
+
+}
diff --git a/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrajectoryDensifier.java b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrajectoryDensifier.java
new file mode 100644
index 0000000..a8d033d
--- /dev/null
+++ b/xp-robotaxi-push-message-boot/src/main/java/com/xiaopeng/pushMessage/utils/TrajectoryDensifier.java
@@ -0,0 +1,148 @@
+package com.xiaopeng.pushMessage.utils;
+
+import org.gavaghan.geodesy.Ellipsoid;
+import org.gavaghan.geodesy.GeodeticCalculator;
+import org.gavaghan.geodesy.GeodeticCurve;
+import org.gavaghan.geodesy.GlobalCoordinates;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+
+public class TrajectoryDensifier {
+
+
+    /**
+     * 轨迹补密主方法
+     * @param originalPoints 原始轨迹点列表(必须按时间排序)
+     * @param distance 补密的间隔距离,例如每 5 米补一个点
+     * @return 补密后的轨迹列表
+     */
+    public static List<TrackPoint> densifyByTime(List<TrackPoint> originalPoints, int distance) {
+        List<TrackPoint> result = new ArrayList<>();
+        if (originalPoints == null || originalPoints.size() < 2) {
+            return originalPoints;
+        }
+
+        // 添加第一个点
+        result.add(originalPoints.get(0));
+
+        for (int i = 0; i < originalPoints.size() - 1; i++) {
+            TrackPoint start = originalPoints.get(i);
+            TrackPoint end = originalPoints.get(i + 1);
+
+            GlobalCoordinates source1 = new GlobalCoordinates(start.getLatitude(), start.getLongitude());
+            GlobalCoordinates target1 = new GlobalCoordinates(end.getLatitude(), end.getLongitude());
+            GeodeticCurve geoCurve1 = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source1, target1);
+            double distance1 =geoCurve1.getEllipsoidalDistance();
+
+            // 如果两点间时间差小于间隔,说明不需要补密,直接添加终点(在循环结束后添加)
+            if (distance1 <= distance) {
+                // 这里不做处理,等待下一轮或直接添加终点
+            } else {
+                // 计算需要插入多少个点
+                long steps = (long) (distance1 / distance);
+
+                for (long j = 1; j <= steps; j++) {
+
+                    // 计算插值比例 t (0.0 ~ 1.0)
+                    double fraction = (double) (j * distance) / distance1;
+
+                    // 线性插值计算经纬度
+                    double newLat = start.getLatitude() + fraction * (end.getLatitude() - start.getLatitude());
+                    double newLon = start.getLongitude() + fraction * (end.getLongitude() - start.getLongitude());
+
+                    result.add(new TrackPoint(newLat, newLon, null));
+                }
+            }
+
+            // 确保每一段的终点被添加(除了最后一次循环,因为循环结束后会添加最后一个点)
+            // 为了避免重复添加,我们只在循环最后添加最后一个点,或者在这里判断
+        }
+
+        // 添加最后一个点
+        result.add(originalPoints.get(originalPoints.size() - 1));
+
+        return result;
+    }
+
+
+
+    /**
+     * 轨迹补密主方法
+     * @param originalPoints 原始轨迹点列表(必须按时间排序)
+     * @param intervalSeconds 补密的时间间隔(秒),例如每 5 秒补一个点
+     * @return 补密后的轨迹列表
+     */
+    public static List<TrackPoint> densifyByTime(List<TrackPoint> originalPoints, long intervalSeconds) {
+        List<TrackPoint> result = new ArrayList<>();
+        if (originalPoints == null || originalPoints.size() < 2) {
+            return originalPoints;
+        }
+
+        // 添加第一个点
+        result.add(originalPoints.get(0));
+
+        for (int i = 0; i < originalPoints.size() - 1; i++) {
+            TrackPoint start = originalPoints.get(i);
+            TrackPoint end = originalPoints.get(i + 1);
+
+            long timeDiffMillis = end.getTimestamp().toEpochMilli() - start.getTimestamp().toEpochMilli();
+            long intervalMillis = intervalSeconds * 1000;
+
+            // 如果两点间时间差小于间隔,说明不需要补密,直接添加终点(在循环结束后添加)
+            if (timeDiffMillis <= intervalMillis) {
+                // 这里不做处理,等待下一轮或直接添加终点
+            } else {
+                // 计算需要插入多少个点
+                long steps = timeDiffMillis / intervalMillis;
+
+                for (long j = 1; j <= steps; j++) {
+                    // 计算当前插入点的时间
+                    Instant newTime = start.getTimestamp().plusMillis(j * intervalMillis);
+
+                    // 如果计算出的时间超过了终点时间,则停止(防止浮点数误差或边界问题)
+                    if (newTime.isAfter(end.getTimestamp())) {
+                        break;
+                    }
+
+                    // 计算插值比例 t (0.0 ~ 1.0)
+                    double fraction = (double) (j * intervalMillis) / timeDiffMillis;
+
+                    // 线性插值计算经纬度
+                    double newLat = start.getLatitude() + fraction * (end.getLatitude() - start.getLatitude());
+                    double newLon = start.getLongitude() + fraction * (end.getLongitude() - start.getLongitude());
+
+                    result.add(new TrackPoint(newLat, newLon, newTime));
+                }
+            }
+
+            // 确保每一段的终点被添加(除了最后一次循环,因为循环结束后会添加最后一个点)
+            // 为了避免重复添加,我们只在循环最后添加最后一个点,或者在这里判断
+        }
+
+        // 添加最后一个点
+        result.add(originalPoints.get(originalPoints.size() - 1));
+
+        return result;
+    }
+
+    // 主函数测试
+    public static void main(String[] args) {
+        List<TrackPoint> track = new ArrayList<>();
+        // 模拟数据:两个点相差 20 秒
+        track.add(new TrackPoint(39.9042, 116.4074, Instant.parse("2026-03-28T10:00:00Z"))); // 北京
+        track.add(new TrackPoint(39.9050, 116.4080, Instant.parse("2026-03-28T10:00:20Z")));
+
+        // 每 5 秒补一个点
+        List<TrackPoint> densified = densifyByTime(track, 10);
+
+        System.out.println("原始点数: " + track.size());
+        System.out.println("补密后点数: " + densified.size());
+        System.out.println("轨迹详情:");
+        for (TrackPoint p : densified) {
+            System.out.println("[" + p.getLongitude() + ", " + p.getLatitude() + "]");
+        }
+    }
+
+}
diff --git a/xp-robotaxi-remote-driving-boot/pom.xml b/xp-robotaxi-remote-driving-boot/pom.xml
index 62c2f34..5440e18 100644
--- a/xp-robotaxi-remote-driving-boot/pom.xml
+++ b/xp-robotaxi-remote-driving-boot/pom.xml
@@ -106,6 +106,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-vehicle-convoy-boot/pom.xml b/xp-robotaxi-vehicle-convoy-boot/pom.xml
index b90b8ac..cefbe0b 100644
--- a/xp-robotaxi-vehicle-convoy-boot/pom.xml
+++ b/xp-robotaxi-vehicle-convoy-boot/pom.xml
@@ -106,6 +106,10 @@
                     <groupId>org.yaml</groupId>
                     <artifactId>snakeyaml</artifactId>
                 </exclusion>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
             </exclusions>
         </dependency>
         <dependency>
diff --git a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
index c3ebd12..dfeca09 100644
--- a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
+++ b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -42,10 +42,7 @@
 import com.xiaopeng.vehicleConvoy.service.IXpFleetVehicleService;
 import com.xiaopeng.vehicleConvoy.service.IXpVehicleAnnualRecordService;
 import com.xiaopeng.vehicleConvoy.service.IXpVehicleService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.*;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
@@ -836,9 +833,12 @@
      */
     @ApiOperation(value = "查询可改派的车辆列表", tags = {"管理后台-订单管理"})
     @GetMapping("/api/v1/vehicle/availableList")
-    @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataTypeClass = Long.class)
-    public R<List<XpVehicle>> listAvailableVehicles(@RequestParam Long orderId) {
-        List<XpVehicle> list = xpVehicleService.listAvailableVehicles(orderId);
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "orderId", value = "订单ID", required = true, dataTypeClass = Long.class),
+            @ApiImplicitParam(name = "orderType", value = "订单类型(1=用户单,2=测试单)", required = true, dataTypeClass = Integer.class)
+    })
+    public R<List<XpVehicle>> listAvailableVehicles(@RequestParam Long orderId, Integer orderType) {
+        List<XpVehicle> list = xpVehicleService.listAvailableVehicles(orderId, orderType);
         return R.ok(list);
     }
 
diff --git a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java
index 0058922..cc85f09 100644
--- a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java
+++ b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/IXpVehicleService.java
@@ -34,7 +34,7 @@
      *
      * @return 车辆列表
      */
-    List<XpVehicle> listAvailableVehicles(Long orderId);
+    List<XpVehicle> listAvailableVehicles(Long orderId, Integer orderType);
 
     /**
      * 查询车辆列表接口-地图
diff --git a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
index 8ed352f..f016164 100644
--- a/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
+++ b/xp-robotaxi-vehicle-convoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -16,10 +16,12 @@
 import com.xiaopeng.api.feignClient.operation.XpElectronicClient;
 import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient;
 import com.xiaopeng.api.feignClient.order.XpOrderClient;
+import com.xiaopeng.api.feignClient.order.XpTestOrderClient;
 import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
 import com.xiaopeng.api.model.operation.XpElectronicFence;
 import com.xiaopeng.api.model.operation.XpElectronicFenceArea;
 import com.xiaopeng.api.model.order.XpOrder;
+import com.xiaopeng.api.model.order.XpTestOrder;
 import com.xiaopeng.api.model.vehicleConvoy.*;
 import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
 import com.xiaopeng.api.vo.operation.ElectronicFenceDetailVo;
@@ -115,6 +117,8 @@
     private RedisTemplate redisTemplate;
     @Autowired
     private XpPushMessageClient xpPushMessageClient;
+    @Resource
+    private XpTestOrderClient xpTestOrderClient;
 
     @Override
     public List<XpVehicle> listByIds(List<Long> ids) {
@@ -125,16 +129,22 @@
     }
 
     @Override
-    public List<XpVehicle> listAvailableVehicles(Long orderId) {
+    public List<XpVehicle> listAvailableVehicles(Long orderId, Integer orderType) {
         // 1. 通过订单ID查询订单信息,获取区域ID
-        R<XpOrder> orderResult = xpOrderClient.queryOrderById(orderId);
-        if (orderResult == null || orderResult.getData() == null) {
-            log.warn("查询订单失败,orderId: {}", orderId);
-            return Collections.emptyList();
-        }
+        Long areaId = null;
+        if(null == orderType || 1 == orderType){
+            R<XpOrder> orderResult = xpOrderClient.queryOrderById(orderId);
+            if (orderResult == null || orderResult.getData() == null) {
+                log.warn("查询订单失败,orderId: {}", orderId);
+                return Collections.emptyList();
+            }
 
-        XpOrder order = orderResult.getData();
-        Long areaId = order.getXpElectronicFenceAreaId();
+            XpOrder order = orderResult.getData();
+            areaId = order.getXpElectronicFenceAreaId();
+        }else{
+            XpTestOrder testOrder = xpTestOrderClient.queryOrderById(orderId).getData();
+            areaId = testOrder.getXpElectronicFenceAreaId();
+        }
 
         if (areaId == null) {
             log.warn("订单区域ID为空,orderId: {}", orderId);
diff --git a/xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages.properties b/xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages.properties
index bf07c98..994dbfc 100644
--- a/xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages.properties
+++ b/xp-robotaxi-vehicle-convoy-boot/src/main/resources/i18n/messages.properties
@@ -41,3 +41,6 @@
 vehicle.import.code.exists=第{0}行车辆编码已存在:{1}
 vehicle.import.vin.exists=第{0}行车辆VIN码已存在:{1}
 vehicle.import.plate.exists=第{0}行车牌号已存在:{1}
+vehicle.distance.too.long=距离过远,无法打开
+vehicle.delete.has.bound.fleet=当前车辆已关联车队:{0}
+vehicle.not.p.gear=车辆非P档,无法开启后备箱

--
Gitblit v1.7.1