无关风月
2026-02-13 1d8fa38794d80659dd263085198fd0e0f9a2cec7
Merge remote-tracking branch 'origin/master'
1个文件已删除
1 文件已重命名
12个文件已添加
23个文件已修改
1547 ■■■■■ 已修改文件
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/PushOrderDto.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/VehicleBaseRespDto.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/operation/ReassignOrderDTO.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automatic/OrderMissionClientFallbackFactory.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automaticPilot/OrderMissionClientFallbackFactory.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automaticPilot/XpuVimClientFallbackFactory.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/ReassignOrderClientFallbackFactory.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/XpPricingClientFallbackFactory.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/vehicleConvoy/XpVehicleClientFallbackFactory.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/OrderMissionClient.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/VmpOpenServiceClient.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/XpuVinClient.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/ReassignOrderClient.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpPricingClient.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/vehicleConvoy/XpVehicleClient.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpGeoQueryEntity.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrderEvaluate.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/vehicleConvoy/XpVehicle.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/RouteAndFareVo.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/KafkaTestController.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/XpuVinController.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java 162 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/ReassignOrderController.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPricingController.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/IXpGeoQueryEntityService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpBannerServiceImpl.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpGeoQueryEntityServiceImpl.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java 274 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/test/GpsPoint.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/test/TaxiPricingDemoService.java 300 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/PushOrderDto.java
@@ -1,5 +1,6 @@
package com.xiaopeng.api.dto.automaticPilot;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -13,4 +14,10 @@
    // 订单id
    @ApiModelProperty("订单id")
    private Long orderId;
    /**
     * 订单操作类型
     */
    private OrderOperationType operation_type;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/automaticPilot/VehicleBaseRespDto.java
New file
@@ -0,0 +1,83 @@
package com.xiaopeng.api.dto.automaticPilot;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class VehicleBaseRespDto implements Serializable {
    private static final long serialVersionUID = -1251766408952592117L;
    /**
     * 车架号
     */
    private String vin;
    /**
     * 大屏虚拟id(兼容旧接口)
     */
    private String vid;
    /**
     * 大屏硬件id
     */
    private String cduId;
    /**
     * sim卡id
     */
    private String iccid;
    /**
     * 物料编码id
     */
    private String vehicleMaterielId;
    /**
     * 车型code.
     * DB, DC, DE就是G3
     * ED 就是 P7
     * VehicleTypeType
     */
    private String vehicleTypeCode;
    /**
     * 车型名称,eg:D10,D20,D21..
     */
    private String vehicleTypeName;
    /**
     * 对外名称,eg:1.0,G3,P5...
     */
    private String vehicleSaleName;
    /**
     * 车牌信息(车牌号)
     */
    private String plateNo;
    /**
     * 车辆用途
     */
    private Integer usage;
    /**
     * 公告车型code
     */
    private String proclamationCode;
    /***
     * 给实时流
     */
    private String batchNo;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/dto/operation/ReassignOrderDTO.java
New file
@@ -0,0 +1,24 @@
package com.xiaopeng.api.dto.operation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
@ApiModel(value = "改派订单参数")
public class ReassignOrderDTO implements Serializable {
    @ApiModelProperty(value = "播单次数")
    private Integer count;
    @ApiModelProperty(value = "用户id")
    private String uid;
    @ApiModelProperty(value = "经度")
    private Double longitude;
    @ApiModelProperty(value = "纬度")
    private Double latitude;
    @ApiModelProperty(value = "订单号")
    private String orderNo;
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automatic/OrderMissionClientFallbackFactory.java
File was deleted
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automaticPilot/OrderMissionClientFallbackFactory.java
New file
@@ -0,0 +1,36 @@
package com.xiaopeng.api.factory.automaticPilot;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
/**
 * 车辆整备Feign客户端降级工厂
 *
 * @author mitao
 * @since 2026-02-11
 */
@Slf4j
@Component
public class OrderMissionClientFallbackFactory implements FallbackFactory<OrderMissionClient> {
    @Override
    public OrderMissionClient create(Throwable cause) {
        return new OrderMissionClient() {
            @Override
            public R<Boolean> pushOrder(PushOrderDto dto) {
                log.error("远程调用获取检查点位信息异常:{}", cause.getMessage());
                return R.fail("远程调用获取检查点位信息异常");
            }
            @Override
            public R<Boolean> cancelOrder(PushOrderDto dto) {
                log.error("远程调用获取检查点位信息异常:{}", cause.getMessage());
                return null;
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/automaticPilot/XpuVimClientFallbackFactory.java
New file
@@ -0,0 +1,21 @@
package com.xiaopeng.api.factory.automaticPilot;
import com.xiaopeng.api.feignClient.automaticPilot.XpuVinClient;
import com.xiaopeng.common.core.domain.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
@Slf4j
public class XpuVimClientFallbackFactory implements FallbackFactory<XpuVinClient> {
    @Override
    public XpuVinClient create(Throwable cause) {
        return new XpuVinClient() {
            @Override
            public R<String> getXpuIdByVin(String vin) {
                log.error("查询XPUID失败: {}", cause.getMessage());
                return null;
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/ReassignOrderClientFallbackFactory.java
New file
@@ -0,0 +1,26 @@
package com.xiaopeng.api.factory.operation;
import com.xiaopeng.api.dto.operation.ReassignOrderDTO;
import com.xiaopeng.api.feignClient.operation.ReassignOrderClient;
import com.xiaopeng.common.core.domain.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
public class ReassignOrderClientFallbackFactory implements FallbackFactory<ReassignOrderClient> {
    private static final Logger log = LoggerFactory.getLogger(ReassignOrderClientFallbackFactory.class);
    @Override
    public ReassignOrderClient create(Throwable cause) {
        log.error("改派服务调用失败: {}", cause.getMessage());
        return new ReassignOrderClient(){
            @Override
            public R<String> reassignOrder(ReassignOrderDTO dto) {
                return R.fail("改派派单失败,"+cause.getMessage());
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/operation/XpPricingClientFallbackFactory.java
@@ -34,10 +34,11 @@
            }
            @Override
            public R<?> saveXpGeoQueryEntity(XpGeoQueryEntity xpGeoQueryEntity) {
                log.error("保存XpGeoQueryEntity失败", cause);
            public R<?> updateXpGeoQueryEntity(String orderId) {
                log.error("更新XpGeoQueryEntity失败", cause);
                return R.fail();
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/factory/vehicleConvoy/XpVehicleClientFallbackFactory.java
@@ -67,6 +67,12 @@
                log.error("查询车辆信息失败,原因: {}", cause.getMessage());
                return R.fail();
            }
            @Override
            public R<XpVehicle> findByVehicleXpuId(String xpuid) {
                log.error("查询车辆信息失败,原因: {}", cause.getMessage());
                return R.fail();
            }
        };
    }
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/OrderMissionClient.java
File was renamed from xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automatic/OrderMissionClient.java
@@ -1,20 +1,12 @@
package com.xiaopeng.api.feignClient.automatic;
package com.xiaopeng.api.feignClient.automaticPilot;
import com.xiaopeng.api.dto.account.XpOperationsUserQueryDTO;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.factory.account.XpAppUserClientFallbackFactory;
import com.xiaopeng.api.factory.automatic.OrderMissionClientFallbackFactory;
import com.xiaopeng.api.model.account.XpOperationsUser;
import com.xiaopeng.api.vo.account.XpOperationsUserWithRoleVO;
import com.xiaopeng.api.factory.automaticPilot.OrderMissionClientFallbackFactory;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
/**
 * 小程序用户Feign客户端
@@ -33,4 +25,13 @@
     */
    @PostMapping("/inner/pushOrder")
     R<Boolean> pushOrder(@RequestBody PushOrderDto dto);
    /**
     * 取消订单
     * @param
     * @return
     */
    @PostMapping("/inner/cancelOrder")
    R<Boolean> cancelOrder(@RequestBody PushOrderDto dto);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/VmpOpenServiceClient.java
New file
@@ -0,0 +1,46 @@
package com.xiaopeng.api.feignClient.automaticPilot;
import com.xiaopeng.api.dto.automaticPilot.VehicleBaseRespDto;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.Map;
@FeignClient(name = "xp-vmp-open-boot")
public interface VmpOpenServiceClient {
    /**
     * 通过vin获取车辆基本信息
     *
     * @param vin
     * @return
     */
    @GetMapping("/logan/vehicleInfo/vin")
    VehicleBaseRespDto getVehicleInfoByVin(@RequestParam("vin") String vin, @RequestParam("respList") List<String> respList);
    /**
     * 查询车辆绑定信息, 通过vin获取车辆xpu id
     * typeList类型,1:XPUID,2:待扩展
     * 参数示例:?vin=TESTE290000000000&typeList=1,2
     * 返回示例:{
     *     "1": "01010101010101010101010101010101",
     *     "2": "xxx"
     * }
     */
    @GetMapping("/logan/vehicle/bind/info/query")
    Map<String, String> getVehicleBindInfoByVin(@RequestParam("vin") String vin, @RequestParam("typeList") List<String> typeList);
    /**
     * 通过车辆绑定信息获取车架号, 通过xpu id获取车辆vin
     * type类型,1:XPUID,2:待扩展
     * 参数示例:?value=00000000000000000000000000000001&type=1
     * 返回示例:{
     *     L1NSPGHB9RB900099
     * }
     */
    @GetMapping("/logan/vehicle/bind/info/getVin")
    String getVinByXpuId(@RequestParam("value") String xpuId, @RequestParam("type") Integer type);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/automaticPilot/XpuVinClient.java
New file
@@ -0,0 +1,24 @@
package com.xiaopeng.api.feignClient.automaticPilot;
import com.xiaopeng.api.factory.automaticPilot.XpuVimClientFallbackFactory;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(contextId = "XpuVinClient",
        value = ServiceNameConstantsEnum.XP_AUTOMATIC_PILOT_SERVICE,
        fallbackFactory = XpuVimClientFallbackFactory.class)
public interface XpuVinClient {
    /**
     * 根据车辆VIN查询XPUID
     * @param vin
     * @return
     */
    @GetMapping("/xpu/getXpuIdByVin")
    R<String> getXpuIdByVin(@RequestParam("vin") String vin);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/ReassignOrderClient.java
New file
@@ -0,0 +1,22 @@
package com.xiaopeng.api.feignClient.operation;
import com.xiaopeng.api.dto.operation.ReassignOrderDTO;
import com.xiaopeng.api.factory.operation.ReassignOrderClientFallbackFactory;
import com.xiaopeng.api.factory.operation.XpSystemSettingClientFallbackFactory;
import com.xiaopeng.api.model.operation.XpFeedbackType;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.dto.ServiceNameConstantsEnum;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(contextId = "ReassignOrderClient", value = ServiceNameConstantsEnum.XP_OPERATION_SERVICE, fallbackFactory = ReassignOrderClientFallbackFactory.class)
public interface ReassignOrderClient {
    @PostMapping("/inner/v1/order/reassignOrder")
    R<String> reassignOrder(@RequestBody ReassignOrderDTO dto);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/operation/XpPricingClient.java
@@ -27,8 +27,8 @@
    /**
     * 保存XpGeoQueryEntity
     */
    @PostMapping("/inner/saveXpGeoQueryEntity")
    R<?> saveXpGeoQueryEntity(@RequestBody XpGeoQueryEntity xpGeoQueryEntity);
    @PostMapping("/inner/updateXpGeoQueryEntity")
    R<?> updateXpGeoQueryEntity(@RequestParam String orderId);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/feignClient/vehicleConvoy/XpVehicleClient.java
@@ -79,4 +79,16 @@
     */
    @GetMapping("/inner/vehicle/findByVehicleVin")
    R<XpVehicle> findByVehicleVin(@RequestParam("vehicleVin") String vehicleVin);
    /**
     * 根据车辆xpuid查询车辆信息
     *
     * @param xpuid
     * @return
     */
    @GetMapping("/inner/vehicle/findByVehicleXpuId")
    R<XpVehicle> findByVehicleXpuId(@RequestParam("xpuid") String xpuid);
}
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/operation/XpGeoQueryEntity.java
@@ -30,7 +30,7 @@
     * 时间戳
     */
    @Field("timestamp")
    private Date timestamp;
    private Long timestamp;
    /**
     * 秒数
@@ -81,11 +81,11 @@
        this.location = location;
    }
    public Date getTimestamp() {
    public Long getTimestamp() {
        return timestamp;
    }
    public void setTimestamp(Date timestamp) {
    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/order/XpOrderEvaluate.java
@@ -30,7 +30,7 @@
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;
    @ApiModelProperty(value = "订单id")
xp-robotaxi-api/src/main/java/com/xiaopeng/api/model/vehicleConvoy/XpVehicle.java
@@ -40,6 +40,9 @@
    @ApiModelProperty(value = "车辆vin码")
    private String vehicleVin;
    @ApiModelProperty(value = "车辆xpuid")
    private String xpuId;
    @ApiModelProperty(value = "车牌号")
    private String plateNumber;
xp-robotaxi-api/src/main/java/com/xiaopeng/api/vo/operation/RouteAndFareVo.java
@@ -1,5 +1,6 @@
package com.xiaopeng.api.vo.operation;
import com.xiaopeng.api.vo.order.XpPricingCardVo;
import io.swagger.annotations.ApiModel;
@lombok.Data
@@ -10,4 +11,7 @@
    private FareVo fareEstimate;
    private XpPricingCardVo xpPricingCard;
}
xp-robotaxi-api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -17,10 +17,12 @@
com.xiaopeng.api.factory.account.XpOperationUserClientFallbackFactory
com.xiaopeng.api.factory.operation.XpElectronicClientFallbackFactory
com.xiaopeng.api.factory.operation.XpOpenCityClientFallbackFactory
com.xiaopeng.api.factory.operation.ReassignOrderClientFallbackFactory
com.xiaopeng.api.factory.vehicleConvoy.UserVehicleClientFallbackFactory
com.xiaopeng.api.factory.vehicleConvoy.XpFleetOperationsClientFallbackFactory
com.xiaopeng.api.factory.pushMessage.XpPushMessageClientFallbackFactory
com.xiaopeng.api.factory.account.UserResourcesClientFallbackFactory
com.xiaopeng.api.factory.vehicleConvoy.VehicleControlClientFallbackFactory
com.xiaopeng.api.factory.automaticPilot.XPUClientFallbackFactory
com.xiaopeng.api.factory.automaticPilot.XpuVimClientFallbackFactory
com.xiaopeng.api.factory.maintenance.XpCheckLocationClientFallbackFactory
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/KafkaTestController.java
@@ -1,21 +1,14 @@
package com.xiaopeng.automaticPilot.controller;
import com.alibaba.fastjson2.JSON;
import com.xiaopeng.api.vo.automaticPilot.proto.up.MsgContent;
import com.xiaopeng.automaticPilot.service.KafkaConsumerService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RestController;
/**
 * Kafka 测试控制器
 */
@Slf4j
@RestController
@RequestMapping("/kafka")
@Api(tags = "Kafka 测试接口")
public class KafkaTestController {
    @Autowired
@@ -31,13 +24,8 @@
     */
    @KafkaListener(topics = "topic-prod-robotaxi-xpu-high", groupId = "group-robotaxi-xpu")
    public void topicProdRobotaxiXpuHigh(String message) {
        try {
            log.info("收到XPU上报高优先级主题消息: {}", message);
            kafkaConsumerService.topicProdRobotaxiXpuHigh(message);
        } catch (Exception e) {
            log.error("处理XPU上报高优先级主题消息失败: {}", message, e);
            throw e;
        }
        log.info("收到XPU上报高优先级主题消息: {}", message);
        kafkaConsumerService.topicProdRobotaxiXpuHigh(message);
    }
    /**
@@ -47,12 +35,7 @@
     */
    @KafkaListener(topics = "topic-prod-robotaxi-xpu-normal", groupId = "group-robotaxi-xpu")
    public void topicProdRobotaxiXpuNormal(String message) {
        try {
            log.info("收到XPU上报低优先级主题消息: {}", message);
            kafkaConsumerService.topicProdRobotaxiXpuNormal(message);
        } catch (Exception e) {
            log.error("处理XPU上报低优先级主题消息失败: {}", message, e);
            throw e;
        }
        log.info("收到XPU上报低优先级主题消息: {}", message);
        kafkaConsumerService.topicProdRobotaxiXpuNormal(message);
    }
}
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/OrderMissionController.java
@@ -8,6 +8,8 @@
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskStatus;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.TaskType;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperation;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType;
import com.xiaopeng.automaticPilot.util.XPUUtil;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.utils.SnowFlake;
@@ -52,4 +54,19 @@
        }
        return R.ok(false);
    }
    @PostMapping("/inner/cancelOrder")
    R<Boolean> cancelOrder(@RequestBody PushOrderDto dto){
        OrderOperation operation = new OrderOperation();
        operation.setOrder_id(dto.getOrderId().toString());
        operation.setTask_id("CANCEL_MISSION_"+ IdUtil.fastUUID());
        operation.setOperation_type(dto.getOperation_type());
        SnowFlake snowFlake = new SnowFlake(0, 0);
        snowFlake.withStartTimestamp(1420041600000L);
        long sequence = snowFlake.nextId();
        xpuUtil.cloudOrderOperation(operation,dto.getVin(),sequence);
        redisService.setCacheObject(String.valueOf(sequence),"cancelOrder_"+dto.getOrderId()+"_"+ dto.getVin(),30l, TimeUnit.MINUTES);
        return R.ok(true);
    }
}
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/controller/XpuVinController.java
New file
@@ -0,0 +1,31 @@
package com.xiaopeng.automaticPilot.controller;
import com.xiaopeng.automaticPilot.util.XPUUtil;
import com.xiaopeng.common.core.domain.R;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("")
public class XpuVinController {
    @Resource
    private XPUUtil xpuUtil;
    /**
     * 根据车辆VIN查询XPUID
     * @param vin
     * @return
     */
    @GetMapping("/xpu/getXpuIdByVin")
    public R<String> getXpuIdByVin(@RequestParam("vin") String vin){
        String xpuId = xpuUtil.getXpuIdByVin(vin);
        return R.ok(xpuId);
    }
}
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/service/KafkaConsumerService.java
@@ -6,12 +6,15 @@
import com.alibaba.fastjson2.JSONObject;
import com.xiaopeng.api.dto.map.OrderRouteAndFareDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.operation.ReassignOrderDTO;
import com.xiaopeng.api.dto.order.PopOrderDto;
import com.xiaopeng.api.dto.pushMessage.PushOrderRouteDTO;
import com.xiaopeng.api.dto.pushMessage.SendMessageDTO;
import com.xiaopeng.api.feignClient.map.XpMapClient;
import com.xiaopeng.api.feignClient.operation.ReassignOrderClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.pushMessage.XpPushMessageClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.order.XpOrder;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
@@ -32,6 +35,7 @@
import com.xiaopeng.api.vo.automaticPilot.proto.up.xpuNavigationRequest.NavigationRequest;
import com.xiaopeng.api.vo.automaticPilot.proto.up.xpuNavigationRequest.OrderPhase;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo;
import com.xiaopeng.automaticPilot.util.XPUUtil;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.enums.OrderStatusEnum;
@@ -52,6 +56,9 @@
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import static org.bouncycastle.asn1.x500.style.RFC4519Style.l;
import static org.bouncycastle.asn1.x500.style.RFC4519Style.uid;
/**
 * Kafka 消费者服务
@@ -77,9 +84,13 @@
    @Autowired
    public RedisTemplate redisTemplate;
    @Autowired
    private UserVehicleClient userVehicleClient;
    @Resource
    private XpPushMessageClient xpPushMessageClient;
    @Autowired
    private ReassignOrderClient reassignOrderClient;
@@ -89,6 +100,24 @@
     */
    public void topicProdRobotaxiXpuHigh(String message) {
        MsgContent msgContent = JSON.parseObject(message, MsgContent.class);
        handleXPUMessage(msgContent, message);
    }
    /**
     * 消费消息 - XPU上报Robotaxi云端的消息topic(低优先级)
     */
    public void topicProdRobotaxiXpuNormal(String message) {
        MsgContent msgContent = JSON.parseObject(message, MsgContent.class);
        handleXPUMessage(msgContent, message);
    }
    /**
     * 处理XPU消息
     * @param msgContent
     * @param message
     */
    public void handleXPUMessage(MsgContent msgContent, String message){
        RtMsgHeader header = msgContent.getHeader();
        MessageType type = header.getType();
        //处理请求消息
@@ -166,94 +195,21 @@
                Object sequence = redisTemplate.opsForValue().get(requestSeq);
                if(sequence!=null){
                    String[] split = sequence.toString().split("_");
                    if(split[0].equals("pushOrder")){
                    String typeStr = split[0];
                    // 推单处理
                    if(typeStr.equals("pushOrder")){
                        PopOrderDto dto = new PopOrderDto();
                        dto.setOrderId(Long.valueOf(split[1]));
                        dto.setXpVehicleVin(split[2]);
                        xpOrderClient.popOrder(dto);
                    }
                }
            }
        }
    }
    /**
     * 消费消息 - XPU上报Robotaxi云端的消息topic(低优先级)
     */
    public void topicProdRobotaxiXpuNormal(String message) {
        MsgContent msgContent = JSON.parseObject(message, MsgContent.class);
        RtMsgHeader header = msgContent.getHeader();
        MessageType type = header.getType();
        //处理请求消息
        if (MessageType.MESSAGE_TYPE_REQUEST == type) {
            //区分业务类型
            RTCmdType cmd = header.getCmd();
            switch (cmd) {
                case SYSTEM_STATUS_XPU:
                    log.info("XPU发布系统运行状态 (XPU→云端):{}", message);
                    systemStatusXpu(msgContent);
                    break;
                case XPU_NAVIGATION_REQUEST:
                    log.info("XPU向云端请求导航 (XPU→云端):{}", message);
                    xpuNavigationRequest(msgContent);
                    break;
                case TRIP_STATUS_UPDATE_EVENT:
                    log.info("行程状态更新(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case PULLOVER_STATUS_EVENT:
                    log.info("靠边停车状态(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case DRIVING_MODE_UPDATE_EVENT:
                    log.info("驾驶模式变化(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case SYSTEM_STATUS_UPDATE_EVENT:
                    log.info("系统状态变化(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case TASK_STATE_UPDATE_EVENT:
                    log.info("任务状态变化(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case ORDER_STATE_UPDATE_EVENT:
                    log.info("订单状态变化(XPU→云端)(XPU→座舱):{}", message);
                    orderStateUpdateEvent(msgContent);
                    break;
                case POINT_ARRIVAL_STATUS_EVENT:
                    log.info("到达目标点状态(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case PICKUP_CONFIRMATION_EVENT:
                    log.info("用户上车确认(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case DROPOFF_INFO_EVENT:
                    log.info("用户下车信息(XPU→云端):{}", message);
                    break;
                case NAVIGATION_DEVIATION_EVENT:
                    log.info("导航偏航(XPU→云端):{}", message);
                    navigationDeviationEvent(msgContent);
                    break;
                case EMERGENCY_STOP_EVENT:
                    log.info("急停(XPU→云端)(XPU→座舱):{}", message);
                    break;
                case NAVIGATION_UPDATE_EVENT:
                    log.info("导航信息变化(XPU→云端):{}", message);
                    break;
                case TASK_QUEUE_UPDATE_EVENT:
                    log.info("XPU待执行任务队列(XPU→云端):{}", message);
                    break;
                case SYSTEM_STATE_ANAPSHOT_SYNC_EVENT:
                    log.info("每次MQTT连接之后触发 (XPU→云端):{}", message);
                    break;
                case ORDER_STATE_UPDATE_TO_CDU_EVENT:
                    log.info("更新订单状态到CDU (XPU→云端):{}", message);
                    break;
                default:
                    log.info("消息不在处理范围内,忽略:{}", message);
            }
        }
    }
    /**
@@ -273,7 +229,9 @@
        Float alt = naviPose.getAlt();
        //获取车辆静态信息
        VehicleStaticInfo staticInfo = systemRuntimeStatus.getVehicle_status().getStatic_info();
        String vin = staticInfo.getVin();
        String xpuId = staticInfo.getXpu_id();
        XpVehicle xpVehicle = xpVehicleClient.findByVehicleXpuId(xpuId).getData();
        String vin = xpVehicle.getVehicleVin();
        //先响应消息
        Long sequence = msgContent.getHeader().getSequence();
        responseMessage(sequence, vin);
@@ -325,6 +283,56 @@
    /**
     * XPU发布系统运行状态---车辆实时位置
     *
     * @param msgContent
     */
    public void systemStatusXpuAndReassign(MsgContent msgContent) {
        //开始处理消息对应的业务逻辑
        SystemRuntimeStatus systemRuntimeStatus = msgContent.getContent_detail().getObject("systemRuntimeStatus", SystemRuntimeStatus.class);
        AbnormalReason abnormalReason = systemRuntimeStatus.getSystem_status().getAbnormal_reason();
        // 判断是否为故障状态
        if (abnormalReason == AbnormalReason.FAULT) {
            log.info("车辆故障,开始处理故障");
            // TODO 添加异常任务
            // 解绑用户与车辆关系
            CancelTaxiPassengerVo cancelTaxiPassengerVo = new CancelTaxiPassengerVo();
            String orderId = systemRuntimeStatus.getRunning_order_status_info().getOrder_id();
            XpOrder xpOrder = xpOrderClient.queryOrderById(Long.parseLong(orderId)).getData();
            XpVehicle vehicle = xpVehicleClient.queryById(xpOrder.getVehicleId()).getData();
            if (vehicle != null) {
                // 修改车辆状态
                vehicle.setOperatingStatus(4);
                xpVehicleClient.updateVehicleById(vehicle);
                cancelTaxiPassengerVo.setVin(vehicle.getVehicleVin());
                cancelTaxiPassengerVo.setUid(xpOrder.getAppUserId().toString());
                cancelTaxiPassengerVo.setOrderNo(xpOrder.getOrderNumber());
                // TODO
//            cancelTaxiPassengerVo.setAppId();
                userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
            }
            // 取消订单
            R<?> r = xpOrderClient.cancelOrder(String.valueOf(xpOrder.getId()));
            if (r.getCode() == R.SUCCESS){
                log.info("取消订单成功");
                // 重新派单
                ReassignOrderDTO reassignOrderDTO = new ReassignOrderDTO();
                reassignOrderDTO.setUid(xpOrder.getAppUserId().toString());
                reassignOrderDTO.setOrderNo(xpOrder.getOrderNumber());
                reassignOrderDTO.setCount(10);
                RealtimePose pose = systemRuntimeStatus.getPose();
                Wgs naviPose = pose.getNavi_pose();
                Double latitude = naviPose.getLatitude();
                Double longitude = naviPose.getLongitude();
                reassignOrderDTO.setLongitude(longitude);
                reassignOrderDTO.setLatitude(latitude);
                reassignOrderClient.reassignOrder(reassignOrderDTO);
            }
        }
    }
    /**
     * XPU向云端请求导航
     *
     * @param msgContent
xp-robotaxi-automaticPilot-boot/src/main/java/com/xiaopeng/automaticPilot/util/XPUUtil.java
@@ -8,16 +8,23 @@
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.xiaopeng.api.dto.automaticPilot.MqttPublishDto;
import com.xiaopeng.api.feignClient.automaticPilot.VmpOpenServiceClient;
import com.xiaopeng.api.feignClient.automaticPilot.XPUClient;
import com.xiaopeng.api.vo.automaticPilot.MqttPublishVo;
import com.xiaopeng.api.vo.automaticPilot.proto.down.*;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudCreateOrder.RTTask;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperation;
import com.xiaopeng.common.core.exception.ServiceException;
import com.xiaopeng.common.core.utils.StringUtils;
import com.xiaopeng.common.core.utils.uuid.UUID;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
 * 自动驾驶接口对接文档
@@ -28,6 +35,15 @@
    @Resource
    private XPUClient xpuClient;
    @Resource
    private VmpOpenServiceClient vmpOpenServiceClient;
    // 查询车管绑定类型,1:XPUID,2:待扩展
    public static final String XPU_ID_TYPE = "1";
    // 查询车管 车辆xpuid信息返回字段,用于按需返回字段
    public static final List<String> TYPE_LIST = Collections.singletonList("1");
    /**
@@ -51,10 +67,11 @@
        jsonObject.put("task", task);
        msgContent.setContent_detail(jsonObject);
        log.info("云端-->XPU 创建订单:{}", msgContent);
        //根据车辆VIN查询XPUID
        String xpuId = getXpuIdByVin(vin);
        //组装请求消息体
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic("topic-prod-xpu-robotaxi-high/" + vin);
        vo.setTopic("topic-prod-xpu-robotaxi-high/" + xpuId);
        vo.setPayload(JSON.toJSONString(msgContent));
        return xpuClient.publish(vo);
    }
@@ -82,14 +99,12 @@
        jsonObject.put("operation", operation);
        msgContent.setContent_detail(jsonObject);
        log.info("云端-->XPU 操作订单:{}", msgContent);
        //根据车辆VIN查询XPUID
        String xpuId = getXpuIdByVin(vin);
        //组装请求消息体
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic("topic-prod-xpu-robotaxi-high/" + vin);
        vo.setTopic("topic-prod-xpu-robotaxi-high/" + xpuId);
        vo.setPayload(JSON.toJSONString(msgContent));
        return xpuClient.publish(vo);
    }
@@ -118,11 +133,32 @@
        jsonObject.put("resposne", responseMessage);
        msgContent.setContent_detail(jsonObject);
        log.info("云端-->XPU 响应消息:{}", msgContent);
        //根据车辆VIN查询XPUID
        String xpuId = getXpuIdByVin(vin);
        //组装请求消息体
        MqttPublishVo vo = new MqttPublishVo();
        vo.setTopic("topic-prod-xpu-robotaxi-high/" + vin);
        vo.setTopic("topic-prod-xpu-robotaxi-high/" + xpuId);
        vo.setPayload(JSON.toJSONString(msgContent));
        return xpuClient.publish(vo);
    }
    /**
     * @description: 根据vin查询xpuId
     * @param: vin
     * @return: xpuId
     */
    public String getXpuIdByVin(String vin)  {
        Map<String, String> xpuIdMapping = vmpOpenServiceClient.getVehicleBindInfoByVin(vin, TYPE_LIST);
        log.info("getMqttPublishTopic vin,{},xpuIdMapping,{}", vin,  JSON.toJSONString(xpuIdMapping));
        if (xpuIdMapping == null || StringUtils.isEmpty(xpuIdMapping.get(XPU_ID_TYPE)) ) {
            log.error("根据vin查询车辆xpuid信息为空,vin={}", vin);
            throw new RuntimeException("根据vin查询车辆xpuid信息为空");
        }
        return xpuIdMapping.get(XPU_ID_TYPE);
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/ReassignOrderController.java
New file
@@ -0,0 +1,29 @@
package com.xiaopeng.operation.controller;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.api.dto.operation.ReassignOrderDTO;
import com.xiaopeng.operation.utils.TaskOrderUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
 * token 控制
 *
 * @author ruoyi
 */
@Slf4j
@RestController
public class ReassignOrderController {
    @Autowired
    private TaskOrderUtil taskOrderUtil;
    @PostMapping("/inner/v1/order/reassignOrder")
    public R<String> reassignOrder(@RequestBody ReassignOrderDTO dto) {
        taskOrderUtil.reassignPushOrder(dto.getCount(),dto.getUid(),dto.getLongitude(),dto.getLatitude(),dto.getOrderNo());
        return R.ok();
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/controller/XpPricingController.java
@@ -23,6 +23,7 @@
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Date;
/**
 * <p>
@@ -49,29 +50,28 @@
    }
    @PostMapping("/base/v1/mini-program/navigation/route-and-fare")
    @ApiOperation(value = "导航-获取路线和费用",tags = {"小程序-获取路线和费用"},response = RouteAndFareVo.class)
    @ApiOperation(value = "导航-获取路线和费用", tags = {"小程序-获取路线和费用"}, response = RouteAndFareVo.class)
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<RouteAndFareVo> getRouteAndFare(@RequestBody @Valid RouteAndFareDto routeAndFareDto, HttpServletRequest request) {
        // uid已通过拦截器otp校验,可以直接使用
        String uid = request.getHeader("XP-Uid");
        return R.ok(xpPricingService.getRouteAndFare(routeAndFareDto,uid));
        return R.ok(xpPricingService.getRouteAndFare(routeAndFareDto, uid));
    }
    // 根据开通城市 获取定价
    @GetMapping("/getPricingByCityId/{cityId}")
    public R<XpPricing> getPricingByCityId(@PathVariable("cityId")Long cityId) {
    public R<XpPricing> getPricingByCityId(@PathVariable("cityId") Long cityId) {
        XpPricing pricing = xpPricingService.lambdaQuery().eq(XpPricing::getCityId, cityId).last("limit 1").one();
        return R.ok(pricing);
    }
    @GetMapping("/base/v1/mini-program/pricing/rules/{openCityId}")
    @ApiOperation(value = "获取费用规则",tags = {"小程序-根据开通城市获取费用规则"},response = String.class)
    @ApiOperation(value = "获取费用规则", tags = {"小程序-根据开通城市获取费用规则"}, response = String.class)
    public R<?> getPricingRules(@PathVariable Long openCityId) {
        XpPricing xpPricing = xpPricingService.getOne(new LambdaQueryWrapper<XpPricing>().eq(XpPricing::getCityId, openCityId).eq(XpPricing::getPricingType, 1).last("limit 1"));
        if(xpPricing!=null){
        if (xpPricing != null) {
            return R.ok(xpPricing.getPriceRule());
        }
        return R.ok("");
@@ -84,20 +84,20 @@
     * @return
     */
    @PostMapping("/base/v1/mini-program/pricing/getWaitTime")
    @ApiOperation(value = "获取等待时间",tags = {"小程序-获取等待时间"},response = Integer.class)
    public R<Integer> getWaitTime(@RequestBody LonLatDto dto){
        return R.ok(xpPricingService.getWaitTime(dto.getLongitude(),dto.getLatitude()));
    @ApiOperation(value = "获取等待时间", tags = {"小程序-获取等待时间"}, response = Integer.class)
    public R<Integer> getWaitTime(@RequestBody LonLatDto dto) {
        return R.ok(xpPricingService.getWaitTime(dto.getLongitude(), dto.getLatitude()));
    }
    /**
     * 保存信息
     * @param xpGeoQueryEntity
     * @param
     * @return
     */
    @PostMapping("/inner/saveXpGeoQueryEntity")
    public R<?> saveXpGeoQueryEntity(@RequestBody XpGeoQueryEntity xpGeoQueryEntity){
        xpGeoQueryEntityService.save(xpGeoQueryEntity);
    @PostMapping("/inner/updateXpGeoQueryEntity")
    public R<?> updateXpGeoQueryEntity(@RequestParam String orderId) {
        xpGeoQueryEntityService.updateByOrderId(orderId);
        return R.ok();
    }
@@ -106,7 +106,7 @@
     * 播单
     */
    @PostMapping("/base/v1/mini-program/order/save")
    @ApiOperation(value = "保存订单",tags = {"小程序-保存订单"})
    @ApiOperation(value = "保存订单", tags = {"小程序-保存订单"})
    @XpClientCheck(checkToken = false, checkOtpToken = true)
    public R<SaveOrderVo> saveOrder(@RequestBody @Validated XpOrderDto dto, HttpServletRequest request) {
        String uid = request.getHeader("XP-Uid");
@@ -115,8 +115,6 @@
        saveOrderVo.setOrderId(l);
        return R.ok(saveOrderVo);
    }
}
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/IXpGeoQueryEntityService.java
@@ -20,6 +20,9 @@
            String time
    );
    /**
     * 保存地理查询实体
     * @param entity 地理查询实体
@@ -27,6 +30,12 @@
     */
    XpGeoQueryEntity save(XpGeoQueryEntity entity);
    /**
     * 修改
     */
   XpGeoQueryEntity updateByOrderId(String orderId);
    /**
     * 根据ID查询实体
     * @param id 实体ID
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpBannerServiceImpl.java
@@ -27,7 +27,6 @@
    @Override
    public List<XpBannerListVo> getXpBannerList() {
        LambdaQueryWrapper<XpBanner> wrapper = new LambdaQueryWrapper<>();
        // TODO 魔法数字
        wrapper.eq(XpBanner::getBannerStatus,1);
        // 当前时间在开始和结束时间范围内
        wrapper.ge(XpBanner::getStartTime,System.currentTimeMillis());
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpGeoQueryEntityServiceImpl.java
@@ -1,17 +1,25 @@
package com.xiaopeng.operation.service.impl;
import com.xiaopeng.api.model.operation.XpGeoQueryEntity;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.operation.repository.XpGeoQueryEntityRepository;
import com.xiaopeng.operation.service.IXpGeoQueryEntityService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metrics;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
 * MongoDB 地理查询服务实现类
@@ -21,6 +29,9 @@
    @Autowired
    private XpGeoQueryEntityRepository repository;
    @Autowired
    private MongoTemplate mongoTemplate;
    /**
     * 通过经纬度查询固定范围500米内、一周内、指定时段的数据
@@ -35,26 +46,43 @@
            double latitude,
            String time
    ) {
        // 创建中心点坐标
        Point point = new Point(longitude, latitude);
        // 设置距离范围为500米
        Distance distance = new Distance(0.5, Metrics.KILOMETERS); // 0.5公里 = 500米
        // 计算一周前的时间
//        // 计算一周前的时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(Calendar.DAY_OF_YEAR, -7);
        Date startTime = calendar.getTime();
        Long startTime = calendar.getTime().getTime();
        // 执行查询 - 使用新的方法,包含时段过滤
        return repository.findByLocationNearAndTimestampAfterAndTimeAndStatusGreaterThan(
                point,
                500,
                startTime,
                time, // 时段过滤
                1 // 状态大于1
        // 1. 创建查询点
        Point referencePoint = new Point(longitude, latitude);
        // 2. 构建 NearQuery - 完全使用 NearQuery 的 API
        NearQuery nearQuery = NearQuery.near(referencePoint, Metrics.KILOMETERS)
                .maxDistance(0.5)  // 转成公里
                .spherical(true);
        // 3.时间>startTime time = time参数
        // 3. 创建额外的查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("timestamp").gte(startTime));
        query.addCriteria(Criteria.where("time").is(time));
        // 将 NearQuery 和额外的查询条件合并
        nearQuery.query(query);
        // 4. 执行查询 - 明确指定集合名
        GeoResults<XpGeoQueryEntity> geoResults = mongoTemplate.geoNear(
                nearQuery,
                XpGeoQueryEntity.class,
                "xp_geo_query_entity"  // 明确指定集合名,避免映射错误
        );
        // 5. 提取结果
        return geoResults.getContent().stream()
                .map(geoResult -> geoResult.getContent())
                .collect(Collectors.toList());
    }
    /**
@@ -67,6 +95,25 @@
        return repository.save(entity);
    }
    @Override
    public XpGeoQueryEntity updateByOrderId(String orderId) {
        Query query = new Query(Criteria.where("orderId").is(orderId));
        XpGeoQueryEntity xpGeoQueryEntity = mongoTemplate.findOne(query, XpGeoQueryEntity.class);
        Long timestamp = xpGeoQueryEntity.getTimestamp();
        long time = new Date().getTime();
        // 计算2个时间的秒数差
        long seconds = (time- timestamp) / 1000;
        Update update = new Update().set("seconds", seconds).set("status", 1);
        if(xpGeoQueryEntity.getStatus()==0){
            mongoTemplate.findAndModify(query, update, XpGeoQueryEntity.class);
        }
        return null;
    }
    /**
     * 根据ID查询实体
     * @param id 实体ID
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/service/impl/XpPricingServiceImpl.java
@@ -20,6 +20,7 @@
import com.xiaopeng.api.vo.operation.FareVo;
import com.xiaopeng.api.vo.operation.RouteAndFareVo;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.order.XpPricingCardVo;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.domain.R;
import com.xiaopeng.common.core.exception.ServiceException;
@@ -35,12 +36,13 @@
import com.xiaopeng.operation.utils.XpPricingUtil;
import com.xiaopeng.operation.utils.holiday.HolidayUtil;
import com.xiaopeng.operation.utils.map.FastDistanceCalculator;
import com.xiaopeng.operation.vo.XpPricingCardVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.stereotype.Service;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
@@ -89,8 +91,6 @@
    @Resource
    private XpElectronicFenceAreaMapper xpElectronicFenceAreaMapper;
    @Resource
    private XpVehicleClient xpVehicleClient;
    @Resource
    private XpPointMapper xpPointMapper;
@@ -206,6 +206,8 @@
//        );
        XpPricingCardVo xpPricingCardVo = new XpPricingCardVo();
        // 3. 并行执行远程服务调用 判断是否同一经营区域
        CompletableFuture<R<Boolean>> diagnosisAreaFuture = CompletableFuture.supplyAsync(
                () -> xpMapClient.diagnosisArea(routeAndFareDto),
@@ -274,6 +276,9 @@
        RouteAndFareVo routeAndFareVo = new RouteAndFareVo();
//        routeAndFareVo.setRoute(routeVo);
        routeAndFareVo.setXpPricingCard(xpPricingCardVo);
        FareVo fareVo = new FareVo();
//        fareVo.setEstimatedDistanceKm(routeVo.getDistance().doubleValue() / 1000);
//        fareVo.setEstimatedDurationMin(routeVo.getDuration() / 60);
@@ -333,7 +338,7 @@
            return 1;
        } else {
            // 已完成接单的数据
            List<XpGeoQueryEntity> validEntities = entities.stream().filter(e -> e.getStatus() > 1).collect(Collectors.toList());
            List<XpGeoQueryEntity> validEntities = entities.stream().filter(e -> e.getStatus() == 1).collect(Collectors.toList());
            // 计算平均等待时间
            OptionalDouble averageOptional = validEntities.stream().mapToDouble(XpGeoQueryEntity::getSeconds).average();
@@ -347,6 +352,8 @@
                    double waitMinutes = (average * count) / 60;
                    if (waitMinutes > 3) {
                        throw new ServiceException("当前区域正在等待中,请耐心等待", I18nKeyConstant.WAITING_TIME);
                    }else if(waitMinutes==0){
                        return 1;
                    }
                    return (int) waitMinutes;
                }
@@ -415,6 +422,8 @@
        // 生成订单数据
        XpOrder xpOrder = new XpOrder();
        xpOrder.setVehicleId(1l);
//        xpOrder.setStartMileage(Double.valueOf(startMileage));
@@ -517,6 +526,16 @@
                xpOrder.setQueueName(s);
                xpOrderClient.updateOrder(xpOrder);
                // 存储mongodb 数据
                XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity();
                xpGeoQueryEntity.setOrderId(orderId.toString());
                xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(),xpPoint.getPointLat()));
                // 计算2个时间的秒数
                xpGeoQueryEntity.setTime(currentTimeSlot);
                xpGeoQueryEntity.setStatus(0);
                xpGeoQueryEntity.setTimestamp(System.currentTimeMillis());
                geoQueryEntityService.save(xpGeoQueryEntity);
                return orderId;
            }
        }
@@ -525,6 +544,18 @@
        redisService.setCacheList(key, Arrays.asList(orderId + "_" + xpPoint.getPointLon() + "," + xpPoint.getPointLat() + "_0" + "_" + uid + "_" + xpOrder.getOrderNumber() + "_" + distance + "_" + duration + "_" + routeAndFareDto.getRoutePlanRule()));
        xpOrder.setQueueName(key);
        xpOrderClient.updateOrder(xpOrder);
        // 存储mongodb 数据
        XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity();
        xpGeoQueryEntity.setOrderId(orderId.toString());
        xpGeoQueryEntity.setLocation(new GeoJsonPoint(xpPoint.getPointLon(),xpPoint.getPointLat()));
        // 计算2个时间的秒数
        xpGeoQueryEntity.setTime(currentTimeSlot);
        xpGeoQueryEntity.setStatus(0);
        geoQueryEntityService.save(xpGeoQueryEntity);
        return orderId;
//
xp-robotaxi-operation-boot/src/main/java/com/xiaopeng/operation/utils/TaskOrderUtil.java
@@ -1,14 +1,15 @@
package com.xiaopeng.operation.utils;
import cn.hutool.core.bean.BeanUtil;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.dto.map.RouteAndFareDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.operation.VehiclePositionByVinDto;
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.map.XpMapClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.UserVehicleClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.VehicleControlClient;
import com.xiaopeng.api.feignClient.vehicleConvoy.XpVehicleClient;
import com.xiaopeng.api.model.operation.XpElectronicFence;
import com.xiaopeng.api.model.operation.XpTradingStrategy;
@@ -16,6 +17,7 @@
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.automaticPilot.VehiclePosition;
import com.xiaopeng.api.vo.operation.RouteVo;
import com.xiaopeng.api.vo.operation.VehiclePositionVo;
import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.domain.R;
@@ -25,8 +27,8 @@
import com.xiaopeng.operation.service.IXpTradingStrategyService;
import com.xiaopeng.operation.service.XpPointService;
import com.xiaopeng.operation.utils.mango.VehiclePositionService;
import com.xiaopeng.api.vo.operation.VehiclePositionVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
@@ -39,6 +41,7 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Component
public class TaskOrderUtil {
@@ -72,6 +75,9 @@
    @Autowired
    private XpMapClient xpMapClient;
    //
    @Autowired
    private OrderMissionClient orderMissionClient;
    // 自定义线程池
@@ -102,7 +108,7 @@
                String[] split = firstElement.toString().split("_");
                // 如果未处理 创建新任务
                if (split[2].equals("0")) {
                    String value = split[0] + "_" + split[1] + "_1" + "_"+split[3] + "_"+ split[4] + "_"+ split[5] + "_"+ split[6] + "_"+ split[7];
                    String value = split[0] + "_" + split[1] + "_1" + "_" + split[3] + "_" + split[4] + "_" + split[5] + "_" + split[6] + "_" + split[7];
                    // 状态改为处理中
                    redisService.updateFirst(name, value);
                    threadPoolTaskExecutor.submit(() -> {
@@ -220,8 +226,8 @@
    @SneakyThrows
    private void processPushOrder(String quoteName, int count, String uid, String[] split, String orderNo, XpTradingStrategy xpTradingStrategy, String distance, String duration, String planRule) {
        System.out.println("进入推单环环节");
        if(count==0){
            count=1;
        if (count == 0) {
            count = 1;
        }
        // 订单状态
        R<XpOrder> xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo);
@@ -596,7 +602,142 @@
                            // 订单价值
                            if (Objects.equals(secondMax, tendencyOrderValue)) {
                                // 订单价值
                                // 时间差权重
                                Integer weightTimeDifference = xpTradingStrategy.getWeightTimeDifference();
                                // 距离差权重
                                Integer weightDistanceDifference = xpTradingStrategy.getWeightDistanceDifference();
                                // 距离权重
                                Integer weightDistance = xpTradingStrategy.getWeightDistance();
                                // 时间权重
                                Integer weightTime = xpTradingStrategy.getWeightTime();
                                // 电量权重
                                Integer weightElectricity = xpTradingStrategy.getWeightElectricity();
                                // 找出最大的值是那个
                                Integer max1 = Math.max(weightTimeDifference, Math.max(weightDistanceDifference, Math.max(weightDistance, Math.max(weightTime, weightElectricity))));
                                //  时间差
                                if (max1.equals(weightTimeDifference)) {
                                    for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                        RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
                                        LonLatDto lonLatDto = new LonLatDto();
                                        lonLatDto.setLongitude(vehiclePosition.getPoint().getX());
                                        lonLatDto.setLatitude(vehiclePosition.getPoint().getY());
                                        routeAndFareDto.setOrigin(lonLatDto);
                                        LonLatDto lonLatDto1 = new LonLatDto();
                                        lonLatDto1.setLongitude(Double.valueOf(split[0]));
                                        lonLatDto1.setLatitude(Double.valueOf(split[1]));
                                        routeAndFareDto.setDestination(lonLatDto1);
                                        routeAndFareDto.setRoutePlanRule(Integer.valueOf(planRule));
                                        R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto);
                                        if (distanceAndDuration.getCode() == 200) {
                                            // 送驾- 接驾
                                            Integer durationDifference = Integer.parseInt(duration) - distanceAndDuration.getData().getDuration();
                                            vehiclePosition.setTimeDifference(durationDifference);
                                        }
                                    }
                                }
                                if (max1.equals(weightDistanceDifference)) {
                                    for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                        RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
                                        LonLatDto lonLatDto = new LonLatDto();
                                        lonLatDto.setLongitude(vehiclePosition.getPoint().getX());
                                        lonLatDto.setLatitude(vehiclePosition.getPoint().getY());
                                        routeAndFareDto.setOrigin(lonLatDto);
                                        LonLatDto lonLatDto1 = new LonLatDto();
                                        lonLatDto1.setLongitude(Double.valueOf(split[0]));
                                        lonLatDto1.setLatitude(Double.valueOf(split[1]));
                                        routeAndFareDto.setDestination(lonLatDto1);
                                        routeAndFareDto.setRoutePlanRule(Integer.valueOf(planRule));
                                        R<RouteVo> distanceAndDuration = xpMapClient.getDistanceAndDuration(routeAndFareDto);
                                        if (distanceAndDuration.getCode() == 200) {
                                            // 送驾- 接驾
                                            Integer distanceDifference = Integer.parseInt(distance) - distanceAndDuration.getData().getDistance();
                                            vehiclePosition.setDistanceDifference(distanceDifference);
                                        }
                                    }
                                }
                                if (max1.equals(weightDistance)) {
                                    for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                        RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
                                        LonLatDto lonLatDto = new LonLatDto();
                                        lonLatDto.setLongitude(vehiclePosition.getPoint().getX());
                                        lonLatDto.setLatitude(vehiclePosition.getPoint().getY());
                                        routeAndFareDto.setOrigin(lonLatDto);
                                        LonLatDto lonLatDto1 = new LonLatDto();
                                        lonLatDto1.setLongitude(Double.parseDouble(split[0]));
                                        lonLatDto1.setLatitude(Double.parseDouble(split[1]));
                                        routeAndFareDto.setRoutePlanRule(Integer.valueOf(planRule));
                                        routeAndFareDto.setDestination(lonLatDto1);
                                        //  调用地图 获取时间
                                        R<RouteVo> r = xpMapClient.getDistanceAndDuration(routeAndFareDto);
                                        if (r.getCode() == 200) {
                                            vehiclePosition.setDistance(Double.valueOf(r.getData().getDistance()));
                                        } else {
                                            vehiclePosition.setDistance(0.0);
                                        }
                                    }
                                }
                                if (max1.equals(weightTime)) {
                                    for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                        RouteAndFareDto routeAndFareDto = new RouteAndFareDto();
                                        LonLatDto lonLatDto = new LonLatDto();
                                        lonLatDto.setLongitude(vehiclePosition.getPoint().getX());
                                        lonLatDto.setLatitude(vehiclePosition.getPoint().getY());
                                        routeAndFareDto.setOrigin(lonLatDto);
                                        LonLatDto lonLatDto1 = new LonLatDto();
                                        lonLatDto1.setLongitude(Double.parseDouble(split[0]));
                                        lonLatDto1.setLatitude(Double.parseDouble(split[1]));
                                        routeAndFareDto.setRoutePlanRule(Integer.valueOf(planRule));
                                        routeAndFareDto.setDestination(lonLatDto1);
                                        //  调用地图 获取时间
                                        R<RouteVo> r = xpMapClient.getDistanceAndDuration(routeAndFareDto);
                                        if (r.getCode() == 200) {
                                            vehiclePosition.setSecond(r.getData().getDuration());
                                        } else {
                                            vehiclePosition.setSecond(0);
                                        }
                                    }
                                }
                                if (max1.equals(weightElectricity)) {
                                    // 计算车的分数  分数最大是车的size
                                    availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getCurrentElectricity).reversed()).collect(Collectors.toList());
                                    int size1 = tendencyElectricity;
                                    // 做比对的分数
                                    int temp1 = availableVehiclesNearby.get(0).getCurrentElectricity();
                                    for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                        vehiclePosition.setCurrentElectricityScore(vehiclePosition.getCurrentElectricityScore() + size1);
                                        if (temp1 != vehiclePosition.getCurrentElectricity()) {
                                            size1--;
                                        }
                                    }
                                }
                                // 算出总分 再来排序计算
                                for (VehiclePositionVo vehiclePositionVo : availableVehiclesNearby) {
                                    vehiclePositionVo.setOrderValueTotal(vehiclePositionVo.getCurrentElectricityScore() + vehiclePositionVo.getDistanceScore() + vehiclePositionVo.getTimeScore() + vehiclePositionVo.getDistanceDifference() + vehiclePositionVo.getTimeDifference());
                                }
                                availableVehiclesNearby = availableVehiclesNearby.stream().sorted(Comparator.comparing(VehiclePositionVo::getOrderValueTotal).reversed()).collect(Collectors.toList());
                                int size2 = tendencyOrderValue;
                                // 做比对的分数
                                double temp2 = availableVehiclesNearby.get(0).getOrderValueTotal();
                                for (VehiclePositionVo vehiclePosition : availableVehiclesNearby) {
                                    vehiclePosition.setValueScore(vehiclePosition.getValueScore() + size2);
                                    if (temp2 != vehiclePosition.getOrderValueTotal()) {
                                        size2--;
                                    }
                                }
                            }
                        }
@@ -616,7 +757,7 @@
                    RLock lock = redissonClient.getLock("FIND_CAR_" + vehiclePositionVo.getVin());
                    lock.lock(10, TimeUnit.SECONDS);
                    System.err.println("队列:"+quoteName+"  车辆:"+vehiclePositionVo.getVin()+"订单"+orderNo);
                    System.err.println("队列:" + quoteName + "  车辆:" + vehiclePositionVo.getVin() + "订单" + orderNo);
                    try {
//                        VehiclePosition vehiclePosition = vehiclePositionService.findByVehicleId(vehiclePositionVo.getVehicle_id());
                        R<XpVehicle> vehiclePositionR = xpVehicleClient.findByVehicleVin(vehiclePositionVo.getVin());
@@ -630,27 +771,15 @@
                        }
                        //  关闭巡游单子 TODO
                        AddTaxiPassengerVo addTaxiPassengerVo = new AddTaxiPassengerVo();
                        addTaxiPassengerVo.setVin(vehiclePosition.getVehicleVin());
                        addTaxiPassengerVo.setUid(uid);
                        addTaxiPassengerVo.setOrderNo(orderNo);
                        // TODO appid
                        addTaxiPassengerVo.setAppId("");
                        PushOrderDto pushOrderDto = new PushOrderDto();
                        pushOrderDto.setOrderId(xpOrder.getId());
                        pushOrderDto.setVin(vehiclePosition.getVehicleVin());
                        BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.addTaxiPassenger(addTaxiPassengerVo);
                        if (baseVehicleUserDto!=null && baseVehicleUserDto.getCode() == 200) {
                            // TODO 下单
                        // 调用推送服务  orderId + carVin
                        orderMissionClient.pushOrder(pushOrderDto);
                            // 调用推送服务  orderId + carVin
                            // 绑定成功  弹出这个队列第一个订单
                            redisService.popFirstElement(quoteName);
                            return;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
@@ -666,33 +795,25 @@
                    lock.lock(10, TimeUnit.SECONDS);
                    try {
                        // 查询车辆状态
                       R<XpVehicle> vehicleR = xpVehicleClient.findByVehicleVin(vehicleVin);
                       if(vehicleR.getCode()!=200){
                           continue;
                       }
                       XpVehicle vehicleId1 = vehicleR.getData();
                        R<XpVehicle> vehicleR = xpVehicleClient.findByVehicleVin(vehicleVin);
                        if (vehicleR.getCode() != 200) {
                            continue;
                        }
                        XpVehicle vehicleId1 = vehicleR.getData();
                        if (vehicleId1.getStatus() != 1 || vehicleId1.getState() != 0) {
                            lock.unlock();
                            continue;
                        }
                        if (vehiclePosition.getHasOrder() == 1) {
                            //  关闭巡游单子 TODO
                        }
                        AddTaxiPassengerVo addTaxiPassengerVo = new AddTaxiPassengerVo();
                        addTaxiPassengerVo.setVin(vehiclePosition.getVin());
                        addTaxiPassengerVo.setUid(uid);
                        addTaxiPassengerVo.setOrderNo(orderNo);
                        // TODO appid
                        addTaxiPassengerVo.setAppId("");
                        BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.addTaxiPassenger(addTaxiPassengerVo);
                        if (baseVehicleUserDto.getCode() == 200) {
                        //  关闭巡游单子 TODO
                        PushOrderDto pushOrderDto = new PushOrderDto();
                        pushOrderDto.setOrderId(xpOrder.getId());
                        pushOrderDto.setVin(vehiclePosition.getVin());
                            redisService.popFirstElement(quoteName);
                            lock.unlock();
                            return;
                        }
                        // 调用推送服务  orderId + carVin
                        orderMissionClient.pushOrder(pushOrderDto);
                    } catch (Exception e) {
                    } finally {
@@ -704,5 +825,70 @@
        }
    }
    /**
     * 订单处理
     * @param count 轮数
     * @param uid
     * @param longitude  经度
     * @param latitude  纬度
     * @param orderNo 订单号
     */
    @SneakyThrows
    public void reassignPushOrder(int count, String uid, Double longitude, Double latitude, String orderNo) {
        System.out.println("进入推单环环节");
        if (count == 0) {
            count = 1;
        }
        // 订单状态
        R<XpOrder> xpOrderR = xpOrderClient.queryOrderByOrderNo(orderNo);
        if (xpOrderR.getCode() != 200) {
            return;
        }
        if (xpOrderR.getData().getStatus() != 1) {
            return;
        }
        XpOrder data = xpOrderR.getData();
        XpTradingStrategy xpTradingStrategy = xpTradingStrategyService.getOne(null);
        for (int i = 0; i < count; i++) {
            log.info("进入找车环节");
            List<VehiclePosition> positionList = vehiclePositionService.findAvailableVehiclesNearby(longitude, latitude, xpTradingStrategy.getOnePushDistance(), xpTradingStrategy.getSimultaneouslyOrderCount());
            // 获取车辆的区域信息
            if (positionList.isEmpty()) {
                continue;
            }
            // 直接派单  定义一个锁来锁定车辆
            VehiclePosition vehiclePosition = positionList.get(0);
            String vehicleVin = vehiclePosition.getVin();
            RLock lock = redissonClient.getLock("FIND_CAR_" + vehiclePosition.getVin());
            lock.lock(10, TimeUnit.SECONDS);
            try {
                // 查询车辆状态
                R<XpVehicle> vehicleR = xpVehicleClient.findByVehicleVin(vehicleVin);
                if (vehicleR.getCode() != 200) {
                    continue;
                }
                XpVehicle vehicleId1 = vehicleR.getData();
                if (vehicleId1.getStatus() != 1 || vehicleId1.getState() != 0) {
                    lock.unlock();
                    continue;
                }
                //  关闭巡游单子 TODO
                PushOrderDto pushOrderDto = new PushOrderDto();
                pushOrderDto.setOrderId(data.getId());
                pushOrderDto.setVin(vehiclePosition.getVin());
                // 调用推送服务  orderId + carVin
                orderMissionClient.pushOrder(pushOrderDto);
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        }
    }
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/service/impl/XpOrderServiceImpl.java
@@ -8,6 +8,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ImmutableMap;
import com.xiaopeng.api.dto.account.GetUserCouponDto;
import com.xiaopeng.api.dto.automaticPilot.PushOrderDto;
import com.xiaopeng.api.dto.operation.LonLatDto;
import com.xiaopeng.api.dto.order.GetOrderNumDto;
import com.xiaopeng.api.dto.order.HistoryEndPointsDto;
@@ -20,6 +21,7 @@
import com.xiaopeng.api.dto.vehicleConvoy.BaseVehicleUserDto;
import com.xiaopeng.api.feignClient.account.XpAppUserClient;
import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient;
import com.xiaopeng.api.feignClient.automaticPilot.OrderMissionClient;
import com.xiaopeng.api.feignClient.operation.XpPointClient;
import com.xiaopeng.api.feignClient.operation.XpPricingClient;
import com.xiaopeng.api.feignClient.operation.XpSystemSettingClient;
@@ -40,7 +42,9 @@
import com.xiaopeng.api.model.vehicleConvoy.XpFleet;
import com.xiaopeng.api.model.vehicleConvoy.XpVehicle;
import com.xiaopeng.api.vo.account.UserCouponVo;
import com.xiaopeng.api.vo.automaticPilot.proto.down.cloudOrderOperation.OrderOperationType;
import com.xiaopeng.api.vo.order.*;
import com.xiaopeng.api.vo.vehicleConvoy.AddTaxiPassengerVo;
import com.xiaopeng.api.vo.vehicleConvoy.CancelTaxiPassengerVo;
import com.xiaopeng.common.core.constant.CacheConstants;
import com.xiaopeng.common.core.domain.R;
@@ -127,6 +131,7 @@
    private final XpSystemSettingClient xpSystemSettingClient;
    private final OrderTrajectoryService orderTrajectoryService;
    private final XpPushMessageClient xpPushMessageClient;
    private final OrderMissionClient orderMissionClient;
    @Autowired
    private MongoTemplate mongoTemplate;
@@ -726,7 +731,6 @@
        // TODO 加配置文件取
        cancelTaxiPassengerVo.setAppId("");
        BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.cancelTaxiPassenger(cancelTaxiPassengerVo);
        if (baseVehicleUserDto.getCode() != 200) {
            throw new RuntimeException("取消订单失败");
@@ -749,6 +753,13 @@
            Integer i = Integer.valueOf(cacheObject.toString());
            redisService.setCacheCancelOrder("CANCEL_ORDER_" + uid, i + 1);
        }
        // 下发命令
        PushOrderDto pushOrderDto = new PushOrderDto();
        pushOrderDto.setOrderId(order.getId());
        pushOrderDto.setVin(xpVehicle.getVehicleVin());
        pushOrderDto.setOperation_type(OrderOperationType.VEHICLE_CANCEL_ORDER);
        orderMissionClient.cancelOrder(pushOrderDto);
    }
    @Override
@@ -769,7 +780,10 @@
        xpOrderCancelService.save(xpOrderCancel);
        // 推送消息
        R<XpVehicle> xpVehicleR = xpVehicleClient.queryById(order.getVehicleId());
        XpVehicle xpVehicle = xpVehicleR.getData();
        // 消息推送
        Map<String, Object> params = new HashMap<>();
        Map<String, Object> content = new HashMap<>();
@@ -784,6 +798,13 @@
        sendMessageDTO.setAppUserId(String.valueOf(order.getAppUserId()));
        xpPushMessageClient.sendStatus(sendMessageDTO);
        log.info("订单取消消息推送完毕");
        // 下发命令
        PushOrderDto pushOrderDto = new PushOrderDto();
        pushOrderDto.setOrderId(order.getId());
        pushOrderDto.setVin(xpVehicle.getVehicleVin());
        pushOrderDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER);
        orderMissionClient.cancelOrder(pushOrderDto);
    }
    /**
@@ -817,6 +838,7 @@
        evaluate.setFeedbackContent(dto.getFeedbackContent());
        evaluate.setFeedbackPictures(dto.getFeedbackPictures());
        evaluate.setFeedbackTypeId(dto.getFeedbackTypeId());
        evaluate.setCreateTime(LocalDateTime.now());
        xpOrderEvaluateService.save(evaluate);
    }
@@ -1743,8 +1765,11 @@
            orderDetailVo.setFeedbackPictures(evaluate.getFeedbackPictures());
            orderDetailVo.setFeedbackContent(evaluate.getFeedbackContent());
            orderDetailVo.setOrderRating(evaluate.getOrderRating());
            XpFeedbackType feedbackType = xpSystemSettingClient.getFeedbackTypeById(evaluate.getFeedbackTypeId()).getData();
            orderDetailVo.setFeedbackTypeName(feedbackType.getFeedbackType());
            if(evaluate.getFeedbackTypeId()!=null){
                XpFeedbackType feedbackType = xpSystemSettingClient.getFeedbackTypeById(evaluate.getFeedbackTypeId()).getData();
                orderDetailVo.setFeedbackTypeName(feedbackType.getFeedbackType());
            }
        }
        List<OrderTrajectory> trajectories = mongoTemplate.find(
                new Query(Criteria.where("orderId").is(orderId))
@@ -1776,35 +1801,35 @@
    @Transactional
//    @ShardingTransactionType(TransactionType.BASE)
    public void popOrder(PopOrderDto dto) {
        XpOrder order = this.getById(dto.getOrderId());
        order.setAcceptanceTime(LocalDateTime.now());
        AddTaxiPassengerVo addTaxiPassengerVo = new AddTaxiPassengerVo();
        R<XpVehicle> byVehicleVin = xpVehicleClient.findByVehicleVin(dto.getXpVehicleVin());
        if (byVehicleVin.getCode() == 200) {
            order.setVehicleId(byVehicleVin.getData().getId());
            addTaxiPassengerVo.setVin(byVehicleVin.getData().getVehicleVin());
        }
        order.setStatus(2);
        // Redis弹出这个队列元素
        // value 订单Id_经纬度_状态_用户id_订单编号_距离_时间
        String popFirstElement = redisService.popFirstElement(order.getQueueName());
        XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity();
        String[] split = popFirstElement.split("_");
        xpGeoQueryEntity.setOrderId(split[0]);
        String[] split1 = split[1].split(",");
        xpGeoQueryEntity.setLocation(new GeoJsonPoint(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])));
        xpGeoQueryEntity.setTimestamp(new Date());
        // 计算2个时间的秒数
        LocalDateTime createTime = order.getCreateTime();
        LocalDateTime acceptanceTime = order.getAcceptanceTime();
        xpGeoQueryEntity.setSeconds((int) Duration.between(createTime, acceptanceTime).getSeconds());
        String currentTimeSlot = DateUtils.getCurrentTimeSlot();
        xpGeoQueryEntity.setTime(currentTimeSlot);
        // 存mongo数据
        xpPricingClient.saveXpGeoQueryEntity(xpGeoQueryEntity);
        this.updateById(order);
        addTaxiPassengerVo.setUid(order.getAppUserId().toString());
        addTaxiPassengerVo.setOrderNo(order.getOrderNumber());
        // TODO appid
        addTaxiPassengerVo.setAppId("");
        BaseVehicleUserDto baseVehicleUserDto = userVehicleClient.addTaxiPassenger(addTaxiPassengerVo);
        if(baseVehicleUserDto.getCode()==200){
            // Redis弹出这个队列元素
            // value 订单Id_经纬度_状态_用户id_订单编号_距离_时间
            String popFirstElement = redisService.popFirstElement(order.getQueueName());
            XpGeoQueryEntity xpGeoQueryEntity = new XpGeoQueryEntity();
            String[] split = popFirstElement.split("_");
            xpGeoQueryEntity.setOrderId(split[0]);
            // 存mongo数据
            xpPricingClient.updateXpGeoQueryEntity(split[0]);
            this.updateById(order);
        }
    }
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/test/GpsPoint.java
New file
@@ -0,0 +1,13 @@
package com.xiaopeng.order.test;
import lombok.Data;
import java.util.Date;
@Data
public class GpsPoint {
    private Double distance;   // 与上一点距离(米)
    private Long locatetime;   // 毫秒时间戳
    private Date createTime;   // 创建日期
    // ... getter & setter
}
xp-robotaxi-order-boot/src/main/java/com/xiaopeng/order/test/TaxiPricingDemoService.java
New file
@@ -0,0 +1,300 @@
package com.xiaopeng.order.test;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
/**
 * 出租车计费引擎服务
 */
public class TaxiPricingDemoService {
    public static void main(String[] args) {
        PricingConfig config = setupMockConfig();
        Calendar cal = Calendar.getInstance();
        cal.set(2026, Calendar.MARCH, 13, 14, 40, 15);
        Date orderTime = cal.getTime();
        // 模拟总里程 25.0 km,以触发多级远途加价
        double totalMillige = 7.874;
        // 模拟 GPS 轨迹点
        List<GpsPoint> points = createMockGpsPoints(orderTime);
        TaxiPricingService service = new TaxiPricingService();
        Map<String, BigDecimal> bill = service.calculateOrderPrice(orderTime, totalMillige, points, config);
        System.err.println("======= 订单计费账单 =======");
        bill.forEach((detail, price) -> System.err.println(detail + ": " + price + " 元"));
        BigDecimal totalAmount = bill.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        System.err.println("--------------------------");
        System.err.println("应付总额: " + totalAmount + " 元");
    }
    public static class TaxiPricingService {
        public Map<String, BigDecimal> calculateOrderPrice(Date orderTime, double totalMileageKm, List<GpsPoint> points, PricingConfig config) {
            Map<String, BigDecimal> result = new LinkedHashMap<>();
            BigDecimal totalMileage = BigDecimal.valueOf(totalMileageKm);
            PricingRule baseRule = config.findMatchedRule(orderTime);
            result.put("起步价(" + baseRule.ruleName + ")"+"-"+baseRule.start+"-"+baseRule.end, baseRule.baseFare);
            if (totalMileage.compareTo(baseRule.baseKm) <= 0) {
                return formatMap(result);
            }
            BigDecimal remainBaseM = baseRule.baseKm.multiply(new BigDecimal("1000"));
            BigDecimal remainBaseMs = baseRule.baseMin.multiply(new BigDecimal("60000"));
            BigDecimal currentTotalM = BigDecimal.ZERO;
            BigDecimal currentTotalMs = BigDecimal.ZERO;
            boolean isOverBaseM = false;
            boolean isOverBaseMs = false;
            // 超出里程和分钟数的集合
            Map<String, BigDecimal> bill = new LinkedHashMap<>();
            Map<String, BigDecimal> activeRuleNameRate = new LinkedHashMap<>();
            Set<String> activeRuleNameList = new HashSet<>();
            for (int i = 1; i < points.size(); i++) {
                GpsPoint curr = points.get(i);
                GpsPoint prev = points.get(i - 1);
                BigDecimal segM = BigDecimal.valueOf(curr.getDistance());
                BigDecimal segMs = BigDecimal.valueOf(curr.getLocatetime() - prev.getLocatetime());
                currentTotalM = currentTotalM.add(segM); // 累计当前已行驶的总里程
                currentTotalMs = currentTotalMs.add(segMs); // 累计当前已行驶的总时间
                PricingRule activeRule = config.findMatchedRule(new Date(curr.getLocatetime()));
                // 扣除起步额度逻辑
                BigDecimal billM = BigDecimal.ZERO;
                if (currentTotalM.compareTo(remainBaseM) > 0) {
//                    billM = currentTotalM.subtract(remainBaseM);
                    isOverBaseM = true;
                }
                BigDecimal billMs = BigDecimal.ZERO;
                if (currentTotalMs.compareTo(remainBaseMs) > 0) {
//                    billMs = currentTotalMs.subtract(remainBaseMs);
                    isOverBaseMs = true;
                }
                // 1. 基础费率计算
//                BigDecimal distFee = billM.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP).multiply(activeRule.perKmRate);
//                BigDecimal timeFee = billMs.multiply(activeRule.perMinRate);
                // 2. 远途加价计算 (基于区间判定)
//                BigDecimal longExtra = calculateLongDistExtra(currentTotalM, billM, config.longSteps);
//                BigDecimal totalSeg = distFee.add(timeFee).add(longExtra);
                // 超出里程
                if (isOverBaseM) {
                    bill.put(activeRule.ruleName + "-"+activeRule.start + "-" + activeRule.end + "_Ml", bill.getOrDefault(activeRule.ruleName + activeRule.start + "-" + activeRule.end + "_Ml", BigDecimal.ZERO).add(segM));
                }
                // 超出时间
                if (isOverBaseMs) {
                    bill.put(activeRule.ruleName + "-"+activeRule.start + "-" + activeRule.end + "_Ms", bill.getOrDefault(activeRule.ruleName + activeRule.start + "-" + activeRule.end + "_Ms", BigDecimal.ZERO).add(segMs));
                }
                // 若不存在规则名称,则添加
                activeRuleNameRate.computeIfAbsent(activeRule.ruleName + "-"+activeRule.start + "-" + activeRule.end + "_Ml", k -> activeRule.perKmRate); // 超出里程的加价
                activeRuleNameRate.computeIfAbsent(activeRule.ruleName + "-"+activeRule.start + "-" + activeRule.end + "_Ms",k ->activeRule.perMinRate); // 超出时间的加价
                activeRuleNameList.add(activeRule.ruleName + "-"+activeRule.start + "-" + activeRule.end + "_Ml");
                activeRuleNameList.add(activeRule.ruleName + "-"+activeRule.start + "-" + activeRule.end + "_Ms");
//                result.put(activeRule.ruleName, result.getOrDefault(activeRule.ruleName, BigDecimal.ZERO).add(totalSeg));
            }
            // 1. 基础费率计算
            for (String ruleName : activeRuleNameList) {
                String[] split = ruleName.split("_");
                if(ruleName.endsWith("_Ml")){
                    BigDecimal exceedValue = bill.get(ruleName);
                    if(Objects.nonNull(exceedValue)){
                        exceedValue = exceedValue.divide(new BigDecimal(1000), 2, RoundingMode.HALF_UP);
                    }else{
                        exceedValue = BigDecimal.ZERO;
                    }
                    BigDecimal exceedRate = activeRuleNameRate.get(ruleName);
                    result.put(split[0], result.getOrDefault(split[0], BigDecimal.ZERO).add(exceedValue.multiply(exceedRate)));
                }else{
                    BigDecimal exceedValue = bill.get(ruleName);
                    if(Objects.nonNull(exceedValue)){
                        exceedValue = exceedValue.divide(new BigDecimal(60000), 2, RoundingMode.HALF_UP);
                    }else{
                        exceedValue = BigDecimal.ZERO;
                    }
                    BigDecimal exceedRate = activeRuleNameRate.get(ruleName);
                    result.put(split[0], result.getOrDefault(split[0], BigDecimal.ZERO).add(exceedValue.multiply(exceedRate)));
                }
            }
            // 2. 远途加价计算 (基于区间判定)
            BigDecimal longExtra = calculateLongDistExtra(BigDecimal.valueOf(totalMileageKm), config.longSteps);
            result.put("远途费", longExtra);
            return formatMap(result);
        }
        /**
         * 远途加价核心逻辑:判断当前行驶到的里程处于哪个加价区间
         */
        private BigDecimal calculateLongDistExtra(BigDecimal billM, List<LongRangeStep> steps) {
            if (billM.compareTo(BigDecimal.ZERO) <= 0) return BigDecimal.ZERO;
            // 当前点所在的公里数
            BigDecimal extraStart = BigDecimal.ZERO;
            BigDecimal extraRate = BigDecimal.ZERO;
            // 匹配区间规则
            for (LongRangeStep step : steps) {
                if (step.isMatch(billM)) {
                    extraRate = step.addPrice;
                    extraStart = step.numStart;
                    break;
                }
            }
            return billM.subtract(extraStart).multiply(extraRate);
        }
        private Map<String, BigDecimal> formatMap(Map<String, BigDecimal> map) {
            return map.entrySet().stream().collect(Collectors.toMap(
                    Map.Entry::getKey, e -> e.getValue().setScale(2, RoundingMode.HALF_UP), (a, b) -> b, LinkedHashMap::new));
        }
    }
    // --- 远途区间模型 ---
    public static class LongRangeStep {
        BigDecimal numStart; // 超过公里数
        BigDecimal numEnd;   // 不足公里数
        BigDecimal addPrice; // 加收单价
        public LongRangeStep(double start, double end, double price) {
            this.numStart = BigDecimal.valueOf(start);
            this.numEnd = BigDecimal.valueOf(end);
            this.addPrice = BigDecimal.valueOf(price);
        }
        public boolean isMatch(BigDecimal currentKm) {
            // [numStart, numEnd)
            return currentKm.compareTo(numStart) >= 0 && currentKm.compareTo(numEnd) < 0;
        }
    }
    public static class PricingConfig {
        PricingRule holiday;
        PricingRule peak;
        PricingRule night;
        List<PricingRule> normals = new ArrayList<>();
        List<LongRangeStep> longSteps = new ArrayList<>(); // 修改为区间列表
        public PricingRule findMatchedRule(Date date) {
            LocalTime t = date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
            if (holiday.isMatch(t)) return holiday;
            if (peak.isMatch(t)) return peak;
            if (night.isMatch(t)) return night;
            for (PricingRule r : normals) if (r.isMatch(t)) return r;
            return normals.get(0);
        }
    }
    public static class PricingRule {
        String ruleName;
        LocalTime start, end;
        BigDecimal baseFare, baseKm, baseMin, perKmRate, perMinRate;
        public PricingRule(String n, String s, String e, double bf, double bk, double bm, double pkr, double pmr) {
            this.ruleName = n;
            this.start = LocalTime.parse(s);
            this.end = LocalTime.parse(e);
            this.baseFare = BigDecimal.valueOf(bf);
            this.baseKm = BigDecimal.valueOf(bk);
            this.baseMin = BigDecimal.valueOf(bm);
            this.perKmRate = BigDecimal.valueOf(pkr);
            this.perMinRate = BigDecimal.valueOf(pmr);
        }
        public boolean isMatch(LocalTime now) {
            return start.isBefore(end) ? (!now.isBefore(start) && !now.isAfter(end)) : (!now.isBefore(start) || !now.isAfter(end));
        }
    }
    public static class GpsPoint {
        private double distance;
        private long locatetime;
        public GpsPoint(double d, long t) { this.distance = d; this.locatetime = t; }
        public double getDistance() { return distance; }
        public long getLocatetime() { return locatetime; }
    }
    private static PricingConfig setupMockConfig() {
        PricingConfig config = new PricingConfig();
        config.peak = new PricingRule("高峰期", "14:40", "14:46", 15.0, 3.0, 5.0, 3.0, 0.8);
        config.night = new PricingRule("夜间行驶", "14:47", "14:48", 18.0, 3.0, 5.0, 3.5, 1.0);
        config.holiday = new PricingRule("节假日", "18:47", "18:48", 18.0, 3.0, 5.0, 4, 2.0);
        config.normals.add(new PricingRule("普通时段", "14:46", "14:47", 10.0, 3.0, 5.0, 2.4, 0.5));
        config.normals.add(new PricingRule("普通时段", "14:48", "17:59", 10.0, 3.0, 5.0, 2.4, 0.5));
        // --- 远途加价区间配置 (关键修改) ---
        // 1. 超过 num1(12) 不足 num2(20), 加收 num3(1.2)
        config.longSteps.add(new LongRangeStep(5.0, 6.0, 1.2));
        // 2. 超过 num4(20) 不足 num5(35), 加收 num6(2.0)
        config.longSteps.add(new LongRangeStep(6.0, 7.0, 2.0));
        // 3. 超过 num7(35) 以后, 加收 num8(3.5) -> numEnd 传个极大值
        config.longSteps.add(new LongRangeStep(7.0, 8.0, 3.5));
        return config;
    }
    private static List<GpsPoint> createMockGpsPoints(Date startTime) {
        List<GpsPoint> list = new ArrayList<>();
        long startTs = startTime.getTime();
        list.add(new GpsPoint(0, startTs));
        // 模拟行驶了 20km
        list.add(new GpsPoint(120, startTs + 2 * 10 * 1000));
        list.add(new GpsPoint(204, startTs + 2 * 20 * 1000));
        list.add(new GpsPoint(231, startTs + 2 * 30 * 1000));
        list.add(new GpsPoint(252, startTs + 2 * 40 * 1000));
        list.add(new GpsPoint(188, startTs + 2 * 50 * 1000));
        list.add(new GpsPoint(150, startTs + 2 * 60 * 1000));
        list.add(new GpsPoint(126, startTs + 2 * 70 * 1000));
        list.add(new GpsPoint(138, startTs + 2 * 80 * 1000));
        list.add(new GpsPoint(119, startTs + 2 * 90 * 1000));
        list.add(new GpsPoint(147, startTs + 2 * 100 * 1000));
        list.add(new GpsPoint(155, startTs + 2 * 110 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 120 * 1000));
        list.add(new GpsPoint(172, startTs + 2 * 130 * 1000));
        list.add(new GpsPoint(202, startTs + 2 * 140 * 1000));
        list.add(new GpsPoint(162, startTs + 2 * 150 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 160 * 1000));
        list.add(new GpsPoint(132, startTs + 2 * 170 * 1000));
        list.add(new GpsPoint(142, startTs + 2 * 180 * 1000));
        list.add(new GpsPoint(262, startTs + 2 * 190 * 1000));
        list.add(new GpsPoint(242, startTs + 2 * 200 * 1000));
        list.add(new GpsPoint(282, startTs + 2 * 210 * 1000));
        list.add(new GpsPoint(222, startTs + 2 * 220 * 1000));
        list.add(new GpsPoint(212, startTs + 2 * 230 * 1000));
        list.add(new GpsPoint(142, startTs + 2 * 240 * 1000));
        list.add(new GpsPoint(262, startTs + 2 * 250 * 1000));
        list.add(new GpsPoint(169, startTs + 2 * 260 * 1000));
        list.add(new GpsPoint(170, startTs + 2 * 270 * 1000));
        list.add(new GpsPoint(180, startTs + 2 * 280 * 1000));
        list.add(new GpsPoint(165, startTs + 2 * 290 * 1000));
        list.add(new GpsPoint(180, startTs + 2 * 300 * 1000));
        list.add(new GpsPoint(198, startTs + 2 * 310 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 320 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 330 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 340 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 350 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 360 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 370 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 380 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 390 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 400 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 410 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 420 * 1000));
        list.add(new GpsPoint(182, startTs + 2 * 430 * 1000));
        return list;
    }
}
xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/controller/XpVehicleController.java
@@ -404,6 +404,20 @@
        XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getVehicleVin, vehicleVin));
        return R.ok(xpVehicle);
    }
    /**
     * 根据XPUID查询车辆信息
     * @param xpuid
     * @return
     */
    @GetMapping("/inner/vehicle/findByVehicleXpuId")
    public R<XpVehicle> findByVehicleXpuId(@RequestParam("xpuid") String xpuid){
        XpVehicle xpVehicle = xpVehicleService.getOne(new LambdaQueryWrapper<XpVehicle>().eq(XpVehicle::getXpuId, xpuid));
        return R.ok(xpVehicle);
    }
    /**
     * 查询可改派的车辆列表
     *
xp-robotaxi-vehicleConvoy-boot/src/main/java/com/xiaopeng/vehicleConvoy/service/impl/XpVehicleServiceImpl.java
@@ -7,6 +7,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaopeng.api.dto.vehicleConvoy.VehicleTemperatureDto;
import com.xiaopeng.api.feignClient.automaticPilot.XpuVinClient;
import com.xiaopeng.api.feignClient.operation.XpElectronicClient;
import com.xiaopeng.api.feignClient.order.XpOrderClient;
import com.xiaopeng.api.model.operation.XpElectronicFence;
@@ -37,6 +38,7 @@
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
@@ -65,6 +67,9 @@
    @Autowired
    private IXpVehicleAnnualRecordService xpVehicleAnnualRecordService;
    @Resource
    private XpuVinClient xpuVinClient;
    @Override
    public List<XpVehicle> listByIds(List<Long> ids) {
@@ -191,6 +196,10 @@
        xpVehicle.setStatus(1);
        // 设置入库时间
        xpVehicle.setWarehousingTime(LocalDateTime.now());
        //绑定XPUID
        String vin = xpVehicle.getVehicleVin();
        String xpuid = xpuVinClient.getXpuIdByVin(vin).getData();
        xpVehicle.setXpuId(xpuid);
        this.save(xpVehicle);
    }
@@ -200,6 +209,10 @@
        // DTO转实体
        XpVehicle xpVehicle = new XpVehicle();
        BeanUtil.copyProperties(dto, xpVehicle);
        //绑定XPUID
        String vin = xpVehicle.getVehicleVin();
        String xpuid = xpuVinClient.getXpuIdByVin(vin).getData();
        xpVehicle.setXpuId(xpuid);
        this.updateById(xpVehicle);
    }